优化文档
处理一个文档,生成一个对项目没有历史背景的读者能够直接使用的版本:无遗留、基于事实、简洁、组织有序,并为声明的读者量身定制。
四个固定顺序的步骤,后跟一个验证关卡。所有被移除的内容都会写入一个记录文件,因此错误的判断是可以恢复的。
调用
refine-document <路径> [--target=agent|human] [--no-record]
| 标志 | 默认值 | 效果 |
|---|---|---|
--target | agent | 最后一步针对哪个读者进行优化。会改变文档本身,而不仅仅是语气——参见步骤 4。 |
--no-record | 关闭 | 跳过记录文件。移除的内容将不可恢复,除非通过版本控制。 |
在触碰文件之前:
- 确认请求中指定了该文档。 此操作将原地重写用户的文件。
- 确认该文件已被版本控制跟踪且工作区干净。 如果不是,请说明情况并获得明确的许可——在
--no-record模式下,这是唯一的恢复路径。 - 在第一条消息中声明您正在使用的目标,包括使用默认值时。静默使用默认值会导致文档为错误的读者定制。
- 多文档: 对每个文档运行一次此过程,每个文档使用一个子代理(如果子代理可用),并向每个子代理传递相同的目标与标志。一个子代理负责一个文件。
输出
| 输出 | 路径 | 内容 |
|---|---|---|
| 优化后的文档 | 原始路径,原地替换 | 仅包含当前状态,且面向目标读者 |
| 记录文件 | 同一目录下的 {name}.changelog.md | 被移除的所有内容,逐字记录并定位——每次运行都会追加 |
| 报告 | 您的回复 | 参见报告 |
步骤顺序
按以下顺序运行这四个步骤,作为对文档的四次独立读取。每一步都会缩减输入,为下一步提供更小的内容;如果顺序混乱,它们会互相抵消——在步骤1将要删除的内容上先进行压缩是徒劳的,而在压缩之前先组织内容会组织填充物。
- 清除遗留——移除所有仅作为对过去引用才有意义的内容。
- 基于事实——每个存留的主张都必须经过验证、引用或标记。
- 简洁——每个事实只出现一次,并以保留事实的最短形式呈现。
- 组织——关键信息优先,然后根据目标读者进行塑形。
步骤 1 —— 清除遗留
必要的子技能: 此步骤使用 strip-legacy-content。它拥有遗留分类法、删除不重写规则以及本技能也写入的 {name}.changelog.md 格式。将 --no-record 映射到该技能的 --no-changelog。
如果该子技能不可用,请移除:历史与演化叙述、决策记录和 ADR、弃用通知、迁移和升级指南、内嵌的变更日志和发布说明、向后兼容章节、被否决的备选方案、带有日期的评论、已废弃的章节。直接删除这些段落;不要重写剩余的散文——步骤 2-4 会处理。
已弃用功能规则。 被标记为已弃用的功能不自动视为遗留内容。应用以下测试,并记录您采取的分支:
该功能是否有“支持旧系统”之外的用途?
- 否——它仅用于向后兼容。移除该功能及其通知。
- 是——这是当前行为。保留它,删除移除时间线和“自v1起”的框架,并在记录文件中标记。
步骤 2 —— 基于事实
文档中的每个断言都是一个主张,包括继承而来的。对每个主张进行分类并采取相应措施。没有第五种选项。
| 类别 | 信号 | 操作 |
|---|---|---|
| 可验证,工件可访问 | 行为、标志、默认值、路径、命令、配置键,并且您可以阅读代码、配置或 --help | 验证它。正确:保留。错误:修正它。 |
| 可验证,工件不可访问 | 相同的主张,但没有可对照验证的仓库、二进制文件或文档 | 完全按照源声明保留该主张,不标记,并在报告中列为未验证。 |
| 需要外部来源 | 标准、协议行为、第三方产品行为、版本支持 | 在其后内联引用主要来源及其日期或版本。无可接受的来源:删除该主张。 |
| 对比或推广性质 | “10倍更快”、“同类最佳”、“极速”、“优雅”、“大多数工程师同意”,以及任何比较对象不属于当前系统的比较(“比Kafka更轻量”) | 删除,除非存在可引用的度量标准——然后陈述该度量标准及其来源。保留事实本身:“使用 Redis Streams 对作业进行排队”。 |
| 不可验证且危险 | 读者可能据此执行不可逆操作(数据丢失、花费、凭证、破坏性命令、安全边界)的未验证主张 | 保留它,在文档中标记为 [unverified],并在报告中列出。 |
标记用于危险情况,而非来源追溯。 关于一个您无法访问的工件的文档大多包含未验证的主张,如果每个都标记,会教会读者跳过这个标记。未验证的来源追溯应属于报告和记录文件;文档中的 [unverified] 保留给那些失败后读者无法撤销的主张。如果文档中存活的标记超过几个,说明您将来源追溯误分类为危险——请重新分类。
切勿编造源文档中没有的事实。 不是配置位置、不是默认值、不是文件格式、不是先决条件——甚至不是那些几乎肯定正确的事实。一个被断言为确定事实的推论与已验证的事实无法区分,而此步骤是防止读者得到错误答案的唯一防线。如果原始来源没有说明,那么优化后的文档也应当保持沉默。
切勿将无来源的主张模糊化。 将“大约快10倍”重写为“非常快”是带有更少精度的相同观点。要么引用它,要么删除它。
切勿因缺乏来源而删除操作指令。 标记优于删除:被标记的指令可以由知情者检查,而被删除的则消失无踪。
对于主张大多涉及外部来源的文档,在继续之前请使用 cite-or-refuse 进行来源验证,并使用 fact-check-document 进行全面主张审核。
步骤 3 —— 简洁
每个事实只出现一次,固定在一个位置。 对于每个事实,选择读者最先会到达的单独章节。在那里完整地陈述它。在其他任何地方,要么删除重复的陈述,要么用指向该章节的指针替换。
直接删除:
- 填充性开头:“值得注意的是”、“简单来说”、“基本上”、“正如你所见”。
- 指示读者做他们正在做的事情:“要安装,请运行安装命令”。
- 作为句子开头的重复章节标题。
- 不改变任何行动的防御性免责声明。
- 演示与之前示例相同内容的示例。
压缩:
- 超过三个项目且跨两个以上属性进行比较 → 使用表格。
- 列出并列项目的段落 → 使用列表。
- 主语是名词化的句子 → 使用动词(“做出决定” → “决定”)。
压缩下限。 当移除下一个词会移除一个事实时停止。一个丢失了事实的更短文档是退步,而不是胜利。词数是工作的症状,绝不是目标。
唯一一个有条件允许的重复 是针对代理目标的头部和尾部对关键块的重复,仅在超过步骤4设定的长度阈值时。低于该阈值,它就是像其他任何重复一样,必须删除。
步骤 4 —— 为声明的读者组织内容
共同原则:排序法则
按阻碍读者的因素排序,而非按主题的历史顺序:
- 这是什么 —— 一句话,没有前奏。
- 阻碍所有其他操作的先决条件 —— 没有它什么都无法启动的环境变量、凭据、所需版本。
- 破坏性和不可逆操作 —— 任何删除、覆盖、花费金钱或无法撤销的操作。这是根据后果而非主题进行放置:即使命令很晦涩,它也应靠近顶部,并且需要标记,而不仅仅是提及。
- 主流程 —— 大多数读者前来的目的,从头到尾。
- 其他所有内容,最常用的优先。
- 边缘情况、故障排除和参考表格 放在最后。
当文档大约有超过五个章节时,顶部应包含一个摘要块;它列出读者在开始任何操作前需要知道的事实,而不是散文的提要。
--target=agent
读者是一个将文档作为上下文加载的模型,通常是在grep一个术语后只读取匹配的片段。生成具有以下形状的文档:
- 始终先放置关键块;仅在长度超过约100行时在末尾重复完全相同的块。 无论长度如何,先决条件、破坏性操作和硬约束始终放在最前面。上下文中部丢失现象 (Liu et al., TACL 2024) 是在数千到数万token的多文档上下文中度量的——一个短到可以一次读完的文档不具有那种“中部”,因此尾部副本只是纯粹的重复,没有检索收益。只有当文档长度超过约100行(即符合需要目录列表#9的条件)时,才进行重复,因为在这种长度下,一个通过grep并读取片段的阅读者可能会落在文档中间而错过该块。低于阈值时,只声明一次,在顶部,就此打住——在那里放第二个副本是步骤3应该已经捕获的退步,而不是此目标的一个特性。当需要重复时:将第一个副本标题设为
## 关键约束,最后一个副本标题设为## 关键约束(重复)——两个唯一的锚点,一个相同的内容体,这是文档可能包含的唯一一个近乎重复的标题。 - 正面措辞。 陈述要采取的行动。当确实需要禁止时,在同一句话中给出正面的替代方案:“写入
state/,而不是/tmp”。模型处理否定陈述的能力明显低于肯定陈述。 - 一个标题,一个可检索的单元。 文档中的每个标题都是唯一的、字面的,并由AI代理会grep的词语组成——除了上述的关键块对。其章节应能独立存在:没有“如上所述”,没有指向另一章节的代词。
- 在使用点使用文字标识符。 完整路径、精确命令行、精确的环境变量名、精确的文件名——每次都使用,而不是一次之后通过引用。
- 可验证的陈述优于叙述。 一个命令、一个路径、一个值、一个退出条件。如果一个句子无法验证,它很可能是解释——仅当它能改变代理的行为时才保留。
- 仅使用 Markdown 结构 —— 标题、列表、围栏代码块、小表格。不要向 Markdown 文档添加 XML 标记方案;将 JSON 或 YAML 块保留给真正是机器可读数据的內容。
- 保留每个事实的最短形式。 输入长度本身就会降低检索性能,并且主题相关但无用的内容会作为干扰因素——近似匹配的散文比没有更糟。
- 无矛盾。 两个相互矛盾的陈述比没有更糟糕。在写作之前解决它们。
- 仅在长度超过约100行时提供目录列表,因为代理可能读取一个切片而非整个文件,否则无法看到范围。
验收标准: 一个代理如果grep一个标题并只读取该章节,能正确操作。
--target=human
读者在阅读之前会先扫描,且只阅读少数文字。当格式没有提供线索时,这种扫描会退化为沿左边缘的F形扫视——结构是防止这种情况的方法,而不是模仿它的方法。生成具有以下形状的文档:
- 文档和每个章节的第一句话就点明要点。 最重要的内容放在前两个段落;就此停下的读者已经得到了他们想要的东西。
- 前置加载的行。 每个标题、列表项和段落都以承载信息的词语开头——行的前两个词会被阅读,其余部分则被扫视。
- 描述性标题:“配置状态目录”,永远不要用“概述”、“备注”、“细节”或“第3节”。
- 一个段落一个想法,最多大约四句话。
- 客观的语言。 中立措辞在可用性方面明显优于推广措辞;这是一个理解上的结果,而非风格偏好。
- 比较用表格,推理用散文。 超过三个项目且跨两个以上属性 → 表格。有联系、因果或细微差别的解释保持散文形式——将论点碎片化为项目符号会丢失联系。
- 保留领域词汇。 在第一次使用时内联定义一次术语。不要简化技术精确性,也不要为了达到可读性公式得分而重写——那些分数无法识别组织结构,并会惩罚正确的术语。
- 在内容超过大约两屏或五个章节时提供目录列表。
验收标准: 读者仅使用该文档就能完成文档所描述的任务。
目标之间必须不同的内容
| 决策 | --target=human | --target=agent |
|---|---|---|
| 关键约束 | 一次,在第一屏,标记 | 低于约100行:一次在顶部;超出时:顶部 和 末尾逐字重复 |
| 章节独立性 | 章节可以建立在前面章节之上 | 每个章节自包含 |
| 交叉引用 | “见上文”可以 | 指明确切的标题 |
| 标题 | 描述性和可读性 | 唯一、文字化、面向 grep |
| 禁止 | “不要做X”可以 | “做Y”承担了禁止的含义 |
| 标识符 | 引入一次后缩短 | 每次都完整且文字化 |
| 理由解释 | 散文保留因果联系 | 仅当它能改变行动时才保留 |
| 目录列表 | 超过约2屏 | 超过约100行 |
| 长度 | 约为原文的一半 | 保留每个事实的最短形式 |
分歧检查——必需。 在写入文件之前,请命名此次运行中因声明目标而做出的至少三个不同决策,并将它们放入报告中。