[控场AI]
· 11 分钟阅读· 5,579 字

AI写的README在说谎?证据优先文档流程

AI写的README在说谎?证据优先文档流程

用证据表、TODO 占位和声明账本,把 AI 写文档从流畅猜测变成可验证的工程流程。

AI 生成文档时最危险的失败模式不是明显错误,而是流畅的、貌似合理的猜测:虚构的 `npm start`、从未存在的 `--verbose`、编造的性能理由。文章指出,问题不在于模型不够聪明,而在于任务结构允许它填补空白。因此提出证据优先的五步流程:证据→大纲→草稿→验证→同步,核心原则是"可见的 TODO 胜过貌似合理的猜测"。配套给出两个提示词:第一个要求模型输出证据表、缺口清单和 RAN/UNVERIFIED 验证清单,在大纲阶段暂停等待批准;第二个把文档审计变成声明账本,双向检查过时声明和未记录变更,按读者危害排序。此外,Why 注释必须来自代码、工单或人,否则标记 TODO(why),这份清单往往是会话中最有价值的输出。

让 Cursor、Claude Code 或 ChatGPT "为这个仓库写一份 README",你会得到一个看起来完全像 README 的东西:功能列表、安装步骤、快速开始、使用示例。直到新同事照着快速开始操作,第二步就失败了——脚本叫 dev 而不是 start,文档里的 --verbose 参数从未存在过,让你复制的 .env.example 根本不在仓库里。

模型没有故障。它只是做了被要求的事:产出一份完整的文档。遇到信息缺口时,它用"这类项目通常有什么"来填充。流畅的行文让猜测看起来和事实一模一样。

AI生成文档的常见问题

为什么"给这个写文档"会出错

失败模式是可预测的:

  • 惯例填充:npm start、--config、DATABASE_URL、LOG_LEVEL——每一个都貌似合理,但任何一个都可能是错的。
  • 编造理由:要求解释"为什么",你会得到"为了避免限流""为了性能"这类没人真正给过的理由。下一个维护者会信以为真。
  • 未测试的命令:没人跑过的安装步骤,和有人跑过的看起来一模一样。
  • 自信的数字:默认值、限制、超时、支持版本——文档里被复制最多的部分,也是最容易编造的。
  • 一次性写作:即使一份完美的文档,也会在下次合并时开始漂移。

这些问题不需要更聪明的模型,需要一个让模型必须展示来源、让"我不知道"有地方可去的流程。

幻觉(Hallucination) 是大语言模型的固有特性:模型本质上是根据上文预测下一个最可能的 token,而非查询数据库。当遇到训练数据中反复共现的模式(如 README 里常见的 npm start),模型会以高置信度补全,而不管当前仓库是否真的如此。这与模型的"智商"关系不大,即使 GPT-4 级别的模型也无法从根本上消除。

这也是为什么文章强调的解法不是"换更强的模型",而是改变任务结构:把开放式写作变成受证据约束的填表作业。一旦要求模型为每条事实附上 文件:行号,预测空间就从"这类项目通常有什么"坍缩到"这个仓库里实际有什么",幻觉发生的概率随之大幅下降。这与 RAG(检索增强生成)的思路一脉相承,但粒度更细,直接落到行号级别。

另一个相关概念是模型的校准(Calibration):理想情况下,模型应当对不确定的内容给出低置信度的表达。但经过 RLHF 训练的对话模型往往被优化为"给出完整答案",导致流畅文本和事实文本在表面上无法区分,这正是文章开头"看起来完全像 README"的根本原因。

核心流程:证据 → 大纲 → 草稿 → 验证 → 同步

  1. 证据:在写任何文字之前,明确读者是谁、文档依赖哪些事实,每条事实附带来源(文件:行号、commit、PR、笔记)。证据没覆盖的内容变成问题。
  2. 大纲:章节映射到证据行。没有证据的章节直接砍掉或保留为可见的 TODO 占位。在这一步砍掉一个章节,成本为零。
  3. 草稿:受大纲约束的文本。命令从脚本复制,不做"改进"。未知内容写成 TODO: <问题>。
  4. 验证:在干净机器上运行复制粘贴路径。grep 每个标识符。检查每个数字和每个"因为"。
  5. 保持同步:每次发布前审计文档与代码的一致性,每次事故后更新运行手册。

如果只从这篇文章带走一条规则:可见的 TODO 胜过貌似合理的猜测。明确告诉模型这一点。模型被训练成"有帮助",而"有帮助"的默认行为就是填补空白。告诉它空白才是有帮助的答案,你得到的结果就会改变。

