Skip to content

代理循环 — 概念

Agent Loop 执行流程

Agent Loop 是 Codex 的核心执行引擎,由 Codex struct(core/src/session/mod.rs)驱动,采用事件驱动的队列对架构:

代理循环的核心迭代过程:

  1. 提交操作Codex::submit(Op) 通过 tx_sub 发送 Submission 到事件循环
  2. 上下文构建build_initial_context() 拼装 system prompt、对话历史(ConversationHistory)、工具声明和 Context Management 信息
  3. 模型调用ModelClientSession::stream() 向 LLM 后端发起流式请求,返回 ResponseStream
  4. 响应解析:从流中解析 ResponseEvent,识别文本输出和工具调用(function call)
  5. 工具执行:若包含工具调用,通过 Sandbox 执行命令或通过 Apply Patch 应用代码修改
  6. 循环迭代:将工具执行结果追加到上下文,回到步骤 3,直到模型不再发起工具调用
  7. 事件通知:每个状态变化通过 rx_event 发送 Event 通知消费者

Codex struct 的核心字段定义(core/src/session/mod.rs):

rust
pub struct Codex {
    tx_sub: Sender<Submission>,       // 操作提交通道
    rx_event: Receiver<Event>,         // 事件接收通道
    agent_status: watch::Receiver<AgentStatus>,  // 状态广播
    session: Arc<Session>,             // 会话状态(Arc 共享)
}

Context Management 上下文管理

Context Management 负责在 LLM 的上下文窗口限制内高效管理输入:

上下文管理的关键机制:

  • 对话历史:每个 turn 产生 TurnItem(文本输出、工具调用、工具结果),存储在 ConversationHistory
  • 压缩策略:当历史超过上下文窗口时,调用 compact_conversation_history() 使用 LLM 生成摘要替换早期历史
  • 工具声明:包括内置工具(shellapply_patch)和 MCP 注册的外部工具,tool_is_model_visible() 过滤模型可见的工具
  • 系统提示:包含角色定义、安全规则、workspace 信息,通过 build_prompt_input() 构建

Session 中的关键上下文管理方法:

方法功能调用时机
build_initial_context()组装完整上下文每个 turn 开始时
record_conversation_items()记录对话条目工具执行完成后
replace_compacted_history()替换压缩后的历史压缩完成后
update_token_usage_info()更新 token 用量每次模型响应后
recompute_token_usage()重算 token 总量历史变更后

Rollout 执行策略

Rollout 控制代理循环的执行行为和终止条件:

Rollout 的核心控制维度:

  1. 迭代次数限制:通过 max_turns 控制单个 turn 内的最多工具调用轮次,防止无限循环
  2. 执行策略(ExecPolicy):通过 PolicyRule 定义每个命令的权限等级(ExecPolicy:Allow/Prompt/Forbidden)
  3. Rollout 记录器RolloutRecorder 记录完整的执行轨迹,用于回放、调试和训练
  4. 中断机制steer_input() 允许在 turn 执行过程中插入新的用户指令或中断当前操作
rust
// RolloutRecorder 记录参数
pub struct RolloutRecorderParams {
    pub cursor: Cursor,
    pub session_meta: SessionMeta,
    // ... 路径和配置
}

Apply Patch 补丁应用

Apply Patch 是 Codex 自定义的代码修改应用机制,解析 LLM 生成的 *** Begin Patch 格式补丁:

补丁格式解析流程(apply-patch/src/lib.rs):

  1. 触发:LLM 调用 apply_patch 工具,参数为 *** Begin Patch 格式的补丁文本
  2. 解析StreamingPatchParser 流式解析补丁文本,生成 Hunk 列表(每个 Hunk 描述一个文件的增/删/改操作)
  3. 验证verify_apply_patch_args() 校验补丁格式和目标文件状态
  4. 应用:将验证通过的 Hunk 原子应用到文件系统
rust
// 补丁解析核心类型
pub struct Hunk {
    // 描述对单个文件的修改操作
}

pub fn parse_patch(patch: &str) -> Result<Vec<Hunk>, ParseError> {
    // 解析 *** Begin Patch ... *** End Patch 格式
}

Apply Patch 与标准 diff/patch 的区别:Codex 使用自定义格式而非 unified diff,因为 LLM 更容易生成这种格式,且支持更灵活的上下文匹配。

相关概念