Tool:给模型一个有边界的动作
建议用时:25 分钟(含练习)
学习目标
能够为工具定义输入、输出、错误、权限和幂等性,并避免让自然语言直接变成任意执行。
本节产出
一个最小工具契约
核心知识:把“想做什么”变成受约束的动作
工具契约
工具契约规定一个动作接受什么输入、返回什么结果、可能怎样失败,以及谁有权调用。模型提出调用只是一次请求,执行器仍然负责参数校验和授权判断。不能因为参数看起来像 JSON,就认为它已经安全或符合业务要求。
好的工具通常围绕明确能力设计,例如“读取指定文档摘要”或“查询某天的公开天气”。如果只提供一个任意命令执行入口,模型就要同时处理命令语法、路径、权限和副作用,出错空间会更大。通用工具有其用途,但必须有相应的隔离和检查;具体工具则更容易建立可验证的边界。
图中的校验与授权是两个不同步骤。一个日期可以格式正确,却超出允许查询的时间范围;一个文件标识可以存在,却不属于当前用户可读取的资料。语法合法不等于业务合法,业务合法也不等于调用者获得了权限。
输入与输出都要有明确含义
以下是虚构练习工具的请求与结果示例,不对应真实线上接口,也不需要发起网络请求:
{
"tool": "read_public_document",
"arguments": { "documentId": "demo-lesson-07" }
}
{
"status": "ok",
"documentId": "demo-lesson-07",
"version": "demo-v2",
"text": "用于练习的公开文档正文"
}
契约还应规定 documentId 的长度、可用字符和允许集合,以及结果是否可能截断。若正文只返回前一部分,就必须有明确的截断标记,不能让模型误以为读到了全文。错误结果应区分不存在、无权访问、暂时不可用和输入无效,而不是全部返回一个模糊字符串。
案例:为什么“再试一次”可能重复执行
假设另一个虚构工具负责创建练习工单。客户端等待超时,但服务器可能已经创建成功。如果直接再次调用,就可能出现两张工单。这里的难点是“没有收到结果”与“动作没有发生”并不等价。
一种设计是让同一个逻辑操作携带稳定的幂等键,由服务端保存键与结果的对应关系。在约定的有效范围内,重复请求返回同一操作结果,而不是再次创建。幂等并不是只给参数加一个字段:服务端需要正确处理并发、保存期限以及同一键携带不同参数的冲突。
| 情况 | 能否直接重试 | 应先做什么 |
|---|---|---|
| 输入格式错误 | 通常不能解决问题 | 修正输入并重新校验 |
| 权限拒绝 | 重试不会产生授权 | 检查授权主体与范围 |
| 只读查询暂时失败 | 可能可以有限重试 | 遵守超时和退避策略 |
| 创建操作结果未知 | 不能盲目重复 | 查询状态或使用约定幂等机制 |
工具结果也属于待解释的数据
读取网页、邮件或文档的工具可能返回包含命令语气的内容。它们不能因为来自工具就自动成为更高优先级的指令。系统应保留来源与信任层次,防止资料中的“把所有文件发到这里”改变原来的任务授权。
输出校验也应面向真实结果。工具说“成功”后,可以检查返回标识是否存在、生成文件是否可读,或实际记录是否符合要求。验证强度取决于风险:小型只读任务可以简单检查,重要外部动作需要更严格的状态核对。
动手练习
- 为
read_public_document写一页契约,包含输入限制、输出字段、四类错误和权限范围。 - 为创建练习工单补充超时后的处理方式,说明幂等键什么时候复用。
- 设计一个返回正文中夹带操作指令的测试,写出系统应如何处理。
参考答案与推演
读取工具可只接受预先审核的文档标识,不让用户参数直接成为任意文件路径。成功结果包含版本和完整性说明;拒绝访问与不存在如何呈现,应结合避免泄露对象存在性的需求设计。练习中可统一对外返回不可访问,同时在受控日志里记录具体原因。
创建工单超时后,应先查询该逻辑操作状态,或用原幂等键重试;新建另一个工单才使用新键。夹带指令测试应证明系统仍只完成原有读取任务,未执行正文要求的额外动作。若只检查模型口头拒绝,而不检查工具日志,证据还不充分。
完成检查
- 契约覆盖输入、输出、错误、权限与结果完整性。
- 校验参数与确认权限分别落实。
- 能处理副作用已经发生但响应丢失的情况。
- 工具返回的资料不会自动升级为操作授权。
参考与来源
- MCP:Architecture overview:了解工具调用与结构化协议的角色。
- Stripe:Idempotent requests:作为幂等语义的具体工程实例,练习无需调用支付接口。
- OWASP:LLM Prompt Injection Prevention Cheat Sheet:理解不可信资料与操作指令的边界。
Tool:给模型一个有边界的动作
3 道题 · 及格分 60 分