大猫OPC
项目记录

给内部知识网关做 MCP 验收:两轮 131 项检查,问题都在检索层

给公司内部知识网关做 MCP 验收,两轮共 131 项检查。第一轮协议与算价几乎满分,但知识库是空的;补完内容后 6 项失败全集中在检索分词与排序上。记下三个具体的坑:词典词短路、假命中、inputSchema 漏参。

说明:本文涉及的企业名称、域名、账号、产品型号与具体金额均已脱敏或按比例改写,不影响结论与数据关系。文中把被测产品称为「A 型工业门」。

背景

公司内部上线了一个知识网关,用 MCP(Model Context Protocol)把内部资料开放给 AI 助手:产品参数、报价口径、安装规范、历史问答,都能通过工具调用查到。协议是 JSON-RPC 2.0 over HTTP,一共暴露 11 个工具。

我以测试身份先做了一轮验收,修复后又做了第二轮。两次结论差得很远,值得记一笔。

11 个工具大致分四类:

  • 身份:whoami
  • 内容:search_products / get_product / search_knowledge / get_knowledge / search_qa
  • 算价:calculate_price
  • 任务与回流:list_my_tasks / draft_task / update_my_task_status / submit_question

怎么测的

第一轮按 20 项必测清单逐项走:协议基础、检索、算价、任务、匿名回流、越权边界。

第二轮 111 项,重点三块:第一轮失败点的回归、检索相关性、算价与网页计算器逐场景比对。

两条自定的规矩,比清单本身更重要:

一、金额不看接口自说自话。 每个报价场景都单独调一次网页计算器,两个数对上了才算通过。接口返回一个漂亮的数字,不等于这个数字是对的。

二、拒绝必须能被证明不是假的。 我先确认自己的任务能改成功,再说"他人的任务改不了"是真拒绝,而不是那个 id 本来就不存在。检索同理——不能看到"有返回"就判通过。

第一轮:协议层意外地扎实

安全相关的几项,做得比预期好:

  • 受限令牌调 tools/list,工具清单只暴露已授权的 2 个。连"有哪些工具"都不泄露,比多数实现干净。
  • 删除类工具是"根本不存在",不是"存在但拒绝"。从设计上消除风险,而不是靠运行时判断。
  • 越权改任务统一返回"没有找到该任务",不区分"不存在"和"不是你的",不泄露存在性。
  • 算价 6 组与网页计算器零偏差,且严格只试算不落库——单据列表实测仍是 0 张。

但第一轮有三个真问题

1. 知识库是空的。 遍历 12 个高频词,只命中 6 条,100% 来自产品参数兜底,fallback 恒为 true。这个网关当时本质上是"产品参数查询器":报价口径、安装规范、售后政策、话术,一律查不到。

2. 无答案的提问污染了检索。 我提交的一条匿名提问,1 分钟内就被 search_knowledge 收录,搜相关词时排在第一位。查下来不是测试造成的——管理员早几天提交的一条空问题(当时 0 回答)同样被命中。索引没有区分"已审核的知识"和"刚提交的问题"。

3. "查到了"其实是沾了产品名的光。 整句「A 型门保温层厚度是多少」有返回,fallback=true,来源标注也对。但单独搜"保温层"是 0 条——库里压根没有这个概念,返回的只是产品整段简介。这种假命中比查不到更危险,因为调用方会把它当答案用。

第二轮:知识库补上了,新问题浮出来

知识库从 0 条变成 37 条。前两个问题确实修好了:source 从"产品参数"变成"知识库",fallback 从恒定 true 变成 false;那两条待回答提问也彻底检索不到了。

105 项通过,6 项失败。失败全部集中在检索精度上。

最典型的一条

知识库里有一条《A 型门·保温性能与导热系数》,正文末尾自己写着:

常见问法:保温层多厚……答法:先给密度与导热系数

写条目的人把用户会怎么问都预置进去了。我拿这句话去问,它排在第 7 位——最后一名。

根因是分词器的"词典词短路":

输入 实际生效的关键词
A 型门保温层厚度是多少 ["A 型门"]
A 型门的保温层厚度 ["A 型门"]
A 型门 保温层(中间有空格) ["A 型门","保温层"]
公司什么时候成立的 ["公司","司什","什么","么时"]

规则很清楚:词典命中一个词之后,整句其余信息被丢掉;没有词典词时,双字切分会产出"司什""么时"这种跨词碎片,而"成立"这种关键动词反而被丢。

后果是两个语义完全不同的问题,返回了一模一样的 7 条结果、一模一样的顺序。

这个缺陷会答错参数,而且不报错

5 个含产品名的问句里,4 个首条是某个小规格型号。问"这个产品最大能做多宽",首条给的是小规格的 3000×3500mm,真答案在另一条《技术参数》里:15 米——差 5 倍。

危险的地方在于它不报错:isError=false,5 条结果,看起来一切正常。调用方拿不到任何信号知道"第一条是错的"。

算价:契约漏了两个参数

small_door_qty 和 window_qty 这两个选配,服务端是支持的——传进去金额完全正确,与网页计算器一致。但它们没写进工具的 inputSchema。

结果是:AI 严格按 schema 构造参数,这两个字段永远传不到。带通道小门的报价只剩基准价,比正确值低约 28%。

引擎不用改一行,补两行声明就行。这是本轮性价比最高的修复项。

结果与数据

两轮合计 131 项检查。

轮次 检查项 通过 失败 / 附注 P0
第一轮 20 18 1 项附注、1 项部分通过 触发 1 项(待回答提问进检索)
第二轮 111 105 6 未触发

P0 三条硬指标(金额与网页不一致、未审核内容被检索、越权未被拦截),第二轮全部未触发。

性能每个接口采样 12 次取 P95,ping / tools/list / search_knowledge / get_product / calculate_price 全部低于 250ms,没有需要优化的地方。

复盘

一、测"拒绝"比测"通过"难。 一个接口报错,可能是拦住了,也可能是这个 id 本来就不存在。只有先证明"正向能成功",反向的失败才有意义。第一轮我差点把一个 404 当成"越权被拦住"。

二、内容为空时,协议层的好成绩会骗人。 第一轮协议、鉴权、算价几乎满分,但用户真正要问的十个问题里九个答不上来。基础设施合格和产品可用是两件事。

三、排序比召回更容易被忽略。 第二轮每条查询都能"返回结果",只看 count 全部通过。真正的问题是第一条对不对。如果验收只看"有没有结果",这 6 项失败一个都发现不了。

四、schema 是契约,不是注释。 服务端支持但没声明的参数,等于不存在。这类问题不报错、不缺数据、手动传参也能过,只有在"完全按 schema 调用"时才会暴露。

如果要排修复优先级:先去词典词短路,再做通用条目与型号条目的分层,最后补 schema 声明。第一条不修,知识库写得再好也发挥不出来。

觉得有用? 转发给需要的朋友
X LinkedIn

大猫

用 AI 和技术,把企业的网站与获客真正做起来。GEO、企业网站与定制工具。。这里记录写作与实操,欢迎交流。

评论(0)

还没有评论,来抢占沙发吧~

发表评论

正在回复

不想每次填昵称?登录 或 注册 后即可一键评论。

评论提交后需管理员审核通过才会显示。