作者以拥有 74 个 MCP 工具的语音 Agent 为例,说明公共榜单无法衡量工具路由、会话稳定性等业务指标。文章主张把迁移条件写成可执行评分规则,以成本、延迟和正确率共同决定是否更换模型。
TL;DR:在把我们的船载语音 Agent 从 Claude Sonnet 迁走之前,我们让新的 GPT-5.6 各档模型跑了与现有模型相同的工具路由基准测试:13 个真实请求、74 个 MCP 工具 schema,根据模型是否调用了正确的工具进行评分。在我们的工作负载和集成约束下,GPT-5.6 得分为 38.5%,而 Sonnet 为 92.3%——所以不迁移。可以直接跳到数据部分。真正可迁移复用的不是分数,而是方法。
这不是什么——看数据之前请先读这一段。 这不是模型基准测试,也无法说明 GPT-5.6 的整体质量。它是一项范围狭窄、目标明确的工作负载适配测试:把候选模型接入我们的集成链路后——一个兼容 OpenAI 的 /v1/chat/completions runner,在使用工具时必须设置 reasoning_effort: "none",下文会详细解释——它能否在包含 74 个 MCP 工具的工具面中,把语音 Agent 收到的请求路由到正确工具?GPT-5.6 完整的工具调用能力位于 Responses API 中,而我们的 runner 并不支持它。这个结果只能说明:“截至今天,它不适合作为这个系统的直接替代品。”除此之外,不能推广到任何场景。如果你读完本文只记住了标题里的分数,那就读错了。请带走这里的方法。
每当新的旗舰模型发布,总会出现同一个问题:我们应该迁移吗?排行榜上的成绩很好看,价格也很诱人,博客文章更是一片赞誉。
但这些都没有衡量你的工作负载。
我们的工作负载是游艇上的语音 Agent。整个架构把确定性下沉到了代码中——口语表达由模板生成,工具结果在工具层完成格式化,组合逻辑则在复合工具中处理。LLM 真正要做的事情很有限:听懂请求,选择正确的 MCP 工具,并使用可用的参数调用它们。比如,“Boundary Pass 现在的水流如何?”必须路由到 currents.get_gate_current,而不是某个通用的传感器读取工具。仅此而已。极致的推理能力并不在关键路径上,工具路由的正确性和延迟才是。
没有任何公开排行榜会评测“能否在我们的 74 个海事 MCP 工具 schema 中正确完成路由”。所以我们一次性搭建了这套基准测试。现在,每个候选模型都必须先通过同一套 15 分钟测试,之后才有资格继续讨论迁移。
替换规则被明确写进了代码,而不是靠感觉做决定。只有在候选模型速度更快、正确率保持在容忍范围内并且运行稳定时,它才会取代现有模型:
def compare(incumbent: Scorecard, candidate: Scorecard, eps: float = 0.05) -> Verdict:
if candidate.error_rate > 0:
return Verdict(False, f"candidate not session-stable "
f"(error_rate={candidate.error_rate:.2f})")
if candidate.latency_p50 >= incumbent.latency_p50:
return Verdict(False, f"candidate not faster "
f"(p50 {candidate.latency_p50:.2f}s vs "
f"incumbent {incumbent.latency_p50:.2f}s)")
if candidate.correctness < incumbent.correctness - eps:
return Verdict(False, f"candidate correctness below tolerance "
f"({candidate.correctness:.2f} < "
f"{incumbent.correctness:.2f} - {eps})")
return Verdict(True, ...)
注意这段规则优化的是什么:在达到正确率门槛的前提下追求速度,而不是追求能力上限。我们希望能被一个更快的模型说服。语音循环的温启动目标低于 5 秒,而现有模型的 p50 超过了 8 秒。如果候选模型速度快 3 倍,同时还能正确路由工具,它会立即赢得这个位置。门槛设为现有模型的正确率减去 ε,是因为下游的文本质量由确定性逻辑保证——模型只需要把正确的工具串联起来。
这套基准测试位于 naturali-agents 中,通过 python -m poseidon.bench 运行。它会执行一个由 13 个请求组成的 golden set,每个请求都标注了预期调用的工具:
{
"id": "current-boundary",
"category": "navigator",
"prompt": "What's the current doing at Boundary Pass?",
"expected_tools": ["mcp__currents__get_gate_current"]
},
{
"id": "safe-to-anchor",
"category": "navigator-multi",
"prompt": "Is it safe to anchor here tonight given the weather and current?",
"expected_tools": ["mcp__pilotbook__assess_anchorage"]
}
现有模型通过其生产环境 backend(Claude Agent SDK)运行。所有候选模型则通过一个扁平的 OpenAI-compatible runner 运行——使用相同的请求、从生产环境 MCP 服务器配置导出的同一组 74 个工具 schema,以及同样基于召回率的评分方式:是否调用了正确工具;额外的探索性调用不会受到惩罚。
# incumbent baseline (SDK backend)
uv run python -m poseidon.bench --model claude-sonnet-4-6
# candidate (any OpenAI-compatible endpoint: hosted or local Ollama)
uv run python -m poseidon.bench --backend openai \
--base-url https://api.openai.com/v1 \
--model gpt-5.6-terra --reasoning-effort none \
--baseline dev/bench-results/2026-07-12-claude-sonnet-4-6.json
--baseline 参数会让运行结果直接输出替换判定。一条命令,一份记分卡,一个答案。
这个 runner 最初是为本地 Ollama 模型构建的。把它指向托管 endpoint 后,它连续出错了两次——而这两次故障恰好说明了真实基准测试能够暴露、排行榜永远不会告诉你的集成细节。
Ollama 会直接忽略 Authorization header,因此测试框架此前从未发送过这个 header。修复方法很简单,而且不会影响本地运行:
def auth_headers() -> dict[str, str]:
"""Bearer auth for hosted OpenAI-compatible endpoints; empty for local
(Ollama ignores auth)."""
key = os.environ.get("OPENAI_API_KEY", "")
return {"Authorization": f"Bearer {key}"} if key else {}
/v1/chat/completions 中,除非将 reasoning_effort 设置为 "none",否则 GPT-5.6 会拒绝 function tools修复身份验证后,只要请求中携带我们的 tools 数组,请求仍会遭到拒绝,直到我们发送 reasoning_effort: "none"。完整推理与工具结合使用是 Responses API 的特性;在 Chat Completions 接口上,两者只能选一个。因此,payload builder 增加了一个透传参数:
def chat_payload(model, messages, schemas, reasoning_effort=None) -> dict:
"""reasoning_effort is passed only when set — GPT-5.6+ rejects function
tools unless it's 'none' (full reasoning + tools needs the Responses
API, which this runner predates)."""
payload = {"model": model, "messages": messages, "tools": schemas,
"tool_choice": "auto", "stream": False}
if reasoning_effort is not None:
payload["reasoning_effort"] = reasoning_effort
return payload
第二个修复对于正确理解测试结果非常重要:它意味着下文所有 GPT-5.6 数据都是在关闭推理的情况下得到的,因为我们所集成的 OpenAI-compatible 接口只有在这种模式下才允许使用工具。这是我们实际部署的直接替换链路所面临的真实约束——本地模型或任何 OpenAI-compatible engine 也会使用同一个接缝——但它的确是一项约束,因此我们明确记录了下来。
同一天,使用相同的 13 请求 golden set、相同的在线 MCP 技术栈,测试全部三个 GPT-5.6 档位,并重新跑了一次现有模型 baseline:
这里有两件事同时成立,而且都很重要。
延迟表现非常出色。 GPT-5.6 的每个档位都轻松达到了低于 5 秒的语音循环目标,而现有模型没有达到。Terra 的 p50 为 2.32 秒,是我们在这个工作负载上测到过的最快工具调用轮次,无论云端还是本地模型都算在内。如果正确率能够保持,这会是一次毫不费力的替换——这正是制定决策规则的意义。
路由能力崩溃了。 失败并不是出现在少数几个高难度请求上的轻微偏差,而是性质上的差异。关闭推理后,三个档位几乎面对所有请求都会选择通用的 mcp__signalk__read_sensor。以下是 Terra 记分卡中的部分结果:
| ask | expected | observed | |
|-----------------|---------------------------------------|-----------------------------|---|
| wind-forecast | mcp__weather__get_marine_forecast | mcp__signalk__read_sensor | ✗ |
| currents-nearby | mcp__currents__currents_near | mcp__signalk__read_sensor | ✗ |
| tide-heights | mcp__currents__get_tide_heights | mcp__signalk__read_sensor | ✗ |
| anchorage-near | mcp__pilotbook__find_anchorages_near | mcp__signalk__read_sensor | ✗ |
| safe-to-anchor | mcp__pilotbook__assess_anchorage | mcp__signalk__read_sensor | ✗ |
一个风况预报问题,竟然通过读取实时传感器来回答。一个锚地问题,也通过读取传感器来回答。Terra 在 13 个请求中有 8 个以相同方式路由到了错误的子系统;Sol 和 Luna 也呈现出相同的错误模式。直接对应单个工具的请求,比如“我的当前水深是多少”,仍然能够正确命中——真正失效的是在大规模工具面中完成路由的能力。
我们以前在小型本地模型上见过完全相同的失败模式——在压力下选择通用工具而不是专用工具,正是 8B 模型常见的行为。如今在这里看到它,能说明一件有用但范围有限的事情:无论是什么能力,让模型可以从 74 个工具中正确选出一个,在这个接口和这种模式下,那部分能力恰好位于我们不得不关闭的组件中。
在最容易过度解读结果的地方,值得再次强调:候选模型运行时受到 OpenAI-compatible 接口施加的约束,即使用工具意味着必须关闭推理。GPT-5.6 设计好的工具调用路径——推理与工具结合使用——位于 Responses API 中,而我们的 runner,以及所有像我们这样用于直接替换 OpenAI-compatible engine 的集成接缝,都不支持这个 API。要进行公平的重新测试,就必须把 runner 移植到 Responses API。这是一项真正的工程工作,目前却没有回报,因此我们没有立即去做,而是将它记录为重新测试的前置条件:如果 runner 将来新增 Responses backend,或者某个 OpenAI-compatible endpoint 开始允许在启用推理的同时使用工具,我们就会重新对 GPT-5.6 进行基准测试。
这也是对整个测试结果最诚实的表述:我们衡量的不是 GPT-5.6 能做什么,而是把它直接放进我们的集成接缝后会做什么。对于迁移决策来说,这才是重要的衡量指标——你要迁移到的是自己的集成链路,而不是供应商效果最理想的演示链路。
标准应该由你制定,而不是由排行榜决定。我们的 Agent 不需要排行榜顶尖的推理能力;它需要在凌晨两点的语音循环中,正确选择 get_tide_heights,而不是 read_sensor。没有任何公开评测会衡量这一点。你的评测应该衡量系统实际让模型完成的工作——趁还没有人催促你迁移时,把这些工作写成一套 golden set 和一条决策规则。
基准测试一旦建成,后续运行成本就很低。整个门禁流程——三个模型、一次全新的 baseline、记分卡和判定结果——只用了大约 15 分钟的实际时间,API 开销也微不足道。上面的两项测试框架修复占据了大部分工作量,而现在这部分成本已经支付完了。
基准测试会在迁移替你发现集成真相之前,先把真相找出来。Bearer 身份验证缺口和 reasoning_effort 约束,都是在一次 15 分钟的基准测试中暴露的。另一种可能,是等到迁移进行到一半、决策在情感上已经无法回头时,才发现这些问题。
负面结果本身也是一种交付物。最终判定保存在带日期的记分卡和架构决策记录中。下次再有新模型发布时,讨论会从“跑一下基准测试”开始,而不是从头再来。
测试框架、golden set 和替换规则都位于 naturali-agents 的 poseidon/bench/ 中。这套方案诞生于我们为一艘纯电动租赁双体船构建 AI 运维层的过程中:在这个系统里,对话引擎是可插拔组件,而工具面才是产品。
相关内容:离散 MCP 工具与 execute_code:各自在什么情况下更有优势 · 修复 LLM 格式问题应该放在工具层,而不是 prompt 中
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。