AI渐进编程之十:如何给 Agent 一根胡萝卜?

AI渐进编程之十:如何给 Agent 一根胡萝卜?

前面几篇我们已经把project_map.mdcurrent_task.mdrevision_log.md讲清楚了。
这一篇继续往下,讲的是另一类同样重要的状态文件:

open_issues.md

它的作用很直接:
把现在暂时不能解决、但又不能忘掉的问题,保存成可追踪、可恢复、可继续处理的项目状态。


1. 为什么还需要open_issues.md

在真实的程序项目里,AI 经常会碰到一些问题:

  • 现在改不了,但以后必须改
  • 现在没有足够证据,不能直接下结论
  • 现在任务范围不包含,但它会影响后续判断
  • 现在可以先放着,但不能装作不存在

比如:

  • 某个接口的重构方向还没定
  • 某个历史兼容行为还没确认要不要保留
  • 某个测试失败了,但根因还不清楚
  • 某个依赖升级会影响多个模块,但这轮不该一起改

如果没有open_issues.md,这些问题就很容易被塞进当前任务里,最后变成:

  • 任务变重
  • 边界变乱
  • AI 开始乱猜
  • 下一轮也不知道该怎么继续

所以本书把这类问题单独放到open_issues.md
它不是“问题堆积页”,而是受控延期


2. 记录问题,是一种受控延期

open_issues.md解决的,不是“现在立刻把所有问题都解决掉”,
而是:

让任务可以先停在一个清晰边界内,把不确定性单独记录下来,后面再处理。

这很重要,因为 AI 在程序项目里最怕两种情况:

第一种,不确定性被直接忽略

比如:

  • 测试失败了,但还没确定根因
  • 兼容性风险还没确认
  • 某个边界行为还没定义

如果系统假装这些问题不存在,它就会在不完整的信息上继续推进,最后容易出错。

第二种,不确定性被塞进当前任务

比如:

  • 当前只该修一个函数
  • 但模型顺手把相关模块、测试、文档一起改了
  • 因为它觉得“顺便统一一下”更好

这就会把一个明确任务,变成一堆混杂目标。

所以,open_issues.md的作用就是:
把不该在当前轮解决的问题,先放进一个可管理的地方。


3. 什么样的问题该进open_issues.md

不是所有问题都要放进去。
本书对收录边界的判断比较明确:

3.1 当前任务可以直接修复的小错误

这种不用放进open_issues.md
直接修掉并验证就行。

3.2 缺少观察依据的想象风险

如果只是“感觉可能有问题”,但没有证据,
就不能直接当成确定问题。
要么先收集证据,要么先建立观察。

3.3 已经关闭的问题

如果问题已经解决,就应该记录解决证据并归档,
而不是继续留在开放问题里。

3.4 纯粹偏好的备忘

如果只是“我希望以后也许改一下”,
那更适合放到设计记录或候选想法列表,
不一定适合进入open_issues.md

所以,open_issues.md不是“什么都往里塞”,
而是只收录那些:

  • 重要
  • 暂时不能解决
  • 但会影响下一轮判断的问题

4. 一个好的问题条目应该长什么样?

本书不喜欢模糊的问题描述。
比如:

  • “这里可能有点问题”
  • “需要更多引用”
  • “以后再说”

这些都太弱了。
它们不能帮助下一轮继续推进。

一个可执行的问题条目,应该尽量包含:

  • 问题位置
  • 问题类型
  • 观察到的现象
  • 影响是什么
  • 需要什么证据
  • 是否需要人类决策

弱条目

- 需要更多测试。

这类条目太抽象,下一轮看到也不知道该怎么处理。
强条目

- Location: checkout/service.py - Type: coverage gap - Observation: empty-cart path is not covered by regression tests - Impact: may hide a checkout edge-case failure - Needed: add test for empty-cart checkout - Status: open

这种条目就比较完整。
它不是为了“写得长”,而是为了让下一轮知道:

  • 问题在哪里
  • 为什么重要
  • 现在不能怎么处理
  • 后面该怎么接

5.open_issues.md和其他状态文件的关系

这一点要和前面几章连起来看。

project_map.md

放长期稳定的项目认知。

current_task.md

放当前这一轮具体要做什么。

revision_log.md

放为什么这么改、改了什么、验证如何。

open_issues.md

放暂时不能解决,但不能忘掉的问题。

它们不是重复,而是分层:

  • project_map.md管“项目认知”
  • current_task.md管“当前任务”
  • revision_log.md管“修改原因”
  • open_issues.md管“未决问题”

所以open_issues.md的位置很明确:
它不是主任务,也不是历史记录,
而是专门收纳那些当前不能解决、但未来必须处理的问题。

6. 为什么开放问题不能一直堆着?

如果open_issues.md不整理,它也会变成负担。

问题一:问题越来越多

如果所有小事都往里塞,最后它会变成一堆看不动的杂项。

问题二:问题不分级

如果没有优先级,下一轮也不知道该先解决哪个。

问题三:长期不关闭

如果已经解决的问题还留在里面,open_issues.md就会失去可信度。

所以开放问题也要管理生命周期。
它不是永久黑洞,
而是一个可关闭、可归档的待办状态。

7.open_issues.md的生命周期

可以把它理解成这样一个流程:

  • 发现不确定性
  • 判断当前不能直接解决
  • 写入开放问题
  • 标记影响和所需证据
  • 后续任务单独处理
  • 解决后记录证据并归档

这和前面讲的revision_log.md很像,
但重点不同:

  • revision_log.md记录已经发生的修改和原因
  • open_issues.md记录还没解决、但不能丢掉的问题

前者偏“已完成”,
后者偏“待处理”。

8. 程序项目里的开放问题

在程序项目里,open_issues.md特别有用。

比如当前任务是修复一个结算问题,
但在修改过程中发现:

  • 老接口和新接口有兼容差异
  • 某些测试仍然没覆盖到边界条件
  • 某个依赖升级可能会影响其他模块
  • 某些行为需要先确认是保留还是弃用

这些问题不一定要在当前轮一起解决。
如果强行都塞进去,就会把一个清晰任务搞乱。

更好的做法是:

  • 当前轮只完成主要修复
  • 发现的问题写入open_issues.md
  • 下一轮再单独处理

这样,当前任务不会被拖垮,
但真正重要的问题也不会丢。

9. 本章小结

这一章想讲清楚的核心是:

open_issues.md不是问题垃圾桶,而是把暂时不能解决、但又不能忘掉的问题,保存成可继续推进的状态。

它的价值在于:

  • 让当前任务保持边界
  • 让不确定性有地方安放
  • 让下一轮能基于已记录问题继续做
  • 让系统不会因为“现在解决不了”就假装没看到

这也就是为什么本书要把开放问题单独分出来:
因为一个好的 AI 编程系统,不只是会做任务,
还要会把没做完的事情放在正确的位置。

下一章,我会继续讲:为什么程序项目比文字任务更适合先讲验收,以及为什么代码的边界、测试和 diff 可以更直接地变成控制条件。