跨平台 Agent 先统一工具契约
文章以发票异常处理为例,为五个 Agent 平台定义可复用的九项工具契约,明确六项读取与三项写入操作。设计强调单一业务职责、明确错误码,以及写操作依赖审批凭证,避免使用权限过宽的通用接口。
AI 深度解读
给同一个 Agent 换五个平台做比较,工具却各自在平台里重新设计,最后测到的可能是接入方式的差异。作者的主张是:先定义一份所有平台共用的工具契约,再让平台适配它,包括工具名称、输入输出、错误和审批条件。
这篇最有用的地方,是把「Agent 能调用什么」和「后端允许它做什么」分开讨论。不过,这仍是虚构公司的参考构建,尚未给出五个平台的实测结果。
九个工具,先分清哪些能查、哪些能改
作者围绕发票异常处理,只设计了九个工具:六个读工具、三个写工具。每个工具对应一个财务人员能理解的业务动作,没有包揽所有能力的 call_erp 或 run_query。
六个读工具分别负责获取发票、采购订单、收货记录、供应商历史,检查重复发票,以及执行三方匹配。这里的三方匹配,就是按规则核对发票、采购订单和收货记录。
其中 run_three_way_match 被明确设计为确定性工具:相同输入必须得到相同结果。金额是否超出容差属于业务规则,不交给模型临场判断。
三个写工具的权限也不同。request_approval 创建人工审批任务,获得批准后返回 approval_id;post_invoice_adjustment 修改 ERP 发票记录,notify_supplier 向供应商发消息,二者都要求传入有效的 approval_id。

这个拆分决定了 Agent 的调查空间和行动边界。查询不会修改业务状态,可以按需调用;修改记录、发送消息则必须过审批。
Schema 负责声明审批要求,流程 API 负责执行审批限制。
把 approval_id 设为必填,只能挡住缺字段的调用。审批是否过期、是否已经使用、是否对应当前发票和操作,仍要由后端检查。
工具契约要管住参数,也要解释失败后的下一步
作者要求每个工具都有输入和输出 Schema。按照原文引用的 MCP 规范,输出 Schema 可以省略,但一旦声明,服务端返回的结构化结果就必须符合它。
对跨平台比较来说,这能减少一种干扰:同一张发票在某个平台返回对象,在另一个平台返回一段自然语言,后续处理难度就不同了。
下面是原文裁剪后的 post_invoice_adjustment 定义,它把调整类型和审批前提放到了工具本身:
{
"name": "post_invoice_adjustment",
"title": "Post invoice adjustment",
"description": "Posts one approved adjustment to an invoice in the ERP. Use only after request_approval has returned an approval_id for this exact invoice, action and amount. Fails with APPROVAL_MISSING if the approval is absent, expired, used or does not match.",
"inputSchema": {
"type": "object",
"properties": {
"invoice_id": { "type": "string" },
"adjustment_type": { "type": "string", "enum": ["price", "quantity", "tax_code"] },
"amount": { "type": "number" },
"currency": { "type": "string" },
"approval_id": { "type": "string" }
},
"required": ["invoice_id", "adjustment_type", "amount", "currency", "approval_id"],
"additionalProperties": false
},
"annotations": { "readOnlyHint": false, "destructiveHint": true, "openWorldHint": false }
}
要看的是 enum、required 和 additionalProperties: false:业务选项固定就枚举,必要条件不能漏,多余字段不接收。原文说每个工具都有输出 Schema,但这段裁剪示例没有展示,不能据此认为完整契约已经交代清楚。
输出也应优先返回后续步骤需要的标识符,例如 posting_id,减少模型从文字里提取信息的负担。
工具描述则回答三个问题:做什么、什么时候用、失败了怎么办。上面的描述明确要求先审批,而且审批必须对应当前发票、动作和金额;只写「提交发票调整」,这些约束就全丢了。
错误也要能指导下一步。原文区分了两类错误:未知工具、请求格式不对等协议错误走 JSON-RPC;API 调用失败、输入无效、业务规则不满足等工具执行错误,通过带有 isError: true 的工具结果返回。
例如,GR_MISSING 表示尚未收货,应挂起发票而非立即重试;PO_CLOSED 要转采购处理;PERIOD_CLOSED 要升级给财务;遇到 APPROVAL_MISSING 则先走审批,不能编造 ID 再提交。
错误名负责分类,错误消息负责指路。否则,模型看到一个含糊的失败,很容易把「现在不能做」理解成「再试一次」。
平台可以换接法,业务边界不能跟着变
同一份契约,作者允许三种落地方式:在平台内把现有 API 暴露为 MCP 工具,让平台调用外部 MCP 服务,或者一对一映射为平台原生工具格式。
映射可以改变接入形式,但工具名称、Schema 和具名错误要保持一致。每次构建都检查九个工具是否齐全,以及写工具在缺少 approval_id 时是否仍会失败;差异计入工具暴露评分。
还有一层容易混淆:MCP 的 annotations 是提示,不是权限控制。
六个读工具标记 readOnlyHint,修改 ERP 的工具标记 destructiveHint,对外通知标记 openWorldHint,此外还有 idempotentHint。客户端可以据此显示确认,网关可以据此施加策略,但标记本身不会拦截调用。原文还强调,除非来自可信服务端,否则客户端应把这些标注视为不可信信息。
所以,工具自称「只读」不等于它真的不会写入;界面弹出确认,也不能替代流程 API 校验审批。
我的判断
我认同先固定业务契约再选接入方式。它既方便比较平台,也让团队能直接审查 Agent 的操作范围。小而明确的业务工具,通常比一个任意执行查询的入口更容易解释权限。
但这是有前提的:团队已经能把业务动作收敛成稳定 API,并有可靠的审批系统。原文没有展开人工审批等待期间如何恢复流程,也没有给出防止重复提交的完整设计。六个读工具可以反复调用,只说明不会修改状态,不代表没有延迟和调用成本。
作者认为,贴近工具的描述比埋在长系统提示词里的要求更能减少错误调用,但没有提供对照数据。这应当视为经验之谈。
原文依据的是截至 2026 年 10 月的 MCP 2026-07-28 规范。它展示了一套设计和待执行的比较方法,尚不能证明五个平台已经实现相同效果。
能拿来做什么
- 给现有 Agent 列一张工具表,逐项标出读写性质、必要输入、输出标识符和失败后的动作,优先检查修改数据与对外发送信息的工具。
- 用 Node 封装业务工具时,把审批有效性检查留在流程 API 内。Schema 必填检查和工具描述都可以保留,但不能替代这一步。
- 把含糊的失败响应改成具名业务错误,明确告诉 Agent 应该等待、补充条件还是转人工,减少没有意义的重试。
- 比较多个 Agent 平台时,复用同一份工具定义和业务输入,并验证缺少审批时的失败行为,避免把工具接法差异算成模型能力差异。