第4章:工具调用——Agent 怎么「做事」

本章解决的核心问题:LLM 只能生成文字,它怎么能「调 API」「搜网页」「写文件」?Function Calling 到底是什么?MCP 又是什么?Agent 乱调工具怎么办?

读完这一章,你会理解 Agent 工具调用的每一个技术细节——从 JSON schema 到执行沙箱,从 MCP 协议到安全策略。


4.1 一个核心认知:LLM 从来不是「执行者」

assets/ai-agent-comics/ch04-01-waiter-host.webp
🎨 漫画图解:〈服务员不亲自炒菜〉

先把一个最容易被误解的点说清楚:

LLM 不会执行任何东西。它只会生成文字。 当你看到 Agent 「搜索了网页」「发了邮件」「写了个文件」——真正执行这些操作的不是 LLM,而是 LLM 之外的宿主程序

LLM 的角色是决策者:它告诉你「我想调用搜索工具,关键词是『新能源汽车销量 2025』」。然后宿主程序收到这个指令,真的去调了搜索 API,把结果拿回来,告诉 LLM「你搜到了这些内容」。然后 LLM 再决定下一步。

sequenceDiagram
    participant User as 👤 用户
    participant Host as 🖥️ 宿主程序
    participant LLM as 🧠 LLM
    participant Tool as 🔧 外部工具

    User->>Host: 「帮我查天气」
    Host->>LLM: Prompt: 用户要查天气,你可以用 get_weather 工具
    LLM->>Host: 我想调用 get_weather(city="北京")
(这是一个 JSON 格式的指令) Host->>Tool: 真的去调天气 API Tool-->>Host: 返回:北京 晴 26°C Host->>LLM: 工具返回结果:北京 晴 26°C
请继续回答用户 LLM->>Host: 「北京今天晴天,气温 26°C。」 Host->>User: 「北京今天晴天,气温 26°C。」

LLM 说的不是「我来查天气」,而是「请帮我查天气」。 前者是执行,后者是决策。这个区别至关重要。


4.2 Function Calling 的完整流程

assets/ai-agent-comics/ch04-02-function-call.webp
🎨 漫画图解:〈一张工具订单的旅行〉

Function Calling(函数调用)是目前最主流的 Agent 工具调用方式。OpenAI 在 2023 年 6 月首次引入,现在几乎所有大模型都支持。

第一步:定义工具

开发者需要提前告诉 LLM:「你可以用哪些工具,每个工具叫什么、干什么、需要什么参数。」

一个工具的 JSON Schema 定义长这样:

{
  "name": "search_web",
  "description": "在互联网上搜索信息。当你需要获取实时信息或验证事实时使用。",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "搜索关键词"
      },
      "num_results": {
        "type": "integer",
        "description": "返回结果数量,默认 5,最大 10",
        "default": 5
      }
    },
    "required": ["query"]
  }
}

这个 JSON 告诉 LLM 三件事:

第二步:LLM 决定调用

当用户的请求需要工具时,LLM 不会直接回答——它会输出一个工具调用指令

{
  "tool_calls": [
    {
      "function": {
        "name": "search_web",
        "arguments": "{\"query\": \"2025年新能源汽车销量排行榜\"}"
      }
    }
  ]
}

注意:LLM 的输出依然是文本——只是格式是结构化的 JSON。宿主程序解析这个 JSON,提取函数名和参数。

第三步:宿主程序执行

宿主程序收到 search_web 的调用请求后,实际去执行搜索结果——调 Google API、Bing API 或 Tavily。

第四步:结果返回给 LLM

宿主程序把搜索结果格式化,作为一条新的消息追加到对话中:

工具 search_web 返回结果:
1. 2025年1-6月新能源汽车销量:比亚迪160万辆、特斯拉...
2. 中汽协:2025上半年新能源渗透率达45%...
3. ...

第五步:LLM 基于结果继续

