把 Claude Code、Codex CLI 或 Gemini CLI 接到同一个 API 网关时,最容易忽略的不是模型名称,而是协议差异:模型列表里能看到名称,客户端却报 404;普通对话能返回文本,一开工具调用就失败;请求返回 200,日志里的模型、用量字段却对不上。

本文只讨论如何验证兼容性,不做服务商排行,也不比较套餐或价格。三种 CLI 不是简单替换同一个 Base URL,它们背后至少涉及 Anthropic Messages、OpenAI Responses 和 Gemini generateContent 三种请求结构。

文中的请求字段以各厂商公开接口结构为依据,示例统一使用占位地址和占位模型名,读者应替换成自己实际使用的配置。

先看清:三种 CLI 不是一个接口换三次名字

客户端方向官方核心接口最小请求重点成功后至少回读
Claude CodePOST /v1/messagesx-api-keyanthropic-versionmessagesmax_tokensidcontentusage、停止原因
Codex CLIPOST /v1/responsesBearer 鉴权、modelinputidstatusoutputusage
Gemini CLIPOST .../v1beta/models/{model}:generateContentx-goog-api-keycontents.partsresponseIdmodelVersioncandidatesusageMetadata

表中的路径和字段来自三家模型厂商当前官方 API 文档。中转平台可能在域名前增加自己的前缀,也可能只兼容其中一部分。“兼容 OpenAI”不能自动推导出兼容 Anthropic Messages 或 Gemini 原生协议。

检查一:路径是否真的存在

最先确认的不是模型名称,而是客户端实际访问的路径。下面的脚本只检查端点是否被网关识别,不要求返回成功内容:

BASE_URL="https://example-gateway.test"

for path in \
  "/v1/messages" \
  "/v1/responses" \
  "/v1beta/models/example-model:generateContent"
do
  code=$(curl -sS -o /dev/null -w '%{http_code}' \
    -X POST "${BASE_URL}${path}" \
    -H 'Content-Type: application/json' \
    -d '{}')
  printf '%-58s %s\n' "$path" "$code"
done

这里不能把所有非 200 都判为“不支持”。401403 往往说明路径存在但鉴权失败,400 可能说明路径存在但请求体不完整;稳定的 404 才更接近“路径或前缀不对”。仍需结合平台文档和完整错误体判断。

检查二:鉴权头不能照搬

三套协议的官方鉴权写法不同。OpenAI Responses 通常使用 Authorization: Bearer ...,Anthropic Messages 使用 x-api-key 并要求 anthropic-version,Gemini API 使用 x-goog-api-key。有些中转站会把它们统一成一种写法,但这必须由文档或真实请求证明。

排障时建议先打印“发送了哪些请求头名称”,不要打印请求头的值。公开截图中只保留密钥前四位和后四位也不安全,最稳妥的做法是完整遮挡。

检查三:用最小请求验证响应结构

下面给出 Messages 和 Responses 两个最小请求。模型名、地址和 Key 都用环境变量提供,避免把真实密钥写进脚本:

# Anthropic Messages 结构
curl "$BASE_URL/v1/messages" \
  -H "x-api-key: $API_KEY" \
  -H 'anthropic-version: 2023-06-01' \
  -H 'content-type: application/json' \
  -d '{
    "model": "'$CLAUDE_MODEL'",
    "max_tokens": 32,
    "messages": [{"role":"user","content":"只回复 OK"}]
  }'

# OpenAI Responses 结构
curl "$BASE_URL/v1/responses" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "'$OPENAI_MODEL'",
    "input": "只回复 OK",
    "max_output_tokens": 32
  }'

最小请求只验证认证、路径、模型名和基本响应结构。它不能证明流式事件、工具调用、长上下文和 CLI 的完整交互已经兼容。

检查四:流式与工具调用要单独测

CLI 工具常常依赖流式事件和工具调用。如果平台只是把最终文本转换成兼容格式,普通 curl 可能成功,CLI 仍会卡在“等待工具结果”。

至少要追加两类测试:一是要求模型分段输出,确认事件顺序、结束事件和异常中断能被客户端解析;二是提供一个无副作用工具,例如只读取固定字符串,确认工具名称、参数、调用标识和工具结果能完整往返。文本能返回,不等于 Agent 工作流可用。

检查五:模型名、分组和实际路由要对上

模型出现在价格页,只能证明目录展示。真实请求完成后,应核对四层信息:请求中的目标模型、响应中的模型字段、账号所属分组、平台调用日志中的实际模型或渠道。如果平台发生自动回退,还要明确记录回退前后的模型,不能因为最终有文本就把它算作目标模型成功。

一个安全的脱敏记录可以长这样:

测试时间:2026-09-05 17:21 CST
目标协议:OpenAI Responses
目标模型:gpt-6-astra
结果标记:返回预期短文本
平台日志:模型字段一致
用量回读:输入 514 Token,输出 22 Token
费用回读:$0.000562
未公开:API Key、请求 ID、账号、上游线路

这条脱敏记录来自笔者运营的 FishAI API 测试环境。客户端收到预期文本,后台日志能对应同一时间窗口、模型、输入输出 Token 和费用。它只证明这一次 Responses 请求形成了“请求—响应—用量—扣费”闭环;不能外推为三种 CLI 全部兼容,也不能外推为长期稳定性。

检查六:失败重试是否造成重复消耗

只记录成功请求,会漏掉失败重试造成的额外消耗。建议为每次验收记录:总请求数、成功数、可重试失败数、实际重试次数、输入 Token、缓存读取、缓存写入、输出 Token 和最终费用。

最简单的总成本口径是:

总成本 = 所有尝试的输入费用 + 缓存费用 + 输出费用 + 失败请求可能产生的费用

如果第一次请求已经发送了长上下文,自动重试又完整发送一次,同一段输入就可能被重复处理。重试必须有上限;同一错误连续出现时,应先判断路径、鉴权、限流还是服务端故障,而不是无限重放。

一张可直接使用的验收表

在决定把某个中转站接进日常开发前,可以用下表保存结果:

检查项通过标准当前结果
协议路径对应端点有明确文档且请求可达通过 / 失败 / 未确认
鉴权不改源码即可安全传递 Key通过 / 失败 / 未确认
最小请求返回结构与目标协议一致通过 / 失败 / 未确认
流式与工具CLI 能完成一次真实工具往返通过 / 失败 / 未确认
路由与日志目标模型、实际模型、用量可核对通过 / 失败 / 未确认
计费与重试成功和失败尝试都能解释成本通过 / 失败 / 未确认

“未确认”不是零,也不是默认通过。特别是流式、工具调用和计费,缺证据时宁可保留未确认。

结论:先完成协议验收

三种 CLI 分别依赖不同的请求结构。可复现的兼容性判断应包括路径、鉴权、最小响应、流式工具、实际路由和计费重试六项。

无论使用自建网关还是第三方兼容服务,都应先用脱敏小样跑完目标协议,再核对自己的调用日志。能说清“请求去了哪里、返回了什么、用了多少 Token、为什么产生这些用量”,再进入更复杂的流式和工具调用测试。

资料核对日期:2026-09-06。官方协议依据:OpenAI Responses API、Anthropic Messages API、Google Gemini generateContent API。模型、路径和平台兼容范围会变化,发布前应再次核对当前文档和账号实际返回。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