ARTICLE · 1221363
让开发文档成为可追溯的Agent记忆
今年 AI 圈最火的一个词一定是 Harness 。
基于 Harness 工程理念打造的 Agent,例如:codex、claude code、deepseek harness 已经让大众真实的感受到了 AI 的"魔力"。
我相信在众多对 Harness 的科普中你一定已经对它是什么有了深入的了解,但我很少看到有人讲:它对普通使用者意味着什么。
大多数人会认为,不开发 Agent、不训练模型,Harness 跟自己没什么关系。在我看来这是个挺大的误解,因为只要你使用AI,你每天和 AI Agent 打交道的那个工作区(Workspace),本身就是 Harness 的一部分。
大家应该都见过这个公式:
Agent = Model + Harness
我想再拆一层,来分解 Harness :
Harness = 记忆 + 边界 + 组合
• 记忆:提供“项目目标 + 已知事实 + 当前状态 + 关键历史”,让系统在多步过程中保持一致性与可追溯性 • 边界:规定“允许的动作/权限范围/安全与成本限制”,以及“触发人工确认或必须停止的条件” • 组合:把工具与步骤按流程编排成可执行的工作流,支持模块化替换、失败重试与降级
如今,模型的能力已经非常强大,大厂开发的各种 Agent 也提供了开箱即用的编排与工具能力。在这种情况下,记忆的管理往往更容易被忽略,但它不仅是影响最终产出质量的重要因素,并且是普通使用者最能主动掌控的一环。在同一套模型与 Agent 下,谁提供了更关键、更完整、且被正确带入后续步骤的“记忆”,谁就更容易得到稳定高质量的结果。
回看 Agent 工程的演进,从提示词、上下文压缩,到 Skill,再到 Harness,它们解决的问题并不完全相同,但始终绕不开的核心就是解决“记忆”的问题:如何让 Agent 在有限的上下文里,知道该知道的事,记住该遵循的规则,并在持续工作中不偏离目标。
这篇文章想要讲的就是普通使用者该如何优化Agent的“记忆”。
记忆不在模型里
首先要理解,模型的每一次调用都是全新的。它本身没有记忆,它能"记得",是因为 Harness 体系要求在每次开工前,把"记忆"作为一段上下文重新喂给了它。
这段上下文有两部分:
• 短的那部分:这次对话刚才说了什么,跑到第几步 • 长的那部分:这个项目是什么、规矩是什么、之前踩过什么坑
短的那部分,由开箱即用的 Agent 自己管理。而长的那部分,来自你的工作区。
你放在工作区里的一切:README、架构说明、设计记录、踩坑笔记、AGENTS.md,或者你不写代码那么要处理的文件和表格——只要 Agent 读得到,它们都会变成模型这一次开工时的"长期记忆"。
只有"可追溯"的东西才算记忆
看到这里你可能会想到一个问题:如果模型读到的是"坏"文档呢?
散落的、互相矛盾的、三年前的、没人维护的文档,喂给模型,它只会更自信地犯错。
更别说一个项目持续使用 AI 辅助开发后,很容易积累数百份文档:需求、实现计划、任务清单、修复分析、评审、二次评审、验证记录,以及临时讨论。它们通常有真实价值,却不一定构成可靠的"记忆"。
某个功能在旧版本目录里有初版方案,在另一个版本目录里有重构计划,最新结论藏在评审修复记录中。旧文档可能同时写着"草案"和"功能已移除"。人需要回忆当时发生了什么,Agent 则可能把最容易搜索到的文件当成当前要求。
我发现问题出在文档之间的"关系"没有建立起来。 谁是谁的前置,谁在哪个版本里推翻了谁,哪一份是不可违背的设计决策,这些关系都没有作为文件的属性被记录下来。
所以我们需要一套规则来建立和维护这些文档的关系,并且通过 Skill 让 Agent 在合适的场景自动去维护、更新这些记忆。
在我的开发实践中,我总结出了这样一套体系。我把需要维护的关系确定为 4 种:有效性、归属、替代关系和证据。
| 归属 | ||
| 有效性 | ||
| 证据 | ||
| 替代关系 |
这样的项目记忆保存在仓库里。它不依赖某个会话保留全部历史,也不等同于让模型永久记住项目。每次工作开始时,Agent 都能重新加载足够小、足够明确的上下文,并沿链接追溯依据。
换句话说,可追溯不是“文档写得好”,而是让这四种关系成为文件本身能查到的属性:打开一份文档,就该能看出它属于哪里、还算不算数、凭什么成立、被谁取代过。
接下来我们聊聊具体的做法,怎么把这些属性真的写进文件,并且让 Agent 在每次开发里替你维护。
一、六类文档作为“关系”的落点
建立“关系”的第一步,是给文档分类,给它们一个“身份”作为关系和管理的落点,其次不同类型的文档,"有效"的定义也根本不同。
在我看来开发文档至少要回答六类不同的问题。
最重要的边界是"当前规范"和"某次变更的 spec"。
• 前者是持续维护的产品契约; • 后者记录当时的改变目标。
不能要求后续读者从所有历史 spec 中自行合成当前规则。
同时,代码事实和产品要求也不是同一件事。实现与已批准要求不一致,可能是 Bug。应记录偏差,而不是为了让文档与代码相符,悄悄把需求改成现有行为。
二、当前知识按「领域」组织,开发过程按「变更」组织
一种适合长期维护的中大型规模仓库的结构如下:

