让 Codex 连续干几天,靠的不是一条超长 Prompt
原创 · 约 26 分钟阅读 · 阅读 --
最后更新于

让 Codex 连续干几天,靠的不是一条超长 Prompt

作者: Alex Xiang


过去我让 AI 改代码,任务通常很短:修一个报错、补一个接口、写几条测试。上下文不够就再解释一遍,改坏了就回滚,半小时内总能收尾。

现在不一样了。一次任务可能横跨内容、代码、构建、浏览器、部署和线上验证,中间还会插入新的要求。它会跑过午饭,跨过晚上,第二天继续。此时最危险的错觉,是觉得只要把 Prompt 写得足够长,Codex 就能一直沿着正确方向跑下去。

长 Prompt 只能把起跑线画得更细,不能替任务保存状态,也不能证明终点已经到了。

2026 年 6 月,OpenAI 发布了 27 页的《Codex-maxxing for long-running work》,把 durable threads、steering、memory、thread automations、goals 和人工复核串成一套长任务方法。白皮书里有一句很关键:强目标要给 Codex 一个可以测试的标准,而不只是叫它“执行计划”。这和我最近一次从设计一直跑到联调的工程任务得到的结论基本一致。

本文把真实过程抽象成一场统一授权系统的虚拟工程演练。假设一个产品原本只有网页登录,现在需要同时支持服务端 Web、SPA、本地 CLI、WSL、远程服务器和后台任务,还要统一身份、权限、Token、审计与用量。系统名称、域名、仓库和业务数据全部虚构,保留的只是工程步骤、失败模式、测试方法和 Codex 运行统计。

主案例:统一登录不是加一个按钮

最初的要求听起来很短:做一套统一登录,让网站和命令行都能使用同一个账号。真正展开后,任务至少穿过七层:

层次需要解决的问题
协议OAuth 2.0、OIDC、Authorization Code + PKCE、Device Authorization 如何分工
身份邮箱、第三方 subject 与稳定 user ID 如何归一
客户端Web、SPA、本地 CLI、远程 CLI 和后台任务分别采用什么 grant
数据client、authorization code、device code、grant、consent 与审计如何建模
密钥JWT 签名私钥、JWKS、kid 和轮换如何保证多副本一致
兼容新授权能力默认关闭时,现有 Cookie 和 API Key 流程是否保持不变
验证单元测试、接口契约、测试环境、浏览器回调和真实 CLI 演示如何闭环

虚拟统一授权系统中的客户端、授权中心与资源服务

任务还在进行中不断增加约束:远程服务器不能依赖本机浏览器;Agent 访问资源 API 要使用受 audience 和 scope 限制的 JWT;用量必须能追溯到用户与客户端;数据库迁移要先完成;多个代码模块要按依赖顺序提交;review 发现阻塞问题后必须回到设计层修正。

这不是“写完 OAuth endpoint”就结束的功能。授权中心签出了 Token,只能证明一条局部路径成立。要宣布完成,还必须证明:老调用没有被误伤,错误配置会尽早失败,CLI 能在真实运行边界中完成授权,资源服务器会拒绝错误 issuer、audience、scope 和过期 Token。

长 Prompt 为什么撑不住

假设开头写一条三千字的指令,把协议、表结构、接口、路径、命令和注意事项全部塞进去。第一轮通常表现很好。问题从第二轮开始:

  • 用户追加了新的边界,初始 Prompt 已经过时。
  • 某个命令失败,后续步骤必须改变。
  • 单元测试通过,但多副本部署使用了彼此不同的临时签名密钥。
  • 浏览器成功返回 authorization code,WSL 里的 CLI 却收不到 loopback callback。
  • 上下文压缩后,模型记得目标,未必记得每个验证结果。
  • 同一个线程越来越长,每次读取历史的成本持续上升。

Prompt 是输入,不是状态机。它既不知道哪些步骤已经成功,也不知道哪些结果后来被新事实推翻。

超长 Prompt 与可验证 Goal 的差别

这次最典型的反例出现在 JWT 签名密钥上。实现最初允许在没有配置私钥时由进程临时生成 RSA key,单进程开发环境里 discovery、JWKS 和 Token 验证都能通过;一旦放进多副本环境,不同实例可能在同一个 kid 下生成不同公钥。请求落到 A 实例时签发的 Token,下一次由 B 实例提供 JWKS,就会随机验证失败;服务重启还会让尚未过期的 Token 集体失效。

