你在代码评审里一定见过这句话:“把 base URL 指向免费模型就行,API 不是一样的吗?”
听起来很合理。现在大多数服务商都说同一套 chat-completions 方言,那还能坏到哪去?
坏的地方比你想的多。请求的形状是共用的,响应的契约不是。而你的解析器,永远只看得见响应。
这里有一条规则:没做过 diff 的模型替换,不要信。下面是一份探针、它通常会击碎的四条信念,以及背后修正过的模型。
“同一个 API”比错了对象
“同一个 API”通常指同一路由、同一字段名。这是最容易的部分,也是失败得最响、最早的部分——三十秒内你就能看到一个 404。
安静的失败在下一层:字段是否存在、字段的形状、错误响应体。这些东西会在凌晨三点打断你的重试逻辑,而不是在你的 curl 命令里。
所以要比对契约,不是比对端点。
信念一:同一路由意味着同一响应契约
路由只是对路径的承诺,对响应体什么都没说。按各家文档和 issue 讨论,容易变化的地方包括:
- finish_reason的取值,以及它什么时候出现;
- usage到底有没有,带的是哪几个计数器;
- 工具调用返回的是列表、字符串,还是什么都没有;
- 错误响应体的键名(error.messagedetail,还是一段裸字符串);
- 流式分块的边界,以及最后一块落在哪里。
这些都不冷门,全都是契约。修正后的模型是:契约就是你的解析器愿意接受的东西。换之前,先把这份清单写下来。
信念二:能解析成 JSON 就算换成功了
这句话把三种不同的检查压成了一个词,得拆开:
- 解析:响应体是不是合法 JSON?
- 结构:里面有没有你代码要索引的字段?
- 语义:内容是否满足任务?
一个免费端点可以通过第一层,栽在第二层。大量响应返回 200,但响应体被你的代码读成None,然后你在三层调用栈深处收到一个AttributeError。
第三层几乎没人测。解析成功,完全不代表答案是对的。修正后的模型是:解析率、结构率、任务率分开统计,一个数字会把 bug 藏起来。
信念三:usage 数字是可以拿来计费的事实
在多数方言里,usage块是可选的。有的端点返回,有的只偶尔返回,有的计数口径还不一样。
问自己一个直白的问题:如果明天usage消失了,你的预算守卫会不会崩?
会崩,那是你的 bug,不是服务商的问题。用本地分词器在自己这一侧数 token,或者数字符,两个都存下来。修正后的模型是:把usage当提示,把自己的计数器当账本。
信念四:我写的五条提示词就是评测
人人都这么干:五条顺风路径的提示词,由写集成的人自己写,全部通过,上线。
那是冒烟测试,而且是很弱的一种。它证明线路通了,对半夜把你叫起来的那些场景一无所知。
黄金集要从失败里长出来,不是从想象里。从日志里捞五条真实提示词,把已经弄坏过解析器的那些放进去。修正后的模型是:样本小没关系,只要用例够刁钻;小样本的友好用例,是表演。
探针本身
这份探针只用标准库 Python,记录的是形状,不是质量。把build_payload和认证头改成你的服务商文档所写的请求形状即可。
它跑四个用例:只返回 JSON、工具调用形状、要求提前停止、空输入。每个用例记录状态码、耗时、是否合法 JSON、finish_reason、usage是否存在、工具调用是否存在、错误键名,以及响应体开头一小段。
用法是跑两次、存两份回执、做一次 diff:
- PROBE_BASE_URL指向 A,输出到 a.md;
- PROBE_BASE_URL指向 B,输出到 b.md;
- 执行diff -u a.md b.md,两份回执都提交。
这样,替换就带上了证据。
怎么读回执
把它当检查清单读,不是当分数读:
- 一个必须返回 JSON 的用例出现json=no,停,你的解析器死在这里;
- 需要工具调用时出现tools=absent,停,或者接受一个变通方案并重测;
- 你要求它停下,却出现finish=length,说明停止处理不一样,去测;
- usage=absent,删掉所有假设它存在的逻辑;
- status=400配着陌生的err_keys,你的错误分类器需要加一个分支。
不要把ms那一列当基准。那只是一个请求跑两次,是冒烟信号,不是延迟结论。
决策表里,中间那一列是大多数替换实际落点。落在那里没问题,只要适配器是显式的,不是意外的。
免费端点能放在哪
这份探针与服务商无关,任何你能访问的端点都能跑。MonkeyCode 的免费模型访问是拿到一个端点来跑探针的地方之一。披露:本文是作为 MonkeyCode 产品推广的一部分准备的。
走这条路有两个实操提醒:密钥放环境变量,绝不写进脚本;探针要从和应用相同的网络位置跑。如果部署在免费服务器选项上,就在那里跑。路径会影响ms,而路径本身就是你在 diff 的东西之一。
局限,以及谁该跳过
诚实说清楚探针不是什么:
- 它不给答案质量打分,没有评分标准,没有裁判;
- 它不测长上下文、流式边界情况、并发;
- 它不是压测,四个用例跑两遍找不到你的饱和点;
- 它抓不到你从没跑过的提示词上的语义漂移。
如果你需要带人工评审的评分式评测,跳过。如果你没有固定的输出结构,也跳过——没有契约,就没有东西可 diff。
如果你的产品按 token 数计费,这份探针只是起点。在信任任何计数器之前,先拿真实账单对一遍。
先问的那个问题
在下一条“API 一样”的评论出现之前,先问一件事:我的代码到底索引了哪些字段?
那份清单就是你的契约。探针一分钟就能把它量出来。然后,替换就不再是一种感觉,而是一份 diff。
热门跟贴