前四篇走完了 Model I/O、Chains 和 RAG,所有流程都有一个共同点:执行路径是开发者预先编排好的。这一篇进入四大模块的最后一个——Agents,核心转变只有一句话:把"下一步做什么"的决定权交给模型。本篇讲清楚工具调用的底层机制,以及如何用 create_agent 搭出第一个能自主行动的智能体;MCP、记忆与中间件放在下一篇。

一、从 Chain 到 Agent:为什么链不够用#

Chain 的工作方式是固定流程:输入按照 prompt | model | parser 的顺序流过每一步,路径在写代码时就定死了。这在很多场景下运行得很好,但有一类问题它天然处理不了——你事先不知道该走哪条路。

举个例子,用户说:"帮我查查北京明天会不会下雨,如果下雨,取消我明天的户外预约。"完成这个任务需要先调天气接口,再根据查到的结果做判断,下雨才调日程接口。问题在于,"是否取消预约"这个分支取决于运行时才知道的天气结果,每次用户输入不同,要走的路径也不同——你没法把它硬编码成一条固定的链。

Agent 的思路是:把模型当作"大脑",让它自己决定下一步做什么。

代码
Chain:开发者编排流程,模型负责执行 → "你告诉它怎么做"
Agent:模型自主编排流程,工具负责执行 → "你告诉它要做什么,它自己想怎么做"

一个完整的 Agent 通常由几个部件协作运转:大模型(大脑,负责推理和规划)、工具(手脚,负责和外部世界交互)、记忆(记住之前发生了什么)、规划与行动(把任务拆解并逐步执行)。其中最基础、也最值得先搞懂的是工具——没有工具的 Agent 就像一个只会说话但没有手脚的人,什么实际操作也完成不了。

二、工具调用的本质:Function Calling#

在写第一行 Agent 代码之前,必须先破除一个误解:模型自身并不能执行任何工具。所谓"工具调用",底层是大模型的 Function Calling 能力,完整流程是这样的:

  1. 你定义工具(函数名 + 参数说明 + 功能描述);
  2. 框架把工具信息转成 JSON Schema,随提示词一起发给模型;
  3. 模型阅读工具描述,根据用户问题决定要调用哪个工具、传什么参数;
  4. 模型返回的不是答案,而是一条**"工具调用指令"**;
  5. 你的代码在本地执行对应的函数;
  6. 执行结果拼回消息列表再发给模型,模型继续推理或给出最终回复。

模型的角色是"调度员"而不是"执行者"。这也直接推出一个重要结论:工具的描述写得好不好,决定了模型能不能正确地选择和调用它——描述就是你和模型之间的说明书。

为了体感这个机制,先看不用 LangChain、直接用 OpenAI SDK 的原生写法(理解原理用,实际开发不需要这样写):

Python
from openai import OpenAI
import json

client = OpenAI()

# 第1步:手写 JSON Schema 描述工具
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "获取指定城市在指定日期的天气",
        "parameters": {
            "type": "object",
            "properties": {
                : {: , : },
                : {: , : },
            },
            : [, ],
        },
    },
}]


 ():
       


messages = [{: , : }]
response = client.chat.completions.create(model=, messages=messages, tools=tools)


messages.append(response.choices[].message)
 tool_call  response.choices[].message.tool_calls  []:
    args = json.loads(tool_call.function.arguments)
    result = get_weather(**args)
    messages.append({
        : ,
        : tool_call.,
        : json.dumps({: result}),
    })


final = client.chat.completions.create(model=, messages=messages, tools=tools)
(final.choices[].message.content)