若目标只是“能签发 JWT”,任务已经完成;若目标是“多副本和重启后仍能稳定验证”,就必须让生产环境缺少稳定私钥时直接启动失败,只把临时密钥留给显式开启的开发模式。

这就是 Goal 和任务清单的区别。

Goal 要写成验收合同

一个弱目标是:

实现统一 OAuth 登录,并让 CLI 能够授权。

更可用的写法是:

实现一套默认不影响旧认证链路的统一授权系统。Web 与本地 CLI 使用 Authorization Code + PKCE,远程 CLI 使用 Device Authorization,后台任务使用受限工作负载身份;资源 API 必须校验 issuer、audience、expiry 和 scope;生产环境缺少稳定签名私钥时 fail fast;数据库迁移、单元测试、测试环境接口验证和真实 CLI 回调全部通过后才算完成。

两者都说了“做什么”,后者还定义了“如何知道做完了”。

我现在更习惯把长任务目标写成四段:

目标:最终用户能看到什么结果。

约束:哪些内容、接口、数据和权限不能改变。

证据:用哪些测试、截图、状态码、查询结果证明完成。

完成条件:哪些检查全部通过后,任务才能关闭。

这四段里,“证据”最容易漏。很多 Agent 任务停在“代码已经改了”,没有走到“行为已经被证明”。

把状态从对话里搬出来

长线程当然能保留大量历史,但对话记录不应该成为唯一状态库。OpenAI 的白皮书也把 memory 描述为可打开、可编辑、可 diff、可复用的东西,并明确区分代码仓库和滚动工作上下文。

在工程任务里,我会把状态分成四类:

状态放在哪里原因
代码与配置Git 工作区可 diff、可测试、可回滚
长期规则AGENTS.md、Skill、README下次任务无需重新口述
当前进度Goal、计划、issue 或任务清单能区分待做、进行中和已完成
验收证据测试输出、截图、构建产物、线上查询防止用记忆代替验证

长任务需要把状态写进可审阅的外部载体

这次任务里,协议选择、数据模型、接口契约和兼容策略先写进设计文档;实现拆成可追踪的问题与 PR;密钥约束写进配置说明和启动校验;每个客户端的接入方式放进示例目录;测试结果保留为可重复运行的命令。review 指出临时密钥问题后,修复不只停在一行代码,还同时补上配置约束和回归测试。

同样,“默认不影响旧认证链路”不能只留在对话中。它必须落实为功能开关、默认值、路由条件和兼容性测试,否则下一次重构很容易无意中把尚未迁移的客户端挡在门外。

判断状态是否真正外置,有一个简单办法:换一个新线程,只读取仓库和任务记录,它能不能继续工作?如果答案是否定的,重要信息仍困在聊天里。

检查点不是频繁提交

长任务需要检查点,但检查点不等于每改一行就提交一次。一个有用的检查点应该满足三个条件:

  1. 当前阶段内部一致。
  2. 有一组能重复运行的验证命令。
  3. 失败后可以从这里继续,而不是重新猜测状态。

统一授权演练被拆成下面几个检查点:

CP1 方案冻结:客户端类型、grant、scope、audience 和兼容边界明确
CP2 数据与协议:模型、迁移、discovery、JWKS、authorize、token、userinfo 完整
CP3 资源接入:JWT 验证、旧认证兼容、审计与用量链路可用
CP4 Review 修复:稳定私钥、错误配置 fail fast、回归测试通过
CP5 环境联调:测试环境配置、接口探测和浏览器授权通过
CP6 端到端演示:CLI 打开系统浏览器、回调、换 Token、调用 API 闭环

CP4 通过,并不代表 CP6 通过。真实 CLI 联调时,系统浏览器已经打开,用户也完成了授权,但页面一直停在“正在授权”。原因不是 PKCE 算法,而是浏览器运行在宿主系统、CLI 运行在 WSL,127.0.0.1 回调能否到达监听进程取决于具体网络与转发边界。

最后的验证不能只看浏览器页面。CLI 必须实际收到 code、校验 state、使用 verifier 换取 Token,并成功调用受保护接口。中间任何一步没有证据,都不能把“页面看起来完成”当成端到端成功。

