一、为什么需要多协议翻译客户端生态的碎片化AI 编程工具生态中不同客户端各自为政催生了三种互不兼容的 API 协议Claude Code→ 使用 Chat Completions 协议Codex CLI→ 使用 Responses API 协议Anthropic SDK→ 使用 Messages 协议三个客户端三种协议但上游服务只提供 Chat Completions 一种接口。这就像一个插座要适配三种不同标准的插头硬接只会短路。传统方案的痛点面对这种局面直觉方案各有短板跑两个代理codex-proxy 做协议翻译 mimo-proxy 做推理缓存 → 运维复杂度翻倍排查问题时要在两个代理之间来回跳转改客户端代码侵入式修改上游开源项目 → 维护成本巨大上游一更新就得重新适配单代理只支持一种协议为了兼容多客户端不得不部署多个实例 → 资源浪费且共享缓存等能力无法复用设计目标基于以上痛点确立了三个核心目标单代理多协议入口一个服务同时暴露三种协议的端点统一缓存推理内容无论请求从哪个协议入口进来reasoning 都走同一套缓存逻辑上游只对接 Chat Completions对外多协议对内统一出口降低维护成本二、整体架构textClaude Code ──→ /v1/chat/completions ──┐ Codex CLI ──→ /v1/responses ──→┤ Anthropic SDK──→ /v1/messages ──→┤ ├──→ reasoning 注入 → Chat Completions → 上游 仪表盘 ──→ /api/* ──→┘请求进入代理后经过一条三层处理流水线协议翻译层将 Responses API 或 Anthropic Messages 协议的请求翻译为 Chat Completions 格式Reasoning 注入层统一调用inject_reasoning为每条消息补全推理内容上游转发层通过stream_proxy完成流式或非流式的向上游转发三层各司其职协议差异被封印在翻译层内部后续链路无感知。三、Responses API 翻译核心请求翻译extract_messagesResponses API 的input数组包含三种 item 类型需要一一映射原始类型翻译后type: messagerole: user或role: assistanttype: function_call合并为一条assistanttool_calls[]type: function_call_outputrole: tool几个关键处理细节连续 function_call 合并当多条 function_call 连续出现时合并为同一条 assistant 消息tool_calls 按序排列——这是 Chat Completions 协议对多工具调用的标准表示instructions → system message将 Responses API 顶层的系统指令字段映射为 Chat Completions 的 system 角色消息消息重排确保tool消息紧跟在对应的assistant消息之后避免上游因消息顺序不当而拒绝请求Schema 字段清理剔除additionalProperties和strict等 Chat Completions 不兼容的字段防止校验报错流式响应翻译stream_responses_sse这是整个翻译层最精细的部分——需要将 Chat Completions 返回的 SSE 事件块实时重组为 Responses API 规定的事件序列。纯文本路径的事件序列textresponse.created → response.in_progress → response.output_item.added (typemessage) → response.content_part.added → response.output_text.delta (×N 次增量) → response.output_text.done → response.content_part.done → response.output_item.done → response.completed工具调用路径的事件序列textresponse.output_item.added (typefunction_call) → response.function_call_arguments.delta (×N 次增量) → response.function_call_arguments.done → response.output_item.done → response.completed每一个 delta 事件都精确对应 Chat Completions chunk 中的内容增量下游客户端完全感知不到中间经过了一层协议转换。四、Anthropic Messages 翻译核心请求翻译extract_anthropic_messagesAnthropic 的 Messages 协议在结构上与 Chat Completions 有显著差异映射关系如下Anthropic 字段Chat Completions 字段system顶层字段role: systemcontent[].type: textrole: assistantcontentcontent[].type: tool_useassistanttool_calls[]content[].type: tool_resultrole: tooltools[].input_schematools[].function.parametersAnthropic 将文本、工具调用、工具结果全部平铺在content数组中而 Chat Completions 是按角色分层的。翻译层需要完成这种“扁平 → 分层”的结构转换。流式响应翻译stream_anthropic_sseAnthropic 的流式事件同样有其独特的事件类型序列textmessage_start → content_block_start (typetext) → content_block_delta (text_delta ×N 次增量) → content_block_stop → content_block_start (typetool_use) → content_block_delta (input_json_delta ×N 次增量) → content_block_stop → message_delta → message_stop每个content_block对应一段独立的内容块文本或工具调用块内通过 delta 事件逐步传递增量内容块之间通过 start/stop 事件明确边界。五、统一 Reasoning 缓存架构上最优雅的一点在于无论请求从哪个协议入口进来最终都汇入同一条缓存链路。协议翻译层将各类请求统一转成 Chat Completions 格式随后与原生 CC 路由走完全相同的inject_reasoning逻辑无需为 Responses API 或 Anthropic 单独维护缓存代码save_reasoning在流结束时统一触发将本轮推理内容持久化这种“翻译先行缓存统一”的设计让新增一个协议入口的成本降到最低——只需实现翻译层缓存能力自动复用。六、模型路由上游调度每个上游服务声明一个模型标识实现请求的精准分发yamlupstreams: - name: DeepSeek model: deepseek-chat url: https://api.deepseek.com/v1 - name: MiMo model: mimo-v4 url: https://api.mimo.com/v1路由逻辑简洁明确请求中的model字段与上游配置精确匹配未命中时自动回退到活跃上游。配合 SQLite 持久化的上游列表模型的新增和切换都可以在线完成无需重启。七、错误透传设计代理层刻意去掉了内部的自动重试循环采用“透明代理”的错误处理哲学上游返回 503 → 原样返回 503 给下游下游客户端Claude Code、Codex CLI 等各自按自己的指数退避策略重连不吞错误、不包装错误信息、不修改状态码流式请求中发生错误时抛出UpstreamError→ 路由层捕获 → 以原始状态码响应客户端这样做的好处是客户端看到的是“直连上游”的错误行为不会因为代理的额外重试而引入超时累积或重复请求也避免了“代理层重试成功但客户端已超时断开”的尴尬局面。八、代码结构概览文件职责src/responses.pyResponses API 请求翻译 流式响应事件映射src/anthropic_translate.pyAnthropic Messages 请求翻译 流式响应事件映射src/routes.py路由注册 请求分发按路径指向不同翻译层src/proxy.pyreasoning 注入与缓存 流式转发核心逻辑src/upstreams.py上游模型路由 SQLite 持久化上游列表每个模块职责单一协议翻译逻辑与核心代理逻辑完全解耦新增协议只需增加翻译文件并注册路由。九、总结这套多协议翻译管线实现了三个“统一”统一入口一个代理同时承载三种协议的端点彻底告别多代理运维的噩梦统一缓存外来请求协议各不相同但在推理缓存层面殊途同归一份代码服务所有入口统一出口上游始终只对接 Chat Completions内部复杂度对外部完全透明流式事件映射做到了位下游客户端感知不到代理的存在。模型路由让一个代理同时服务多个供应商而错误透传设计保证了代理不成为链路中的“黑盒”。整个方案的核心思路可以概括为一句协议差异是入口的事缓存和转发是所有人的事。