双轨评估:MCP 智能体的模型得分与产品得分

Dev.to ML 2026-10-30T21:55:38.306063

简而言之:双轨评测用同一批用例,分别跑「只给模型」和「走完整产品」两条路,分数各算各的。2026 年 8 月,同一个 Qwen3-4B 智能体在模型轨拿到 42/70(没过上线门槛),在产品轨拿到 46/70(过了)。全部提升都来自一条守卫规则——stall rule(既没调用工具、也没向用户提问的一轮,直接打回重来)。而我引以为傲的参数修复,实测收益为零。

我在做一个跑在本机的小智能体:Qwen3-4B(4-bit 量化,MLX 推理)驱动 Lovie Formation MCP 服务器(195 个工具),业务是美国公司注册。动手训练之前,我先写了一套评测。然后我花了两天时间优化一个数字——而这个数字从设计上就根本看不到产品。真是够讽刺的。

评测设置

套件:70 个完整流程用例 × 3 个随机种子,按维度打分后取多数票,采样参数与生产环境一致。其中一个 14 例的「核心」子集是上线门槛,要求 12/14。

模型轨(golden)

直接调用 engine.generate,只对模型输出的第一次工具调用打分。

基线:42/70,核心 11/14。没过门槛。

盲区

模型轨根本不跑编排器(orchestrator)。所以这些东西它一概看不见:步骤映射、支付占位符的打回处理、参数类型强制转换,还有我正在加的两条新守卫。

作为「模型本身」的度量,它是干净的——它本来就是为这个写的。问题是我一直把它当产品指标来读。

同一批用例上的产品轨(system-golden)

跑真实的对话轮循环,对同一批用例打分,但打分的对象是服务器实际收到的调用——在所有修复、打回和守卫都执行完之后。

它连的是一个 DryRunMCP:schema 和服务器指令从真实端点来(匿名的 tools/list 就够了),但 callTool 只返回一个假的成功,并把请求记录下来。之所以要这样:这些用例会让一个注册流程走完名称、地址、股东等环节,而这些都是真实服务器上的活数据,评测轨道绝不能创建真实记录。

轨道 总分 核心
golden(模型) 42/70 11/14
system-golden(产品) 46/70 12/14

模型没过门槛,产品过了。

两条轨回答的是不同的问题,所以这两个数字不是「之前」和「之后」的关系。

我给每项保护机制都加了环境变量开关(LOVIE_NO_STALL_BOUNCE、LOVIE_NO_ARG_REPAIR),然后重跑产品车道,结果如下:

Stall bounce Arg repair Total Core
on on 46/70 12/14
off on 42/70 11/14
on off 46/70 12/14
off off 42/70 11/14

可见,全部收益都来自 stall bounce(拦截空转轮次)。

这条规则的逻辑是:如果助手的一轮回复既没有调用工具,也没有向用户提问,就把它回弹一次。在更早的 78 个用例中,28 个基线失败里有 27 个是“什么都没调用”的轮次,其中 14 个既没调用也没提问——例如先说一句“我会把它注册成 C 公司,就这么办”,然后就没有下文。

在这个产品里,一轮回复既不做事也不提问,永远不可能正确。所以这是个确定性触发器,不需要去猜模型的意图。

设计约束,每条都有测试固定:

拒绝类别的成绩保持在 8/8。回弹从未把模型逼到编造地址。

ArgumentRepair:实测收益为零

ArgumentRepair 在调用发出前,按工具自身的 inputSchema 重塑参数:扁平值 ↔ 包裹值、嵌套对象与数组,以及在和 schema 的枚举列表匹配无歧义时做枚举规范化(例如 "LLC" → ENTITY_TYPE_LLC)。

不变式:它只重塑模型发来的内容,绝不增加或删除字段,遇到歧义枚举就原样放过。

实测结果:零收益。没有任何类别发生变化。

早前我把一次冒烟测试当成了它有效的证据,因为执行调用里出现了 ENTITY_TYPE_LLC。其实那个值是模型自己输出的。我看到正确结果,就把功劳记到了自己代码头上,没检查它到底有没有起作用。

它保留下来是出于维护原因,这点要说清楚:它用一条从工具契约推导出的规则,替换掉一份硬编码的四字段列表——那份列表是在多次线上事故后一点点加长的。

流程上改了什么

两条通道,绝不混用:模型通道回答的是「训练有没有改变模型?」,产品通道回答的是「产品能不能用?」。上线闸门(ship gate)只看产品通道。每加一道新校验,都配一个开关,这样它的效果是测出来的,不是猜出来的。如果你在评估一个大语言模型(LLM)产品(法律类也好,其他也罢),先问清楚:这个分数来自模型通道还是产品通道,又是哪个组件挣来的。

常见问题

AI 智能体里的「僵持规则」(stall rule)是什么?
当某一轮助手既没有调用工具、也没有向用户提问时,这条规则会把这轮回复打回一次。在这个案例里,它单靠这一条就把产品通道从 42/70 提到 46/70。

为什么要把模型通道和产品通道分开?
只测模型的评估看不到编排层的那些校验逻辑,所以同一个模型可能过不了模型闸门、却能过产品闸门。两边的数字回答的是不同问题,不能直接比较。

怎么把收益归因到某一道具体校验上?
每道校验都配一个开关(一个环境变量 flag),然后把同一批随机种子在关闭该开关的情况下重跑一遍。


Daniel Aydin 是 Lovie(lovie.co)LegalTech 产品线的总经理。他在土耳其接受律师训练,并非美国执业律师,在旧金山 SF Vibe House 主持 Legal AI Vibe Lab。Lovie Formation(lovie.co/formation)是一项 AI 原生的美国公司注册服务,提供 MCP 服务器,让 Claude、ChatGPT 这类 AI 智能体也能帮你开公司;每一份递交到州政府的文件,都会有人工复核。

原文首发于 Substack。

摘要:双轨评测的做法是:同一批测试用例,一轨只跑模型本身(模型轨),另一轨跑完整产品(产品轨),两边的得分分开记录。2026 年 8 月,同一个基于 Qwen3-4B 的 agent 在模型轨拿到 42/70,没能通过上线门槛;在产品轨拿到 46/70,通过了。全部提升都来自一条保护规则——卡壳规则(stall rule):某一轮既不调用工具、也不向用户提问,就直接打回。我原本引以为傲的参数修复(argument repair),实测收益为零。

我正在做一个跑在设备端的小型 agent,模型用的是 Qwen3-4B。

查看原文