Claude Code vs Codex CLI:AI 编程助手 API 调用机制的深度逆向对比

发布时间:2026/7/4 1:26:24

Claude Code vs Codex CLI:AI 编程助手 API 调用机制的深度逆向对比 一次对 claude.exe (225MB) 和 codex.exe (308MB) 的二进制逆向分析揭示了两种截然不同的 Agent 协议设计哲学。引言AI 编程助手已经成为许多开发者的日常工具。当我们在终端里输入帮我修复这个 bug敲下回车——背后到底发生了什么每一次工具调用、每一个 让我先看看这个文件到底对应多少次 API 请求每次请求都要把完整的系统提示词重新发送一遍吗这些问题看似是实现细节但实际上它们直接决定了推理速度、token 成本、上下文质量以及为什么你在一个工具里能连续对话两小时而在另一个里半小时就开始失忆。本文通过对Claude CodeAnthropic和Codex CLIOpenAI两个二进制文件的逆向分析试图回答这些问题。一、物理形态两个二进制文件维度Claude CodeCodex CLI文件claude.execodex.exe路径npm/anthropic-ai/claude-code/bin/npm/openai/codex/.../bin/大小225 MB308 MB类型PE32 Console x86-64PE32 Console x86-64节数1210语言TypeScript → Bun 编译Rust → MSVC 编译JS 引擎Bun (JavaScriptCore)V8 (嵌入)配置语言JSON/TOMLStarlark (Bazel 方言)API 后端api.anthropic.comchatgpt.com/backend-api/codexAPI 协议Anthropic Messages API (HTTP)OpenAI Responses API (WebSocket)两者的共同点是都把自己编译成了独立可执行文件——不是 Node.js wrapper不是 Python 脚本而是包含了完整运行时环境的原生二进制。这意味着你不需要安装 Node、Python 或任何运行时依赖下载即用。但它们的共同点到此为止。在 API 调用机制上两者做出了截然不同的选择。二、核心差异有状态 vs 无状态2.1 Claude Code无状态 HTTP每次全量发送Claude Code 的每次 API 调用都是一个独立的 HTTP POST 请求POST https://api.anthropic.com/v1/messages Authorization: x-api-key sk-ant-... anthropic-version: 2023-06-01 Content-Type: application/json ​ { model: claude-fable-5, system: You are Claude... [~8000 tokens 的系统提示词], messages: [ {role: user, content: 帮我修复这个 bug}, {role: assistant, content: [ {type: tool_use, name: Grep, ...} ]}, {role: user, content: [ {type: tool_result, ...} ]}, // ... 完整历史 ... ], tools: [/* ~50 工具定义每个包含完整 JSON Schema */], max_tokens: 32000, thinking: {type: enabled, budget_tokens: 16000} }关键特征每次请求都携带完整上下文系统提示词、工具定义、完整对话历史——全部重新发送服务端无状态每个请求之间没有关联服务端不维护任何会话状态Prompt Caching 补偿Anthropic 的服务端缓存机制将重复的系统提示词成本降低约 90%2.2 Codex CLI有状态 WebSocketTurnStart/TurnSteer 分离通过对codex.exe二进制的逆向分析我们发现它实现了一个精巧的有状态协议核心是两个消息类型TurnStartParams20 个字段——创建会话TurnStart 请求 { clientUserMessageId: string, // 客户端消息 ID input: UserInput, // 用户输入 responsesapiClientMetadata: {...}, // 客户端元数据 (版本/OS/终端类型) additionalContext: [...], // Skills, Memory, Git status... environments: {...}, // 环境变量 runtimeWorkspaceRoots: [...], // 工作区根目录 approvalPolicy: string, // on-request | never | always approvalsReviewer: string, // 审核者设置 sandboxPolicy: string, // readonly | workspace-write | ... serviceTier: string, // Free | Plus | Pro | Team | Enterprise effort: string, // low | medium | high | xhigh outputSchema: {...}, // 输出格式约束 collaborationMode: string, // primary | review | ... multiAgentMode: string, // disabled | proactive | ultra // 系统提示词和工具定义也在此发送 system_prompt: ..., tools: [...] }TurnSteerParams6 个字段——增量追加TurnSteer 请求 { expectedTurnId: string, // 服务端状态索引 // 只发送工具调用的结果不重复系统提示词和工具定义 tool_results: [...] }关键特征TurnStart 全量TurnSteer 增量一个 turn 内只有第一次发送完整上下文expectedTurnId 作为状态索引服务端通过它查找内存中的会话状态服务端有状态维护 system prompt tools conversation history KV cache验证机制如果 expectedTurnId 不匹配当前活跃 turn → 返回 400 no active turn to steer三、协议对比一次用户交互的全流程假设用户输入帮我修复 login 模块的空指针异常模型需要 5 步完成搜索 → 读取 → 分析 → 编辑 → 总结。Claude Code 的流程用户消息 #1 (Turn 开始) │ ├─ API 请求 #1: POST /v1/messages │ ├─ system: [8,000 tokens] │ ├─ tools: [2,000 tokens] │ ├─ user_msg: 帮我修复... │ └─ 总输入: ~11,000 tokens │ ├─ API 请求 #2: POST /v1/messages │ ├─ system: [8,000 tokens] ← 再次发送 │ ├─ tools: [2,000 tokens] ← 再次发送 │ ├─ 完整历史 tool_result │ └─ 总输入: ~15,000 tokens │ ├─ API 请求 #3: POST /v1/messages │ ├─ system: [8,000 tokens] ← 再次发送 │ ├─ tools: [2,000 tokens] ← 再次发送 │ ├─ 完整历史 tool_result │ └─ 总输入: ~18,000 tokens │ ├─ API 请求 #4: ... (继续累积) │ └─ API 请求 #5: ... └─ 总输入: ~25,000 tokens ​ 累计 input tokens: 原始 ≈ 11K 15K 18K 21K 25K 90,000 tokens 考虑 Prompt Caching (systemtools 缓存后降价 90%): 实际 ≈ 11K 6K 9K 12K 16K 54,000 tokensCodex CLI 的流程用户消息 #1 (Turn 开始) │ ├─ TurnStart (WebSocket msg #1) │ ├─ system_prompt: [3,000 tokens] │ ├─ tools: [5,000 tokens] │ ├─ context: [2,000 tokens] │ └─ 总输入: ~10,000 tokens (截断限制) │ ├─ TurnSteer (WebSocket msg #2) │ ├─ 只发增量: tool_result next_prompt │ ├─ 不重复 system_prompt │ ├─ 不重复 tools │ └─ 总增量: ~2,000 tokens │ ├─ TurnSteer (WebSocket msg #3) │ └─ 增量: ~3,000 tokens │ ├─ TurnSteer (WebSocket msg #4) │ └─ 增量: ~3,000 tokens │ └─ TurnSteer (WebSocket msg #5) └─ 增量: ~2,000 tokens ​ 累计 input tokens: ~10K 2K 3K 3K 2K 20,000 tokens可视化对比同一个任务5 步完成input tokens 消耗: ​ Claude Code (无缓存): ████████████████████████████████████████ 90,000 Claude Code (有缓存): ████████████████████████ 54,000 Codex CLI: ████████ 20,000 ├────────────────────────────────────────┤ 0 90,000 tokens四、技术细节Codex 的 TurnSteer 是如何工作的4.1 协议定义从二进制逆向提取在codex.exe的.rdata段中找到了嵌入的 TypeScript 类型定义文件// TurnSteerParams.ts (嵌入在 codex.exe 中的源文件) /** * Required active turn id precondition. * The request fails when it does not match the currently active turn. */ expectedTurnId: string以及错误处理逻辑expectedTurnId must not be empty no active turn to steer4.2 服务端状态维护OpenAI 的服务端维护一个Turn Session Store结构大致如下TurnSession { turn_id: turn_abc123, thread_id: thread_xyz, // ⬇ 以下内容在 TurnSteer 时不再传输 system_prompt: { // 完整的系统指令 base_instructions: ..., personality: friendly, skills: [...], memory_entries: [...] }, tool_registry: { // 完整的工具注册表 fs/readFile: { schema: {...} }, fs/writeFile: { schema: {...} }, command/exec: { schema: {...} }, // ... 50 工具 }, conversation: [ // 累积的完整对话 {role: user, content: ...}, {role: assistant, tool_calls: [...]}, {role: tool, content: ...}, // ... ], settings: { // Turn 级设置快照 approval_policy: on-request, sandbox_policy: workspace-write, service_tier: plus, effort: medium }, model_state: { // GPT-5.5 推理状态 kv_cache: [...], // 已计算的 KV Cache position: 15432 // 当前 token 位置 } }4.3 为什么 TurnSteer 能这么快关键是KV Cache 复用。当 GPT-5.5 处理 TurnStart 时它对 system prompt tools user message 进行了 prefill计算结果保存在 KV cache 中。当 TurnSteer 到达时服务端通过expectedTurnId找到对应的 session将 tool_result 追加到 conversation_history直接从已有的 KV cache 继续解码不需要重新 prefill这意味着 TurnSteer 的Time-To-First-Token (TTFT)接近零——模型不需要重新处理系统提示词和工具定义直接产出下一个 token。对比 Claude Code每次 HTTP POST 都要完整地 prefill system prompt tools history即使有 Prompt Caching 降低了计费成本prefill 的延迟是无法跳过的。五、设计哲学两种世界观5.1 为什么 Anthropic 选择无状态 HTTPClaude Code 的设计哲学: 可靠性 效率 简单 精巧 优点: ├─ 容错性极强: 任何一个请求失败重试就是完整的 ├─ 服务端简单: 不需要维护 WebSocket 会话状态 ├─ 无状态扩展: 请求可以路由到任意服务器 ├─ 跨 turn 复用: Prompt Caching 可以横跨多个请求 ├─ 调试友好: 每个请求都是可独立复现的 └─ 1M 上下文窗口: 有空间容纳重复发送的开销 代价: ├─ 每次请求都要发送完整 payload网络开销 ├─ 每次请求都要 prefill延迟 └─ 依赖服务端缓存来降低成本不是所有场景都生效5.2 为什么 OpenAI 选择有状态 WebSocketCodex CLI 的设计哲学: 效率 简单 精巧 通用 优点: ├─ Token 成本极低: turn 内不重复发送上下文 ├─ TTFT 极低: KV Cache 持续复用 ├─ 实时性好: WebSocket 天然支持 streaming 通知 ├─ 分层设计: TurnStart/TurnSteer/TurnInterrupt 各司其职 └─ 协议级支持: turn 是一等概念不是通过无状态模拟 代价: ├─ 服务端复杂度高: 需要维护大量并发 Turn Session ├─ 容错性差: 断连 整个 turn 丢失 ├─ 不可跨 turn 复用: 每个用户消息都是新 TurnStart ├─ 硬截断风险: 10K tokens 的截断上限 └─ 调试困难: 无法独立复现单个 TurnSteer5.3 上下文管理策略对比策略Claude CodeCodex CLI窗口大小最高 1M tokens272K tokens截断方式Auto-compact 自动摘要10K tokens 硬截断长对话管理渐进压缩 → 摘要激进截断 → 丢失跨 turn 记忆Memory 文件系统Memory 系统 (类似)子 Agent独立上下文窗口共享 session这解释了为什么很多用户感觉 Claude Code 在长对话中更持久——不是因为它不丢上下文而是因为 1M 的窗口太大在达到极限之前 Auto-compact 已经帮你摘要了。而 Codex 的 10K 硬截断意味着如果你的对话 system prompt tools 超过了这个阈值早期内容会被直接丢弃。六、模型配置对比从二进制中提取Claude Code 的模型列表环境变量定义ANTHROPIC_DEFAULT_FABLE_MODEL → claude-fable-5 ANTHROPIC_DEFAULT_OPUS_MODEL → claude-opus-4-8 ANTHROPIC_DEFAULT_SONNET_MODEL → claude-sonnet-4-6 ANTHROPIC_DEFAULT_HAIKU_MODEL → claude-haiku-4-5 ANTHROPIC_SMALL_FAST_MODEL → (备选快速模型)Opus 4.8 配置1M context window, 支持 extended thinkingFable 5 配置Mythos-class tier, 共享底层模型Codex CLI 的模型列表嵌入 JSON{ slug: gpt-5.5, display_name: GPT-5.5, description: Frontier model for complex coding, research, and real-world work., context_window: 272000, max_context_window: 272000, auto_compact_token_limit: null, truncation_policy: { mode: tokens, limit: 10000 }, default_reasoning_level: medium, supports_parallel_tool_calls: true }GPT-5.4同样 272K 窗口但max_context_window: 1,000,000预留扩展GPT-5.4-Mini小型快速模型GPT-5.3-Codex编程优化模型前代GPT-5.2长运行 Agent 优化七、安全与认证对比维度Claude CodeCodex CLI认证方式API Key / OAuth / AWS Bedrock / GCP Vertex / FoundryChatGPT OAuth / API Key / AWS Bedrock沙箱策略readonly / workspace-write / danger-full-access / linux-seccompreadonly / workspace-write / danger-full-access / windows-sandbox审批机制never / on-request / always Reviewer Agentnever / on-request / always Guardian Agent遥测端点api.anthropic.comab.chatgpt.com/otlp/v1/metrics Sentry联邦认证OIDC Federation WIFJWT Agent Identity两者在安全模型上高度相似——都有沙箱分层、审批门控、代码审查 Agent这是这个品类的基本安全基线。差异主要在于实现细节Claude Code 支持更多企业认证方式Vertex AI、FoundryCodex 的 Windows 沙箱集成更深。八、总结问题Claude Code 的答案Codex CLI 的答案每次 API 调用都发系统提示词吗是。但 Prompt Caching 将成本降到 10%不。TurnStart 发一次TurnSteer 不发一个用户消息调用多少次 APIN 次每个 tool round-trip 一次 HTTP POST1 次 TurnStart (N-1) 次 TurnSteer谁能用更少的 token 完成同样任务~54,000有缓存时~20,000无缓存也低谁的首字延迟更低每次都要 prefillTurnSteer 时 KV Cache 直接续接近零延迟谁的长对话体验更好1M 窗口 auto-compact272K 窗口 10K 硬截断谁的架构更简单无状态 HTTP水平扩展友好有状态 WebSocket运维复杂度高谁更容易调试每个请求是独立的、可复现的依赖会话状态复现需要模拟整个序列后记差异在于它们在同一个根本问题上做出了相反的选择上下文状态应该由客户端管理还是服务端管理Anthropic 的回答是客户端负责每次把完整上下文发给我我用缓存帮你省钱。 OpenAI 的回答是你第一次发完整上下文后面只发增量我帮你在服务端记着。两种方案经过各自优化后的总成本和体验差距并没有看起来那么大——真正的差异在于生态位。Claude Code 靠 1M 窗口 Prompt Caching 在持久对话这个场景里占优Codex CLI 靠 KV Cache 复用在快速迭代的场景里更敏捷。最终用户感受到的差异往往不是协议层的选择导致的而是上下文管理策略——你是愿意用大窗口容纳全量历史还是用小窗口做激进截断。在这个意义上协议设计反映的其实是产品理念你要的是一个能陪你聊一下午的编程搭档还是一个快速高效完成当前任务的工具。分析日期2026-07-03分析目标claude.exe (225MB, Bun编译) 和 codex.exe (308MB, Rust编译)

相关新闻