AI 编码工作流:停止重复劳动的系统方法

原文:https://dev.to/sizzlebop/the-ai-coding-workflow-that-finally-stopped-making-me-repeat-myself-8ol(作者 @sizzlebop)

我经常使用 AI 编码代理。有一段时间,最烦人的部分与它们能否编写代码无关。而是每次新会话都感觉像在和一个技术上读过项目但对之前发生的事情一无所知的人合作。

代码能告诉代理很多东西。它可以看到结构、检查函数、追踪数据流、读取 package.json,并弄清楚应用程序做什么。但它通常无法看到代码周围的一切。为什么我选择这种方法而不是那种?我已经试过那个库了吗?这段看起来奇怪的代码是故意的吗?另一个代理已经花了两个小时调试这个确切的问题了吗?我是否在三次会话前特别说过我不想添加那个抽象?这些信息倾向于在会话之间消失,除非你有意给它一个存储的地方。

所以随着时间的推移,我围绕这个问题构建了一个小系统。因为它对我非常有效,我清理了它,移除了任何项目特定的内容,制作了一些虚构示例,并将整个东西放入一个可重用的仓库。

它始于 AGENTS.md

我已经有一个 AGENTS.md 文件,包含常见的项目规则。比如:

  • 不要触碰无关代码
  • 优先使用最简单的解决方案
  • 不要默默做出架构决策
  • 保留工作提示和逻辑,除非它们确实需要更改
  • 不要在每次小编辑后运行大型测试套件
  • 除非我要求,否则不要提交、推送、部署或删除东西

基本上,所有我厌倦了重复的东西。这帮助很大。但最终我意识到我试图让 AGENTS.md 做太多工作。这里有区别:

我希望你如何工作。

和:

这个项目为什么以这种方式工作。

以及这两者与:

我们已经尝试过这个。它失败了。请不要让我们再次学习这个教训。

之间的区别。所以我把它们分开了。

四个文件

系统最终有四个 Markdown 文件,每个回答不同的问题。

  • AGENTS.md:代理在这里工作时应如何行为?
  • OVERVIEW.md:项目现在如何工作?
  • MEMORY.md:它为什么这样构建,我们拒绝了哪些替代方案?
  • ERRORS.md:什么已经失败,什么替代方案有效?

AGENTS.md 留在根目录。其他三个位于 /DOCS。这种分离结果比我预期的要重要得多。

OVERVIEW.md 是项目当前的状态

OVERVIEW.md 基本上是技术地图。它可以包含如下内容:

  • 技术栈
  • 重要目录
  • 主要应用流程
  • 数据模型
  • 路由
  • API
  • 认证行为
  • 测试命令
  • 部署说明
  • 当前限制

重要部分是它描述了现在。它不是开发日记。如果项目停止使用一个数据库并开始使用另一个,我不会追加:

更新:我们不再这样做。

我更改文档以反映当前真实情况。这给代理一个起点,在它开始浏览代码库并试图从头重建整个应用程序之前。

MEMORY.md 用于决策

这对我更有用的地方。MEMORY.md 不是所有发生事情的列表。它专门用于决策,否则推理可能会消失。例如:

我们在进行元数据提取之前保存记录,因为用户的主要操作应该成功,即使远程站点超时。

然后我可以记录被拒绝的替代方案及其原因。这样未来的代理不会看那个流程并决定:

嗯,这似乎反了。我来清理一下。

它知道这个顺序是故意的。这就是代码通常无法给你的上下文。我使用的一个好测试是:

一个称职的开发者以后看这段代码,是否会因为不知道我们为什么选择它而合理地改回去?

如果是,它可能属于 MEMORY.md。如果只是:

添加了设置页面。

那是一个日志条目。它不需要记忆。

ERRORS.md 用于痛苦的东西

这个可能是不言自明的。但我不想让它变成错误跟踪器。正常的 bug 会发生。你发现它们,修复它们,继续前进。ERRORS.md 用于那些花费足够时间,我真的不想下一个代理重复整个冒险的情况。比如:

  • 一个 API 行为与预期不同
  • 测试失败由共享状态引起,而不是被测试的功能
  • 一个只适用于一个连接的配置细节
  • 一个需要多次尝试才能理解的依赖不兼容性
  • 一些极其愚蠢的边缘情况,只有在最终弄清楚后才看起来明显

条目记录:

  • 什么不起作用
  • 什么替代方案有效
  • 值得记住的教训

然后下次类似情况发生时,代理可以在从零开始之前检查那个。

真正重要的部分其实是那些没有被记录下来的内容

一开始,面对这样的系统,显然很容易产生记录一切的诱惑。

但这会彻底毁掉它。

如果 MEMORY.md 变成了变更日志,没人会想去读它。

如果 ERRORS.md 变成了 Markdown 格式的 Jira,有用的故障排查经验就会淹没在成百上千条无聊的 Bug 报告里。

如果 OVERVIEW.md 变成了每一次架构变更的流水记录,你将不再清楚哪些部分描述的是当前的应用状态。

因此,我最终为添加内容设定了相当高的标准。

对于 OVERVIEW.md

这次变更是否导致文档中的某些内容变得不正确或不完整?

对于 MEMORY.md

这里是否存在一个真正的决策,而其他人将来可能会在不了解原因的情况下合理地推翻它?

对于 ERRORS.md

这次失败是否足够痛苦或出乎意料,以至于有人可能会浪费大量时间重新发现它?

如果不是,就不添加任何内容。

这可能是整个系统更重要的部分之一。

上下文只在内容量保持合理时才有用。