这里的"可见的 TODO"指的不是偷懒,而是一种显式的知识边界标记。传统文档之所以危险,是因为它把"已知"和"猜测"混在同一段文字里,读者无法区分。而 TODO 占位符强制把两者分离:读者看到 TODO 就知道此处需要向维护者确认,看到正文则可以信任。

这一原则与软件工程中的 fail-fast 理念相通:与其让错误静默传播到下游(新同事照着跑失败),不如在源头就暴露缺口。在实践中,TODO 还应附带一个具体问题(TODO: 这个参数默认值是 30 秒还是 3 分钟?),而不是笼统的 TODO: 补全,因为可回答的问题才可能被真正回答。

对模型而言,明确告知"空白才是有帮助的答案"是一种逆向激励。对话模型默认被训练成填补空白以显得有用,只有在 prompt 中显式重定义"有用"的含义,模型的行为才会转向。这也是本文所有提示词规则的共同底层逻辑:用规则对抗训练倾向。

免费提示词一:基于证据而非感觉写 README

这个提示词适用于 Cursor(用 @ 引用仓库)、Claude Code(可读文件),或 ChatGPT/Copilot Chat(粘贴文件树、清单和脚本)。

你是一位资深工程师,正在为此仓库撰写 README。你只写代码、配置和我给你的文件能够支持的内容。任何无法从证据中支持的内容都变成可见的 TODO,而不是猜测。

## 上下文
- 要读取的仓库/路径:{{REPO_PATHS}}
- 项目用途,用我的话描述(可能不完整):{{PROJECT_PURPOSE}}
- 谁读这份 README:{{AUDIENCE}}
- 我知道能跑通的命令,或"未知":{{KNOWN_COMMANDS}}

## 流程(先规划再写)
1. 证据扫描。读取清单文件、脚本(Makefile、package scripts、CI workflows)、入口点、配置和环境变量读取、LICENSE 和现有文档。记录每条依赖的事实及其来源文件:行号。
2. 缺口。列出读者需要但证据没告诉你的事。每个缺口变成 TODO,附带给维护者的问题。
3. 大纲。提出章节;每章注明使用的证据行。在此停止,等待我的批准。
4. 草稿。快速开始按干净克隆顺序:前置条件、安装、配置、运行、测试。命令严格从脚本复制。
5. 验证清单。README 中的每条命令、路径、环境变量和参数及其来源,标记 RAN(仅当你成功执行过)或 UNVERIFIED。

## 输出
### 证据表 | # | 事实 | 来源(文件:行号)| 使用章节 |
### 缺口与 TODO
### 提议大纲
### README.md(批准后)
### 验证清单 | 条目 | 来源 | RAN / UNVERIFIED |

## 规则
- 绝不编造代码中不存在的 API、CLI 参数、环境变量、配置键、命令、默认值或行为。未知内容标记为 TODO: <问题>。
- 不添加仓库未配置的徽章、注册表或 CI 服务。
- 无证据不使用"极速""生产就绪"等表述。
- 许可证行必须与 LICENSE 文件一致;如果没有,写 TODO。
- 短而正确胜过长而貌似合理。

三个部分起了主要作用:

  • 证据表:每个章节都必须指向证据行。没有 Dockerfile 的 Docker 章节没有东西可指。
  • 大纲后暂停:你审查的是十行结构,而不是三页文字。
  • RAN / UNVERIFIED:在聊天界面中,一切都是 UNVERIFIED,这是诚实的。你运行快速开始,然后翻转标签。

预期会有一些 TODO。一份从不完整材料写出的 README 如果零 TODO,那才是该被怀疑的。

免费提示词二:文档漂移审计

文档曾经是对的。但之后某个参数被改名、默认值变了、新的必需环境变量出现了。这个提示词把"文档看起来还行"变成一份可操作的账本。

你是一位细致的技术审查员,正在对照当前代码审计文档。你把文档中的每条具体陈述都视为待验证的声明。代码是真相来源;你绝不为了让文档正确而修改代码。


**文档漂移(Documentation Drift)** 是代码演化过程中文档与实现逐渐分叉的现象,它与代码腐化(Code Rot)同源但更难察觉,因为文档不会编译失败。漂移有两种方向:一是文档描述了已不存在的旧行为(forward drift),二是代码新增了面向用户但文档未提及的能力(backward drift)。多数团队只检查前者,而提示词二中的 UNDOCUMENTED 裁决正是为了覆盖后者——这类缺口往往更危险,因为用户根本不知道新功能存在。

审计的粒度选择也很关键:把"文档中的每条具体陈述"拆成可验证的原子声明(命令、参数、默认值、端口、限制),是让审计可机械化的前提。模糊的"介绍部分写得不清楚"无法验证,而"`--timeout` 默认值是 30 还是 60"可以被 `grep` 直接裁定。

