第八部分:Agent Loop 状态机
总体结构
入口
→ 准备上下文并调用模型
处理
→ 处理文本、工具调用、工具结果和新输入
出口判断
├─ continue:继续下一轮
├─ compact:压缩后继续
├─ break:正常结束
└─ return error:异常或取消
run_turn() 承担本段内层循环的编排,run_sampling_request() 负责一次模型采样及其工具处理。下面的状态图是源码控制流的概念归纳,不是代码里已有的枚举;采样过程中会边读流边启动工具,并非模型流结束后才开始执行工具。
一次 Turn 的主流程
用户输入
↓
准备规则、Skill、MCP、工具和环境
↓
调用一次模型
↓
处理文本、工具调用和工具结果
↓
判断是否还有工具或新输入
├─ 有,且上下文足够 → continue
├─ 有,但上下文已满 → compact → continue
└─ 没有 → 运行 Stop Hook
├─ Hook 要求补充 → 写入提示 → continue
└─ 允许结束 → break
关键判断变量位于 core/src/session/turn.rs:
model_needs_follow_up:模型或工具是否要求继续。has_pending_input:用户或子 Agent 是否有新消息。needs_follow_up:以上两者的合并结果。token_limit_reached:是否达到自动压缩阈值;本轮还需要继续时,阈值命中或主动换窗口请求才触发should_roll_over。stop_outcome.should_block:Stop Hook 是否阻止结束;还需有有效补充提示,才会再次请求模型。stop_outcome.should_stop:Hook 是否明确要求停止,命中时直接break,不再运行后续 legacy after-agent hook;它不是唯一的结束条件。
这不是一个单独的状态枚举,而是由这些判断值和 continue、break、return 共同组成的状态机。
这里的结束是“本次 run_turn 返回”,不是删除 Session,也不是关闭 Agent。外层 RegularTask 还会检查待处理输入,必要时再次调用 run_turn;没有后续输入才进入任务收尾。普通错误有些会先发错误事件再返回,取消则按 TurnAborted 向上传递,不能把所有失败都等同于 return error。
代码锚点
core/src/session/turn.rs:155:Turn 初始化和首次上下文准备。core/src/session/turn.rs:304:主loop,读取待处理输入。core/src/session/turn.rs:370:构造历史输入并调用run_sampling_request。core/src/session/turn.rs:412-473:合并 follow-up、待处理输入和 token 状态,决定是否压缩。core/src/session/turn.rs:490:上下文压缩后continue。core/src/session/turn.rs:503-562:Stop Hook 和最终break。core/src/tasks/regular.rs:76-95:外层检查待处理输入,决定是否再次调用run_turn。
源码基线:OpenAI Codex
d58d0e5841e0de08e251673db2d5af8cf3a1ad51。文中的流程图用于标出本篇所处的运行阶段。