Skip to content

代理循环 — 练习

练习 1:追踪一次完整的代理循环

从一个简单的用户指令(如"创建一个 hello world 程序")出发,追踪代理循环的完整执行过程。

参考答案

codex "创建一个 hello world 程序" 为例,完整执行过程如下:

  1. CLI 入口cli/src/main.rscli_main() 将指令分发到 exec 模式
  2. Session 创建Codex::spawn(CodexSpawnArgs) 创建 tx_sub/rx_event 队列对,初始化 Session
  3. 提交用户输入codex_thread.submit(Op::UserInput("创建一个 hello world 程序"))
  4. 上下文构建session.build_initial_context() 拼装:
    • System prompt(角色定义 + 安全规则)
    • 工具声明(shellapply_patch 等 function definitions)
    • 用户消息
  5. 首次模型调用ModelClientSession::stream() 通过 WebSocket/SSE 发送到 LLM 后端
  6. 模型响应:LLM 返回工具调用 shell("echo 'print(\"hello world\")' > hello.py")
  7. 工具执行Session 通过 SandboxManager::transform() 包装命令,在沙箱中执行
  8. 结果回传:将执行结果(stdout/stderr)追加到上下文
  9. 二次模型调用:LLM 判断任务完成,返回纯文本响应
  10. Turn 完成:发送 Event::TurnCompleted,包含 TurnItem 列表

整个过程中,每一步状态变化都通过 rx_event 通道通知消费者,消费者(TUI/Exec/SDK)据此更新界面或输出。

练习 2:分析上下文构建过程

分析代理循环如何将对话历史、文件内容、工具调用结果构建为 LLM 的输入上下文。

参考答案

上下文构建的核心在 Session::build_initial_context() 方法中,组装以下内容:

  1. System Prompt:由 build_prompt_input() 构建,包含角色定义("你是 Codex,一个编程助手")、安全规则、workspace 根目录信息、可用工具描述。这是上下文的固定前缀,每次 turn 都包含。

  2. 对话历史ConversationHistoryTurnItem 的列表。每个 TurnItem 包含:

    • 用户输入(UserInput
    • 模型输出(文本 + 工具调用)
    • 工具执行结果(stdout/stderr/exit code)
    • 审批记录(如果涉及人工审批)
  3. 工具声明:内置工具(shellapply_patch)+ MCP 注册的外部工具。tool_is_model_visible() 根据工具的 UI 可见性元数据过滤,确保模型只看到应使用的工具。

  4. 压缩策略:当对话历史超过上下文窗口时,compact_conversation_history() 使用 LLM 对早期历史生成摘要,调用 replace_compacted_history() 替换原始历史。这确保了长时间对话不会因上下文溢出而失败。

上下文的 token 用量通过 update_token_usage_info() 持续跟踪,recompute_token_usage() 在历史变更后重新计算总量。

练习 3:理解 Rollout 策略

分析 Rollout 如何控制代理的迭代次数和终止条件。

参考答案

Rollout 策略从三个维度控制代理行为:

  1. 迭代次数控制:每个 turn 内的模型调用 + 工具执行循环受 max_turns 参数限制。当达到上限时,代理停止发起工具调用,将当前结果作为 turn 的最终输出。这防止了代理陷入无限循环(如反复尝试修复一个无法修复的 bug)。

  2. 执行策略过滤ExecPolicyPolicy::check() 方法在工具执行前评估每个命令。Decision 枚举有三个值:

    • Allow:自动执行(如 lscat 等低风险命令)
    • Prompt:需要用户审批(如 rmnpm install 等中风险命令)
    • Forbidden:直接拒绝(如明确的危险操作)

    规则通过 add_prefix_rule()add_network_rule() 添加,支持按命令前缀和网络域名匹配。

  3. 执行轨迹记录RolloutRecorder 记录每个 turn 的完整执行过程,包括模型输入/输出、工具调用和结果。RolloutRecorderParams 包含 Cursor(会话位置)和 SessionMeta(会话元数据),用于后续回放和分析。

此外,steer_input() 提供了运行时中断机制:用户可以在 turn 执行过程中插入新指令或要求中断,SteerInputError 枚举处理了无活动 turn、turn 类型不匹配等边界情况。

拓展挑战

  • 追踪 compact_conversation_history() 的调用时机和压缩算法
  • 分析 SteerInputError 各变体在实际使用中的触发条件
  • 阅读 RolloutRecorder 的持久化格式,理解轨迹数据如何存储
  • 分析 Event 枚举的所有变体,理解事件分类体系