最后,**代码是真相来源(source of truth)** 这一规则在智能体场景下尤其重要。一个有写权限的 agent 如果被告知"让文档正确",可能会反向修改代码或重新引入已删除的参数以匹配文档。明确写入"仅改文档、绝不改代码",是防止自动化工具好心办坏事的关键护栏。
## 上下文
- 要审计的文档:{{DOC_PATHS}}
- 用于验证的代码:{{CODE_PATHS}}
- 文档上次正确之后发生的变化(git log / diff --stat,或"未知"):{{CHANGE_SUMMARY}}
- 谁读这些文档、他们用文档做什么:{{READER}}

## 流程
1. 提取每条可检查的声明并赋予 ID:命令、CLI 参数、环境变量、配置键、默认值、端点、文件路径、函数名、版本、端口、限制、行为陈述("重试三次")。
2. 逐条对照代码验证:
   MATCH(引用行号)/ DRIFT(代码说 X,文档说 Y;都引用)/ MISSING-IN-CODE(列出搜索词)/ UNDOCUMENTED(代码中面向用户但无文档提及)/ UNVERIFIABLE(说明什么能定论)。
3. 按读者危害排序:HIGH = 复制粘贴失败、数据丢失、安全、错误限制;MEDIUM = 边缘情况错误;LOW = 措辞。每条裁决附加置信度。
4. 报告并停止。不要编辑任何内容。

## 输出
### 摘要(各裁决计数,前五项 HIGH 危害)
### 声明账本 | ID | 文档位置 | 声明 | 裁决 | 证据/搜索词 | 危害 | 置信度 |
### 未记录的面向用户变更
### 预防(1-3 条使用仓库已有工具的建议)

## 规则
- 绝不编造 API、参数、环境变量或行为。
- 如果文档描述了代码没有的行为,报告 DRIFT 并询问哪个正确。
- UNVERIFIABLE 是可接受的裁决。不要升级为 MATCH。
- 不确定的内容标记 TODO: verify <问题>。

两个细节很重要:

  • 双向检查:文档中的过时声明只是漂移的一半,另一半是没人写下来的新必需环境变量——这就是 UNDOCUMENTED 部分。
  • "代码是真相来源"是规则,不是感觉:没有这条,有写权限的智能体可能会"好心地"重新添加已删除的参数,让 README 再次正确。

在发布前对用户最先接触的文档运行它:README 快速开始、安装页、配置参考。粘贴发布的 git diff --stat 作为变更摘要,让模型知道漂移最可能在哪里。

Why 注释:拯救下一个维护者的规则

叙述代码的注释(# 遍历用户)是噪音。解释"为什么"的注释是黄金,也是模型编造最多的地方。修复方法是一个简单约束:

Why 注释必须来自代码本身、工单、提交信息或人。否则写 TODO(why): <问题>。

然后阅读模型产生的 TODO(why) 问题列表。这往往是整个会话最有价值的输出:一份精确列出某人离开后会消失的知识清单。粘贴到 PR 里,让作者回答。

10 分钟幻觉检查

合并任何 AI 写的文档之前:

  1. 提取每条命令、参数、环境变量、配置键、端点和文件路径。
  2. 在仓库中搜索每一条(git grep -n "<标识符>")。找不到的,在被证明无辜之前都有罪。
  3. 在干净环境中按顺序运行复制粘贴路径。
  4. 每个数字(默认值、限制、端口、版本)都需要来源行。
  5. 每个"因为"都需要来源。没有来源,就没有因为。

不要让 AI 单独写这些:安全或合规声明、SLA、许可证文本、事故披露或破坏性操作步骤。那里的每句话都由人负责。

有效的结构

部分目的
角色"资深工程师从证据出发写作"、"记录员"、"审计员"
输入路径、读者、真实源材料(代码、PR 正文、笔记)
流程先证据和大纲,后文字
输出契约带 Source 和 RAN / UNVERIFIED 列的表格
规则绝不编造;未知写 TODO;仅改文档;代码是真相来源

一个标题为"来源(文件:行号)"的列必须逐行填写,空白单元格以一种自信段落永远做不到的方式暴露出来。这就是全部诀窍。

拿一份你熟悉的文档试试:仅从代码用提示词一重新生成你自己的 README,或用提示词二审计它,检查它提出的每条声明和每个 TODO。

#AI文档生成#README最佳实践#提示词工程#文档漂移#代码文档一致性#AI编程工具#技术文档审计
分享:

相关推荐