← 返回博客
python2026-09-16 11:43:343 分钟 · 879 0

LangChain 原理与实战(四):Tool 与 Agent,让模型自己挑工具

链把步骤写死,Agent 把选择权交给模型。这篇讲清 Tool 怎么定义、模型怎么 bind_tools、AgentExecutor 怎么循环"思考-调工具-看结果",并跑通一个能查天气、能算数的最小智能体。

前面三篇的链,每一步都是你写死的:先检索、再生成、顺序不变。可有些任务你事先不知道要走几步。比如"北京今天适不适合跑步",模型得先查天气,再判断温度风力,可能还要算个体感温度。步骤数取决于查回来的结果。

Agent 就是把这个"下一步调谁"的决定权交给模型。你给它一堆工具,它自己决定调哪个、调几次,直到能回答为止。

工具就是一个带说明的函数

@tool 装饰器,把一个普通函数变成 LangChain 能识别的 Tool。函数的 docstring 会原样告诉模型这个工具干嘛用、什么时候用。

from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """查询指定城市的当前天气,返回温度和天气状况。"""
    # 真实场景这里调天气 API,示例写死
    return f"{city} 今天 22 度,多云,风力 3 级"

@tool
def calculator(expr: str) -> str:
    """计算四则运算表达式,比如 '23*7+4'。"""
    return str(eval(expr))

模型看不到函数体,只看名字、参数 schema 和 docstring。所以 docstring 得写清楚:输入输出是什么、什么时候该用。写得糊,模型就乱调。

把工具绑给模型

现代模型支持"函数调用"(也叫 tool calling):它不直接执行函数,而是返回"我想调 get_weather,参数是北京"这样的意图,由你的代码去真正执行。LangChain 用 bind_tools 把工具列表挂到模型上:

from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini")
model_with_tools = model.bind_tools([get_weather, calculator])

这一步只是让模型"知道"有这两个工具可用,并不会自动循环调用。

AgentExecutor 负责循环

bind_tools 只会跑一轮:模型说要调工具,你执行,把结果塞回去,但模型不会自动接着干。要循环,得用 create_tool_calling_agent + AgentExecutor

from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个爱用工具助理,能调就调,别瞎编。"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(model, [get_weather, calculator], prompt)
executor = AgentExecutor(agent=agent, tools=[get_weather, calculator], verbose=True)

print(executor.invoke({"input": "北京今天适不适合户外跑步?算一下体感温度 22-0.5*3"})["output"])

{agent_scratchpad} 是占位符,运行时会放"模型刚才的思考、调了什么工具、返回了什么"。AgentExecutor 的循环逻辑是:把问题给模型 → 模型返回工具调用 → 你执行并把结果回填 → 再给模型 → 直到模型不再要调工具、直接给答案。verbose=True 能把每一轮打印出来,第一次跑建议开着看它怎么想。

这里和"链"的区别

链是写死的管道,输入进去、输出出来,中间不分叉。Agent 是带循环的控制流:模型每轮决定"调哪个工具、还是直接答",可能调两三次才收尾。代价是行为不如链可预测,好处是能应对你事先编不出的多步任务。

一个判断口径:步骤固定、顺序确定,用链;步骤数取决于中间结果,用 Agent。

给 Agent 加检索能力

Agent 也能直接拿第三篇的 retriever 当工具,让它自己决定"这问题该查资料还是直接答":

from langchain.tools.retriever import create_retriever_tool

retriever_tool = create_retriever_tool(
    retriever,
    "search_docs",
    "搜索公司内部文档,回答产品和政策相关问题时使用。",
)
executor = AgentExecutor(
    agent=create_tool_calling_agent(model, [get_weather, calculator, retriever_tool], prompt),
    tools=[get_weather, calculator, retriever_tool],
)

create_retriever_tool 把 retriever 包成一个 Tool,描述和前两个一样写清楚适用场景,模型自然会按需调用。

这一篇记住什么

  • Tool 是带 docstring 的函数,@tool 一键封装。
  • bind_tools 让模型知道有哪些工具;真正循环靠 AgentExecutor
  • {agent_scratchpad} 承载思考与工具结果,必须有。
  • 步骤写死用链,步骤数不定用 Agent。

下一篇把 RAG、工具、多轮记忆揉到一起,做一个能查你文档、能调接口、还能接着上一句聊的知识库问答 Agent。那是这个系列的综合实战。

相关推荐

本文为原创文章,采用CC BY-NC-SA 4.0协议授权,转载请保留署名与原文链接。原文链接:https://www.wxbuluo.com/article/213