小项目可以只保留一个规范文件、一个架构文件和变更记录;没有独立平台发布就不必拆发布目录。
这里有两个注意点:
• 不建议把版本号作为开发材料的主要归属。一个变更可能延期,也可能分平台发布;如果它的身份绑定版本目录,延期就会导致搬家、断链或多份副本。版本更适合作为引用变更的发布视图。 • 也不必把 features、bugs、reviews、fixes 拆成彼此隔绝的顶层仓库。一次功能交付里的评审与修复应留在同一个变更中。独立审计可以单独建档,再关联它产生的修复事项。技术债同样是一种待处理变更,不需要另建第二套待办状态。
三、让事项身份稳定,让状态诚实
每个变更有一个稳定 ID,例如 CHG-2026-001。ID 不随发布延期或完成状态改变,已经分配的 ID 不再复用。多人(多worktree)并行开发合并代码时唯一ID也可以帮助Agent快速定位文档冲突。
当然也可以直接使用已有 Issue ID;顺序编号并不是唯一选择。
这个体系中最重要的是动手新建一条变更记录之前,让Agent先搜一遍。
例如,新建的是 docs/changes/2026/CHG-2026-NNN-<slug>/README.md。那么搜索就是在 docs/changes/、docs/specs/、docs/decisions/ 里 grep 相关的关键词并查看和维护变更的“摘要” docs/changes/index.md。
变更具体 changes 的 README 只维护必要的元数据:

