# 25. Agent Loop 全景知识图谱与端到端复习

本章不新增一套与前文平行的概念,而是以一次完整 Agent Loop 为主轴,把第 1—20 章重新组织成多张互相对照的架构图。阅读时始终追踪同一个业务事实:用户目标如何成为模型输入,模型提议如何成为受控副作用,结果如何回到 Context,系统又如何停止、压缩、恢复或分发给子 Agent

本章是第二遍学习使用的“完整地图”:第一次阅读先看 0.6 节,建立主链和章节位置;学完各专题后再回到本章,把正常执行、异常恢复、Context、Memory、安全、Multi-Agent 和可观测体系串在一起。这样既避免一开始被细节淹没,也能在复习时检查知识之间是否真正连通。

# 25.1 图谱阅读方法:一条主链,八个观察视角

观察视角 核心问题 主要章节
Harness 全景 哪些组件共同把概率模型变成可治理系统 1、2、17、18
端到端时序 一次 Turn 中谁先调用谁,事实何时持久化 2、4、13、14、17
Loop 与停止 为什么继续下一 Step,什么时候才允许完成 4、16、23
状态与恢复 崩溃、取消、断线后从哪条事实继续 2、9、17、18
Context–Memory 模型本轮看到什么,什么会跨会话保留 5、7—12、15
安全执行 模型提议如何经过授权与 OS 强制边界 6、14、19、20
Multi-Agent 任务、消息、工作区与权限如何分别隔离 3、16、19、20
观测与评测 如何解释行为、定位失败并形成优化闭环 13、18、23、24

八个视角共享同一组稳定标识:thread/session_id → turn_id → step_id → call_id/task_id → artifact/event_id。其中 artifact_id 表示执行产物 ID。图中如果两个模块不能用这些 ID 或明确的父子关系关联,就意味着它们之间仍存在恢复、审计或一致性缺口。

# 25.2 Harness 全景功能架构图

这张图体现 Harness 的核心原理:模型不直接接触操作系统,也不拥有最终完成权。模型只在一个固定 Step Context 上产生文本或动作提议;Runtime 把提议交给 Tool、安全和状态平面;Verifier 再依据外部证据判断是否完成。Context、权限、Rollout 和 Trace 必须引用同一 Step/Call 快照,否则模型看到的动作、用户批准的动作与实际执行动作可能不是同一个事实。

Claude Code 的 query → StreamingToolExecutor → executeToolCall → Session Storage 与 Codex 的 RegularTask → run_turn → ToolRouter/Handler → Rollout 都能映射到这张图:query.ts:280toolExecution.ts:614regular.rs:38turn.rs:1288

# 25.3 一次 Turn 的端到端时序图

时序中的两个“先持久化”非常关键:模型响应中的 ToolCall 要先写入持久化事件记录,ToolResult 也要先保存最终状态,然后才能推送 UI 或进入下一次采样。这样断线只会丢失临时展示,不会让 Runtime 忘记已执行的副作用。Codex 的 History/Rollout 写入与 Claude Code 的 JSONL/有序写队列分别体现了这一原则:session/mod.rs:1389sessionStorage.ts:549

# 25.3.1 同一次 Turn 中的控制流、数据流与状态流

三条流不能混为一谈:控制流可以重新运行,数据流可以裁剪或压缩,但已经确认的副作用状态不能被重算覆盖。恢复时先用状态流重建“已经发生什么”,再恢复控制流决定“下一步做什么”,最后重新构建数据流需要的 Context;顺序反过来就可能重复执行工具或使用过期权限。

# 25.4 Agent Loop 控制流与停止条件图

Loop 的“继续”必须带结构化原因:工具结果需要观察、验证失败、用户追加输入、Stop Hook 阻塞、上下文需要压缩、计划需要修订或预算允许重试。while true 只表达重复,无法决定下一轮应改变 Context、权限、输出预算还是任务图。Claude Code query.ts 中不同 transition reason 与 Codex 外层 RegularTask、内层 Turn Loop 的分层,都是把继续原因显式化:query.ts:1095regular.rs:49

