第四章学习笔记:给 Agent 装上手脚之后,怎样让它用对工具?

本文是对第四章《工具》的学习整理。上一篇:第三章学习笔记:Agent 真正的记忆,不是保存,而是想对。

一张报销单,为什么需要一整套工具设计?

假设我对 Agent 说:“把这张发票报销了,填好系统,提交前让我看一眼。”

它需要先读懂发票图片,找到报销规则,再查询项目和预算;随后填写表单、上传附件,最后在提交这个会改变业务状态的动作前停下来。仅仅列出 read_pdf、search_policy、fill_form、submit_expense 四个函数,并不能保证它做对。

我读第四章时抓住的主线是:工具设计是在规定 Agent 能看见什么、能改变什么,以及每一步如何被检查。 模型的能力决定它能否想出下一步;工具的接口则决定这个想法能否忠实、安全地落到真实世界。

这条主线可以拆成三个问题:

  1. 能力怎样表达? 做成专用工具、通用执行器,还是一份可查阅的 Skill?
  2. 能力怎样被找到? 工具越来越多时,一次给模型看多少?
  3. 调用怎样可信? 输入、输出、权限、执行结果和失败后的重试,怎样形成闭环?

先分清五类工具:同样是“调用”,后果并不一样

第四章沿用第一章的五类工具,但重点展开由 Agent 主动调用的前三类。

类型 报销场景中的例子 设计时最该盯住什么
感知 读发票、查政策、查预算 返回的信息是否完整、可定位、可继续读取
执行 写报销单、上传文件、提交申请 权限、副作用、验证与重试
协作 请财务 Agent 核对规则、请我确认 交接边界、来源、等待与取消
用户沟通 发进度卡片、提醒补材料 消息如何跨渠道送达
事件触发 财务审批完成后唤醒 Agent 如何注册并处理异步事件

一个常见误会是按 MCP 服务器给工具分类。 同一台“文件服务器”既可能提供只读的 read_file,也可能提供会删除内容的 delete_file。服务器或产品名称并不能替代对每个动作后果的判断。书中也把用户沟通和事件触发的深入设计留到第六章,因为它们离不开异步运行时。

第一处取舍:给 Agent 一个按钮,还是给它一套工作台?

报销提交可以被做成 submit_expense:字段固定、权限清楚、便于审计。读取不同格式的附件,则可以交给一个通用的 read_document;处理偶发的表格转换,也许只需受限的代码执行器加一份 Skill。

我会用四个判断来选择能力形态:

要问的问题 倾向的形式 原因
动作是否高风险、需要精确授权和审计? 专用工具 可以把许可范围收紧到具体动作
参数是否有复杂嵌套和联合约束? 专用工具 结构化 schema 更容易校验
步骤是否经常变化、主要是操作指引? Skill + 通用工具 修改文档和脚本的成本较低
任务是否开放、需要组合未知步骤? 通用执行器 让模型用代码或命令组织流程

这里的 ACI(Agent-Computer Interface) 很有启发:工具应围绕 Agent 要完成的目标设计,而不是把每个底层 API 端点机械地包装一遍。十个只负责搬运字段的小工具,可能让 Agent 在一张报销单上来回传参十次;一个边界清楚的目标级接口,反而更容易使用。

但“通用工具优先”是一种设计起点,不是一张无限授权书。若把报销系统的生产写权限直接交给 shell,再用 Skill 文字要求 Agent 小心,就失去了专用接口能提供的强约束。能力越开放,越需要在执行环境、权限和验证上补足约束。

工具描述,首先要教会模型“什么时候用”

书中强调的不是堆砌参数名,而是写清调用决策。对两个搜索工具而言,下面的差别就很实在:

find_file:按文件名查找,适合已知文件名或后缀;无法搜索文件内容。若要找发票号在何处出现,请用 search_file_content。

这段描述同时给出了使用时机和反例。参数格式也应给可照着填的例子,例如时间字段注明时区、精度和样例值。返回值要说明哪些字段可以信任、何时会分页、是否可能截断。

如果 Agent 反复选错工具,我会先检查这些描述,而不是立即换模型。工具说明本身就是模型做决策时看到的界面。

