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