本地 CLI 通过系统浏览器与 loopback callback 完成 PKCE

幂等决定任务能不能安全续跑

长任务一定会重试。网络会断,部署会超时,进程会中止,用户也可能中途改变方向。只要同一步执行两次会产生额外副作用,自动续跑就不可靠。

典型风险包括:

  • 重复执行数据库迁移,留下半成品结构。
  • authorization code 被兑换两次。
  • Device Flow 轮询没有遵循 intervalslow_down
  • 重试创建 client 时生成多个不同 secret。
  • 测试失败后重复写入授权、审计或用量记录。

检查点、失败恢复和幂等保护

幂等不只是后端接口概念。Agent 工作流也需要自己的幂等键和状态检查:

def exchange_authorization_code(code, verifier):
    grant = load_grant_for_update(code)
    if grant.used_at or grant.expires_at <= now():
        raise InvalidGrant()
    verify_pkce(grant.code_challenge, verifier)
    grant.used_at = now()
    return issue_tokens(grant)

这里不仅要检查 used_at,还要让“读取未使用状态”和“标记已使用”处于同一个短事务中。否则两个并发请求都可能在对方提交前读到未使用状态,最终把一次性 code 兑换两次。

一个任务若无法回答“上一步究竟成功没有”,就不应该自动重试有副作用的操作。

验收证据要分层

我把这类授权任务的证据分成四层:

第一层:静态结构

  • client、grant、consent、code 与审计模型约束正确。
  • redirect URI 精确匹配,PKCE 只接受安全方法。
  • access token 明确包含 issuer、audience、expiry 与 scope。
  • 生产配置不允许静默使用临时签名私钥。

第二层:构建产物

  • 数据库迁移可以向前执行,并能在目标环境确认表结构。
  • discovery 与 JWKS 输出符合约定。
  • authorize、token、userinfo 和资源验证单元测试通过。
  • 旧 Cookie、API Key 或未开启 OAuth 的路径保持原行为。

第三层:浏览器行为

浏览器与 CLI 联调检查:

  • 登录与同意页能正确展示 client、resource 和 scope。
  • state、nonce 和 PKCE verifier 在回调后被正确校验。
  • 拒绝授权、code 过期和重复兑换有明确错误。
  • 本地 CLI 能打开系统浏览器,并接收 loopback callback。
  • 无头环境能切换到 Device Authorization,而不是无限等待。

第四层:环境事实

  • 测试环境 discovery、JWKS 与授权端点可访问。
  • 正确 Token 能访问目标 API,错误 audience 或 scope 被拒绝。
  • 多副本读取同一套稳定公钥,重启后已有 Token 仍可验证。
  • 审计和用量记录能关联用户、client、resource 与授权方式。

这四层不能互相替代。单元测试无法证明 WSL 的回环地址真的可达,浏览器显示“授权成功”也不能证明 CLI 已经拿到并验证了 Token。

规划用 High,执行用 Medium

推理档位不应该从头到尾固定。统一授权任务前半段的难点是做取舍:五类客户端怎样分类,哪些协议能力必须首期完成,旧认证如何兼容,Token、审计和用量边界放在哪里。这些问题一旦判断错,后面代码写得越快,返工越大。因此方案 review、威胁建模、接口边界和阻塞性 review 修复阶段使用 gpt-5.6-sol high

设计冻结后,工作重心变成按既定契约实施:补模型和迁移、写 endpoint、更新依赖、运行测试、修复类型错误、部署测试环境、执行接口探测和跑 CLI demo。这些步骤仍需要推理,但搜索空间明显收窄,改用 gpt-5.6-sol medium 更合适。

核心实施窗口约 5 小时 11 分钟。从本地主线程记录汇总得到:

阶段档位turns总 tokensreasoning tokens
规划、设计复核、威胁建模与核心骨架Sol High1272,486,25737,128
开发收尾、环境配置、联调与测试Sol Medium752,121,71420,687
合计19124,607,97157,815

其中输入 tokens 为 124,383,597,缓存输入为 122,325,248,缓存比例约 98.34%。统计采用线程累计计数在窗口起止点及档位切换点做差,避免重复累加同一轮的阶段性记录。这组数来自一个已经很长的主线程,绝大部分是反复携带的缓存上下文,不等于新生成了一亿多 Token,也不能直接当成 API 账单。它更适合说明另一件事:长期线程保留连续性的同时,也会不断背负历史。