为什么不用把所有东西都塞进 AGENTS.md?

我尝试过那种巨型指令文件的方向。

我并不喜欢它。

AGENTS.md 通常是每次会话上下文的一部分,无论其内容是否全部相关。

如果它包含了每个项目决策、每条调试经验、每个架构细节、每条写作规则、每个发布流程,以及我六个月积累的所有零散偏好,它就会变成一堵巨大的指令墙,与实际任务形成竞争。

它还混合了行为模式不同的信息。

行为规则相当稳定。

架构会变化。

决策历史会增长。

调试历史则以完全不同的方式增长。

所以现在,AGENTS.md 主要告诉代理去哪里看以及如何行事,而不是试图包含整个项目大脑。

然后我添加了技能

这部分让系统感觉更加完整。

我创建了一个 project-context 技能,用来教代理如何使用这些文件,而不是依赖代理去猜测。

它涵盖的内容包括:

  • 每个文件应在何时被读取
  • 如何搜索大型 MEMORY.md 文件,而不是将全部 700 行内容转储到上下文中
  • 如果文档与代码不一致时该怎么做
  • 如何处理与先前记录的决策相冲突的请求
  • 什么情况有资格创建新条目
  • 什么内容绝对不应该被记录

我特别喜欢的一条规则是:

代码是描述实际发生情况的权威。文档是描述设计意图的权威。

如果两者不一致,这就是有用的信息。

代理不应盲目信任过时的文档,但也不应假设当前代码就代表了预期的设计。

如果我要求做一件 MEMORY.md 中说我们已经拒绝过的事情,代理不应只是拒绝执行。

原因是有时效的。

但它应该告诉我:

我们之前因 X 原因拒绝过这个变更。你仍然想更改它吗?

这样,推翻决策就是有意为之,而非意外。

我还为写作创建了另一个技能

这部分与上下文系统略有分离,但它符合我使用编码代理的方式。

我有一个 clear-writing 技能,用于处理文档、README、安装说明、错误消息、发布说明和其他项目写作。

一直困扰我的一件事是,代理对所有内容都采用相同的写作风格。

安装指南应该清晰得乏味。

README 的开头不应该听起来像波音维护手册。

所以这个技能首先会判断写作类型。

指令性写作对句子结构、术语和歧义有更严格的规则。

而那些需要有明确风格的写作则有不同的规则,以免它变成那种典型流畅但怪异的 AI 文本。

这对于上下文系统本身并非必需,但由于我将两者结合使用,就包含了它。

现在的工作流大致如下

在代理更改现有项目之前:

  1. 阅读相关的项目文档。
  2. 使用 OVERVIEW.md 理解当前系统。
  3. 检查 MEMORY.md 中与待更改事项相关的决策。
  4. 如果任务涉及调试或以前出过问题的区域,检查 ERRORS.md
  5. 查看实际实现代码。

然后执行工作。

之后:

  1. 如果 OVERVIEW.md 中的任何内容变得不真实,就修正它。
  2. 只有在做出真正的决策时,才在 MEMORY.md 中添加内容。
  3. 只有在失败确实值得记住时,才在 ERRORS.md 中添加内容。
  4. 否则,就保持它们原样。

基本上就是:

更改前先阅读,学习后再记录。

这并非某个庞大的 AI 记忆系统

没有向量数据库。

没有嵌入。

没有后台记忆代理。

没有独立服务。

根本没有数据库。

它就是 Markdown 文件。

这正是其要点所在。

我以前构建过 RAG 系统和记忆层,那些绝对有其用途。

但解决这个问题,我并不需要那些东西。

我只需要重要的项目知识能够存活超过一个编码会话。

纯文本文件可搜索、可编辑、受版本控制、易于人类阅读,也易于编码代理使用。

这就足够了。

我把它做成了一个可复用的仓库

GitHub 仓库 agent-context-kit

一旦我意识到自己有多么依赖这套配置,我就觉得它可能对其他人也有用。

所以我制作了一个通用的 AGENTS.md 版本,移除了我的个人项目规则,并为支持文档创建了模板。

我还虚构了一个名为 Lantern 的项目,并填写了 OVERVIEW.mdMEMORY.mdERRORS.md 的示例版本。

这似乎比给人们三个完全空白的文件,然后说:

好了,现在去记录你的架构吧。

要有用得多。

这些示例展示了这些文件在项目实际运行一段时间后可以是什么样子。

这个仓库也包含了这两个技能(skill)及其模板/参考材料。

我绝不是说每个人都需要这套配置

你可能只想要 MEMORY.md

你可能已经有架构文档,只想要调试日志。

你可能讨厌我的文件夹结构。

你可能使用完全不同的智能体(Agent)工作流。

这些都没问题。

我认为有用的部分是分离:

行为(behavior)

当前状态(current state)

决策(decisions)

失败记录(failures)

一旦我不再把所有这些都当作一大块"上下文"(context),我的编码会话就明显不那么重复了。

智能体不再建议一些之前被否决过的想法。

我不必再重新解释那么多架构决策。

而且,当某个棘手的问题已经被调试过一次后,终于有一个有用的地方可以存放这些知识了。

最主要的是,我构建这个是因为我厌倦了重复自己。

事实证明,Markdown 在记忆方面相当出色。

我觉得这比另一个"智能体记忆"MCP 服务器或数据库有用得多。

我很想听听你的想法,以及你是否有改进它的建议。

原文:https://dev.to/sizzlebop/the-ai-coding-workflow-that-finally-stopped-making-me-repeat-myself-8ol(作者 @sizzlebop)

发布评论
全部评论(0)