LangChain 最核心的扩展能力

  1. 自定义工具:把任意 Python 函数包装成 LLM 能调用的工具
  2. 自定义链:灵活组装你的业务逻辑,不是简单的 Prompt | LLM

一、自定义工具(Custom Tools)

1. 什么是自定义工具?

简单来说,自定义工具就是把你的 Python 函数包装成 LLM 能理解、能自主调用的工具

比如:

  • 你写一个天气查询函数 → 包装成工具 → LLM 能自主调用查天气
  • 你写一个数据库查询函数 → 包装成工具 → LLM 能自主查数据库
  • 你写一个文件读写函数 → 包装成工具 → LLM 能自主读写文件

2. 自定义工具的 3 个核心要素

(1)@tool 装饰器

把普通 Python 函数变成 LangChain 工具的 “魔法装饰器”。

(2)清晰的 docstring(最重要!)

这是 LLM 的 “工具使用说明书”,LLM 完全靠看 docstring 来判断:

  • 这个工具是做什么的
  • 什么时候用这个工具
  • 参数是什么
  • 返回什么

docstring 写得越清楚,LLM 越会正确调用工具!

(3)正确的参数和返回值

参数要明确类型,返回值要是字符串(方便 LLM 理解)。

二、实战:自定义天气查询工具

我们用 OpenWeatherMap 免费 API 来做天气查询工具,稳定、免费、国内可访问。

1. 准备工作

(1)获取 OpenWeatherMap API Key

  1. 访问 OpenWeatherMap 官网
  2. 注册账号(免费)
  3. 登录后进入「My API Keys」,复制你的 API Key

(2)安装依赖

pip install -U langchain langchain-openai langchain-community python-dotenv requests

三、完整代码:自定义天气工具 + 自定义链 + ReAct Agent

import os
import requests
from dotenv import load_dotenv

# langchain 相关的模块
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import create_react_agent, AgentExecutor, create_tool_calling_agent
from langchain_core.output_parsers import StrOutputParser
from langchain_core.callbacks import BaseCallbackHandler, StdOutCallbackHandler


# 加载环境变量
load_dotenv()

# 配置
OPEN_WEATHER_API_KEY = os.getenv("OPEN_WEATHER_API_KEY")
ZHIPU_API_KEY = os.getenv("ZHIPU_API_KEY")

# 初始化LLM
llm = ChatOpenAI(
    api_key=ZHIPU_API_KEY,
    base_url="https://open.bigmodel.cn/api/paas/v4",
    model='glm-4.6',
    temperature=0.01
)

