GPT 中转站背后是不是 Claude:自己从响应的字段里看
有的中转站把 GPT 的请求转给别家的模型,再把格式改回来。这种转换有时会在响应里留下痕迹。本文讲清 OpenAI 两种接口各自正常的响应长什么样、哪些字段不该出现、怎么用一条命令自己看,以及这个办法查不出什么。
你请求的是 GPT,中转站后面实际跑的可能是别家的模型,比如 Claude,中间由它做一层接口格式的转换,把响应改成 OpenAI 的样子再返回给你。
OpenAI 没有 Claude 思考签名那样的加密凭据可查,但这种转换有时会留下痕迹:响应里出现了 OpenAI 自己不会返回的字段。看这些痕迹不需要专门的工具,一条命令就行。
先说这个办法的边界:它只能发现留下了痕迹的转换。 没有发现异常,不等于模型是真的。
先分清你用的是哪种接口
OpenAI 有两种接口,响应的样子不同。两种的用量字段名字不一样,这是最容易看错的地方。
| Chat Completions | Responses | |
|---|---|---|
| 请求地址 | /v1/chat/completions |
/v1/responses |
响应的 id |
chatcmpl- 开头 |
resp_ 开头 |
响应的 object |
chat.completion |
response |
| 用量字段 | prompt_tokens、completion_tokens、total_tokens,另有两项明细 |
input_tokens、output_tokens、total_tokens,另有明细 |
表里的内容取自 OpenAI 的官方文档和 API 参考。
Codex 用的是 Responses 接口;中转站文档里说的“OpenAI 兼容”,通常指的是 Chat Completions。你在测哪一种,就对照哪一列。
哪些东西不该出现
检测工具 Veridrop 在公开说明里列出了它当作“后端指纹”的几种痕迹。它们出现在一个声称是 GPT 的响应里,说明中间有接口转换:
| 痕迹 | 说明 |
|---|---|
用量里有 claude_ 开头的字段,例如 claude_cache_creation_5_m_tokens |
Claude 的缓存用量被带了过来 |
用量里有 usage_source: anthropic 这样的字段 |
直接写明了来源 |
Chat Completions 的响应里,用量用的是 input_tokens、output_tokens |
这是 Anthropic 接口的命名,Chat Completions 应该是 prompt_tokens、completion_tokens |
第三条一定要结合接口来看。在 Responses 接口里,input_tokens、output_tokens 是 OpenAI 自己的正常命名,不是痕迹。把这一点弄反,会冤枉一个正常的中转站。
另外,响应最外层的 id 也值得看一眼:Chat Completions 的响应,id 应该以 chatcmpl- 开头。
自己动手看
下面用 GPT-6.1 Sol 举例。把地址和 key 换成你的中转站的。
Chat Completions 接口:
curl -sS https://你的中转站地址/v1/chat/completions \
-H "Authorization: Bearer 你的key" \
-H "content-type: application/json" \
-d '{
"model": "gpt-6.1-sol",
"messages": [{ "role": "user", "content": "用一句话介绍 HTTP 状态码 404。" }]
}'
Responses 接口:
curl -sS https://你的中转站地址/v1/responses \
-H "Authorization: Bearer 你的key" \
-H "content-type: application/json" \
-d '{
"model": "gpt-6.1-sol",
"input": "用一句话介绍 HTTP 状态码 404。"
}'
拿到返回的 JSON 后,不要看它回答了什么,看这几处:
- 最外层的
id和object,是否和上面表里对应的那一列一致; usage里有哪些字段,名字是否和这种接口应有的一致;usage里有没有上一节列的那些多出来的字段;- 有没有
usage。像这样不用流式输出的请求,官方的响应里都带着用量,没有的话你就没法对账。
装了 jq 的话,在命令后面加上 | jq '{id, object, usage}',只看这三项。
注意要看原始的响应。经过 SDK 或者编程工具之后,多余的字段可能已经被丢掉了,所以要用 curl 这样直接发请求的办法。
再测一项:严格的结构化输出
第二个可以自己测的点,是结构化输出。OpenAI 的文档写明,结构化输出保证返回的是合法的 JSON,并且符合你给的 schema。
用 Chat Completions 接口,要求严格按 schema 返回:
curl -sS https://你的中转站地址/v1/chat/completions \
-H "Authorization: Bearer 你的key" \
-H "content-type: application/json" \
-d '{
"model": "gpt-6.1-sol",
"messages": [{ "role": "user", "content": "北京的邮政编码是多少?" }],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "answer",
"strict": true,
"schema": {
"type": "object",
"properties": { "city": { "type": "string" }, "postcode": { "type": "string" } },
"required": ["city", "postcode"],
"additionalProperties": false
}
}
}
}'
看返回的 content。正常情况下它是一段纯 JSON。如果它是包在 Markdown 代码块里的(以三个反引号加 json 开头),按 Veridrop 的说明有两种可能:
- 中转站没有把
response_format这个参数传给上游; - 传了,但后面的模型不理解严格模式,很可能不是 GPT。
这两种可能,单看这一次响应分不开。而且结构化输出失败还有别的原因,比如模型拒绝回答、输出被截断。所以这一项没通过,结论也只能写到“结构化输出在这家站上不可靠”为止。
这个办法查不出什么
| 情况 | 为什么查不出 |
|---|---|
| 中转站把多余的字段清理干净了 | 痕迹是转换时没处理好才留下的,处理得仔细就没有 |
| 同厂的贵模型换成了便宜模型 | 都是 OpenAI 的模型,响应的格式完全一样 |
| 有时真、有时假 | 你只看了这一次请求 |
所以结论要这样下:看到了痕迹,基本可以确定中间有接口转换;没看到,什么也确定不了。
还有一种情况不算造假,不要误判:有的中转站把各家的模型都统一成 OpenAI 兼容的接口,你通过这个接口明确请求的就是 Claude 模型,响应里带着 Claude 的痕迹是正常的。有问题的是你请求 GPT、拿到的却带着别家的痕迹。
响应里的 model 字段不能当证据
响应里有一个 model 字段,写着这次用的模型。它只是一个字符串,中转站想填什么都可以,不能用来证明任何事。同理,问模型“你是谁”也没有用,见问“你是什么模型”为什么验证不了真假。
小结
- 先分清接口:Chat Completions 和 Responses 的用量字段名字不同。
- 看原始响应里的
id、object和usage,找不该出现的字段。 - 看到痕迹能下结论,没看到不能。
- 想要更完整的判断,用自己的 key 到 Veridrop 检测一次,它会把协议、能力和用量几类检查合起来看。
Claude 这边有更硬的线索,见thinking signature 是什么;其他的掺假手段见中转站怎么掺假。