上一篇我讨论了一个常见误区:让 Codex 一次改完 8 个文件,生成代码可能更快,验收却往往更慢。

问题并不只在于文件多,而在于多个变化同时发生以后,我很难回答三个问题:

  • 当前错误是从哪一步引入的?

  • 这一步到底完成了没有?

  • 下一步继续修改,会不会把一个未经验证的假设扩散到更多文件?

所以,遇到跨组件、状态管理、接口层和类型定义的任务时,我不会只给 Codex 一张“待修改文件清单”。文件清单只能说明修改范围,不能约束执行过程。

我更关心的是:先改什么,改到什么程度算完成,用什么证据证明可以进入下一步,以及出现什么情况必须停下来重新判断。

一个可执行的计划,不是把需求换成编号列表

下面这种计划看起来很清楚,其实对控制多文件修改帮助不大:

  1. 修改类型定义。

  2. 修改接口请求。

  3. 修改状态管理。

  4. 修改表单组件。

  5. 修改页面。

  6. 运行测试。

它只描述了动作,没有描述边界。

例如“修改状态管理”可能只需要增加一个字段,也可能顺手改变加载、缓存和错误处理逻辑;“修改页面”可能只是接入新组件,也可能把原有交互一起重构。只要完成标准不明确,Codex 就很容易把一个步骤理解成一组可以自由扩展的工作。

我现在会把计划写成四部分:

依赖顺序 + 本步目标 + 完成证据 + 暂停条件

这四部分缺一项,计划都可能停留在“任务说明”层面,还不能真正用来控制执行。

检查点一:先固定基线和影响范围

多文件修改开始前,我先要求 Codex 回答:当前行为是什么,调用链经过哪里,哪些行为不能被改变。

这一阶段不是马上写代码,而是建立后续验收使用的基线。至少应确认:

  • 用户从哪个入口触发功能;

  • 页面、组件、状态和请求层之间怎样传递数据;

  • 哪些文件是直接修改对象,哪些只是调用方;

  • 项目现有的类型检查、测试、构建或代码检查怎样运行;

  • 本次需求明确不处理什么。

这里的完成证据,可以是一个简短的影响范围表,而不是代码:

位置 当前职责 本次是否修改 验收方式
类型定义 描述请求与响应结构 类型检查通过
请求层 组装参数并调用接口 请求参数可核对
状态层 管理页面共享状态 视需求而定 状态流检查或测试
表单组件 收集并校验输入 交互路径验证
页面容器 连接表单与提交动作 页面行为验证

如果实际调用关系与需求描述不一致,或者必须修改计划外的公共模块,我会让 Codex 先暂停。此时继续生成代码,只会建立在错误的影响范围上。

OpenAI 的 Codex 代码库理解用例也强调,正式修改前应先识别相关模块、状态流和潜在风险。对我来说,这一步的价值不是“多分析一会儿”,而是避免把猜测直接变成跨文件改动。

检查点二:先确定契约,再修改调用方

前端多文件任务中,最容易向外扩散的通常是契约:

  • TypeScript 类型;

  • 组件的 props 和 emits;

  • 接口的请求参数与返回结构;

  • 状态模块对外暴露的方法;

  • 表单字段与校验结果。

如果调用方和提供方同时修改,最终即使类型检查通过,我也未必知道它们是否一起偏离了原需求。因此我通常先让 Codex完成最小契约修改,再单独检查兼容性。

这一检查点要回答:

  1. 新增或修改了哪一个公开约定?

  2. 原有调用方是否仍然可用?

  3. 是否为了方便实现,擅自把可选字段改成必填,或者改变了默认值?

  4. 契约变化是否迫使任务扩展到计划外文件?

完成证据可以是类型检查、针对契约的单元测试,或者一份明确的新旧结构对比。只说“相关文件已修改”不算完成。

如果契约仍存在歧义,我宁可停在这里,也不会让不确定性继续进入状态层和页面层。

检查点三:单独打通状态和数据流

契约确定以后,我再处理数据怎样进入、保存、转换和提交。

这一阶段需要特别检查三个问题:

  • 状态是否仍然只有一个可信来源;

  • 页面字段到接口参数之间是否发生了隐式转换;

  • 加载、成功、失败和清理状态是否成对出现。