必须停止的条件包括用户取消、墙钟/Token/费用/Step 预算耗尽、不可恢复安全错误、连续无进展和外部系统明确终止。模型输出自然语言“完成”只是一项完成提议;只有验收通过且系统中没有未完成 ToolCall、Task 或审批时,Runtime 才能写入 Turn 终态。

# 25.5 什么场景会触发上下文压缩

触发判断不能只写成“当前 Token 超过 80%”。生产系统至少有四类触发:

  1. Pre-sampling 预测触发:当前尚未超限,但加上下一批 World State、用户输入或工具 Schema 后将接近阈值。
  2. Turn 执行中触发(mid-turn):工具结果加入 Context 后仍需继续循环,而下一次请求的有效输入已经达到自动压缩阈值。
  3. Reactive 触发:Provider 明确返回 Prompt Too Long,Runtime 先清理异常大项,再重建请求。
  4. 显式触发:用户手动压缩,或 Session Memory 已有可靠摘要边界,可主动替换旧历史。

压缩通常不应只由 Session 累计消耗的 Token 触发;累计成本预算可以要求停止或提醒,但窗口压缩真正依据的是下一次请求会发送给模型的有效输入。相反,单个 50K Token 工具输出即使总窗口尚有空间,也应先受“单项内容硬上限”约束,避免一项内容挤掉全部计划和约束。

Codex 将 Turn 开始前(pre-turn)与 Turn 执行中(mid-turn)的初始上下文插入策略分开,并在替换后重算 Token;Claude Code 会调整切分位置以保持 ToolUse/ToolResult 配对,再恢复 Plan、Skill、Hook 和后台 Agent 状态:compact.rs:57compact.rs:368sessionMemoryCompact.ts:317compact.ts:1471

# 25.6 在线状态机与崩溃恢复流程

# 25.6.1 Turn 在线状态机

状态机中的 Interrupted 不等于 Failed。采样中断通常可以从已持久化边界重建;工具运行中断则必须区分“确认未执行”“已有终态”和“可能产生副作用但结果未知”。只有前两类能自动继续或复用,第三类需要下游幂等查询或人工确认。

# 25.6.2 进程重启后的恢复流程

恢复必须重放事实再修复边界,不能反序列化一个旧内存对象后继续运行。权限、cwd、MCP 连接和文件系统可能已经变化,因此旧 StepContext 只能用于审计,恢复后的下一 Step 必须重新捕获世界状态。Claude Code 沿 parentUuid 选择主链并恢复 Plan/Skill,Codex 的 Resume/Fork 分支则恢复历史、有效配置和持久化前缀:conversationRecovery.ts:409session/mod.rs:1317

# 25.6.3 出现异常时如何判断:先确认副作用,再决定恢复动作

判断异常时使用下面的固定顺序:

  1. 先查持久化事件,不先猜错误文本:确认 ToolCall、审批、执行开始和 ToolResult 分别记录到了哪一步。
  2. 再查外部事实:文件是否已修改、远端任务是否已创建、支付或发布是否已经发生。
  3. 再判断幂等性:重复执行是否安全,是否存在业务幂等键,是否只能查询而不能重放。
  4. 再判断 Context 是否过期:权限、工作目录、工具 Schema、文件版本或计划假设变化后,必须创建新 Step 快照。
  5. 最后选择恢复动作:复用、重试、重新规划、等待审批、人工确认或停止。