这组记录支持三个判断:

  1. 高档推理应该放在错误代价最高的决策点,不必覆盖所有机械执行步骤。
  2. 能写进设计文档、issue、代码和测试结果的状态,应尽快外置,减少线程对完整聊天历史的依赖。
  3. 当后续工作只依赖已经冻结的契约时,可以新开执行线程,只携带目标、约束、检查点和当前证据。

“始终使用同一个线程”不比“每次都开新线程”天然高明。真正需要保留的是决策连续性,而不是所有聊天文本。

人必须卡住哪些动作

长任务不是无人值守。自动化范围越大,越要把不可逆动作单独拦住。

我通常把动作分成三档:

档位示例默认策略
可逆读取文件、搜索、运行测试、生成草稿可自动执行
可回滚但有影响修改代码、创建分支、部署预览执行后提供证据
不可逆或外部影响大删除数据、合并、生产发布、付费、群发必须人工确认

长期自动化中的人工审批门

白皮书的三个循环示例也保留了同样边界:Codex 可以准备回复、证据和建议,用户负责批准、时机和最终决定。Remote control 的价值是让人可以在手机上及时解除阻塞,不是让审核消失。

在统一授权演练中,Codex 可以生成迁移、准备配置、创建 PR、部署测试环境并运行端到端 demo;生产私钥写入、数据库生产迁移、正式启用 OAuth、合并发布仍要保留人工审批。代码能通过测试,不代表它已经获得改变生产身份边界的授权。

什么时候继续,什么时候停

Codex 适合继续推进的信号:

  • 完成条件明确,并且能用工具验证。
  • 当前失败是可诊断、可重试的工程问题。
  • 下一步不会产生不可逆外部影响。
  • 仓库状态和已有用户修改能够被准确识别。
  • 即使上下文压缩,也能从外部记录恢复进度。

应该停下来找人的信号:

  • 两种产品方向都合理,需要业务判断。
  • 数据删除、生产发布或费用支出缺少授权。
  • 连续三次遇到同一外部阻塞,环境没有变化。
  • 验收标准互相冲突。
  • 继续尝试只会扩大改动面,不能增加新证据。

“能继续调用工具”不等于“继续调用工具有价值”。一个成熟的长任务 Agent,既要会推进,也要会识别决策边界。

我现在使用的长任务模板

下面这份模板比堆叠背景资料更有用:

目标
- 描述最终可观察结果,不要只写“执行某个方案”。

约束
- 不得改变的接口、数据、用户修改和权限边界。
- 不允许执行的不可逆操作。

状态载体
- 代码与配置:Git
- 决策与规则:AGENTS.md / Skill / ADR
- 当前进度:Goal / issue / checklist
- 证据:测试、截图、日志、线上查询

检查点
- 每个阶段的输入、输出和重复验证命令。

完成条件
- 功能测试
- 构建与静态审计
- 桌面和移动端验证
- 线上回读
- 未提交改动和副作用检查

重试策略
- 哪些操作幂等
- 哪些操作需要先查询状态
- 哪些操作失败后必须交还人工

交付
- 改了什么
- 如何验证
- 尚未完成什么
- 哪些动作仍需人工批准

它看起来像工程管理,不像 Prompt 技巧。原因很简单:当 Codex 开始连续工作几小时甚至几天,问题已经从“怎么提问”变成“怎么运行一个可靠的执行系统”。

最后

一条超长 Prompt 能让 Codex 更快进入状态,却不能替代目标、记忆、检查点、幂等和验收。真正让任务持续推进的,是一套可以在对话之外保存、检查和恢复的工作结构。

OpenAI 在 2026 年 6 月 22 日发布的 Codex-maxxing for long-running work 已经把方向说得很清楚:工作需要一个可以长期存在的地方,也需要可验证的目标和人在关键节点上的判断。完整的 27 页白皮书 值得读一遍。

我的补充只有一句:长任务最后拼的不是模型能记住多少,而是系统丢掉一部分上下文后,仍然能不能知道自己做到哪里、下一步做什么,以及凭什么宣布完成。

打开原图 ↗