很多 AI 生成的前端代码,单看某个文件没有明显问题,组合起来却会出现“双份状态”:组件内部保存一份,状态模块再保存一份,页面容器还计算一份。正常路径可能暂时能用,一旦关闭重开、返回页面或请求失败,三份状态就开始不同步。

所以这个检查点的目标不是让界面先“动起来”,而是证明数据流本身闭合。可以优先使用已有测试、类型检查、请求参数断言,或者对关键状态转换进行人工核对。

如果需要新增第二个状态源,Codex 必须说明理由;如果原状态归属判断错误,则回到上一个检查点调整计划,而不是在组件中继续补同步代码。

检查点四:把页面接入当作一次独立集成

前面的契约与数据流通过以后,才进入页面和组件集成。

此时我给 Codex 的目标会很窄:只把已确认的数据能力接入现有交互,不顺手重构布局、命名、样式和无关组件。

这一阶段至少验证:

  • 正常路径能否从用户操作走到正确请求;

  • 表单值、页面显示和状态模块是否一致;

  • 保存、取消、关闭等原有行为是否仍然成立;

  • 原本不在需求内的页面区域是否保持不变。

我尤其会看完整操作路径,而不只看静态页面。一个按钮能显示出来,不代表它触发了正确的状态变化;一次请求成功,也不代表弹窗关闭后再次打开仍然正常。

如果接入页面时发现组件契约不够用,我不会允许 Codex 在页面里先绕过去。计划应退回契约检查点,明确修改原因,再重新向下执行。

检查点五:集中验证异常和生命周期

正常路径完成,不等于任务完成。

前端问题经常藏在生命周期和异常分支里,例如:

  • 连续点击导致重复提交;

  • 较早发出的请求晚返回,覆盖了新状态;

  • 请求失败后 loading 没有恢复;

  • 弹窗关闭后残留上一次数据;

  • 组件卸载后异步回调仍然更新状态;

  • 页面切换后缓存与界面不一致。

这些问题不适合等到所有代码完成以后一次性扫尾。因为一旦失败,我需要知道它属于状态设计、组件生命周期,还是页面接入问题。

我会把异常验证单独设为检查点,并让每个场景有可观察结果。例如:

场景 预期结果
快速重复点击提交 只产生允许的请求次数,按钮状态可恢复
请求失败 保留或恢复正确表单状态,并显示项目既有的错误反馈
关闭后重新打开 按需求重置或回显,不混入上一次临时状态
快速切换对象 旧请求结果不能覆盖当前对象

这里不能凭空假定项目一定存在某种测试工具。应优先复用仓库已有的测试和检查方式;没有自动化覆盖时,就把需要人工验证的操作和观察点写清楚。

检查点六:最后审查完整差异,而不是只看运行结果

前五个检查点解决“每一步是否可信”,最后一个检查点解决“组合以后是否仍然符合任务边界”。

我会让 Codex重新审查完整差异,并检查:

  • 是否出现计划外文件;

  • 是否夹带无关重构、格式化或依赖升级;

  • 临时日志、注释和兼容代码是否残留;

  • 原有行为是否被无意删除;

  • 类型检查、测试、构建等仓库现有检查是否通过;

  • 哪些结论已经验证,哪些仍需要人工确认。

这里有一个很重要的区别:检查命令通过,是交付证据的一部分,不是全部证据。

类型检查无法证明交互正确,构建成功无法证明请求竞态已经处理,正常路径通过也无法证明关闭重开没有残留。最终交付应把命令结果、差异审查和关键用户路径放在一起说明。

我会怎样把 6 个检查点写进计划

下面是一份可以直接复用的模板。它不是要求每次都写得很长,而是确保关键约束没有丢失。

