MCP 接入实测:32 个工具让误调用率涨到 19% 后,我们做了五个动作把它压到 2.2%

MCP 这个词在今年从”一个新协议”迅速变成了”一个默认动作”——很多团队看到 Model Context Protocol 支持了,第一反应是把自己系统里二十几个 API 全接上,然后等 agent 自己发挥。我们上个月就这么干的,一周内 agent 的误调用率从 3% 涨到 19%,用户投诉量跟着翻了三倍。

这篇是那之后的复盘:接 32 个 MCP 工具、跑了 1400 次真实调用得到的结论——MCP 的问题不是”接得不够多”,是”接得太随意”。工具的数量和参数的自由度,才是决定 agent 靠不靠谱的变量。

一、先讲清楚:MCP 解决了什么,没解决什么

MCP 做对了一件大事:它统一了”模型如何获得工具”的接口,把各家各式的 function calling 规范成一套客户端—服务器协议。对工程侧这是纯利好,接一个新系统从”写一套适配层”变成”起一个 MCP server”,边际成本大幅下降。

但它没有解决、甚至放大了一个老问题:工具语义的清晰度。在 function calling 时代,工具定义是你自己写的,你心里有数;到了 MCP 时代,一个团队可能同时挂了 5 个不同来源的 server,每个 server 的工具描述、参数命名、返回结构都由不同人定义,而模型要在一次调用里理解全部三十几个选项。

我们在排错时统计过误调用的原因分布:

  • 38% 是参数填错——尤其是有多个相似可选值的参数,模型会随机挑一个”看起来对”的。
  • 29% 是工具选错——两个工具名字和描述相似(get_user vs fetch_customer),模型选了错的那个,而且错的也能跑通。
  • 21% 是调用时机错——本来能直接回答的问题,模型非要去查工具,查完反而答错。
  • 12% 是被返回值带偏——工具返回一段半截的错误信息,模型当成事实继续往下推。

注意这个分布:没有一个原因是”协议不通”。全部是语义问题。这就是 MCP 接入的真实工作重心。

二、32 个工具接入后的失控记录

我们把工具按业务分了三组接进来,第一周就炸了三处:

分组 工具数 接入后误调用率 主要症状
查询类(只读) 14 4.2% 参数选错、该直接答的强查
写操作类 9 18.6% 该确认的不确认,重复提交
跨系统组合类 9 22.4% 半途失败后无法回滚,状态残留

写操作和组合类出事率高四到五倍。最典型的一起事故:用户说”把我上周的订单改一下地址”,模型按顺序调了订单查询→地址校验→地址更新,第二步因为城市字段格式没对上返回了一个”部分匹配”的软错误,模型把这个软错误理解成了”校验通过”,直接执行了第三步。一单发去了错误的城市,客服跑了三天。

复盘时才看清:那个”部分匹配”的返回结构,和”完全通过”的返回结构是同一套字段,只有一个 confidence 数字不同。模型没有能力对这种差异做可靠判断——它不是一个校验器,它是一个最可能的下一个词预测器。

三、收敛:把”全量接入”改成”受控接入”

我们后来的改造动作,效果按顺序排:

1. 工具描述重写,把”能做什么”改成”该在什么时候用”。这是收益最大的一步,误调用率从 19% 降到 7.1%。原来写get_orders: 获取用户订单,改成get_orders: 仅在用户询问订单历史、物流状态、订单详情时使用。不用于查询账户余额或退款政策——那些用 get_account 和 get_policy。主动写清”不该什么时候用”,比写清”能做什么”更能压住误触发。

2. 合并同义工具。把 get_user / fetch_customer / query_account 三个近乎重复的工具合并成一个 get_customer,单一职责。工具数从 32 降到 24,工具选错率从 29% 的占比降到 9%。

3. 参数全部改成枚举,消灭自由文本。凡是取值范围可枚举的参数,一律枚举化并给每个值写一句适用场景。参数填错的占比从 38% 降到 11%。

4. 给写操作加确认闸门。所有产生副作用的工具,在 MCP server 侧强制要求显式 confirmed: true 参数,且该参数只能由”用户刚刚表达过同意”的上下文填充。模型自己编一个 true 无意义,服务端校验会话内的确认记录。把安全边界放到模型外面,这是唯一可靠的方案。

5. 返回值结构化,把”部分成功”和”完全成功”拆成不同结构。软错误不再复用成功返回的字段,改成独立的 error 结构并带 action_required 字段。模型一旦看到这个结构,策略里明确写”停下来问人”。

改造动作 误调用率(写操作) 误调用率(查询) 累计收益
初始全量接入 18.6% 4.2% —
+ 工具描述重写 11.3% 2.0% 最大单项
+ 同义工具合并 9.4% 1.4% 明显
+ 参数枚举化 6.8% 1.1% 明显
+ 写操作确认闸门 2.9% 1.1% 事故归零
+ 返回结构分离 2.2% 0.9% 收尾

五步做完,写操作误调用率从 18.6% 降到 2.2%,而工具数反而少了 8 个。这个结果本身就说明问题:我们不是在优化模型,我们是在清理自己制造的混乱。

四、落地清单

  • 接入前先给每个工具写”该用/不该用”两句。写不出”不该用”的工具,通常意味着它和别的工具边界不清,先合并。
  • 写操作必须有服务端确认闸门,不依赖模型自觉。这是底线,不是优化项。
  • 参数枚举化优先于参数说明优化。给模型十个精确选项,胜过一段解释。
  • 先接只读工具跑两周,再接写操作。让只读阶段把描述、命名、参数的问题暴露完,再开写权限。
  • 建一个误调用样本集,每周回归。32 个工具的下场就是没有回归——不回归的工具集会缓慢腐烂。

总结

1400 次调用的结论可以压成一句话:MCP 把接入变简单了,因此把”接入时想清楚”这件事变得比以往任何时候都重要。工具越多、参数越自由,模型的出错面就越大,而这个面完全由工程侧控制。

更重要的认知转变是:你接入的不是”能力”,是”责任的转移”。每接一个写操作工具,就是把一部分业务风险交给一个概率系统。所以安全边界必须画在模型外面——确认闸门、权限校验、回滚机制,这些不是给模型用的,是给模型失败时兜底的。

最后一个判断:下一阶段的竞争不在”谁的 MCP server 更多”,在”谁的工具语义更干净”。协议已经平权,差别会回到最朴素的工程素养上:命名、边界、枚举、失败语义。

互动提问:你们现在接了几个 MCP 工具?有没有统计过”工具选错”和”参数填错”各占多少?还是只有用户投诉这一个信号?

互动提问:写操作的确认闸门,你们是放在模型侧提示词里,还是放在 MCP server 侧强制校验?评论区想看看大家的做法。

分享到:

微博
Twitter
LinkedIn

— IMAI 编辑部 | 2026-10-29

发表评论