Agent Loop
Abstract
Agent Loop 是 Coding Agent 的心跳:接收输入 → 调用 LLM → 执行工具 → 回填结果 → 继续推理 → 直到完成。
- Codex CLI 更像一个基于 turn 的状态机,每轮都有明确输入、配置、工具结果和事件输出
- Claude Code 更像一个持续流式执行的产品化 Agent loop,通过工具调用、权限确认和上下文更新不断推进任务
基本循环
无论具体实现如何变化,Coding Agent 的核心循环都围绕同一件事:让模型在 推理(reasoning) 和 行动(action) 之间反复切换。
flowchart LR
Input[用户输入] --> Model[调用 LLM]
Model --> Decision{是否需要工具?}
Decision -->|否| Done[完成回答]
Decision -->|是| Tool[执行工具]
Tool --> Result[工具结果]
Result --> Model
真正的差异不在“有没有循环”,而在循环如何被组织
状态放在哪里、工具何时执行、结果如何回填、权限如何确认、上下文溢出时如何恢复。
Codex:Turn-Based State Machine
Codex 更适合理解为 turn-based state machine。每一轮 turn 都会携带一组相对固定的配置,例如模型、沙箱策略、审批模式、会话历史和工具定义。模型在当前 turn 中流式输出文本、推理片段或工具调用;工具执行完成后,结果会写回历史,再进入下一轮。
用户输入
↓
创建 TurnContext(模型、配置、沙箱策略、权限)
↓
构建 Prompt(基础指令 + 历史 + 工具 schema)
↓
流式接收模型响应(SSE 或 WebSocket)
↓
从响应中解析工具调用
↓
对每个工具调用:
├── 检查审批
├── 应用沙箱策略
├── 在沙箱中执行
└── 收集结果
↓
将结果追加到历史
↓
向 UI 发送事件
↓
下一轮 Turn(若模型需要继续)
关键设计
Codex 的 turn 边界让执行过程更容易推理:一轮 turn 有明确的输入、上下文、工具调用、工具结果和事件输出。即使中间存在流式输出和异步工具执行,turn 仍然是状态同步的重要边界。
关键组件
- TurnContext
- 描述当前轮执行所需的配置,例如模型信息、沙箱策略、审批模式和会话设置
- 代码位置:
codex-rs/core/src/session/turn_context.rs
- ResponseItem
- 带类型的历史条目,记录模型消息、推理内容、工具调用、工具结果、压缩标记等对话历史
- 代码位置:
codex-rs/protocol/src/models.rs
- ContextManager
- 负责管理上下文历史,包括 token 预算、历史截断、摘要和压缩
- 代码位置:
codex-rs/core/src/context_manager/history.rs
并发模型
Codex 基于 Tokio 做异步 I/O,模型流、工具执行和 UI 事件可以通过异步任务协同推进。ToolOrchestrator 负责调度工具调用,并处理审批请求与结果回填。
优缺点总结
优势在于每一轮具有清晰的边界:当某一轮失败时,可以围绕该 turn 实现取消、重试或错误恢复,便于系统内状态管理和错误控制。
但这也带来一定复杂性:系统必须细致处理 turn 内部的流式事件管理、工具 futures 的并发调度、审批请求的等待,以及结果顺序的正确还原。
Claude Code:Streaming Agent Loop
Claude Code 更适合从用户可观察行为上理解为 streaming agent loop。用户提交请求后,系统会持续向模型发送上下文、接收流式响应、发现工具调用、执行工具、追加工具结果,并在需要时继续请求模型。
用户输入
↓
组装 System Prompt(cached sections + dynamic context)
↓
规范化消息以适配 API
↓
从 Claude API 流式接收响应
↓
处理 stop_reason:
├── "tool_use" → 提取 tool blocks
│ ├── 检查权限(canUseTool)
│ ├── 执行工具(读取类并行,写入类串行)
│ ├── 追加工具结果
│ └── 回到 API 调用
│
├── "end_turn" → 返回文本响应,结束
│
├── "max_tokens" → 自动压缩上下文,继续
│
└── "stop_sequence" → 处理 stop hooks
关键设计
Claude Code 的循环更强调连续体验:工具调用、权限确认、进度展示、上下文压缩和最终输出都可以作为流式事件不断反馈给用户。它的边界不一定像 Codex turn 那样硬,而更像一个持续推进的执行管线。
关键组件
- Conversation / Query Orchestrator:维护一次会话中的消息、模型调用、工具结果和执行状态
- Stream Event:向 UI 或调用方持续输出文本、工具调用、权限请求、进度和错误等事件
- Permission System:决定工具是否可以执行,是否需要用户确认,或是否应该拒绝
- Tool Executor:执行文件读取、搜索、命令、编辑、MCP 等工具,并把结果回填给模型
并发模型
Claude Code 的工具执行需要区分只读操作和有副作用操作:
- 只读工具:例如搜索、文件读取等,通常更适合并发执行
- 写入或命令类工具:例如编辑文件、执行命令等,需要更谨慎的权限确认和顺序控制
- 结果回填:工具结果需要以模型可理解的形式追加回上下文,供下一轮推理使用
优缺点总结
体验细腻:用户可以更早看到事件、进度、权限提示和部分结果。 代价是控制流更复杂,状态可能分散在会话、工具执行器、权限系统和 UI 事件之间。
重要性
Agent Loop 决定了 Coding Agent 的工程性格。
Codex 的 turn-based 模型更像一个可审计的执行单元:每轮都能看到模型拿到了什么上下文、发起了什么工具调用、工具返回了什么结果,以及下一轮为什么继续。这种结构适合强调边界、沙箱和可恢复性的系统。
Claude Code 的 streaming loop 更像一个持续运行的交互产品:它可以自然地展示进度、暂停等待权限确认、继续执行工具、处理上下文压缩,并把这些状态转化成用户可感知的体验。这种结构适合强调交互流畅性和工具权限控制的产品。
核心差异
| 维度 | Codex(Turn-Based) | Claude Code(Streaming) |
|---|---|---|
| 边界 | 每轮迭代有明确的 TurnContext | 对用户更像连续事件流,边界感更弱 |
| 状态 | 每轮配置和上下文边界更明确 | 会话状态持续更新,和工具、权限、UI 事件交织 |
| 流式 | 模型输出、工具进度和事件可流式展示,但 turn 仍是重要结构 | 文本、工具、权限和进度更自然地组成连续事件流 |
| 恢复 | 适合围绕当前 turn 做取消、重试和错误恢复 | 适合在执行过程中处理权限等待、上下文压缩和继续执行 |
| 取消 | 更容易以 turn 为单位管理取消 | 更容易在事件流中暂停或中止任务 |
Auto-Continuation
Coding Agent 通常不会在第一次模型输出后就停止。如果模型决定调用工具,系统会执行工具并把结果追加回上下文,让模型继续推理。
- Codex CLI:如果模型输出工具调用,工具结果会写回历史,并进入下一轮 turn,直到模型不再需要继续调用工具。
- Claude Code:如果模型返回工具调用,循环会继续执行工具并再次请求模型;如果上下文过长,则可能先压缩上下文再继续。
从用户角度看,这些 continuation 往往被包装成一次完整任务:用户发出请求,Agent 在后台经历多轮“思考-行动-反馈”,最后返回结果。
Context Overflow
当会话历史超过模型上下文窗口时,Agent Loop 必须处理上下文溢出,否则模型无法继续可靠工作。
- Codex CLI:更适合把上下文管理看作 history 的压缩、摘要和裁剪问题,目标是在保留关键任务状态的同时降低 token 占用。
- Claude Code:更强调在连续执行过程中触发压缩和恢复,让用户感知到的任务流尽量不中断。
上下文管理会直接影响 Agent 的长期任务能力:如果压缩过度,模型会丢失关键约束;如果压缩不足,任务会被上下文窗口打断。