LLM 看到工具返回的结果,基于这些信息生成最终回答——也可能决定「信息不够,再搜一次」或「换个工具」。

flowchart TB
    A[👤 用户输入] --> B{🧠 LLM 判断}
    B -->|「我能直接回答」| C[💬 直接输出文本]
    B -->|「我需要用工具」| D[📤 输出工具调用 JSON]
    D --> E[🖥️ 宿主程序执行工具]
    E --> F[📥 工具返回结果]
    F --> B
    C --> G[✅ 最终回答]

4.3 工具描述怎么写:一个好的 Tool Definition

assets/ai-agent-comics/ch04-03-tool-definition.webp
🎨 漫画图解:〈工具说明书决定成败〉

工具描述的质量直接影响 Agent 的表现。一个写得很烂的工具定义,LLM 要么不会用,要么用错。

烂的工具定义

{
  "name": "do_stuff",
  "description": "做事情",
  "parameters": {
    "properties": {
      "x": {"type": "string"}
    }
  }
}

LLM 根本不知道这个工具是干什么的、什么时候该用、参数 x 应该填什么。

好的工具定义

{
  "name": "create_obsidian_note",
  "description": "在 Obsidian vault 中创建一篇新的 Markdown 笔记。使用场景:用户要求「记下来」「创建笔记」「新建一篇关于XX的文档」。注意:如果目标路径已存在同名文件,需要询问用户是否覆盖。",
  "parameters": {
    "type": "object",
    "properties": {
      "file_path": {
        "type": "string",
        "description": "笔记文件的相对路径,例如 'notes/会议记录/2025-01-15 周会.md'。必须以 .md 结尾。"
      },
      "content": {
        "type": "string",
        "description": "笔记的完整 Markdown 内容。建议包含 YAML frontmatter。"
      },
      "tags": {
        "type": "array",
        "items": {"type": "string"},
        "description": "可选的标签列表,会写入 frontmatter 的 tags 字段。例如 ['meeting', 'weekly']"
      }
    },
    "required": ["file_path", "content"]
  }
}

一个好工具定义的三个要素

  1. 清晰的使用场景:告诉 LLM「什么时候该用这个工具,什么时候不该用」。
  2. 精确的参数说明:每个参数的意义、格式、约束、示例。
  3. 边界条件提示:工具有什么限制?什么情况下会失败?

4.4 MCP:Agent 世界的 USB-C

assets/ai-agent-comics/ch04-04-mcp-market.webp
🎨 漫画图解:〈MCP 万能工具集市〉

2024 年 11 月,Anthropic 开源了 MCP(Model Context Protocol)——一个 Agent 与外部工具和数据源通信的开放标准。

为什么需要 MCP?

在 MCP 出现之前,Agent 工具调用的生态是一团乱麻:

flowchart TB
    subgraph 没有 MCP 的时代
        Agent1[Claude] -->|专属适配| Gmail1[Gmail 插件]
        Agent1 -->|专属适配| GitHub1[GitHub 插件]
        Agent1 -.->|不支持| DB1[数据库插件]
        Agent2[ChatGPT] -->|专属适配| Gmail2[Gmail 插件]
        Agent2 -.->|不支持| GitHub2[GitHub 插件]
        Agent2 -->|专属适配| DB2[数据库插件]
    end

每个工具需要为每个 Agent 单独开发适配器。N 个 Agent × M 个工具 = N × M 个适配器。碎片化到令人绝望。

MCP 的方案

MCP 定义了一个标准协议——Agent 只需要实现 MCP 客户端,工具只需要实现 MCP 服务端。一个工具开发一次,任何支持 MCP 的 Agent 都能用。

flowchart TB
    subgraph 有 MCP 的时代
        Agent1[Claude] --> MCP[MCP 协议]
        Agent2[ChatGPT] --> MCP
        Agent3[开源 Agent] --> MCP
        MCP --> Tool1[Gmail]
        MCP --> Tool2[GitHub]
        MCP --> Tool3[数据库]
        MCP --> Tool4[文件系统]
        MCP --> Tool5[任意工具...]
    end