异常场景 关键判断证据 正确动作 禁止动作
模型或 MCP 暂时不可用 没有进入工具副作用,重试预算仍有余量 退避并限次重试,必要时熔断 无限快速重试
Prompt 超出窗口 Provider 错误、预测 Token、单项大小 先处理超大项,再压缩并重建 Context 删除系统规则或未完成任务
参数或 Schema 校验失败 工具尚未执行,字段或类型不合法 把结构化错误交给模型修正 用原参数重复调用
权限拒绝或审批过期 Policy/Approval 有明确最终状态 返回拒绝观察,换方案或重新申请 绕过审批或关闭沙箱
工具超时但结果未知 只有开始事件,没有可靠 ToolResult 查询外部事实;无法确认则人工处理 unknown 当作 failed 自动重试
沙箱违规 内核事件、退出码、规范化动作和 Profile 停止并计算可解释的最小权限差异 任意非零退出码都改成无沙箱重试
验收失败 测试、编译、Diff 或业务检查未通过 把证据加入 Context,局部重新规划 仅凭模型声称完成而结束 Turn
子 Agent 失联 租约、心跳、Task owner、执行产物状态 使旧租约失效,再重新分配未完成任务 两个 Worker 同时提交同一任务

# 25.7 Context–Memory–Prompt 数据流图

这张图要记住三个边界:

  • Memory 不等于 Context:Memory 是可持久化候选,Context 是一次 Step 实际选中的有界视图。
  • Rollout 不等于 Prompt History:Rollout 是用于恢复的原始事件记录,Prompt History 是根据模型能力、预算和协议约束生成的模型可见视图。
  • 压缩不等于删除事实:压缩只替换模型可见历史,原始事件、执行产物和来源记录仍用于审计、恢复,以及按原始记录重新构建状态。

Codex History::for_prompt 在发送前补齐调用结果、移除孤立输出、适配多模态并截断 FunctionCall 输出;World State 又只渲染相对基线的变化,说明 Context 是一个有类型的编译过程,而非字符串拼接:history.rs:141history.rs:325environment.rs:115

# 25.8 安全工具执行与信任边界图

安全链中每层解决的问题不同:Schema 防止结构错误,Semantic Validator 理解工具语义,Hook 是扩展治理点,Authorization 判断主体是否可请求,Approval 是本次动作的交互授权,Sandbox 则由 OS 强制“即使进程恶意也不能越界”。审批通过不能自动关闭沙箱,Feature Flag 为真也不能跳过权限链。

参数规范化必须只做一次并形成 hash,审批、Policy、Sandbox 和 Audit 都引用同一动作对象。Claude Code 的执行顺序与 Codex requested/granted permission 交集、SandboxManager 后端编译共同体现了这一不变量:toolExecution.ts:682policy_transforms.rs:126manager.rs:272

# 25.9 Multi-Agent 协作、隔离与汇总图

Multi-Agent 的四个一致性域必须分别管理:Spawn 决定执行实体是否存在,Mailbox 决定信息是否送达,Task Store 决定责任和依赖状态,Worktree/Patch 决定文件修改如何隔离。消息发送成功不代表任务 owner 已转移,Worktree 创建成功也不代表 Agent 获得额外权限。最终 Join 必须同时检查 Task 终态、证据、Diff 与 Agent 生命周期。

根 Agent 不应复制所有子 Agent 的历史,只保留任务摘要、状态、证据和执行产物引用;否则子任务越多,协调者的 Context 越容易膨胀。Claude Code 的 AgentTool、Task Store、Worktree 与 Codex 的 AgentControl、父子 Thread 和通信事件都体现了这些独立边界:runAgent.ts:412TaskUpdateTool.ts:276spawn.rs:452agent_communication.rs:6

# 25.10 Rollout、Trace、Metric 与 Eval 的质量闭环

四种数据必须从同一领域事件派生,但不能保存相同内容:Rollout 可以在受控权限下保留回放所需原文;Trace 保存因果、时间和脱敏属性;Metric 只保存取值种类较少的聚合指标;Eval 读取 Rollout 与执行产物并产出质量标签。它们共享 turn_id/step_id/call_id,才能从线上告警定位到单次执行轨迹,再把失败转成可复现的 Eval 用例。

成功指标不能只有 HTTP 200。一次 Turn 可能请求成功却修改错文件,因此需要同时观察任务验收率、验证通过率、用户纠正率、重复工具调用、压缩后事实丢失、权限拒绝与沙箱违规。Codex TurnTimingState 对采样、压缩、工具等待分别计时,Claude Code Session Trace 对 model/tool/approval/hook 建立 Span,正是为了把“慢”和“错”分解到可行动环节:turn_timing.rs:43sessionTracing.ts:49