# 自定义天气查询工具
@tool
def get_weather(city: str) -> str:
    """
    【天气查询专用工具】查询指定城市的实时天气信息
    当用户询问天气、温度、湿度、风速等气象信息时,必须调用此工具
    :param city: 城市名称,支持中文(如“北京”)或英文(如“Beijing”)
    :return: 实时天气信息的字符串,包括温度、湿度、天气描述、风速
    """
    base_url = "https://api.openweathermap.org/data/2.5/weather"
    params = {
        "lon": 116.40, # 经度
        "lat": 39.90, # 纬度
        # "q": city,
        "appid": OPEN_WEATHER_API_KEY,
        "units": "metric", # 摄氏度
        "lang": "zh-CN", # 中文秒速
    }

    try:
        response = requests.get(url=base_url, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()

        # 解析天气数据
        weather_desc = data["weather"][0]["description"]
        temp = data["main"]["temp"]
        humidity = data["main"]["humidity"]
        wind_speed = data["wind"]["speed"]
        city_name = data["name"]

        return (
            f"【{city_name} 实时天气】\n"
            f"天气:{weather_desc}\n"
            f"温度:{temp}℃\n"
            f"湿度:{humidity}%\n"
            f"风速:{wind_speed} m/s"
        )
    except requests.exceptions.RequestException as e:
        return f'天气查询失败:{str(e)}'
    except KeyError:
        return "未找到该城市的天气信息,请检查城市名称是否正确"

# 自定义链 Custom Chain
# 自定义链的两种方式:
# 1. RunnableLambda 最简单 适合简答的
# 2. 继承Runnable 最灵活 适合复杂的逻辑

# 例子1: 用 RunnableLambda 做一个简单的文本长度统计链
def count_text_length(text: str) -> str:
    """统计文本长度的自定义函数"""
    return f"文本长度: {len(text)}个字符"

# 包装成 Runnable
length_counter = RunnableLambda(count_text_length)

# 例子2:组装一个完整的自定义链(翻译 + 长度统计)
translation_prompt = ChatPromptTemplate.from_template(("""把下面的文本翻译成英文:{text}"""))
translation_chain = translation_prompt | llm | StrOutputParser()

# 自定义链: 先翻译 在统计长度
custom_chain = (
    {"text": RunnablePassthrough()}
    | translation_chain
    | (lambda x: {"original": x, "length": count_text_length(x)})
)

# 把自定义工具加入ReAct Agent
# 工具列表 把查询天气的工具加进去
tools = [get_weather]

# ReAct 提示词
prompt = ChatPromptTemplate.from_messages([
    ("system", """
   你是一个强大的智能助手,能通过调用工具解决问题,会调用工具查天气。
   核心规则:
   1.  严格按照「Thought → Action → Observation」的格式执行
   2.  当用户询问天气时,必须调用 get_weather 工具
   3.  只有获取了足够的信息,才能输出 Final Answer
   4.  禁止编造信息
   """),
    ("user", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

# 创建 ReAct Agent
# agent = create_react_agent(llm, tools, prompt)
# 【关键修复】用新版 create_tool_calling_agent,兼容性更好
agent = create_tool_calling_agent(llm, tools, prompt)

agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True, #开启详细日志
    handle_parsing_errors=True,
    callbacks=[StdOutCallbackHandler()]
)

# 主程序
def main():
    print("=== 🚀 Langchain 自定义工具 + 自定义链 + Agent ===")
    print("1. 测试自定义天气工具")
    print("2. 测试自定义链(翻译+长度统计)")
    print("3. 测试 ReAct Agent (自助调用天气工具)")
    print("输入 q 退出\n")
    while True:
        choice = input("请选择功能 (1/2/3/q): ").strip()
        if choice.lower() == "q":
            print("👋 再见!")
            break

        # 测试1: 自定义天气工具
        if choice == "1":
            city = input("请输入城市名称:").strip()
            result = get_weather.invoke(city)
            print(f"\n 🌤️ 天气查询结果:\n {result}\n")

        # 测试2: 自定义链
        elif choice == "2":
            text = input("请输入要翻译的中文文本:").strip()
            result = custom_chain.invoke(text)
            print(f"\n 📄 翻译结果:{result["original"]}")
            print(f"📏 {result["length"]}\n")

        # 测试3:ReAct Agent
        elif choice == "3":
            query = input("请输入你的问题 (比如:北京今天天气怎么样?)").strip()
            result = agent_executor.invoke({"input":query})
            print(f"\n 🤖 Agent最终回答:{result["output"]} ")

        else:
            print("⚠️ 无效选择,请重新输入! \n")

if __name__ == "__main__":
    main()

四、.env 文件配置

DOUBAO_API_KEY=你的豆包APIKey
OPENWEATHER_API_KEY=你的OpenWeatherMapAPIKey

五、代码核心部分详解

1. 自定义天气工具:@tool 装饰器

@tool
def get_weather(city: str) -> str:
    """
    【天气查询专用工具】查询指定城市的实时天气信息
    当用户询问天气、温度、湿度、风速等气象信息时,必须调用此工具
    
    :param city: 城市名称,支持中文(如“北京”)或英文(如“Beijing”)
    :return: 实时天气信息的字符串,包括温度、湿度、天气描述、风速
    """
    # ... 具体实现
  • @tool:把函数变成工具
  • docstring 极其重要:LLM 完全靠它判断什么时候用工具
  • 参数和返回值明确:方便 LLM 理解

2. 自定义链:RunnableLambda

def count_text_length(text: str) -> str:
    return f"文本长度:{len(text)} 个字符"

# 包装成 Runnable
length_counter = RunnableLambda(count_text_length)
  • RunnableLambda:把普通 Python 函数变成 LangChain 可调用的链
  • 可以和其他链用 | 操作符串联

3. 把工具加入 Agent

tools = [get_weather]
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
  • 把自定义工具加入 tools 列表
  • Agent 就能自主判断什么时候调用工具了

六、运行效果演示

测试 1:自定义天气工具

plaintext

请选择功能 (1/2/3/q): 1
请输入城市名称:北京

 🌤️ 天气查询结果:
 【Beijing 实时天气】
天气:clear sky
温度:15.23℃
湿度:12%
风速:1.84 m/s

测试 2:自定义链

请选择功能 (1/2/3/q): 2
请输入要翻译的中文文本:七里香

 📄 翻译结果:“七里香”根据上下文不同,可以翻译为:

1.  **Seven Mile Fragrance** (直译,最通用的翻译)
2.  **Orange Jasmine** 或 **Chinese Box** (植物学名称,指九里香/月橘)
3.  **Common Jasmine Orange** (周杰伦同名专辑及歌曲的官方英文译名)
📏 文本长度: 168个字符

测试 3:ReAct Agent

=== 🚀 Langchain 自定义工具 + 自定义链 + Agent ===
1. 测试自定义天气工具
2. 测试自定义链(翻译+长度统计)
3. 测试 ReAct Agent (自助调用天气工具)
输入 q 退出

请选择功能 (1/2/3/q): 3
请输入你的问题 (比如:北京今天天气怎么样?)北京天气怎么样?


> Entering new AgentExecutor chain...

Invoking: `get_weather` with `{'city': '北京'}`
responded: 我来帮您查询北京的天气情况。

【Beijing 实时天气】
天气:clear sky
温度:15.23℃
湿度:12%
风速:1.84 m/s根据查询结果,北京目前的天气情况如下:

🌤️ **天气状况**:晴朗(clear sky)
🌡️ **温度**:15.23℃
💧 **湿度**:12%
💨 **风速**:1.84 m/s

今天北京天气不错,晴朗的天空,温度适宜,湿度较低,微风轻拂,是个比较舒适的天气。

> Finished chain.

七、总结

  1. 自定义工具的核心@tool 装饰器 + 清晰的 docstring
  2. 自定义链的核心RunnableLambda 或继承 Runnable
  3. Agent 调用工具的核心:把工具加入 tools 列表,LLM 会自主判断
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