状态词表必须有明确语义。
以我开发中的实际情况为例:可以从 proposed、planned、in-progress、blocked、done、cancelled 开始;历史迁移确有需要时再加入 unknown 和 superseded。
几个容易混淆的边界:
• done 表示约定范围内完成验收,不代表已经发布。 • unknown 表示历史证据不足,不是"看起来应该做完了"。 • 已经交付的方案后来被替代,原变更仍然完成;旧规范可以标记废弃并指向新规范。 • 未完成方案被另一方案取代,才适合使用 superseded,并给出替代关系。
四、架构文档
架构文档需要分层:
1. 摘要:系统边界、跨领域不变量、阅读入口。它帮助 Agent 判断接下来该读什么。 2. 详细合约:当前有效的所有权、数据流、并发边界、失败处理和平台差异。修改对应领域时读取。 3. 历史证据:旧方案、实施经过、当时的验证结果。需要解释过去时读取。
总体架构文件保留模块模块划分、依赖方向和跨域关系,领域文件维护具体合约。产品规范描述外部可观察行为,避免复制整套内部实现细节。
“摘要”的要点是:帮助选择阅读范围。把长文删到很短,并不自动得到好的摘要。把二十多个标题合成八个标题,也不会降低实际阅读成本。
五、引用应该跟随语义,而不是章节序号
具体文档中的章节号是展示顺序,不适合成为长期地址。一次更新导致内容重排后,全仓的"见 §9.3"都可能失效。
更稳定的引用形态是文件路径与语义锚点,例如 architecture/editor.md#editor-document-ownership。可以用英文 slug 标题作为稳定标识,在其后补中文解释;具体渲染行为要在实际工具中验证。
整理旧引用时,先建立对照:旧文档与位置、原规则、目标文件与锚点、处置说明。需要验证的是原规则是否有去向,而不是新文件里一共有多少条目。
当前文档、Agent 指令和代码注释中的有效引用应更新。历史记录通常保留当时语境,通过映射解释旧位置。确需修复历史链接时,只修引用,并记录原因,不顺手改写当时的结论。
六、项目记忆需要证据
这里的关键认知是:"类型名还能搜到"和"规则仍然成立"之间有明显距离。
在实践中我认为有以下几个要点:
1. 记录证据时,优先给出 commit、文件与符号,以及必要的测试或复现步骤。 2. 行号可以辅助定位,但单独的行号会随着修改漂移。 3. 尚未核验的部分明确标注,不能因为整份文件移进了 architecture 目录,就宣称其中所有断言已经核验。
另外,不必每次都重审整个知识库。应优先核验高风险领域和本次实际修改的规则,逐步扩大覆盖。对大规模历史文档,这是比一次性补齐所有证据更可持续的做法。
七、用脚本检查规则的执行情况
规范写得再清楚,没人照着做也等于没写。而"照着做"这件事,Agent和人都可能疏忽。所以我们通过脚本来检查规范的执行情况。
这类脚本只查四类东西,全是机械判定:
status: donesupersedes 指向不存在的 ID | |
[规范](../Documentation-Guide.md) | |
这些规则的共同点是:对错不需要判断,只需要比对。 字段在不在、值在不在词表里、 文件在不在、链接打不打得开。
它输出的是退出码而不是报告:0 没问题,1 有问题,2 参数错。所以挂进任何脚本或者 CI 都行。
还有一个很实用的机制叫基线:把已知的旧问题记在文件里,之后只对新增的问题报错。这样你不用为了启用它,先花两周修完所有历史欠账。
脚本检查的局限
脚本检查最容易给人的错觉,是它绿了你会以为文档没问题。
在真实的开发中,我遇到过4种在最开始的设计的脚本检查中漏掉的问题:
• 模糊匹配掩盖断链。 按文件名辅助搜索对代码风格里的定位提示有用,但真正的 Markdown 链接必须按它的解析语义走。文件所在目录没有 README,而仓库根目录恰好有个同名文件,不代表这个链接能打开。 • 示例标题不是真实锚点。 直接用正则扫所有井号标题,围栏代码块里的示例也会 "通过"锚点检查。 • 按数量冻结债务会漏报替换。 同一个文件修掉一条旧断链、同时新增一条,错误总数不变,但问题变多了。 • 索引和交接也会过期。 某个优化已经完成,README 的交接区却还写着未开始。这种矛盾对 Agent 伤害最大,因为交接区往往是他最先读的东西。
所以在使用脚本检查时要有意识到:它是回归护栏,不是质量证明。并且也需要查漏补缺持续迭代。
八、AGENTS.md、Skill、治理规范各司其职
这里需要警惕的是三种载体最容易被写成三份重复的规则。
治理规范 docs/Documentation-Guide.md是你项目自己的规范。例如,目录结构、文件命名、状态词表、完成条件的定义、检查命令、阅读预算。当然它也不是必须的,如果小型项目可以在AGENTS.md、docs的readme中直接定义这些规则。
Skill 则回答"如何执行新建、继续、评审、迁移和收尾"。
写 Skill 时有两条容易被忽略的约束:
• 不要假设目标项目已经有某个文件名、目录、标识符或检查器。 先读它现有的 AGENTS.md和文档入口,再沿用既有约定。• Skill 应引用现有规范,按当前任务加载相关记录,调用仓库里真实存在的检查命令。 它不应复制全部架构。 • 它不应把所有内容都强制扩展成五份文档。小事项一份 README 足够;复杂事项再拆 spec、plan、tasks、verification。流程的价值来自减少遗漏,而不是增加填写量。
九、验收成果
最后,当你搭建好这套体系后,最重要的是设计场景验证这些规范是否能被Agent自动的执行和遵守。同时在持续的开发中和你的Agent交流持续完善属于你项目的真实细节。
用一次普通开发检验整个体系
假设我现在要修复富文本编辑器撤销错误。你应该看到:
1. Agent 先从文档入口找到当前编辑器规范与架构合约,再搜索相关历史变更。已有进行中的同一事项就继续维护,否则建立新的变更记录。 2. 修复过程中,计划和任务说明准备做什么,验证记录说明实际测试了什么。 3. 结束时,更新当前合约中的受影响规则;若没有改变系统边界,就不往架构摘要追加实现经过。留下一个短交接快照,链接实际证据和未解决事项。
一次任务之后,新建一次Agent对话,再修改同一需求的细节,这一轮对话中Agent应能迅速回答:现在的规则是什么,为什么改过,代码在哪里,验证到了哪里。
这四个问题,本质上就是 Agent 每次开工时要去回答的四个问题。 它们比目录数量、文章行数或文档总量更适合作为治理成效的判断依据。
改动边界检验
这张表总结的是各种“改动”操作的边界:什么该做,什么可以不做。
写在最后
回到开头那个问题:Harness 跟普通使用者有什么关系?
关系在于,你可能改变不了模型的智力,也可能没得选 Agent 用哪套工具。但在 Harness 的记忆方面,工作区里放什么、怎么放,是你说了算。你把它当垃圾场,它就是垃圾场;你把它整理成一份可追溯的知识库,Harness 每一次开工,都能准确的拿到需要的信息。
所以让开发文档可追溯,从来不是"给团队看"的规范问题,也不是为了让目录看起来整齐。
你是在给 Agent 装记忆。
One More Thing:三个开箱即用的Skill
我把文章介绍的这套经验整理成了三个开箱即用的 Skill,开源在了我的github,点击「阅读原文」即可跳转:
jade-maintain-dev-docs | ||
jade-design-maintained-project-docs | ||
jade-design-lightweight-project-docs |















































































