6.2 工具集成与 API 编排:选择、组合与编排 一个 Agent 不会只用一个工具。真实的 Agent 身后往往站着几十上百个工具——查天气、查股价、发邮件、写数据库、调内部 API……怎么管这些工具、怎么让 LLM 在海量工具里挑对的、怎么把多个工具串成一条流水线、怎么处理调用失败,是本节的主题。 6.2.1 工具管理的核心挑战 当工具数量从几个增长到几十上百个,新的工程挑战浮现: 挑战 | 表现 工具过多 | 全塞 Prompt 会爆窗口、冲淡注意力 工具相似 | 多个工具功能重叠,LLM 易选错 依赖复杂 | 工具调用之间有先后依赖 错误传播 | 一个工具失败影响后续整条链 版本管理 | 工具会升级,旧调用可能失效 6.2.
一个 Agent 不会只用一个工具。真实的 Agent 身后往往站着几十上百个工具——查天气、查股价、发邮件、写数据库、调内部 API……怎么管这些工具、怎么让 LLM 在海量工具里挑对的、怎么把多个工具串成一条流水线、怎么处理调用失败,是本节的主题。
当工具数量从几个增长到几十上百个,新的工程挑战浮现:
| 挑战 | 表现 |
|---|---|
| 工具过多 | 全塞 Prompt 会爆窗口、冲淡注意力 |
| 工具相似 | 多个工具功能重叠,LLM 易选错 |
| 依赖复杂 | 工具调用之间有先后依赖 |
| 错误传播 | 一个工具失败影响后续整条链 |
| 版本管理 | 工具会升级,旧调用可能失效 |
所有工具由工具注册表(Tool Registry) 统一管理。它是一个工具的「目录」,记录每个工具的元信息:
| 字段 | 内容 |
|---|---|
| name | 工具名(唯一标识) |
| description | 描述(给 LLM 看) |
| parameters schema | 参数定义 |
| handler | 实际执行的函数/端点 |
| permission | 权限要求(只读/写/高危) |
| version | 版本号 |
| category | 分类(信息/计算/通信/系统) |
| cost | 调用成本(用于预算控制) |
注册表不仅是「目录」,还是 Agent 调用工具的唯一入口——所有调用必须经过注册表,便于统一校验、审计、限流。
💡 注册表的核心价值是「唯一入口」:没有注册表,LLM 调啥就执行啥,安全无从保障;有了注册表,所有调用都过一道闸门(权限校验、版本检查、审计日志)。这是 Agent 安全的第一道工程防线。
当工具数量超过 20-30 个,不能把它们全塞进 Prompt——会冲淡 LLM 注意力,反而降低选择准确率。这时需要工具检索(Tool Retrieval)——根据当前任务,动态挑出最相关的几个工具暴露给 LLM。
工具检索的流程几乎复用 RAG(5.3 节):
| 维度 | RAG | 工具检索 |
|---|---|---|
| 检索对象 | 文档 | 工具描述 |
| 目的 | 补知识 | 缩小工具范围 |
| 索引 | 文档向量 | 工具 description 向量 |
| Top-K | 通常 3-5 | 通常 5-10 |
⚠️ 工具检索的常见坑:description 写得不好(太短、太抽象),会导致检索召回不准——明明该用「send_email」却召回了「post_message」。工具检索的质量,90% 取决于 description 质量。
对超大规模工具集(百上千个),常用层次化组织——先按类别粗筛,再在类内细选:
全部工具(1000+) ├── 信息查询类(100) │ └── (任务命中此类 → 在 100 个里细选) ├── 数据处理类(200) ├── 通信类(50) └── 系统类(80)
两阶段检索:先选大类(用类别 Embedding),再在大类里选具体工具。这与 RAG 的「召回-精排」两阶段思路一致。
当 Agent 需要调用多个工具完成任务,就涉及编排(Orchestration)——按什么顺序、怎么组合。
工具调用一个接一个,前一个的输出是后一个的输入。
Step 1: get_user_id(email="alice@x.com") → uid=123 Step 2: get_orders(uid=123) → orders=[...] Step 3: send_summary(orders) → 发邮件
多个无依赖的工具同时调用,等全部完成后合并。
并行: Step A: get_stock(AAPL) Step B: get_stock(MSFT) Step C: get_stock(GOOGL) 合并: 3 个结果一起送给 LLM 分析
真实任务常是「串并混合」——某些步并行,某些步串行:
Step 2A/2B/2C 并行(都依赖 Step 1,但互不依赖),Step 3 等三者完成后串行。
| 依赖关系 | 编排 |
|---|---|
| A 输出是 B 输入 | 串行 |
| A、B 互不依赖 | 并行 |
| A、B 部分依赖 | 视情况 |
LLM 在规划阶段应当显式标注每步的依赖(这是 Plan-and-Execute、ReWOO 的核心),编排器据此决定并行还是串行。
💡 并行是免费的性能红利:识别无依赖的工具调用、并行执行,能让总延迟降低数倍。这正是 ReWOO、Plan-and-Execute 相对纯 ReAct 的核心优势(第 3.4 节)。
工具调用不可能 100% 成功——API 会超时、参数会错、权限会拒绝。必须有明确的错误处理策略。
| 错误类型 | 例子 | 处理 |
|---|---|---|
| 网络错误 | 超时、连接拒绝 | 指数退避重试 N 次 |
| 参数错误 | 类型错、缺字段 | 错误回喂 LLM 修正 |
| 权限拒绝 | 401/403 | 不重试,换路径或求助 |
| 业务错误 | 余额不足、库存为 0 | 回喂 LLM 决策 |
| 服务不可用 | 5xx | 切换备用工具或降级 |
重试 1: 立即 重试 2: 等 1s 重试 3: 等 2s 重试 4: 等 4s 重试 5: 等 8s → 仍失败则放弃
指数退避避免「惊群效应」——服务出问题时,所有客户端同时重试反而加重负载。
无论哪种错误,都应当格式化后回喂 LLM(6.1 节原则),让 LLM 决定:
工具调用不能无限等。生产 Agent 必须配套超时与预算控制:
| 控制类型 | 做法 |
|---|---|
| 单工具超时 | 每个工具设最大执行时间(如 30s) |
| 任务总超时 | 整个 Agent 任务的最大时长 |
| 调用次数上限 | 单任务最多调用 N 次工具 |
| Token 预算 | 单任务最多消耗 N Token |
| 金钱预算 | 高成本工具(如付费 API)的累计上限 |
任务预算: - 工具调用 ≤ 25 次 - 总时长 ≤ 5 分钟 - Token ≤ 50K - 付费 API 累计 ≤ $1
⚠️ 预算控制是生产 Agent 的强制标配。没有预算控制的 Agent,会在边界任务上「烧钱失控」——一个 100 步的死循环,可能轻松烧掉几十美元。预算必须显式、必须可观测、超限必须降级。
| 反模式 | 表现 | 后果 | 正确做法 |
|---|---|---|---|
| 全工具暴露 | 上百个全塞 Prompt | 注意力稀释 | 工具检索 |
| description 太短 | 一句话 | 检索召回差 | 详细描述 |
| 无依赖分析 | 全串行 | 延迟高 | 识别并行机会 |
| 错误吞掉 | 失败返回空 | Agent 困惑 | 错误回喂 |
| 无重试 | 一次失败就放弃 | 偶然错误毁任务 | 指数退避 |
| 无超时 | 工具卡死全任务等 | 整体超时 | 单工具+总超时 |
| 无预算控制 | 不限次数/Token | 烧钱失控 | 多重预算 |
| 工具版本不管理 | 升级后旧调用失效 | 调用失败 | 版本化注册表 |
工具编排不是孤立的——它与 Agent 范式紧密耦合:
| Agent 范式 | 编排方式 |
|---|---|
| ReAct | 串行为主(每步等观察) |
| ReWOO | 显式标注依赖、并行执行无依赖部分 |
| Plan-and-Execute | 先规划依赖图,再调度执行 |
| 多 Agent | Agent 之间也按编排协作(第 7 章) |
ReWOO 和 Plan-and-Execute 之所以比 ReAct 快,本质就是显式管理工具依赖、最大化并行。理解这一点,就理解了工具编排的工程价值。
下一节《6.3 代码解释器》将讨论让 Agent 自己写代码解决问题——这是函数调用无法覆盖的「未知能力」领域。