很多人第一次接触 Claude Code 时,都会被它的交互体验、工具调用能力和工程化工作流打动;但与此同时,也会自然产生一个问题:能不能保留 Claude Code 这一层的体验,同时把底层编程模型切到 Codex / GPT-5.4 这一类 OpenAI 模型?
答案是可以,但不能“直接改一个地址”就完事。真正落地时,你会碰到协议不兼容、网关字段兼容、流式响应桥接、推理强度控制等一串现实问题。本文不是概念介绍,而是一篇基于真实部署过程整理出来的实战教程:我们会把 Claude Code 接到 gpt-5.4,并让它在实际运行时走 xhigh 推理,同时保留稳定可用的 CLI 体验。
一、这套方案到底解决了什么问题?
如果你已经有一套 OpenAI 兼容网关,例如:
Sub2API- 自建 OpenAI Responses 代理
- 公司内部统一大模型网关
你很容易会想到,直接把:
ANTHROPIC_BASE_URL=http://your-gateway
塞给 Claude Code,然后希望它直接工作。但这一步通常会失败。原因很简单:
Claude Code对外说的是 Anthropic 风格协议。- 很多现成网关只暴露 OpenAI 风格接口,例如
/responses、/chat/completions。 - 两边虽然都叫“模型调用”,但请求体结构、流式事件格式、工具调用结构并不完全一致。
所以,我们真正要解决的不是“模型能不能访问”,而是:
- 让
Claude Code看到的是它熟悉的 Anthropic Messages 接口。 - 让底层模型仍然走
gpt-5.4。 - 把中间的协议差异、安全字段差异、流式输出差异都吸收掉。
二、最终架构
我们最终采用的链路是:
Claude Code
-> LiteLLM
-> sidecar strip-proxy
-> Sub2API
-> OpenAI gpt-5.4 / gpt-5.4-mini
每一层的职责都很清楚:
- Claude Code:保留 CLI 体验、工具调用、会话管理。
- LiteLLM:对外暴露 Anthropic 兼容接口,把
claude-sonnet-4-6等模型别名映射到 OpenAI 模型。 - sidecar strip-proxy:处理少量但关键的兼容细节,例如移除上游不支持的字段、按模型注入推理强度。
- Sub2API:作为已有 OpenAI 兼容网关,继续负责真正的上游账号与模型转发。
三、为什么不能只用 Sub2API?
这里是最容易误判的地方。
如果你的网关只提供了 OpenAI 风格接口,例如:
/responses/v1/responses/chat/completions
那么它并不能直接替代 Anthropic Messages 接口。Claude Code 真正依赖的是:
/v1/messages/v1/messages/count_tokens
这也是为什么很多人第一次尝试时会遇到以下现象:
- 浏览器登录流程反复出现。
- CLI 提示
Service temporarily unavailable。 - 明明网关可以访问模型,但
Claude Code就是用不起来。
问题不是账号,而是协议。
四、LiteLLM 在这里扮演什么角色?
LiteLLM 是这套方案里最关键的一层,因为它让我们可以:
- 对
Claude Code暴露 Anthropic 兼容入口。 - 对后端继续使用 OpenAI 模型。
- 把
claude-sonnet-4-6这种“表面模型名”映射到gpt-5.4。
实际映射大致如下:
claude-sonnet-4-6 -> openai/gpt-5.4
claude-opus-4-1 -> openai/gpt-5.4
claude-haiku-4-5 -> openai/gpt-5.4-mini
这一步非常重要,因为 Claude Code 本身不会主动去请求一个叫 gpt-5.4 的 Anthropic 模型名。它发出来的通常仍然是 claude-sonnet-4-6 这种名称,而 LiteLLM 负责做内部路由。
五、真实踩坑:为什么还需要一个 sidecar?
按理说,LiteLLM 已经足够强大,但真实部署时我们仍然补了一个很薄的 sidecar。原因有两个,而且都非常现实。
1. 上游网关不支持某些字段
在真实调用过程中,Claude Code -> LiteLLM 转成 OpenAI Responses 请求后,会携带一些字段,其中最典型的是顶层 user 字段。
而我们的 Sub2API 上游在这一点上比较严格,会直接报错:
Unsupported parameter: user
这类问题最烦人的地方在于:
- 你手工发一个最简
curl请求可能是通的。 - 一旦换成真实的
Claude CodeCLI,请求就多带了字段,立刻失败。
所以我们加了一层 sidecar,在转发给 Sub2API 前,把不兼容字段剥掉。
2. 我们希望“按模型”控制推理强度
如果你想让底层 gpt-5.4 默认走高推理,最稳妥的做法不是依赖上层客户端“也许会传”,而是在你可控的桥接层统一注入:
"reasoning": { "effort": "xhigh" }
但这里有一个细节必须注意:
gpt-5.4适合强制xhighgpt-5.4-mini不建议一起强制拉满
所以我们最终采用的是:
- 仅当模型名精确等于
gpt-5.4时,注入xhigh gpt-5.4-mini保持默认
六、核心配置示例
下面给一个足够接近生产的 LiteLLM 配置示例。
1. config.yaml
model_list:
- model_name: gpt-5.4
litellm_params:
model: openai/gpt-5.4
api_base: http://strip-proxy:4100
api_key: os.environ/SUB2API_API_KEY
- model_name: gpt-5.4-mini
litellm_params:
model: openai/gpt-5.4-mini
api_base: http://strip-proxy:4100
api_key: os.environ/SUB2API_API_KEY
- model_name: claude-sonnet-4-6
litellm_params:
model: openai/gpt-5.4
api_base: http://strip-proxy:4100
api_key: os.environ/SUB2API_API_KEY
- model_name: claude-opus-4-1
litellm_params:
model: openai/gpt-5.4
api_base: http://strip-proxy:4100
api_key: os.environ/SUB2API_API_KEY
- model_name: claude-haiku-4-5
litellm_params:
model: openai/gpt-5.4-mini
api_base: http://strip-proxy:4100
api_key: os.environ/SUB2API_API_KEY
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
litellm_settings:
drop_params: true
2. docker-compose.yml
services:
strip-proxy:
image: node:20-alpine
container_name: sub2api-strip-proxy
restart: unless-stopped
working_dir: /app
command:
- node
- /app/sub2api-strip-proxy.mjs
environment:
TARGET_HOST: "192.168.31.24"
TARGET_PORT: "8080"
volumes:
- ./sub2api-strip-proxy.mjs:/app/sub2api-strip-proxy.mjs:ro
litellm:
image: docker.litellm.ai/berriai/litellm:main-stable
container_name: litellm
restart: unless-stopped
depends_on:
- strip-proxy
command:
- --config
- /app/config.yaml
- --host
- 0.0.0.0
- --port
- "4000"
env_file:
- .env
ports:
- "4001:4000"
volumes:
- ./config.yaml:/app/config.yaml:ro
3. sidecar 的核心逻辑
这个 sidecar 做的事情非常少,但非常关键:
- 把请求体中的
user字段移除 - 当模型是
gpt-5.4时,补上reasoning.effort = xhigh - 保留流式响应,避免破坏 CLI 体验
伪代码逻辑如下:
if (payload.model === "gpt-5.4") {
payload.reasoning = {
...payload.reasoning,
effort: "xhigh"
}
}
delete payload.user
forward(payload)
七、本机 Claude Code 应该怎么配?
本机不需要再直连 Sub2API,而是直接连 LiteLLM 的 Anthropic 兼容入口。
export ANTHROPIC_BASE_URL="http://192.168.31.24:4001"
export ANTHROPIC_API_KEY="YOUR_GATEWAY_KEY"
export ANTHROPIC_AUTH_TOKEN="YOUR_GATEWAY_KEY"
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
几个实用建议:
- 如果你只是测试 CLI,先用
claude -p "只回复 OK"做最小验证。 - 如果你刚改完
~/.zshrc,记得source ~/.zshrc或重开终端。 - 如果旧终端里还残留着旧的
ANTHROPIC_BASE_URL,你会误以为“新网关没生效”。
八、部署时最值得记住的几个经验
经验 1:先验证协议,再验证模型
很多排障一上来就盯着“是不是 key 不对”“是不是模型名不对”,但实际上第一步应该验证:
/v1/messages能不能返回/v1/messages/count_tokens能不能返回
如果这两条不通,就别急着研究模型参数了。
经验 2:手工 curl 通,不代表 Claude Code 一定通
真实 CLI 请求常常会多带一些字段,例如:
usertools- 流式标记
- 计费或追踪相关字段
这类字段才是很多“明明 curl 正常、CLI 却不行”的根因。
经验 3:不要把 mini 模型也默认拉到 xhigh
这是一个特别容易“图省事”做错的点。gpt-5.4-mini 的定位本来就不是和主模型拼极限推理深度,如果你一把梭把它也强制拉到 xhigh,通常只会增加延迟和成本,不一定提高性价比。
经验 4:健康检查不要想当然
我们在实战里就遇到过一个很典型的小坑:LiteLLM 容器本身没问题,但镜像里没有 curl,结果健康检查一直红。服务其实是好的,只是探针写错了。
正确思路是:健康检查要依赖镜像里确定存在的工具。
九、推荐的验证顺序
如果你要自己复刻这套方案,建议按这个顺序走:
- 验证
Sub2API /responses能直接调用gpt-5.4 - 验证 LiteLLM 的
/v1/messages能正常返回 - 验证
/v1/messages/count_tokens正常 - 验证
claude --bare -p "只回复 OK" - 最后再验证普通
claude -p和交互式claude
这样排障效率最高,因为你每一步都只验证一层,不会把问题揉成一团。
十、日常运维命令
# 查看容器状态
cd /opt/litellm
docker-compose ps
# 重建 LiteLLM
docker-compose up -d --force-recreate litellm
# 重建 sidecar
docker-compose up -d --force-recreate strip-proxy
# 查看 LiteLLM 日志
docker logs -f litellm
# 查看 sidecar 日志
docker logs -f sub2api-strip-proxy
十一、这套方案适合谁?
如果你符合下面任意一种情况,这套做法都很值得尝试:
- 你喜欢
Claude Code的代理式工作流,但想把底层模型切到 OpenAI 体系。 - 你已经有统一的 OpenAI 兼容网关,不想再单独维护一套 Anthropic 直连配置。
- 你希望对模型路由、推理强度、字段兼容做更细粒度控制。
结语
把 Claude Code 接到 Codex / GPT-5.4,本质上不是“换模型”这么简单,而是一次完整的协议桥接与工程化收口。真正决定体验成败的,往往不是模型本身,而是中间这几层:
- Anthropic 与 OpenAI 协议的衔接
- 请求字段兼容
- 流式响应稳定性
- 按模型定制推理策略
一旦这些都收拾好,你就能同时拿到两边的优点:上层保留 Claude Code 的工作流体验,下层切到自己更想用的编程模型。
如果你也在做类似的桥接实践,一个最值得记住的结论是:不要追求“一步到位”,而要把每一层单独验证清楚。 只有这样,这套链路才能从“能跑”真正变成“可长期稳定使用”。


评论