对应mcp-tools第 2.1 节(2.2 参数、2.3 返回结构见第二、三节) · 形态:一页 + 可复制文本
用途:模型选工具、填参数、理解返回,唯一依据就是你写的这段契约。写不清不是它笨。
一、描述四段(复制填写)
【用途】一句话说明这个工具做什么(动词开头,不超过 20 字)
【什么时候用】列出 2–3 个具体场景,写清对象与条件
【什么时候不要用】列出 2–3 个易混场景,并指明该用哪个工具
【返回什么】返回的关键字段,以及失败时的返回形态
为什么第三段最重要
最多人漏「什么时候不要用」。不写边界,它就会在不该用的地方用——然后你会觉得它「变笨了」,其实是描述没写边界。
名字怎么起
| 坏名字 | 问题 | 好名字 |
|---|---|---|
query | 查什么?模型只能猜 | get_invoice_by_number |
handle | 动词太空 | submit_expense_report |
data_tool | 名词 + tool,无信息 | list_open_tickets |
起名规则:动词 + 对象(+ 限定条件)。同一个系统里,动词只用几个固定词:get(单条)/ list(多条)/ create / update / delete / submit。
二、完整示例
【用途】按发票号码查询发票明细与报销状态。
【什么时候用】
· 用户给出具体发票号码,要查这张票的金额、开票方、是否已报销;
· 报销单关联了发票号,需要核对票面信息与报销单是否一致。
【什么时候不要用】
· 只有客户名或日期、没有发票号 → 用 list_invoices_by_customer;
· 要查一整批(超过 20 张)→ 用 export_invoices,本工具逐张查询会很慢;
· 要修改报销状态 → 用 update_reimbursement_status,本工具只读。
【返回什么】
成功:invoice_number / amount / issuer / issue_date / reimbursement_status / report_id
失败:error_code(NOT_FOUND / FORBIDDEN / UPSTREAM_TIMEOUT)+ 可读 message
三、参数:能写进结构的,不要写进描述
原则一句话:结构能管的,不靠自觉。 参数凡是没约束的,模型就会自己填一个——填得很合理,合理到你看不出来错。
| 约束项 | 写在哪 | 例 |
|---|---|---|
| 类型 | 参数定义 | amount: number,不是「金额」 |
| 必填 | 参数定义 | invoice_number 必填;include_void 可选 |
| 枚举 | 参数定义 | status: draft / submitted / approved |
| 范围 | 参数定义 | limit: 1–100,默认 20 |
| 格式 | 参数定义(正则) | 发票号 ^\d{8,20}$ |
| 示例 | 参数描述 | "invoice_number": "01234567" |
参数约束检查表
| # | 检查项 | 通过标准 | 不通过的表现 |
|---|---|---|---|
| 1 | 每个参数都有类型 | 无 any / 无未声明 | 传 "100" 和 100 都进得来 |
| 2 | 区分必填与可选 | 必填项缺失时明确报错 | 缺参数时用空值继续跑 |
| 3 | 枚举值穷尽 | 列出全部合法值 | 模型自己造一个「看起来对」的值 |
| 4 | 有取值范围 | 数字有上下限,字符串有长度 | limit: 100000 把下游打挂 |
| 5 | 有默认值说明 | 默认为空时,行为可预期 | 默认行为不明确,结果每次不同 |
| 6 | 每个参数有示例 | 至少一个真实格式的示例 | 模型按「常见格式」编,格式不对 |
| 7 | 没有「万能参数」 | 不存在 options / params 这类透传字段 | 把下游的参数直接透出去,等于没有约束 |
第 7 条是隐蔽的坑:options: object 这种透传参数,看起来灵活,实际把所有约束都作废了——模型可以往里塞任何东西,而你的服务端照样接受。
四、返回结构:四段最小集
返回一段自然语言,模型每次都要重新理解一遍,结果必然不稳;返回结构化字段,它只需要取值。
| 段 | 字段 | 作用 |
|---|---|---|
| 状态 | status: ok / error | 一眼判断成败,不用读文本 |
| 数据 | data(对象或数组) | 只放业务字段,不放日志与内部 id |
| 错误码 | error_code(枚举) | 让模型能据此选下一步动作 |
| 可读消息 | message | 给人看的一句话,不影响程序判断 |
错误返回的写法差异
| 坏写法 | 问题 | 好写法 |
|---|---|---|
| 「操作失败」 | 等于没说,模型只能瞎猜 | 「账户不存在,请确认客户编号」 |
| 「系统异常」 | 无法区分是参数问题还是服务问题 | 「下游超时(已重试 2 次),请稍后再试」 |
| 「权限不足」 | 不知道缺哪个权限 | 「当前账号无 report:read 权限,请联系管理员开通」 |
判断标准:模型读到这句话,能不能做出正确的下一步。不能,就是没写好。
返回体积
| 情况 | 做法 |
|---|---|
| 结果 > 50 条 | 分页(limit + offset),返回 total |
| 单条记录字段 > 20 个 | 返回摘要字段 + 一个「取详情」的工具 |
| 含长文本(正文、日志) | 截断到 200 字 + 标注「已截断」,另给取全文的工具 |
整段塞回去不是信息,是噪声——它会把真正重要的几个字段淹掉。
五、常见误用
| 误用 | 后果 |
|---|---|
| 描述只写「用途」一段 | 模型在相邻场景里选错工具,你以为是模型问题 |
名字用 query / handle / process | 无法区分,选错率高 |
| 参数全可选、无类型 | 模型编造参数值 |
用 options 透传 | 所有参数约束作废 |
| 返回自然语言长句 | 下游每次重新理解,输出不稳定 |
| 错误只返回「失败」 | 模型无法自我修正,只能反复重试 |
六、自查清单(交付前逐条打勾)
- [ ] 工具名是「动词 + 对象」,动词来自固定词表
- [ ] 描述四段齐全,第三段(不要用)至少 2 条
- [ ] 每个参数有类型、必填标记、示例
- [ ] 枚举参数列全了合法值
- [ ] 数字参数有范围,字符串有长度或格式约束
- [ ] 没有透传型万能参数
- [ ] 返回含状态、数据、错误码、可读消息
- [ ] 错误消息能指导下一步动作
- [ ] 大结果有分页或截断策略
九条全过,再进 02-鉴权与权限清单.md——描述写错的代价是选错,权限写错的代价是赔钱,两件事不能混。