# 25.11 二十个知识维度在主链中的位置

知识维度 在 Agent Loop 中的位置 必须守住的核心原理
1. Harness 包住整个端到端闭环 模型、执行、上下文、状态、安全、治理共享稳定事实 ID
2. Runtime Turn/Step/ToolCall 生命周期 状态所有权清晰,取消向下传播,终态只写一次
3. Multi-Agent Plan 后的任务分发与 Join Spawn、Message、Task、Workspace 是四条独立协议
4. Agent Loop 每次采样与工具观察之间 继续与停止原因结构化,完成权属于 Runtime/Verifier
5. Skill Context 候选发现与按需注入 渐进披露;Skill 声明需求但不授予权限
6. MCP Tool Registry 的外部能力来源 连接版本与工具快照一致,远端能力服从统一受控执行流程
7. 长期记忆 从原始事件记录后台抽取,并在下一会话召回 后台生成、保留来源、合并验证和使用反馈
8. 短期记忆 当前 Turn 的 Working State 事实、结构化投影和滚动摘要分层
9. 上下文压缩 模型采样前或 Turn 执行中的历史替换 不破坏调用配对的切分位置、一次完成的检查点写入、重新注入关键内容和可评测性
10. 上下文窗口 Context 编译的物理预算 输入、输出、单项、分类和累计成本多层预算
11. Prompt Engineering Context Items 到 Provider 请求 按权威层级编译,稳定前缀与动态后缀分离
12. Context Engineering 每个 Step 的模型可见投影 确定、有界、可归因、可失效
13. Agent UX Runtime Event 到用户界面 UI 是状态机只读投影,命令经 Runtime 确认后才生效
14. Tool Use 模型提议到结构化结果 校验、Hook、权限、沙箱、持久化不可绕过
15. Memory 跨 Working/Episodic/Semantic/Procedural/Prospective 类型决定生命周期、写入权、失效与召回方式
16. Planning Goal 到 Plan Artifact 与 Task DAG 方案、调度、审批是三份不同契约
17. Session 贯穿全部 Step 的顶层状态容器 关键记录先持久化再可见,恢复时根据事件重建状态
18. 可观测 根据所有状态变化生成观测数据 Rollout、Trace、Metric、Eval 使用同一来源关联,并按敏感级别脱敏
19. 权限 Tool 执行前的控制面 规范化动作、规则来源、最小委托和 Deny 优先
20. 沙箱 Tool 副作用发生的执行面 统一 Profile 编译到 OS Enforcement,不能静默降级

# 25.12 一次完整复习的推荐顺序

第一遍只沿第 25.3 节时序图口述正常路径,确保能在 5 分钟内讲清 UserInput → Step Context → Model → Tool → Result → Next Step → Verify。第二遍在每个节点加入异常:模型超长、工具拒绝、审批等待、沙箱违规、进程崩溃、MCP 断线、子 Agent 冲突。第三遍用第 25.11 节表格逐项检查 20 个维度是否都能落到主链位置和一个明确不变量。

面试回答时推荐采用固定结构:先画第 25.2 节六平面全景,再用第 25.3 节走一次时序;面试官追问长任务就展开压缩、Memory 与恢复,追问生产安全就展开权限—沙箱链,追问复杂任务就展开 Plan—Task DAG—Multi-Agent,追问线上质量就展开 Rollout—Trace—Eval 闭环。这样所有知识点都围绕一条 Agent Loop 主线展开,不会变成互不相干的术语清单。

# 25.13 判断架构是否正确的关键不变量

组件名称会变化,但下面这些规则不能被破坏。复习源码或设计新系统时,应优先检查不变量,而不是检查是否存在某个同名类。

