有了 LLM,为什么文档还是错的?Amendary 如何做文档维护
We have LLMs now. Why are the docs still wrong?
针对代码变更后文档仍长期出错的问题,开发者正在构建 Amendary:连接 GitHub 与 Notion 或 GitHub 上的文档,选定要监控的页面并映射到对应仓库,再依据代码变更或指定的发布信号检查文档。发现可支撑的不一致时,它会附上来源起草修正,供人在审核队列中确认后再应用。
你改了一个默认值,合并了 PR,然后继续做下一件事。测试通过了。甚至还有人记得更新 README。一周后,另一个人照着 Notion 里的设置指南操作,问为什么应用的行为不一样。wiki 里还有另一个页面说的也略有不同。哪个才是对的?
这正是我想花时间解决的那类文档问题。我们已经有工具能在几秒钟内写出一整篇指南,但上周二变得不正确的那句话仍然留在那里。而且在有人依赖它之前,它看起来完全合理。
写第一版现在容易多了
给 LLM 一些代码,让它解释某个服务是如何工作的。你可以得到一个有用的起点:安装步骤、配置选项、对某个没人愿意写文档的函数的解释。你仍然需要检查它,但跨过空白页这一步容易多了。
所以很自然地会问,为什么代码一变我们就不能照做一遍。把 diff 交给 agent,让它更新文档,然后让它开一个 PR。如果相关文档在同一个仓库里,而且任务清晰,这会是一个有用的工作流。我不会否定它。
但它应该更新哪些文档?README、部署 runbook、Notion 里的客户指南,还是全部?提这个要求的人甚至还记得所有这些页面的存在吗?生成段落的质量很重要,但在到达那个段落之前还有相当多的工作要做。
一次代码变更,多个不同的读者
举个简单的例子。超时从 30 秒改成 60 秒。代码很清楚,diff 很小,改文档里的一个数字听起来够简单了。
工程参考文档可能需要在变更落地的同时就更新这个新默认值。客户指南可能需要等到发布。runbook 可能描述了一个仍然为 30 秒的显式覆盖值,完全不应该改。历史事故报告大概应该保留事故期间为真的那个值。
现在想象一下让 agent 找出每一处提到 30 秒的地方并修正。它可能会给出一组非常有说服力的修改。你仍然得弄清楚哪些说法变得不正确了,哪些一直说的是别的东西,哪些本就应该描述过去。
这就是为什么我认为文档和代码之间的关系如此重要。谁读这个页面?它描述的是哪个仓库?它解释的是默认分支上的内容,还是客户已经收到的内容?没有这些上下文,哪怕是一个小小的修正也可能是错误的修正。
索引给你的是候选,不是答案
你可以把文档放进向量索引,检索与代码变更最接近的片段。这听起来是减少发送给模型的文本量的合理方法。但一个关于超时的片段与 diff 相似,并不意味着它的说法是错的。它可能描述的是另一个服务、一个显式覆盖值,或者一个仍在支持的旧版本。
文本搜索也有它自己的问题。客户页面可能说导出会在一分钟内完成,而被改动的函数叫 build_customer_archive。搜索函数名找不到那句话。搜索每一处提到导出的地方可能会返回半个帮助中心。仍然需要某个人,或者某个模型,来决定哪种关系才重要。
然后是时效性。如果你的索引里仍然包含昨天版本的页面,你可能会针对别人已经修复过的文本起草一份更正。你需要在写作前检索当前源文件,检查你打算替换的段落是否仍然存在,并且要有办法处理冲突的编辑。否则,你可能推理正确,却仍然覆盖了错误的内容。
我认为,当我们把检索当作一种寻找值得检查之处的方式时,它才是有用的。证据必须来自实际的变更和当前文档。相似度分数无法替代这种检查。
仍然需要有人来核对答案
还有另一个我觉得容易被低估的环节:审查结果。一个 agent 可能返回三段润色过的文字,而你原本只期望一个数字发生变化。它们读起来很通顺。但它们也可能引入一个并不存在的配置选项,删除一个有用的例外,或者把未来的行为描述得好像已经发布了一样。
我不想花二十分钟把重写后的页面与代码仓库逐一比对,来判断它是否可信。我想看到旧段落、建议的更正,以及支持这一更正的变更。如果只有一个说法变得不准确,那么小改动要容易推理得多。
即便是 diff 也需要一些谨慎。改动的一行可能位于测试夹具中,而不是实现中。一个新的默认值可能只在某个特定标志启用时才生效。如果我们过于激进地削减上下文,模型看到的就只是数字在变化,而没有它周围的条件。发送更多上下文会有帮助,但也会给模型更多无关的东西去解释。没有什么单一的提示词能让这些选择消失。
而有时候正确的做法就是不编辑。一次重构可能触及大量文件,却没有改变任何读者需要知道的内容。如果每一次代码变更都产生文档工作,我们就又制造了一个人们最终会不再关注的队列。
Amendary 在其中扮演的角色
我正围绕这项维护工作构建 Amendary。你连接 GitHub 以及你的文档已经所在的地方,比如 Notion 或 GitHub。你选择要监视的页面,并将它们映射到它们所描述的代码仓库。这个选择很重要:连接一个目标不应该意味着每个页面突然都变成 agent 可以重写的东西。
Amendary 会根据代码变更或你为面向客户的页面选择的发布信号,检查已映射的文档。当它发现一个有依据的不匹配时,它会起草一份更正,并附上来源。你可以在应用之前,在审查队列中检查它。对于 GitHub 文件夹目标,你可以让文档变更通过一个由你合并的拉取请求来交付。
模型当然是其中的一部分。它有助于理解某个变更是否影响某个段落,以及如何表达更正。但映射、证据、审查,以及把变更送回正确的文档,这些也都需要正常运作。仅仅生成一个好句子并不能完成这项工作。
它仍然需要一个负责人
我很想说,你连接 Amendary 之后就再也不用考虑文档了。我不认为那会是一个诚实的承诺。
一个页面可能被映射到错误的仓库。一次发布可能解释得太少。产品决策背后的原因可能只存在于一次对话中,而不在代码里。模型可能遗漏某些东西,或者提出一个需要更多上下文的更正。自动化检查无法告诉你客户需要理解的一切。
在付费方案中,所有者可以为符合条件的更正启用自动申请。这可以减少日常工作量,但不会把不确定的变更变成事实。有些编辑仍然需要审核。而且如果你使用 GitHub PR 作为目标,仍然需要有人先合并文档 PR,目标分支才会发生变化。
准确和有用之间也有区别。一份指南可能所有数字都正确,却仍然让人无法照着做。它可能完美解释了实现方式,却从未回答读者真正的问题。团队里仍然需要有人在意这一点。
我希望不再做的事
我希望更少出现有人不得不在 Slack 里问某个页面是否仍然正确的情况。我希望审核更正的人无需重新做一遍完整的调查,就能理解它为什么存在。我还希望产品中的一个小改动,在需要时能带来文档中一个小的、可解释的改动。
LLM 对此有帮助。Amendary 是我的一次尝试,把这种帮助放进一个随产品变化而运行的工作流中,并对读取和编辑的内容划定边界。两者都没有消除决定我们希望文档说什么的需要。
对我来说,这已经是一个有用的目标了。少花时间寻找过时的句子,多花时间确保解释真正能帮助下一个读到它的人。
来源:Hacker News · amendary.com