会话中途切换模型,零成本

· 3 分钟阅读

这是一个设计决定,而不是一项功能。大多数 agent 工具都是先照着某一家厂商写,之后再去适配其他厂商。这个先后顺序听起来像实现细节,其实就是问题的全部。

「之后再适配」意味着:等第二家厂商接进来时,第一家厂商的假设早已成了承重结构。它们藏在对话存储里,藏在工具调用的表示方式里,藏在流式响应的解析逻辑里——一年后没人会想到去这些地方找。你能注意到的只有症状:换厂商意味着一次迁移,而会话进行到一半要做迁移,就意味着你不会去换厂商。

假设藏在哪里

最容易想到的地方是 HTTP 调用,而这恰恰是错的。任意两家厂商的端点,差距不过一个周末的工作量。真正昂贵的,是你拿到响应之后怎么处理它。

举一个细节。大多数厂商用产生工具结果的那次调用的 id 来标识这个结果,Gemini 却用函数名来标识。如果你的对话存储是按厂商 A 的描述方式保存工具结果的,那么支持 Gemini 就不是新写一个 HTTP 客户端的事——而是要改动你写过的每一份对话记录早已采用的结构。

这就是整个问题的缩影。没有哪个适配层能修好它,因为这些信息在写入时就已经被丢掉了。

中立的历史记录

另一条路是:在写第一个厂商之前就定下来,历史记录不属于任何一家厂商。

OHarness 用引擎自己定义的结构(packages/engine/src/core/types.ts)保存会话记录,而不是任何厂商的格式。一个工具结果同时带有 toolName 和 toolCallId——不是因为引擎两个都需要,而是因为 Gemini 需要名字,其他厂商需要 id,而中立格式必须能渲染成任意一种。

厂商的传输格式在请求发出的那一刻才生成,在响应被合并回来时就丢弃。没有任何东西以它的形式持久化。

所以会话中途切换厂商,什么都不用转换。不是因为转换很快,而是因为根本不存在需要转换的旧结构。

具体能换来什么

模型是一种有定价、有容量、有速率限制、也会有糟糕一周的东西。当这些由别人决定、而你只有一个模型时,它们就成了你的问题。可替换后端的意义不在新鲜感——而在于某家厂商改条款的那天,你可以有自己的态度。

它也让平常的场景顺利跑通。先用便宜的模型起草,难的部分切到贵的模型,网络不好或者代码不该离开公司时,换成你自己机器上的本地模型。这些都在同一个会话里。

不是免费的部分

坦白说说代价:中立格式是一种承诺。每一项各厂商之间有差异的能力——推理强度、提示词缓存、并行工具调用、图片支持——都必须表达成模型上的一个标记,而不能根据厂商去推断,因为发错了结构得到的是 400,而不是一个打了折扣的回答。这是真实的成本,只付一次,而且付在看得见的地方。

另一种选择是在项目存续期间,一遍又一遍地在暗处付这笔账。


OHarness 是一套开源的 agent harness,采用 MIT 许可证。它原生支持 Anthropic、OpenAI 和 Google Gemini,支持任意 OpenAI 兼容端点,也支持 Ollama、LM Studio 和 vLLM 等本地运行时。架构参考说明了分层是如何被强制执行、而不只是停留在设计意图上的;什么是 agent harness 介绍了背后的整体思路。