OpenAI 协议兼容层
概述
claude-code 支持通过 OpenAI Chat Completions API(/v1/chat/completions)兼容任意 OpenAI 协议端点,包括 Ollama、DeepSeek、vLLM、One API、LiteLLM 等。
核心策略为流适配器模式:在 queryModel() 中插入提前返回分支,将 Anthropic 格式请求转为 OpenAI 格式,调用 OpenAI SDK,再将 SSE 流转换回 BetaRawMessageStreamEvent 格式。下游代码(流处理循环、query.ts、QueryEngine.ts、REPL)完全不改。
环境变量
| 变量 | 必需 | 说明 |
|---|---|---|
CLAUDE_CODE_USE_OPENAI | 是 | 设为 1 启用 OpenAI 后端 |
OPENAI_API_KEY | 是 | API key(Ollama 等可设为任意值) |
OPENAI_BASE_URL | 推荐 | 端点 URL(如 http://localhost:11434/v1) |
OPENAI_MODEL | 可选 | 覆盖所有请求的模型名(跳过映射) |
OPENAI_MODEL_MAP | 可选 | JSON 映射,如 {"claude-sonnet-4-6":"gpt-4o"} |
OPENAI_ORG_ID | 可选 | Organization ID |
OPENAI_PROJECT_ID | 可选 | Project ID |
使用示例
架构
请求流程
模型名解析优先级
resolveOpenAIModel() 的解析顺序:
OPENAI_MODEL环境变量 → 直接使用,覆盖所有OPENAI_MODEL_MAPJSON 查表 → 自定义映射- 内置默认映射(见下表)
- 以上都不匹配 → 原名透传
内置模型映射
| Anthropic 模型 | OpenAI 映射 |
|---|---|
claude-sonnet-4-6 | gpt-4o |
claude-sonnet-4-5-20250929 | gpt-4o |
claude-sonnet-4-20250514 | gpt-4o |
claude-3-7-sonnet-20250219 | gpt-4o |
claude-3-5-sonnet-20241022 | gpt-4o |
claude-opus-4-6 | o3 |
claude-opus-4-5-20251101 | o3 |
claude-opus-4-1-20250805 | o3 |
claude-opus-4-20250514 | o3 |
claude-haiku-4-5-20251001 | gpt-4o-mini |
claude-3-5-haiku-20241022 | gpt-4o-mini |
[1m] 后缀(Claude 特有的 modifier)。
文件结构
新增文件
修改文件
| 文件 | 改动 |
|---|---|
src/utils/model/providers.ts | 添加 'openai' provider 类型 + CLAUDE_CODE_USE_OPENAI 检查(最高优先级) |
src/utils/model/configs.ts | 每个 ModelConfig 添加 openai 键 |
src/services/api/claude.ts | 在 stripExcessMediaItems() 后插入 OpenAI 提前返回分支(~8 行) |
package.json | 添加 "openai": "^4.73.0" 依赖 |
消息转换规则
Anthropic → OpenAI
| Anthropic | OpenAI |
|---|---|
system prompt(string[]) | role: "system" 消息(\n\n 拼接) |
user + text 块 | role: "user" 消息 |
assistant + text 块 | role: "assistant" + content |
assistant + tool_use 块 | role: "assistant" + tool_calls[] |
user + tool_result 块 | role: "tool" + tool_call_id |
thinking 块 | 静默丢弃(请求侧) |
工具转换
| Anthropic | OpenAI |
|---|---|
{ name, description, input_schema } | { type: "function", function: { name, description, parameters } } |
cache_control, defer_loading 等字段 | 剥离 |
tool_choice: { type: "auto" } | "auto" |
tool_choice: { type: "any" } | "required" |
tool_choice: { type: "tool", name } | { type: "function", function: { name } } |
消息转换示例
流转换规则
SSE Chunk → Anthropic Event 映射
| OpenAI Chunk | Anthropic Event |
|---|---|
| 首个 chunk | message_start(含 usage) |
delta.reasoning_content | content_block_start(thinking) + thinking_delta |
delta.content | content_block_start(text) + text_delta |
delta.tool_calls | content_block_start(tool_use) + input_json_delta |
finish_reason: "stop" | message_delta(stop_reason: "end_turn") |
finish_reason: "tool_calls" | message_delta(stop_reason: "tool_use") |
finish_reason: "length" | message_delta(stop_reason: "max_tokens") |
块顺序
当模型返回reasoning_content 时(如 DeepSeek),块顺序与 Anthropic 一致:
reasoning_content 时:
finish_reason 映射
| OpenAI | Anthropic |
|---|---|
stop | end_turn |
tool_calls | tool_use |
length | max_tokens |
content_filter | end_turn |
事件序列示例
纯文本响应:功能支持
Thinking(思维链)
请求侧:不需要显式配置。支持思维链的模型(DeepSeek 等)会自动返回delta.reasoning_content。
响应侧:delta.reasoning_content 被转换为 Anthropic thinking content block:
Prompt Caching
请求侧:OpenAI 端点使用自动缓存,无需显式设置cache_control。
响应侧:OpenAI 的 usage.prompt_tokens_details.cached_tokens 被映射到 Anthropic 的 cache_read_input_tokens:
message_start 的 usage 中报告缓存命中量。
工具调用(Tool Use)
完整支持 OpenAI function calling 格式。所有本地工具(Bash、FileEdit、Grep、Glob、Agent 等)透明工作——它们通过 JSON 输入输出通信,格式无关。 工具参数以input_json_delta 形式流式传输,由下游代码拼接解析。
不支持的功能
| 功能 | 策略 |
|---|---|
| Beta Headers | 不发送 |
| Server Tools (advisor) | 不发送 |
| Structured Output | 不发送 |
| Fast Mode / Effort | 不发送 |
| Tool Search / defer_loading | 不启用,所有工具直接发送 |
| Anthropic Signature | thinking block 的 signature 字段为空字符串 |
| cache_creation_input_tokens | 始终为 0(OpenAI 不区分创建/读取) |
测试
测试覆盖矩阵
| 功能 | convertMessages | convertTools | streamAdapter | modelMapping |
|---|---|---|---|---|
| 文本消息转换 | ✅ | |||
| tool_use 转换 | ✅ | |||
| tool_result 转换 | ✅ | |||
| thinking 剥离 | ✅ | |||
| 完整对话流程 | ✅ | |||
| 工具 schema 转换 | ✅ | |||
| tool_choice 映射 | ✅ | |||
| 纯文本流 | ✅ | |||
| 工具调用流 | ✅ | |||
| 混合文本+工具 | ✅ | |||
| finish_reason 映射 | ✅ | |||
| thinking 流 | ✅ | |||
| thinking+text 切换 | ✅ | |||
| thinking+tool_use 切换 | ✅ | |||
| 块索引正确性 | ✅ | |||
| cached_tokens 映射 | ✅ | |||
| OPENAI_MODEL 覆盖 | ✅ | |||
| 默认模型映射 | ✅ | |||
| 未知模型透传 | ✅ | |||
| [1m] 后缀剥离 | ✅ |
端到端验证
代码统计
| 类别 | 行数 |
|---|---|
| 新增源码 | ~620 行 |
| 新增测试 | ~450 行 |
| 改动现有代码 | ~25 行 |
| 总计 | ~1100 行 |