一个AI编程代理说功能做完了,测试全绿,解释听起来也合理。这时候有人问了一句:如果我把那个请求再跑一遍,会发生什么?
这个问题能改变一个项目的形状。它逼着"做完"必须变成可观察的东西,答案需要一次实验,而实验需要一种能被证伪的方式。
有人围绕这个思路搭了一个极小的任务清单应用。最终你会得到一个能跑的程序、两个故意做坏的版本,以及一个装满证据的文件夹,用来展示每个版本到底守住了哪些承诺。
什么叫证据驱动开发
这套工作习惯被称作证据驱动开发:写下一条主张,决定什么结果能推翻它,跑对应的实验,让结果决定下一步。
编程代理可以在每一步帮忙,但证据必须保持可检查,不能只信代理的总结。
这个名字不是新造的。Jan Bosch 在2017年的书《Speed, Data, and Ecosystems》里就有"证据驱动开发"一章,内容把需求、假设和实验连在一起。这里只是把这个词用在一套代理辅助的实操流程上,并不声称发明了什么方法论。
AI领域也有相关工作。Xia 等人描述过"评估驱动开发与运维"(EDDOps),把它当作面向大模型代理的持续反馈回路。那篇论文覆盖的代理生命周期,比这个小应用要宽得多。
TDD 依然提供有用的红-绿-重构循环,BDD 帮助用可讨论的例子表达行为。在这套流程里,证据驱动开发指的是把主张、执行条件、观察到的结果和由此产生的决定连在一起的那份纪律。
一个小应用,一条真承诺
这个应用叫 Tiny Tasks,功能就是添加任务和列出任务。Python 加 SQLite 就够了,应用和实验运行器只用 Python 标准库,需要 Python 3.10 或更新版本并带 SQLite 支持。
配套仓库里有完整源码、封面图和记录下来的证据。克隆下来就能跟着做:
- 仓库名:copyleftdev / evidence-driven-development
- 定位:一个可运行的证据驱动开发教程,包含可证伪的主张、SQLite 重试、负对照和可复现结果
- 依赖:不需要应用依赖、API密钥、模型账号、网络服务或云资源
跑起来的命令很直接:先添加一条任务,再添加一次同样的任务,然后列出任务,跑单元测试,最后跑证据脚本。
第二次创建会返回原来那条任务,并带上 created: false。要真正新建一个动作,得换一个新的请求ID。标题在比较前会先去掉首尾空白。默认数据文件是 .local/tasks.sqlite,可以用 --db PATH 指定别的文件,位置放在 add 或 list 子命令之前。冲突的请求复用和非法输入会返回错误。
仓库里还固定了一个源码版本,checkout 到那个提交,就能复现文章里用的代码。add 命令返回一条任务,list 命令会启动一个新进程再把它读回来。
请求ID属于用户想做的那个动作。调用方重试同一个动作时,发的是同一个ID。真正的新任务会拿到新ID,哪怕标题碰巧一样。这个小小的区分,给出了一个值得去证明的东西。
先写一条会输的主张
"让任务清单可靠"这种说法留的解读空间太大。所以在动手实现之前,先写了一份实验契约。
仓库把那些主张记在 experiments/001-reliable-tasks/experiment.json 里,同时声明了三轮重启、八个并发重试进程、两次独立重复,以及必须真正执行到的场景。
这些数字只是教学用的小工作量,不是统计意义上的可靠性估计,也不是吞吐量目标。
在向代理要代码之前,先给它这样一份任务:
- 搭一个本地任务清单,能添加和列出任务。
- 先提出可观察的主张,以及能推翻它们的结果。
- 让已确认的任务能跨新进程保留。
- 把每个创建请求ID绑定到一个规范化标题和一条任务上。
- 演练并发重试和冲突复用。
- 保持应用足够小,只用本地合成数据。
- 不要声称实验没有演练到的性质。
主张要自己审。一个代理如果把"能扛住中断"悄悄缩窄成"在同一个对象里能跑两次",就可能为一个错误承诺写出漂亮的测试。
给代理一个留下证据的地方
这个项目有几个各司其职的小文档:
- AGENTS.md:工作规则和命令
- docs/plan.md:任务进度和交接
- docs/decisions.md:决定及其理由
- experiments/001-reliable-tasks/experiment.json:写代码之前定下的主张
- README.md:发现和局限
- runs//:实际输出和源码哈希
AGENTS.md 告诉代理这些东西放在哪。实验文件定义主张。运行目录记录实际发生了什么。决定文档解释我们因此选了什么。
热门跟贴