协议层的"有损翻译"
Claude Code 是一个高度自动化的 Agent,极度依赖流式数据的精确结构。原生 Anthropic API 使用 Server-Sent Events(SSE)中的精细事件流来处理工具调用,整个过程被严格分发在三个阶段:
content_block_start:定义类型和初始化content_block_delta:增量填充内容content_block_stop:标记结束
每个事件都带有特定的 index 和 type 标记,形成一套严格的状态机。
而反代对接的 Google API 响应结构完全不同,使用 candidates.content.parts.functionCall 对象,一次性返回完整的工具调用信息,根本没有增量事件的概念。
这意味着反代项目必须实现一个庞大的转换层,用硬编码的映射表和字符串拼接逻辑来"拼凑"Anthropic 格式。这种拼凑是非原子性的——在 Antigravity-Manager 的源码中,专门实现了 handle_parse_error() 函数来处理解析失败,并在错误率超过 5 次时主动断开连接。
最终结果就是你实际遇到的那些问题:反代层解析失败触发错误恢复或断开连接,生成格式错误的 SSE 事件(缺少字段、index 错乱),Claude Code 客户端收到不完整事件后工具调用失败、上下文丢失、任务中断。
思维链签名传递的脆弱性
Extended Thinking(扩展思考)是 Claude Code 最核心的推理能力,也是反代最容易翻车的环节。
原生 Anthropic API 中,思考功能使用 type: "thinking" 数据块,并附带一个 signature 字段来标识思考内容的来源。格式如下:
{"type": "thinking", "thinking": "...", "signature": "..."}
而 Google Vertex API 支持的是 thoughtSignature 字段,格式不同:
{"text": "...", "thought": true, "thoughtSignature": "..."}
虽然 Vertex 本身支持签名,但在多层转换中问题频出。反代通过字符串拼接来传递签名,而 Vertex 可能返回 Base64 编码的签名,反代需要尝试解码——如果解码失败但仍然传递原始值,签名长度可能不足(小于 10 个字符),直接触发验证失败。
签名一旦在传递过程中损坏,thinking 块会被降级为普通 text 块。这带来的连锁反应相当严重:Claude Code 会把推理过程当成普通输出,Agent 的逻辑判断出错,多轮对话中历史思考内容被错误清理,上下文推理能力持续下降。这就是为什么你用反代时会明显感觉 Agent 的"记忆力"越来越差。
一个简单的判断方法:WebSearch
如果你想快速分辨自己用的 Claude 中转站是原生还是反代,试试让它做联网搜索。
关键在于理解两种搜索能力的区别:
WebFetch 是本地能力。模型返回 tool_use: WebFetch 指令后,Claude Code CLI 在你的本地电脑上发起 HTTP 请求,获取网页内容后再发回给模型。只要反代能正常传回模型的 tool_use 指令,WebFetch 就能正常工作。
WebSearch 是云端能力。模型返回 tool_use: WebSearch 后,由 Anthropic 服务器调用搜索引擎 API(Google、Bing 等),搜索结果由 Anthropic 服务器返回。反代系统只做协议转换,不提供搜索服务,搜索引擎 API 需要 Anthropic 内部集成的付费密钥。
所以判断方法很直接:如果你的 Claude Code 只能用 WebFetch 而无法使用 WebSearch(报错或提示工具不存在),那大概率走的是反代渠道。
本质问题
反代无法复刻原生体验,根本原因在于它必须在"结构化流式状态机协议 + 推理签名语义"与另一套完全不同的响应机制之间做实时转换。这种转换不可避免地依赖硬编码与拼接,属于非原子、非同构的"协议拟合"。在简单的单轮对话中或许还能凑合,但在复杂多轮、工具密集的 Agent 任务中,随机性失真几乎是必然的。
对于把 Claude Code 当作核心生产力工具的开发者来说,这个认知很重要:如果你的工作流高度依赖 Agent 的多步推理和工具调用能力,反代带来的不稳定性可能会让你在"节省的成本"和"浪费的调试时间"之间算不过来账。频繁的任务中断和需要手动输入"继续"来恢复执行,本身就是一种隐性成本。