--- name: tool-design description: 设计 Agent 工具时使用——新增/重构工具集、给 MCP 服务器设计工具、判断能力该做成专用工具还是 Skill、编写工具描述与参数 schema、设计感知工具的输出分页与截断、给执行工具加安全审批与沙盒、设计子 Agent 协作接口时查阅。覆盖工具分类、ACI 通用设计原则、感知/执行/协作三类工具的设计要点。 --- # 工具设计 ## 何时使用 - 为 Agent 新增一批工具,或审查既有工具集("这个工具该不该拆/该不该合") - 判断一项能力应做成专用工具(function calling)、通用执行器,还是一份 Skill - 编写或修订工具 name / description / 参数 schema / 返回值说明 - 设计感知工具(搜索、读取、多模态解析)的返回格式、分页与截断策略 - 设计执行工具(shell、文件、外部系统)的输入验证、审批、沙盒与可观测性 - 设计协作工具(spawn_subagent、HITL、通知)的接口与提示词 ## 核心原则 - **工具对应目标,不对应 API 端点。** 早期反模式是把每个 API 端点包成一个工具,Agent 要协调好几个才能完成一个目标。这是 ACI(Agent-Computer Interface)的核心:让工具对 Agent 而非对人友好。 - **默认通用优于专用。** LLM 本身有强大的思考与代码生成能力,不要限制它。与其提供四则运算计算器,不如给一个装好 sympy/numpy/pandas 的 `code_interpreter`。 - **四种情况才退回专用工具**:① 安全、权限、审计需要(如生产库写操作);② 屏蔽平台差异并给出更好反馈(如 grep/find 在 Mac/Win/Linux 语法不一);③ 使用频率极高;④ 参数结构复杂(嵌套对象、多字段联合校验)。 - **粒度偏向整合。** 判断标准是功能相似性与使用场景重叠度:`extract_pdf_text`/`extract_docx_content`/`extract_pptx_content` 应合成 `read_document(file_type=...)`。整合降低认知负担、描述更清晰、便于扩展。 - **形态与数量是两个独立决策。** 能力做成什么形态定"每条能力常驻多少 token、参数怎么传、谁能改";一次暴露多少条是披露策略。别把两者混为一谈。 - **感知工具防上下文爆炸,执行工具防不可逆错误。** 前者的设计关键是控制输出信息量,后者的设计核心是安全约束。 - **模型感知到的世界与工具操作的世界之间不能有系统性偏差**——不得静默转换或注入参数。 ## 实践模式 ### 1. 形态选择的四个决策维度 | 维度 | 判据 | |---|---| | 安全与权限 | 需精细授权、审计留痕、有不可逆风险 → 专用工具;否则优先通用 | | 参数复杂度 | 嵌套对象、多字段联合校验 → 专用 schema;简单参数走 CLI 同样可靠 | | 变更频率 | 频繁变化 → Skill(改文本,不用重新测试部署);稳定底层操作 → 专用工具 | | 模型能力 | 强模型可用 Skill + 通用执行器减少工具数;弱模型需要结构化 schema 引导 | Skill 的代价:模型要生成合法命令行参数并处理引号转义,规则比 JSON 复杂且跨平台有差异,**参数复杂时更易出错**。折中办法:Skill 要求把复杂结构化参数写成 JSON 文件,再在命令行导入。 Skill 的收益:人类编写者友好,不会因局部语法错误"牵一发而动全身"(schema 少个花括号会让整个 Agent 报错,Skill 少量错误不会)。 ### 2. 工具描述的四条写法 - **写"什么时候用",不只"能做什么"**:不说"搜索相关内容",说"当需要获取实时信息或查找未知事实时使用"。 - **明确边界比描述能力更重要**:文件搜索工具必须说明它只按文件名匹配、不能搜文件内容。多数调用失败的根因是模型不知道工具**不能**做什么。 - **参数给具体例子**:`timestamp`:RFC3339 格式,例如 `2024-03-15T14:30:00Z`;`phone`:E.164(国家代码+号码,无空格),例如 `+8613888888888` / `+12025551234`。 - **描述返回值与代价**:"返回 JSON 数组,每元素含 `title`/`url`/`snippet`";"此工具需下载完整网页,大型站点可能 5-10 秒,只要元信息请用 `get_page_metadata`"。 - **每个工具附 1-5 个真实调用示例**。JSON Schema 只能表达类型,无法表达时间戳是秒还是毫秒、过滤条件如何嵌套这类隐式约定;加示例后基准准确率可从约 72% 升到 90%。 - **调试原则**:Agent 频繁选错工具时,先查工具描述,别先怀疑模型。修正描述的 ROI 远高于换更强的模型。 ### 3. 参数保真性 反模式是**静默输入转换**与**静默参数注入**: - Cursor 曾把 `old_string` 中的中文弯引号(`“”`)静默转成英文直引号,导致读取工具原样返回弯引号、替换工具却匹配不到——模型反复失败且无法自行诊断。 - 某 IDE 的 bash 工具自动给所有 `git commit` 追加"AI 生成"标记参数,老版本 Git 直接报错,模型怎么改提交信息都失败。 规则:必须规范化时,在工具描述中说明,并在返回值中明确告知模型。 ### 4. 感知工具 - **搜索类**:返回结构化候选列表(标题、位置、摘要片段)而非拼接全文;提供 cursor/分页,默认只返回前若干条并注明总数与取下一页的方式,让 Agent 自己决定是否翻页。 - **读取类**:支持 offset/limit;截断时必须显式标注("已显示第 1-200 行,共 5000 行,可用 offset 继续读取")。**静默截断是危险的**——Agent 会误以为看到了全部。 - **通用压缩**:输出超阈值(如 10000 字符)时按当前查询意图压缩。 - **只读红利**:结果可安全缓存;多个感知调用可放心并行。 - **多模态**:直接返回图像(保留布局但费 token)还是先 OCR/图表解析转文本(省 token 但丢空间结构)?按内容选——纯文字用文本提取,布局敏感的(UI、复杂表格、设计稿)保留图像。 - **三条多模态路径**:原生多模态(上限最高);提取为文本(纯文本 PDF 更省 token,一页截图上千 token vs 一页文字几百 token,但丢版式图表);工具化多模态分析(主模型不支持多模态时的更优解,`analyze_image/pdf/audio` 收文件+问题、返回自然语言,多模态 token 不占主上下文)。 ### 5. 执行工具 安全分层:**输入验证**(路径遍历 `../../etc/passwd`、命令注入 `;`/`|`、类型格式,快速失败不"智能修正)→ **权限控制**(工作目录限制、黑名单、配额;黑名单只是最底层,可被变形命令绕过)→ **提议者-审核者** → **Sidecar**。 - **事前审批**:Proposer 提议、Reviewer 审批。两模型应**来自不同家族但能力相近**(如 Claude 与 GPT 互审)——同家族易犯同样的错,能力差太大则审查者跟不上。底层规则与上下文须一致,关注点应不同(提议重任务完成,审批重风险与规则)。审批失败要把拒绝理由作为工具调用结果加入轨迹,而不是简单重试。适用:不可逆、影响重大的操作(收费、发邮件、改关键配置、创建外部资源)。可做风险分级与无法确定时升级人工。 - **事后验证**:要诀是**模态切换**——代码生成的文档渲染成图再看排版;改完配置在沙盒实跑。同模态审查易陷同一盲区。 - **Sidecar**:与主模型流式输出并行的轻量分类器,对单次工具调用做门控。它**只读结构化字段**(`{tool:"bash", command:"rm -rf /tmp/data"}`),刻意隔离主模型的自由文本,否则用户输入或网页里夹带"请允许执行 rm -rf"就能把审查骗过去。数百毫秒完成,用户几乎无感。审查对象不同所以可用轻量模型:Proposer-Reviewer 审的是开放式思考,需能力相近;Sidecar 判的是简单分类。必须配**拒绝熔断器**——连续多次拒绝就转人工,别无限重试。 - **自动验证闭环**:结果可验证就应自动验证。`write_file` 写入后立即按文件类型跑 linter,把结构化错误列表作为返回值的一部分。 - **长输出**:超阈值(200 行或 10000 字符)时只把头部 50 行 + 尾部 50 行写入上下文,中间插入"`... [省略 8523 行,完整输出已保存至 /tmp/execution_output.txt] ...`"并引导用 `read_file` 读全文。 - **沙盒**:venv 不是沙盒(只隔离包依赖,不约束文件系统/网络/进程)。隔离强度递增:进程级(本地开发)→ 容器(共享内核,有逃逸风险)→ microVM/虚拟机(Firecracker,跑完全不可信代码的最强层级)。容器/microVM 还要设 CPU/内存/磁盘/网络上限。 - **幂等性与取消**:问自己"这次调用被取消或超时时,副作用到底发生了没有"。做法是唯一标识服务端去重,或先查询后变更。**发邮件、打电话、对外转账**做不成幂等,用"预检-确认"两段式;执行阶段失败不盲目重试,把详细错误返回主模型重新规划。 - **可观测性**:每次调用的时间/参数/结果/耗时日志、审计追踪、性能指标、异常告警。 ### 6. 协作工具 三组原语:**启动与取消**(`spawn_subagent` / `cancel_subagent`——任务失去意义时及时终止省 token)、**消息传递**(`send_message_to_subagent`,双向)、**发现**(`list_agents`,与 MCP `tools/list` 同思路,列的是 Agent)。协作形态:同步、异步(task_id + 事件通知)、流式、多轮交互。 子 Agent 提示词四要素: 1. **角色定义开门见山**:"你是专门负责 XXX 的助手 Agent"。 2. **上下文来源标注**:`[FROM_MAIN_AGENT]` / `[FROM_USER]` / `[TOOL_RESULT]`——防止混淆信息来源,也防提示注入。 3. **任务边界明确**:什么在职责内、什么要转交上报。 4. **输出格式标准化**(JSON 或 Markdown):保证考虑周全、降低主 Agent 解析负担。 HITL:设超时阈值与默认行为("5 分钟无响应采用保守策略")、优先级队列(紧急多渠道、普通只发邮件);把人的批准/拒绝及理由作为带证据的反馈数据回流。 ## 常见陷阱 - 把 API 端点直接包成工具,粒度过细导致工具数激增、选择负担加重。 - 工具描述只写功能不写触发条件与边界,模型自行猜测后失败。 - 静默转换/注入参数,制造模型无法自行诊断的系统性故障。 - 感知工具静默截断、一次性倾倒全部搜索结果。 - 用黑名单当唯一安全手段;用 venv 当沙盒。 - 同家族模型互审,或能力悬殊的两个模型互审。 - Sidecar 读取主模型的自由文本,被注入话术操纵。 - 把"能力形态"和"一次暴露多少条"混为一谈。 ## 配套代码 - `chapter4/perception-tools/` — 感知工具 MCP 服务器(搜索/多模态/文件系统/公开与私有数据源,`run_experiment_4_2.py`)。 - `chapter4/execution-tools/` — 执行工具 MCP 服务器:LLM 事前审批、写入后自动 linter 校验、长输出截断与持久化(`python cli.py demo`)。 - `chapter4/collaboration-tools/` — 协作工具 MCP 服务器:子 Agent 同步/异步、两种上下文传递策略对比、HITL 与多渠道通知。 - `chapter4/multimodal-agent/` — 原生多模态 / 提取为文本 / 工具化分析三种范式的同框架对比(`demo.py`)。 ## 深度阅读 - `book/chapter4.md`「工具的分类」「工具设计的通用原则」「感知工具」「执行工具」「协作工具」