# 任务目标
- 要解决的用户问题:
- 明确不处理的范围:
- 必须保持不变的行为:
​
# 已知信息与未知项
- 已确认:
- 尚未确认:
- 需要先检查的文件或调用关系:
​
# 影响范围
| 文件或模块 | 当前职责 | 预计修改 | 验收证据 |
| --- | --- | --- | --- |
​
# 执行检查点
​
## 1. 基线与影响范围
- 本步目标:
- 允许修改:不修改代码,先完成定位
- 完成证据:
- 暂停条件:实际调用链或范围与预期不一致
​
## 2. 契约
- 本步目标:
- 允许修改:类型、接口契约、组件公开接口
- 完成证据:
- 暂停条件:契约存在歧义或影响计划外调用方
​
## 3. 状态与数据流
- 本步目标:
- 允许修改:请求层、状态层、数据转换
- 完成证据:
- 暂停条件:出现新的状态源或隐式兼容逻辑
​
## 4. 页面集成
- 本步目标:
- 允许修改:目标页面和组件
- 完成证据:
- 暂停条件:需要绕过既定契约或重构无关区域
​
## 5. 异常与生命周期
- 本步目标:
- 需要验证的场景:
- 完成证据:
- 暂停条件:异常暴露出上游设计问题
​
## 6. 完整差异与回归
- 本步目标:
- 运行的仓库检查:
- 人工验证路径:
- 仍未验证的事项:
​
# 交付说明
- 实际修改范围:
- 验证结果:
- 已知限制:
- 建议后续工作:

模板里最关键的不是标题,而是每一步都有“完成证据”和“暂停条件”。

完成证据防止 Codex 只报告自己做过什么;暂停条件则防止它在发现需求与代码不一致时,擅自扩大范围继续完成一个看似完整的结果。

一个演示任务,怎样从文件清单变成执行计划

假设有这样一个演示需求:在已有编辑弹窗中增加一个字段,并随保存请求提交。这里仅用于说明计划方法,不代表我的真实项目经历。

如果只按文件列任务,可能会得到:修改类型、接口、状态、表单和页面。

换成检查点以后,计划会变成:

  1. 确认弹窗打开、回显、提交和关闭的现有数据流,记录不能改变的行为。

  2. 确认新字段的类型、是否必填、默认值和请求字段名;契约不明确则暂停。

  3. 修改请求参数映射及必要的状态转换,用类型检查或现有测试验证。

  4. 在表单中接入字段,再由页面走通一次正常的打开、编辑、保存路径。

  5. 验证取消、失败、关闭重开和快速切换对象时,新字段不会残留或错配。

  6. 审查完整差异,确认没有顺手重构其他表单字段,并执行仓库已有检查。

两份计划涉及的文件可能完全相同,但第二份更容易验收,也更容易在出错时定位原因。

计划变化时,必须显式重新规划

真实代码库很少完全符合最初设想。执行到一半发现新的调用方、新的公共类型,或者项目已有封装与需求描述不同,都很正常。

我不要求 Codex死守一份错误计划,但要求变化必须显式发生:

  1. 说明发现了什么新事实;

  2. 指出它影响哪个检查点;

  3. 列出需要新增或移除的文件;

  4. 补充相应的完成证据;

  5. 等计划调整后再继续修改。

这不是增加流程负担,而是在保护前面已经验证过的结论。最危险的情况不是计划发生变化,而是代码范围已经变化,计划和验收方式却还停在原地。

计划不是越细越好,而是每一步都能作出判断

过度详细的计划同样会失效。

如果把每个变量名、每一行代码都提前写死,Codex 在接触真实实现后没有调整空间;计划也很快变成一份过期说明书。我判断计划颗粒度是否合适,只看一件事:完成这一步以后,我能不能基于明确证据决定“继续、回退,还是重新规划”。

OpenAI 关于复杂问题迭代的官方用例建议,在任务前先定义评估方式,每次只做一个聚焦的改进,在有意义的变化后重新运行评估,并记录变化与结果。这和我控制多文件修改的思路是一致的:计划的价值不在于预测所有代码,而在于把每一步都变成可验证的小闭环。

写在最后

多文件前端任务真正需要控制的,不是文件数量,而是不确定性传播的距离。

我的 6 个检查点可以概括为:

  1. 先固定基线和影响范围;

  2. 先确定契约,再动调用方;

  3. 单独验证状态和数据流;

  4. 把页面接入作为独立集成;

  5. 集中检查异常与生命周期;

  6. 用完整差异和回归证据收尾。

这样做以后,Codex 不只是拿到一组待办事项,而是拿到了一条有边界、有证据、遇到异常会停下来的执行路径。

至此,第六天的两篇文章完成了从“为什么一次性生成会增加验收成本”到“怎样用计划控制多文件修改”的闭环。下一篇我会继续讨论:前端工作中,哪些任务适合交给 AI,哪些判断必须留在人手里;随后再把这些边界整理成第一版个人 AI 协作流程。本系列会持续更新。

参考资料

更多推荐