§1 / 问题:AI 写完代码,你其实不知道它好不好
用 AI 写代码有个很反直觉的地方:它写得越快,你越不知道它写得对不对。
Cursor 跑完一次,你会得到修改过的文件、一次 diff、你点了 accept 或 reject。这个流程解决了"我看到结果了"的问题,但没有解决"这次比上次好还是差"的问题。
积累几十次之后,你对自己这套 AI coding 工作流的认知其实是:感觉还不错。但感觉这东西不准。
更具体地说,有两个问题靠感觉解决不了:
跨 run 比不了。 同一个 feature,让 AI 跑两次,出来的文件大概率不一样。你没有办法判断这次是不是比上次更好。可能是模型随机性,可能是 prompt 写法有影响,也可能是你项目里的命名约定 AI 这次记住了下次忘了。没有任何客观信号。
不知道它在哪摔过跟头。 AI 在项目里犯过的错,下次还会再犯。比如它第一次幻觉了一个 import { useAuth } from 'next-auth/client'(这个导出不存在),你手动修好了。但下一次跑类似的功能,它大概率会再犯,因为没有持久化的机制告诉它"这条路走不通"。
这两件事本质上是同一个问题:流水线缺少质量记忆。
§2 / 解法 A:Harness 自评分,零额外 LLM 调用
我的方案是每次 run 跑完算一个 0-10 的分数,叫 Harness Score。
4 个维度加权:
| 维度 | 权重 | 怎么算 |
|---|---|---|
| Spec Compliance | 30% | Spec(md) 里的验收条件 vs 实际输出的 diff |
| DSL Coverage | 25% | DSL(json) 里的 models/endpoints 有多少被实现了 |
| Compile/Lint | 20% | tsc --noEmit 的退出码 |
| 3-pass Review | 25% | LLM 评审,给出通过/需修改/不通过 |
除了 Review 那个 25% 需要 LLM 参与(本来就要人审或者调 LLM 审),其它三个维度全是机械计算的。没有任何额外的 LLM 调用,没有"用更强的模型打分"这种循环论证。
分数还和 prompt hash 绑定:相同 prompt 多次跑可以横比,分数涨了就是好了,跌了就是有问题。这才是重点——不是要替代人审,是给"质量趋势"一个量化入口。
Harness Score 8.4 / 10
compliance 8.6 · coverage 9.2 · compile 10 · review 7.1
7.1 的 review 分拉低了总分,说明那 25% 的内容 LLM 觉得有问题。要么是 spec 里写得不够清楚导致实现跑偏,要么是代码本身有逻辑问题。这个信号在裸眼 review 的时候很容易漏掉——你看着文件觉得还行,但 LLM 作为第三方读的时候能指出哪里不合规。
为什么没用"再调一个 LLM 当裁判"?
这个方向我试过,有两个问题:
- 循环论证:让模型 A 生成,让模型 B 评分,然后根据 B 的反馈改 A——本质上你在训练一个模型裁判,但这个裁判本身没有 ground truth。评分高了不代表代码真的好,只代表模型 B 和模型 A 看法一致。
- 贵:每次 run 额外调一次 LLM 做评分,对于高频使用的场景(我每天可能跑 5-10 次)是一笔不小的开销。
Harness 的定位是温度计,不是裁判。温度计不需要被训练,它只需要读数准确。
§3 / 解法 B:Fix-history,把"此路不通"持久化
第二个设计是 Fix-history,解决的是"AI 重复踩同一个坑"的问题。
原理很简单:
每次 AI 写出的 import 被自动修复过(找不到文件 / 没有那个导出),就把这次失败追加到一个 append-only 的 ledger 文件 .ai-spec-fix-history.json。
下一次 codegen 之前,把这个 ledger 渲染成一段 prompt 注入:
=== Prior Hallucinations in This Project (DO NOT REPEAT) ===
❌ Do NOT: import { useAuth } from 'next-auth/client'
Reason: named export did not exist (seen 3x, last 2026-04-08)
Previously fixed by rewriting the import path
注入逻辑本身只有几十行:一个把 ledger 渲染成 prompt 段落的函数。ledger 持久化大概 300 行。整体上没用 RAG、没微调、没 vector DB。
为什么是这个方案而不是 RAG?
RAG 的思路是"把你的 codebase 向量化,query 时检索相关上下文"。这个方案很优雅,对"找相似模式"这类需求也确实有效。但对"幻觉"这个具体问题,RAG 有两个缺陷:
- overhead 高:你需要 embedding model、需要 vector DB、需要在每次写文件前做检索。对于"防止重复犯同一个错"这个极具体的需求,投入的架构太大了。
- 覆盖不了这类错误:RAG 擅长找到"相似的正确代码",但它不擅长记住"这条路走不通"。一个 append-only 的 ledger 反而更直接——我只记录失败,不记录成功。
Fix-history 的覆盖面比 RAG 窄,但它对"已经犯过的错不再犯"这个具体问题覆盖率够用。
§4 / 两个设计的局限性
说清楚不打算解决什么:
Harness 不是银弹。 它测的是"实现和 Spec 的吻合度",不是"代码的 runtime 正确性"。一个 spec compliance 9.0 的项目,如果有逻辑 bug,Harness 不会帮你发现——这部分还是靠测试和人审。Harness 的价值是把"我这次跑完觉得还行"变成一个可记录的量化数字。
Fix-history 只防已知错误。 它只记录"已经犯过的错",对新错误没有预防能力。如果 AI 第一次在某个文件里犯了一个新错,Fix-history 无效,必须等它犯过一次才能记入 ledger。这是一个 append-only 的记忆系统,不是推理引擎。
适用场景:8-15 个文件的 feature 级任务,用一句话描述清楚需求,能接受流水线跑完再 review 一次。如果你在做的是探索式开发、函数级单步调试、或者需求还没想清楚要边写边改——ai-spec 不适合,Cursor 更合适。
§5 / 现在的状态
913 个测试,支持 9 个 provider(DeepSeek/Qwen/GLM 国内可直接用,Claude/Gemini 需代理),MIT。
GitHub: github.com/hzhongzhong…
npm: npm install -g ai-spec-dev
站点: ai-spec.dev
流水线现在是这样的:
$ ai-spec create "给 user 模块加登录功能"
✔ Spec generated .ai-spec/specs/user-login.md
✔ DSL validated .ai-spec/dsl/user-login.json
✔ data src/models/User.ts src/models/Session.ts
✔ service src/services/AuthService.ts
✔ api src/api/auth.ts
✔ test src/tests/auth.spec.ts
3-pass review ✔
Harness Score 8.4 / 10
11 files written · restore: ai-spec restore 20260408-143022-a7f2
你不需要相信它会完美——它每次都会给你一个分数,这个分数会告诉你它在哪里摔过、以及这次是不是比上次好。这是我认为流水线应该提供的基本承诺。