MCP 的角色就是 Agent 世界的 USB-C——一个统一的接口标准。任何实现了 MCP 的工具(无论是 Google Drive、PostgreSQL 还是你的 Obsidian vault),都能被任何支持 MCP 的 Agent 调用。

MCP 的架构

┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│  MCP 客户端  │ ◄─────► │  MCP 协议   │ ◄─────► │  MCP 服务端  │
│  (Agent 侧)  │  JSON-RPC │  (传输层)   │  JSON-RPC │  (工具/数据)  │
└─────────────┘         └─────────────┘         └─────────────┘

为什么你应该关心 MCP

因为在第7章你做 Obsidian Agent 时,你可能想让 Agent 不只搜索笔记,还能读邮件、查日历、更新数据库——用了 MCP,这些能力就变成「USB 式」的了。一个工具写好一次,未来所有 Agent 项目都能复用。


4.5 工具调用的安全与权限

assets/ai-agent-comics/ch04-05-safety-gate.webp
🎨 漫画图解:〈工具城的五道安全门〉

Agent 有了「动手能力」,也意味着它有了「搞破坏」的能力。一个被恶意利用的 Agent——或者一个判断失误的 Agent——可能:

安全策略

策略 做法 效果
白名单 只允许调用预定义的几类工具 最安全,但灵活性受限
人工确认 在执行高危操作前弹窗让用户确认 安全 + 灵活,但打断体验
沙箱 在隔离环境中执行工具,限制文件系统和网络访问 Docker 容器级别的安全
速率限制 限制每轮对话的工具调用次数 防止无限循环烧钱
审计日志 记录每一次工具调用及其结果 出问题时能追溯

Claude Code 的安全设计是一个好参考:它在执行写操作之前会请求用户确认,每轮对话限制工具调用频率,所有操作都有日志。在第7章做 Obsidian Agent 时,我们也会实现基本的安全策略。


4.6 工具调用的常见翻车

翻车1:参数幻觉

LLM 有时会「编」一个参数。比如工具要求 file_path 必须是 .md 结尾,LLM 可能输出 file_path: "my_note.txt"——格式不对。

解法:宿主程序侧做参数校验,格式不对的直接拒绝并告诉 LLM 正确格式。

翻车2:工具选择错误

用户说「帮我查一下最近有什么 AI 新闻」,LLM 可能去调用「读取本地文件」工具而不是「搜索网页」工具。

解法:工具描述写清楚使用场景。在 Prompt 中加入工具选择的指引。

翻车3:死循环

LLM 反复调用同一个工具但得不到期望的结果,陷入「调工具 → 结果不对 → 再调一次 → 还是不对」的循环。

解法:设置最大调用轮次(比如 20 轮),超过后强制终止并让 LLM 总结当前结果。这是 Claude Code 的默认策略。


本章小结

要点 一句话
LLM 不执行 LLM 只会「说它想调什么」,真正执行的是宿主程序
Function Calling LLM 输出一个 JSON,宿主程序解析并执行
工具定义 好描述 = 使用场景 + 参数说明 + 边界条件
MCP Agent 世界的 USB-C——统一工具调用标准
安全三件套 白名单 + 人工确认 + 调用次数限制
翻车预防 参数校验、工具选择指引、最大轮次限制

下一章预告

前三章我们搞懂了 Agent 的架构、RAG 和工具调用,但还有一个根本问题悬而未决:Agent 的行动能力到底是怎么学来的? 它不是「提示词工程」吗?还是 Agent 经过了特殊的训练?

下一章是整个系列技术含量最高的一章:Agent 的训练三阶段、强化学习怎么让 Agent 从失败中学、为什么 Agent 训练比 LLM 难一个数量级。

第5章:Agent 是怎么被训练出来的


← 上一章 回到目录 下一章 →
第3章:RAG 第5章:Agent 是怎么被训练出来的