保真性:Agent 看到的参数必须是实际执行的参数

第四章有一个很容易被忽视的故障:参数传递层悄悄把中文弯引号改成英文直引号,导致 Agent 明明复制了文件里的原文,却始终无法精确替换。类似地,后台偷偷给命令追加参数,也会让模型在错误原因上反复猜测。

这提醒我,工具接口最基本的契约并非“帮模型智能修正”,而是把转换讲清楚,并把实际执行内容反馈回来。对报销来说,如果工具自动把含税金额改成未税金额,却只返回“提交成功”,模型和用户都失去了核对的机会。

第二处取舍:能力可以很多,但不能把所有说明书摊在桌上

能力的表达形式和一次展示多少能力是两道独立的题。即使全部使用 MCP,也可以只展示索引、需要时再加载完整 schema;即使全部使用 Skills,目录大到一定程度仍然需要组织和搜索。

第四章介绍了从轻到重的几种办法:

少量核心工具常驻
    ↓
按任务预筛候选工具
    ↓
Agent 遇到能力缺口时主动搜索
    ↓
需要操作细节时再读取 Skill 或完整 schema

我喜欢把 Skill 想成工具书:启动时只看目录,遇到“怎样上传带附件的报销单”才翻相关章节。MCP 更像统一插座,解决外部工具如何接入;Skill 更像可查阅的工作说明。两者可以配合,MCP 服务器也能供给 Skill。它们并不是必须二选一的产品阵营。

渐进披露还有一个与第二章的上下文工程笔记直接相连的好处:减少无关 schema 占用的上下文,并尽量保持静态前缀稳定。书中引用了按需加载、主动发现降低 token 消耗或改善工具选择的案例数据;这些是原书转述的案例与实验结论,我没有在本笔记中独立复现。具体系统的收益仍要用自己的任务集测。

这里也有代价:动态发现可能找错工具,漏掉真正需要的工具,或在调用中途改变模型可见的能力集合。所以“未找到”必须是明确结果,而不是悄悄挑一个最像的工具凑数。

第三处取舍:感知工具应该给线索,而不是倾倒全文

回到报销例子,搜索政策时,我希望先得到“标题、来源、摘要、更新时间”的候选列表,再决定读哪一条。如果搜索工具直接把几十份政策全文塞进上下文,Agent 反而更容易漏掉关键例外。

我会检查感知工具是否具备三种能力:

  • 可逐步深入:搜索先给候选,读取支持 offset、limit 或分页游标;
  • 截断要明示:告诉 Agent 已显示哪一段、总量多少、怎样继续读;
  • 结果可追溯:保留来源位置和足够的结构,便于核对原文。

静默截断尤其危险。Agent 可能看到政策前 200 行就断言“没有例外条款”,而真正的限制写在第 250 行。上下文压缩能帮忙控制体积,却不能替代明确的“还有内容未读”。

感知动作通常是只读的,所以独立读取和搜索适合并行,也容易缓存。但“只读”并不等于信息永远有效:预算余额、审批状态这类数据会变化,缓存需要有效期或重新查询的规则。

图片、PDF 和音频:先问自己会丢掉什么

发票图片能走三条路径:主模型直接看图、先 OCR 成文本、或调用专门的图像分析工具后只返回提取结果。选择依据不是“哪条最先进”,而是任务依赖什么信息。

如果只需发票号和金额,文本提取可能便宜且足够;如果要判断盖章位置、表格行列对应或涂改痕迹,仅有文字可能丢掉证据;如果主模型不支持视觉,工具化分析能把问题和图片一起交给另一个模型。

我的补充判断是:对于会影响报销金额的字段,最好同时保留原始附件与提取位置。多模态工具的简短答案方便推理,但后续仍需要回到原图核对。

第四处取舍:执行工具必须回答“真的发生了什么”

写入报销草稿与点击“正式提交”,在 UI 里也许只差一个按钮,在系统设计上却是两类动作。前者通常可修改、可预览;后者可能触发审批、记账或通知。

第四章给执行工具安排了多层保障,我把它理解成一条从意图到证据的链:

检查输入与权限 → 评估风险 → 执行操作 → 核对真实结果 → 记录并反馈
  • 输入校验与权限:路径、数据类型、配额先由确定性代码检查;敏感写操作只暴露所需范围。简单命令黑名单不足以挡住变形调用。
  • 事前审查:不可逆或影响重大的动作,可以让独立审核视角检查收款方、金额、目标环境与用户意图;必要时交给人确认。模型审核会降低部分错误风险,却不能替代权限控制。
  • Sidecar 门控:对单次工具调用的结构化参数做快速风险分类,在放行前不执行。它的任务比全面评估业务合理性窄,因此可以使用较轻的审查模型。
  • 事后验证:写代码后运行 linter,提交表单后查询记录状态。返回“API 调用成功”与“用户目标完成”不是一回事。

还有两处工程细节特别值得记住。

其一,venv 只隔离 Python 依赖,不隔离文件、网络或进程权限。通用执行器要靠真正的系统权限、容器或虚拟机约束,并限制资源消耗。

其二,超时不等于失败。提交报销请求超时后,系统可能已经建单;立即重试可能产生重复申请。能由服务端支持的操作应使用唯一请求标识去重;否则要先查询状态,再决定是否重试。对于邮件、电话等对外动作,更应先核对是否已经发生。

我认为这里最深的一句是:执行工具的返回值应该描述外部世界的状态,而不只是描述函数有没有抛异常。

协作工具:把任务交出去,还要能收回来

当报销涉及陌生税务规则,主 Agent 可以请专门的 Agent 核对;当提交需要我的判断,它需要请求人工确认。这两种协作都要求交接清楚:目标是什么、提供了哪些证据、谁有权决定、结果用什么格式返回。

对子 Agent,第四章归纳了创建、发消息、取消、发现等基本原语。它们不只是“多开几个模型”。真正的难点在于:主 Agent 是否传了足够但不过量的上下文;子 Agent 是否能区分用户原话、主 Agent 的指令和工具返回;子任务失去意义时能否及时取消。

对人工介入,不能只弹一个“请批准”按钮就算完成设计。人可能暂时不在线,因此还要定义等待、超时、提醒和保守的默认处理。人的批准、拒绝及理由也可以成为后续改进规则或 Skill 的证据。

在报销例子中,“提交前让我看一眼”就是明确的任务边界。Agent 可以先把材料整理到可审阅的状态,但正式提交需要把具体金额、归属项目和附件清单呈现给我,而不是用一句模糊的“是否继续”代替。

如果我现在要设计一套工具,会先问这七件事

  1. 这个工具读取信息,还是会改变真实世界?
  2. 它的名称和说明能否让模型知道何时使用、何时不能使用?
  3. 输入是否原样传递;若有规范化,模型能否看到实际执行的值?
  4. 输出是否保留来源、分页方式、截断标记和错误原因?
  5. 能否只展示当前任务需要的能力,并在找不到时明确反馈?
  6. 超时、取消或重试后,如何确认副作用是否已经发生?
  7. 哪些动作需要自动验证,哪些动作需要独立审查或人工决定?

这些问题比“再接入多少个 MCP 服务器”更接近任务完成率。第三方 MCP 服务器和 Skill 还会扩大信任边界:描述文字可能携带提示注入,Skill 可能包含本地执行的代码。接入时要审查内容、控制版本和凭证权限,而不是把“能安装”误当成“可信任”。

写在最后

读完第四章,我对“Agent 有工具”这句话多了一层警惕。工具数量是能力的清单,不是可靠性的证明。

一套好的工具系统,会让 Agent 找到正确的能力、看见足够的证据、忠实传递参数、在风险前停下、在执行后核对。这样模型的推理才能变成可追踪的行动;否则,再聪明的模型也可能在一个静默截断的结果、一次隐藏的参数转换,或一次超时后的盲目重试里把事情做错。

第四章配套实验记录

实验4-1:主动工具发现(Active Tool Discovery)

在 127 个 MCP 工具的目录下,主动发现方案与全量注入方案均完成 3/3 个任务,工具选择准确率均为 100%;按需注入将单任务 schema 从 50,597 tokens 降至 1,853~6,092 tokens,端到端总耗时由 1,766 秒降至 282 秒。

查看完整实验记录