范围 必须始终成立的规则 被破坏后的典型现象 关联章节
身份关联 Thread、Turn、Step、ToolCall、Task、Event 使用稳定 ID 串联 Trace、UI、恢复记录无法对应同一次动作 2、17、18
Step 一致性 模型看到的 Context、Tool Schema 和随后解析调用的 Registry 来自同一快照 模型按旧工具定义生成参数,Runtime 却用新定义执行 2、6、12
写入顺序 关键事实先持久化,再通知 UI 或进入下一 Step UI 显示成功,但进程重启后系统忘记副作用 14、17
调用配对 每个 ToolCall 都有唯一、可对应的 ToolResult 或明确的未知状态 压缩后出现孤立调用,模型重复调用工具 9、14
状态单向性 已完成、失败、取消等最终状态不能退回运行中 迟到进度把已完成任务重新显示为执行中 13、17
完成判定 模型只能提出完成;验收通过且没有未完成工作时 Runtime 才能结束 Turn 模型说“完成”但测试失败、审批仍等待或子任务未结束 4、16、23
权限绑定 审批、策略、沙箱和审计引用同一个规范化动作及哈希 用户批准的命令与真正执行的对象不同 19、20
最小权限 子 Agent、MCP 和远程 Runtime 获得的是父权限与任务所需范围的交集 权限在委托过程中不断扩大 3、6、19
沙箱强制 权限允许只是控制决策,副作用仍必须由 OS 或远程隔离环境强制限制 应用层校验被绕过后可直接访问宿主资源 20
Context 有界 每类内容和单项内容都有上限,并为模型输出保留空间 单个日志挤掉目标、计划和安全规则 8—12
Memory 可追溯 长期记忆保留来源、作用域、时间和删除状态 旧摘要覆盖新事实,删除后仍能从索引召回 7、15
任务唯一归属 同一 Task 在同一时刻只有一个有效执行者,过期 Worker 不能提交 多个 Agent 覆盖同一文件或重复产生外部副作用 3、16
恢复先查事实 重启后先重放事件并确认外部副作用,再决定是否重试 把结果未知的旧调用当成失败并重复执行 17、25.6
观测同源 Rollout、Trace、Metric 和 Eval 从同一领域事件派生 指标告警无法定位到具体轨迹,评测与线上行为不一致 18

# 25.14 一页复习卡:从用户目标到可验证结果

# 25.14.1 六十秒口述模板

一个生产级 Agent 不是“模型加几个工具”,而是由 Harness 管理的可恢复状态机。用户输入先进入 Session 并创建 Turn;Runtime 在每个 Step 固定世界状态、权限和工具目录,再由 Context Builder 按预算组合规则、历史、计划、Skill、Memory 与证据。模型只能生成文本或 ToolCall,动作必须经过参数校验、权限、必要审批和沙箱。ToolResult 先以稳定 call_id 持久化,再进入下一 Step。系统根据验证结果、未完成任务、预算和安全状态决定继续或停止。长任务通过压缩、事件恢复和 Multi-Agent 扩展;Rollout、Trace、Metric 与 Eval 使用同一组 ID 形成质量闭环。

# 25.14.2 十个自测问题

  1. 能否解释 Session、Turn、Step、ToolCall、Task 和 Agent 的区别?
  2. 为什么模型看到的 Tool Schema 必须与执行时的 Registry 属于同一 Step 快照?
  3. ToolCall 和 ToolResult 为什么必须先持久化再进入下一 Step?
  4. 哪四类情况会触发上下文压缩,压缩后必须重新注入什么?
  5. Memory、Context、Prompt History 和 Rollout 分别是什么?
  6. Approval 与 Sandbox 分别解决什么问题,为什么不能互相替代?
  7. 工具超时且结果未知时,为什么不能直接按失败重试?
  8. Multi-Agent 中 Spawn、Message、Task 和 Worktree 为什么是四条独立协议?
  9. Runtime 在什么条件下才能把 Turn 标记为完成?
  10. 如何用相同的 turn_id/step_id/call_id 从告警定位到轨迹,再生成 Eval 用例?

如果这十个问题都能结合一条源码入口、一个异常分支和一个设计取舍回答,说明已经形成完整知识体系,而不是只记住了术语。

最后更新: 2026/8/5 22:05:21