乐于分享
好东西不私藏

AI笔记之LangChain工具封装与 Agent 构建 — 知识汇总

AI笔记之LangChain工具封装与 Agent 构建 — 知识汇总
AI笔记之

工具封装与 Agent 构建 — 知识汇总

了解AI,拥抱变化

主题:LangChain工具封装与Agent构建 + 智能体多工具调用机制

整体架构总览

一、天气查询工具的动态化封装

1.1 城市编码动态获取

将原本硬编码的城市标识修改为动态参数 city_code。用户输入城市名(如"北京"、"太原")后,先调用 get_city_code 函数获取对应的城市编码,再将该编码传递给天气 API 进行查询,从而实现不同城市天气的动态获取。

1.2 响应数据精简优化

原始 API 返回的 JSON 数据冗余较多,需提取关键字段:实时温度和天气状况。通过 response.json() 获取数据,依据官网文档层级结构,从 data['result']['real_time'] 中提取具体数值。最终输出格式化为简洁字符串,例如:"天气晴,温度 XX 度",提升信息可读性。

二、LangChain 工具注册机制

2.1 @tool 装饰器的作用

普通 Python 函数无法被 LangChain 智能体直接识别,必须使用 @tool 装饰器进行修饰。装饰后,智能体可通过内省机制读取函数的功能描述、参数定义等元数据,从而理解该工具的用途及调用方式。

from langchain.tools import tool

@tool

def get_weather(city: str) -> str:

    """调用天气查询接口,实时查询城市的天气"""

    # ... 函数实现

    return f"天气:{wd}, 温度:{temp}摄氏度"

关键要点:

  • @tool 装饰器自动解析函数元数据,生成标准 JSON Schema

  • Schema 包含:函数名称、功能描述(docstring)、参数名称与类型、必填项标识

  • docstring 内容会被大模型读取,用于判断何时调用该工具

  • 函数必须有 docstring,否则报 ValueError

  • 装饰后函数变为 StructuredTool 对象,不能用 () 直接调用,需用 .invoke()

三、智能体执行工作流

智能体调用工具的核心流程分三步:

意图解析。 接收用户输入的 Prompt 需求,智能体分析并解析用户的具体意图。

工具匹配。 根据解析后的意图判断是否需要调用工具,在已注册的工具列表中匹配最合适的工具。

执行与反馈。 执行对应的 Python 函数获取天气数据结果,将执行结果整合进最终回复,返回给用户。

四、单工具与多工具调用

4.1 单工具调用

from langgraph.prebuilt import create_react_agent

tools = [get_weather]

agent = create_react_agent(chat, tools)

result = agent.invoke({"messages": [("user", "今天上海天气怎么样?")]})

print(result["messages"][-1].content)

4.2 多工具调用

只需将新工具名称添加到现有的工具序列中即可,智能体支持注册多个工具(2个、5个或10个以上)。

tools = [get_weather, cheng]

agent = create_react_agent(chat, tools)

questions = ["今天上海天气怎么样", "2乘3等于几"]

for q in questions:

    result = agent.invoke({"messages": [("user", q)]})

    print(f"Q: {q}")

    print(f"A: {result['messages'][-1].content}\n")

确保内存中存在对应的函数定义是工具被成功调用的前提条件。

五、多场景综合测试验证

构建包含三个问题的测试集:

结论: 系统能准确区分可调用工具的任务与不可处理的任务,并给出相应响应。智能体应具备清晰的工具边界意识,对于未注册工具对应的需求,应优雅降级为文本建议而非强行调用或报错。

六、智能体代码实现细节

7.1 关键组件导入与创建

  • 导入 create_react_agent 用于创建智能体(langgraph 包)
  • LLM 对象:复用之前配置的大语言模型实例(如智谱 AI 模型)
  • 工具列表:将已装饰的函数封装为列表传入

7.2 提示词模板

create_react_agent 内部已内置 ReAct prompt,不需要手动 hub.pull。ReAct 范式定义了推理与行动的循环逻辑:思考 → 选择工具 → 观察结果 → 再思考 → 最终回答。

7.3 执行日志查看

遍历 result["messages"] 可查看完整执行过程:

for msg in result["messages"]:

    print(f"[{type(msg).__name__}] {msg.content if msg.content else msg.tool_calls}")

输出示例:

[HumanMessage] 今天上海天气怎么样?

[AIMessage] tool_calls=[{'name': 'get_weather', 'args': {'city': '上海'}}]

[ToolMessage] 天气:晴,温度:28摄氏度

[AIMessage] 上海今天晴,温度28°C

七、常见问题排查与核心要点

变量未定义错误: 确保工具函数在调用前已正确定义并导入,tools 列表需在 create_react_agent 之前定义。

索引越界错误:检查输入数据的结构,确保 Prompt 输入格式正确(如使用字典 {"messages": [...]} 而非纯字符串),避免解析失败导致的下标越界。

参数类型错误: 模型可能将参数封装为字符串而非独立类型,采用"宽松输入+内部解析"策略(如接收字符串后正则提取)比强制要求模型输出特定 JSON 格式更具鲁棒性。

工具抽象的重要性:将业务逻辑(如天气查询)封装为标准化工具并通过装饰器注册,是实现 LLM 能力扩展的关键,使得模型能像调用本地函数一样使用外部服务。

Prompt 模板化策略:create_react_agent 内置 ReAct 模板,大幅降低构建复杂 Agent 的门槛,同时保证推理逻辑的稳定性。

调试可视化的必要性:在 Agent 开发初期,通过遍历 messages 观察模型的"思考链"(Chain of Thought),是定位工具调用失败或逻辑偏差的最有效手段。

接口兼容性设计:当 LLM 无法精确传递结构化参数时,采用"宽松输入+内部解析"的策略(如接收字符串后正则提取)比强制要求模型输出特定 JSON 格式更具鲁棒性。

工具边界管理:智能体应具备清晰的工具边界意识,对于未注册工具对应的需求,应优雅降级为文本建议而非强行调用或报错。