Skip to content
Go back

从 Codex 源码学 Agent 工程|02 长任务架构:Codex 如何持续工作

Edit page

会话、轮次、慢命令进程、上下文窗口与 goal 模式如何叠在一起,让 Codex 在长任务里持续推进而不把「还在忙」当成一种状态。

上一期讲了 Codex 如何把模型请求、工具执行和结果串成一轮。今天把时间拉长:测试要跑很久、中途读很多文件、你又临时补要求——它还能怎么继续?这是长任务架构:Codex 如何持续工作。

先认清几层对象

  • 会话:围绕任务积累的历史与相关配置;
  • 当前一轮:有自己的任务句柄和取消信号;
  • 模型请求与工具调用:上一期的内层循环,同一轮里可走很多次;
  • 慢命令进程:模型请求可能已结束、那次工具调用也可能已返回,但测试进程仍在跑——程序要留住句柄、收集输出,供后续继续读;
  • 模型窗口与持久记录:前者决定下次请求带什么;后者保存发生过的事与恢复所需检查点——用途不同,压缩上下文时更要把两者拆开;
  • 可选的 goal(目标)模式:跨轮次的目标推进。

即使没有 goal 扩展,普通「模型 + 工具」循环也能把一项工作做得很久。看到 Codex「还在忙」时,不能只用「运行中」概括:可能是模型在请求,也可能是命令还没结束。

内层循环与「先返回、后观察」

继续条件仍是:模型输出是否还需后续处理、输入队列有没有可消费内容。一次响应结束只说明这次模型输出结束了;结束前还有 stop hooks 一类检查。内层正常返回后,外层还会复查输入,处理临近结束才到达的消息。

慢测试不能把每次工具等待都设成「干等十分钟」。常见做法是:调用 exec 类命令启动测试后,先等一个有限观察窗口——窗口内结束就直接返回结果;到点还没结束,就把已有输出和一个会话编号先返回。下面的测试进程仍继续跑,进程管理器留着句柄。之后模型可用类似 write_stdin 的接口带上编号:不发送内容时可继续读输出;若启用了 TTY 交互会话,还能写入交互输入。名称里虽有「写入」,也承担后续观察——不会因此重新跑一遍测试。进程退出后再读,才得到退出状态和剩余输出。

要分别记录「这次等了多久」和「进程有没有结束」。把观察窗口结束当成测试失败,可能重复启动;当成测试完成,又会在没结束时提前汇报。

输出缓冲与两条路径

后台持续读命令输出:一条路径收进有容量上限的缓冲(常保留头尾,中间过多则截断)——长命令不能无限占内存;返回有截断时,模型不能假设读到完整日志。另一条路径把增量日志送到用户界面——界面刷到某行错误,不代表模型已收到那一行。排查时要核对本轮请求里实际带了什么。

窗口变长时的压缩入口

修一次测试可能加上大段文件内容和报错;全部带着走,上下文迟早到上限。Codex 会借助窗口使用情况,在任务仍需继续时,达到压缩阈值或收到显式压缩请求就进入压缩。走本地还是远端路径取决于配置与模型服务能力。成功后得到替换后的历史,后续请求用新窗口继续;检查点会写入恢复信息。压缩也可能失败,不能当正常可用记录继续跑;压缩成功也不保证无损——旧约束若遗漏,要重新核对原始要求与文件。

可选:goal 目标模式

goal 保存目标状态、预算与用量。空闲事件到来时,扩展检查能力与记录,读取持久目标;状态仍是 active 才生成下一轮续跑输入。读目标到启动下一轮这段常用锁保护并发时序。还要检查线程是否仍允许启动——用户刚发起新任务、当前已忙时,自动续跑就不应提交。用户暂停、工作阻塞、目标完成或预算触顶,都会挡住自动续跑;原因要记清楚。预算在工具结束、轮次结束等时点核算,不承诺「刚好到某个 token 就掐断一切」。goal 管的是跨轮次推进;普通工具循环本身也可以很长。

用户介入:追加 vs 取消

测试还在跑时你补一句「还要兼容旧接口」:要求先进输入队列,在允许消费的位置写入上下文,让后续模型请求看到——不会凭空改写已发出的请求,也不表示当前工具立刻停下。结束附近还会复查队列,减少漏掉新要求的机会。

取消是另一条链路:传播取消信号,工具按自己的规则收尾,审批等待要清理,异步任务有短暂退出机会。注意:已写入的文件不会因取消自动改回;远端作业已提交,停当前轮次也不等于撤销远端——后续要核对实际状态。

重启会话后如何接着做

保存的历史、压缩检查点、之后的工具结果与轮次记录,程序要先确定从哪重放:有有效检查点就用替换历史与保留上下文,再处理后续事件;否则从历史起点重建。本地可用 JSON 等持久化;宿主也可接其他存储。重建模型上下文 ≠ 把所有进程和外部系统拉回重启前:工作区差异要查;测试进程若已消失,历史里的编号也不会自动复活;远端作业可依任务编号查状态,别直接重复提交。

串一遍长任务修 bug

提交要求 → 读测试、查实现、改代码 → 启动慢测试(观察窗口先返回,进程继续)→ 信息写入历史;窗口达阈值则压缩并写检查点 → 测试返回退出状态与剩余输出 → 核对修改与用户要求 → 若启用 goal,满足则可标记完成并停自动续跑,否则等空闲与状态允许再开下一轮。

排查「卡在哪」时:模型在等工具?进程还没结束?已进入压缩或恢复?本轮已结束则看 goal 是否启用、状态是否允许续跑。

下一期单独看上下文:任务做久了哪些信息继续放进请求,压缩之后怎么接着查和执行。


Edit page
Share this post on:

Previous Post
从 Codex 源码学 Agent 工程|03 上下文压缩:满了之后怎么办
Next Post
从 Codex 源码学 Agent 工程|01 Agent 循环:请求、工具调用与结束条件