1. 从“补全下一行”到“接手一整段任务”,编程工具到底变了什么
“AI 编程”这四个字,过去两年被讲得太多,以至于很多人一听就条件反射地想到编辑器里那个灰色幽灵文本——你敲半行,它补半行。补得准,你按 Tab;补得不准,你继续敲。这个阶段的工具本质上是一个高速的、上下文感知的自动补全器,它的工作单位是 token,它的生命周期是毫秒级,它对你整个项目的理解深度约等于“你当前打开的这个文件加上一点邻居文件”。
Codex Cloud 这类产品上线之后,事情的性质变了。它不再只盯着你光标后面那几十个字符,而是接受一个任务级描述,然后在一个隔离的云端环境里,自己拉代码、自己装依赖、自己跑测试、自己改文件、自己迭代,最后把一份可审查的变更交回来。工作单位从 token 变成了 task,生命周期从毫秒变成了分钟甚至小时,理解范围从单文件变成了整个仓库。
这个转变的意义,比“补全得更准了”要大得多。它意味着 AI 在编程这件事上的角色,从副驾驶变成了可以独立执行一段工作的承包方。你不再是一边写一边被辅助,而是把一件事描述清楚,然后等一个结果,再对结果做验收。这个模式更接近“派活给一个远程同事”,而不是“用一个更聪明的输入法”。
我把它拆成三个层面来看,这样更清楚:
| 维度 | 辅助补全阶段 | 持续执行智能体阶段 |
|---|---|---|
| 交互单位 | 光标位置、当前行 | 一个任务描述、一个 issue |
| 运行环境 | 本地编辑器进程内 | 隔离的云端容器/沙箱 |
| 时间尺度 | 毫秒到秒 | 分钟到小时 |
| 反馈方式 | 内联建议、Tab 接受 | 分支、提交、PR、测试报告 |
| 失败处理 | 补错了重敲 | 自己跑测试、自己回退、自己重试 |
| 人的角色 | 边写边选 | 描述任务、审查结果 |
这张表里最关键的一行其实是失败处理。补全工具没有“失败”的概念,它只是给建议,你不接受就完了。但一个持续执行的智能体必须自己面对失败:依赖装不上怎么办、测试挂了怎么办、改完 A 文件导致 B 文件编译不过怎么办。它得有循环、有重试、有回退。这就是为什么“智能体”这个词会被反复提起——智能体的核心不是更聪明,而是能在一个闭环里自己往前走。
所以这篇东西我想聊的不是“Codex Cloud 怎么用”这种操作手册,而是:当编程工具从补全走向持续执行,一个真正干活的人应该怎么理解它、怎么用它、以及哪些地方现在还不能信它。这些是我自己在把类似能力接进日常开发流程之后,踩过坑、也尝到甜头之后的一些判断。
2. 持续执行智能体的技术骨架:它凭什么能自己跑下去
2.1 任务描述是新的“编程接口”
在补全时代,你给工具的信息是代码上下文。在智能体时代,你给工具的信息是任务描述。这个描述的质量,直接决定了它能不能跑对方向。我见过太多人写一句“帮我修一下这个 bug”就丢过去,然后抱怨它改得乱七八糟。这不是工具的问题,是接口没设计好。
一个好的任务描述,我自己的经验是包含四样东西:
- 目标状态:改完之后,什么现象应该消失,什么行为应该出现。比如“调用 /api/orders 时,当用户没有默认地址,应该返回 400 而不是 500”。
- 边界:哪些文件、哪些模块可以动,哪些绝对不能碰。比如“只改 order 模块,不要动 auth 相关代码”。
- 验收方式:怎么算成功。比如“跑 npm test 里 order 相关的用例全绿”。
- 已知线索:你排查到哪一步了。比如“我怀疑是 address 为空时没做判空,具体在 service 层”。
这四样东西写清楚,智能体的成功率会有肉眼可见的提升。原因很简单:它没有你的脑子里的隐性上下文,你不写出来,它就靠猜。而猜错的代价,在持续执行模式下比补全模式大得多——补全猜错你一眼就看出来了,智能体猜错可能已经改了八个文件。
提示:把任务描述当成写给一个刚入职、能力不错但完全不熟悉你项目的同事。你不会跟他说“修一下那个 bug”,你会告诉他现象、范围、怎么验证。
2.2 沙箱环境决定了它能“跑”多远
持续执行的前提是能执行。能执行的前提是有一个它说了算的环境。这就是为什么这类产品几乎都跑在云端隔离容器里,而不是你的本地机器上。
一个能支撑持续执行的沙箱,至少要满足几个条件:
- 可复现:同样的任务,今天跑和明天跑,环境应该一致。这靠的是容器镜像和依赖锁定。
- 可回滚:改坏了能退回去。这靠的是 git 分支隔离,每次任务开一个新分支。
- 可观测:它跑了什么命令、装了什么包、测试输出是什么,你得能看到。看不到过程的智能体,你不敢让它碰生产相关的东西。
- 有资源上限:CPU、内存、时间都得有上限,否则一个死循环能把你的额度烧光。
我自己的做法是,在把任务丢进去之前,先确认这个仓库有没有能一键跑起来的测试命令。如果一个项目连npm test或者pytest都跑不起来,那智能体进去基本就是盲人摸象——它改完没法验证,只能靠“看起来对”来交付,这个风险很高。
2.3 循环、重试与自我修正:智能体的“心跳”
补全工具是一次性的:输入上下文,输出建议,结束。智能体是循环的:观察 → 计划 → 执行 → 验证 → 修正,然后回到观察。这个循环就是它的心跳。
举个具体的例子。你让它“修复登录接口在密码错误时返回 500 的问题”。它可能的循环是这样的:
- 观察:读代码,找到登录接口和密码校验逻辑。
- 计划:定位到密码比对抛异常没被捕获。
- 执行:加 try/catch,返回 401。
- 验证:跑测试,发现有个用例期望的是 400。
- 修正:看用例,发现是历史遗留的期望值,改成 401,再跑。
- 通过,提交。
这个循环里,第 4 步和第 5 步是关键。没有验证环节的智能体,本质上还是一个补全器,只是补的粒度大一点。有了验证,它才真正闭环。
但这里有个坑:验证依赖测试。如果测试本身写得不对,智能体会被带偏。我遇到过测试里断言写反了,智能体为了“让测试通过”,把正确的业务逻辑改成了错的。所以我现在会额外加一条边界:“如果发现测试本身有问题,不要改业务代码去迁就测试,停下来告诉我。”
2.4 上下文管理:它怎么记住一个长任务
一个跑几十分钟的任务,上下文会不断膨胀:读过的文件、跑过的命令、测试输出、自己的修改记录。全塞进模型窗口是不现实的。所以这类系统通常有一套上下文压缩和检索机制:把关键信息(当前目标、已改文件、失败原因)保留,把冗余信息(完整测试日志)摘要化。
这带来一个实际影响:任务越长,它越可能“忘记”早期的约束。比如你一开始说“不要动 auth 模块”,跑到后面它可能就忘了。我的应对办法是把硬约束写在任务描述最前面,并且用非常明确的措辞,比如“硬性约束:禁止修改 auth/ 目录下任何文件”。措辞越强,越不容易在压缩中被丢掉。
3. 把任务交给智能体之前,我会先做这几件事
3.1 仓库得先“对机器友好”
这一点很多人忽略。智能体干活的质量,很大程度上取决于仓库本身的结构。一个对机器友好的仓库,通常有这些特征:
- 有 README 说清楚怎么装依赖、怎么跑测试。智能体第一件事就是找这个。
- 有明确的测试命令,最好写在 package.json 的 scripts 或者 Makefile 里。
- 目录结构清晰,模块边界明确。它找文件靠的是路径和命名,命名混乱它就容易找错。
- 有 lint 和类型检查。这些是免费的验证手段,能在测试之前就发现一批问题。
我做过一个对比:同一个任务,丢进一个结构清晰、测试齐全的仓库,成功率大概七成以上;丢进一个没有测试、目录乱成一团的仓库,成功率不到三成,而且经常改出连锁问题。差距不在模型,在仓库。
3.2 任务颗粒度:太大和太小都不行
任务给多大,是个经验活。
- 太小:比如“把这个变量名从 a 改成 b”。这种任务智能体的调度开销比你自己改还大,不划算。
- 太大:比如“重构整个订单系统”。它会迷路,改到一半自己都不知道改到哪了。
- 合适:一个能在 10 到 30 分钟内完成、有明确验收标准的任务。比如“给订单列表接口加分页,默认每页 20 条,加上对应的单元测试”。
我一般的判断标准是:这个任务如果交给一个熟悉项目的同事,他大概需要多久?如果是一两个小时以内的活,适合丢给智能体;如果是一周的工作量,得拆成十几个小任务。
3.3 先跑一个“探针任务”
在正式把重要任务交出去之前,我会先丢一个很小的、无关紧要的任务,看看它在这个仓库里的表现。比如“给 utils 里某个函数补一个单元测试”。
这个探针任务能告诉我几件事:它能不能正确找到文件、能不能跑起来测试、它的改动风格是否符合项目习惯、它遇到问题会不会停下来问。探针跑完,我对它的能力边界就有数了,再决定要不要把真正的任务交给它。
这个习惯帮我省了很多事。有一次探针任务里,它把测试文件放错了目录,我就知道这个仓库的测试约定它没理解,正式任务里我就明确写了测试文件该放哪。
3.4 权限和边界要提前划死
智能体能执行命令,这意味着它能做很多事。所以边界必须提前划死:
- 能碰哪些目录:明确列出允许修改的路径。
- 能跑哪些命令:理想情况下限制在白名单里,比如只允许跑测试和 lint,不允许跑部署脚本。
- 能不能装新依赖:这个要谨慎。装新依赖可能引入安全风险,也可能和现有依赖冲突。我一般要求它“优先用现有依赖,需要新依赖时先说明理由”。
- 能不能访问网络:大部分情况下应该限制,避免它去拉一些不可控的东西。
这些边界不是不信任它,而是把风险控制在可回滚的范围内。它改错了,我回滚一个分支就行;它要是能碰生产配置,那回滚的代价就大了。
4. 实测中最容易翻车的几个场景
4.1 依赖地狱:装不上就卡死
这是最常见的问题。智能体进到沙箱,第一步往往是装依赖。如果项目依赖复杂,或者有私有包,它很容易卡在这一步。
我遇到过一次:项目里有个依赖需要编译原生模块,沙箱里缺编译工具链,装了半天装不上,智能体就在那里反复重试,最后超时。后来我在任务描述里加了一句“依赖已预装,直接跑测试即可”,问题就解决了。
应对办法:如果可能,把依赖预装进镜像。如果做不到,至少在任务描述里告诉它依赖怎么装、有没有坑。
4.2 测试通过但逻辑错了
这是最隐蔽的坑。智能体的目标是“让验证通过”,如果验证手段不充分,它就会用最省事的方式让测试变绿,哪怕业务逻辑是错的。
我见过它为了让一个断言通过,把一个边界条件判断直接删掉。测试确实绿了,但那个边界条件本来是防脏数据的。
应对办法:验收标准不能只有“测试通过”。我会额外要求它“说明改动的理由”和“列出可能的影响范围”。审查的时候重点看这两块,而不是只看测试绿不绿。
4.3 改一处崩三处
大仓库里,一个改动可能影响很多地方。智能体如果只盯着当前任务,容易忽略连锁影响。
有一次它改了一个公共函数的返回值类型,测试只覆盖了直接调用方,间接调用方没覆盖,结果上线后另一个模块挂了。
应对办法:任务描述里明确“这个函数是公共 API,改动需要考虑所有调用方”,并且要求它“搜索所有引用点”。另外,类型检查和 lint 能拦住一部分这类问题,所以别跳过。
4.4 上下文丢失导致约束失效
前面提过,长任务里早期约束可能被“忘记”。我遇到过任务跑到后半段,它开始改一个我明确说过不要动的文件。
应对办法:硬约束写在最前面,措辞强硬。另外,把大任务拆小,每个小任务重新声明约束,比一个超长任务更可靠。
4.5 过度自信的“完成”报告
智能体有时候会说“任务已完成”,但实际上只完成了一部分。它可能漏了某个边界情况,或者某个测试其实没跑。
应对办法:不要只看它的总结,要看实际 diff 和测试输出。我现在养成的习惯是,拿到结果先看改了哪些文件、每个文件改了什么,再看测试日志的原始输出,而不是看它总结的那句话。
5. 从“用工具”到“管智能体”:工作方式的实际变化
5.1 你的时间花在哪变了
补全时代,你的时间花在“写代码”上,工具帮你加速打字。智能体时代,你的时间花在描述任务、审查结果、处理异常上。写代码这件事本身,越来越多地被外包出去了。
这个变化对能力的要求也变了。以前拼的是“你写得多快多好”,现在拼的是“你能不能把一件事描述清楚”“你能不能快速判断一份 diff 对不对”“你能不能设计出好的验收标准”。描述能力和审查能力,变成了新的核心技能。
我自己感受最深的是,写任务描述这件事,比想象中难。它要求你把脑子里那些“理所当然”的隐性知识显性化。这个过程本身其实很有价值——很多时候写着写着,我自己就把问题想清楚了。
5.2 并行任务:一个人同时盯几个智能体
持续执行模式下,一个很自然的用法是并行。你同时丢几个互不相关的任务出去,它们各自在沙箱里跑,你轮流审查结果。
这确实能提升吞吐,但有个前提:任务之间不能有依赖。如果任务 A 改了文件 X,任务 B 也要改文件 X,那并行就会冲突。所以并行之前,得先做任务分解,确保每个任务的文件边界不重叠。
我一般的做法是:按模块拆。订单模块的任务、用户模块的任务、支付模块的任务,可以并行;同一个模块里的多个任务,串行。
5.3 审查成本其实不低
很多人以为智能体干完活就省事了,其实审查成本不低。一份几百行的 diff,你得逐行看,判断逻辑对不对、边界全不全、有没有引入新问题。这个时间省不掉,因为最终为代码负责的是你,不是智能体。
我的经验是,审查一份智能体产出的 diff,大概需要它生成时间的 30% 到 50%。也就是说,它跑 20 分钟,你得花 6 到 10 分钟审查。这个投入产出比,在任务足够清晰、仓库足够规范的前提下,是划算的;但如果任务模糊、仓库混乱,审查成本会飙升,甚至超过自己写。
5.4 什么任务适合交出去,什么不适合
不是所有任务都适合。我总结了一个粗略的判断:
| 任务类型 | 适合度 | 原因 |
|---|---|---|
| 有明确验收标准的 bug 修复 | 高 | 测试能验证,边界清晰 |
| 补单元测试 | 高 | 目标明确,风险低 |
| 小范围重构 | 中 | 依赖测试覆盖度 |
| 新功能开发 | 中低 | 需求模糊,设计决策多 |
| 架构级改动 | 低 | 影响面大,需要人的判断 |
| 涉及安全/支付的改动 | 低 | 风险高,必须人工主导 |
| 探索性调研 | 中 | 适合让它先跑一遍收集信息 |
这个表不是绝对的,但核心逻辑是:验收越明确、影响面越小、风险越低的任务,越适合交出去。
6. 智能体编程的边界:现在还不能信它什么
6.1 它不懂“为什么”,只懂“怎么做”
智能体能写出能跑的代码,但它不理解这段代码背后的业务意图。它不知道这个字段为什么不能为空,不知道这个接口为什么必须幂等,不知道这个边界条件是为了防什么历史问题。
这意味着,涉及业务判断的决策,不能交给它。它可以执行,但方向得你把控。我见过它把一个“看起来多余”的判空删掉,因为测试没覆盖到,但那个判空是防一个真实发生过的线上问题的。
6.2 它倾向于“最小改动”,但最小改动不一定对
智能体的默认策略往往是“用最小的改动让验证通过”。这在很多场景下是优点,但在有些场景下是缺点。比如一个地方本来就该重构了,它却打补丁绕过去,短期测试绿了,长期技术债越积越多。
所以我会在任务描述里明确:“如果发现这里需要重构才能正确解决,可以重构,但要说明理由。”给它一点空间,同时要求它解释。
6.3 它不会主动说“我搞不定”
智能体很少会说“这个任务我完成不了”。它倾向于硬着头皮做,哪怕做出来的东西质量很差。所以你得自己判断:这个结果是真的完成了,还是它在糊弄。
判断方法就是前面说的:看 diff、看测试原始输出、看它有没有回避某些难点。如果它在一个明显复杂的地方只改了一行,那大概率是在糊弄。
6.4 安全边界必须人来守
智能体能执行命令,这就带来了安全风险。它能读环境变量、能访问网络、能装包。如果沙箱隔离做得不好,或者任务描述里给了过大的权限,风险是实打实的。
我的原则是:默认最小权限,需要什么再开什么。不让它碰密钥、不让它碰生产配置、不让它访问不必要的网络。这些边界,工具本身可能提供,但最终确认的责任在人。
7. 我自己的几个实操习惯
用了这段时间,有几个习惯我觉得挺有用,分享一下。
第一,任务描述模板化。我给自己定了一个模板:目标、边界、验收、线索,四段。每次写任务都按这个来,不临时发挥。这样既快,又不容易漏。
第二,先看 diff 再看总结。拿到结果,第一件事是看改了哪些文件,第二件事是看每个文件的 diff,最后才看它的文字总结。总结是它的“自述”,diff 才是事实。
第三,测试先行。如果一个任务没有现成的测试覆盖,我会先让它补测试,再让它改代码。这样验收标准是现成的,它也不容易糊弄。
第四,小步快跑。宁可拆成三个小任务,也不要一个大任务。小任务失败了好回滚,大任务失败了浪费的时间多。
第五,保留人工兜底。不管智能体多能干,最终合并代码的决定权在我手里。它产出的是候选方案,不是最终答案。
第六,记录失败案例。每次它翻车,我都会简单记一下:什么任务、什么原因、怎么解决的。积累下来,就是一份“这个仓库里智能体容易踩的坑”清单,下次写任务描述时直接参考。
8. 这件事往后会怎么走
从补全到持续执行,这个方向基本是确定的。工具会越来越能“自己干活”,人的角色会越来越偏向“定义问题”和“验收结果”。
但我不觉得这意味着程序员会消失。恰恰相反,能把问题定义清楚、能设计出好的验收标准、能快速判断方案好坏的人,会变得更值钱。因为当执行变得便宜,稀缺的就是判断力。
对个人来说,现在值得练的能力,我觉得是这几个:把模糊需求拆成清晰任务的能力、设计验收标准的能力、快速审查代码的能力、以及知道什么该交给机器什么该自己扛的判断力。这些能力,不管工具怎么变,都用得上。
至于工具本身,我的态度是:用,但别全信。把它当成一个能力不错、但需要明确指令和严格验收的远程同事。给它清晰的活,给它能验证的标准,然后认真审查它的产出。这样用下来,它是真的能帮你省时间;反过来,如果指望它自己“理解”你的意图然后完美交付,那大概率会失望。