{"componentChunkName":"component---src-templates-blog-post-jsx","path":"/git-knowledge-loop/","result":{"data":{"markdownRemark":{"id":"6f46b038-7f2d-54c3-957d-08f7e0bb9629","excerpt":"很久没有写博客了，距离我上一篇 正式的博客 已经过去了三年多，连 npm 都构建失败了。直到让 Claude 帮我修复后才得以发布这篇文章。 毫无疑问，这三年，尤其是 2025 年底 Opus 4.…","html":"<p>很久没有写博客了，距离我上一篇 <a href=\"https://mthli.xyz/gpt-limit/\" target=\"_blank\" rel=\"noopener noreferrer\">正式的博客</a> 已经过去了三年多，连 npm 都构建失败了。直到让 Claude 帮我修复后才得以发布这篇文章。</p>\n<p>毫无疑问，这三年，尤其是 2025 年底 Opus 4.5 发布以来，编程领域发生了翻天覆地的变化，我相信现在还在坚持手写业务代码的程序员应该是少数了。虽然我有时还是会手写一些，毕竟代码也是一种 prompt。</p>\n<p>在这个过程中，我们很自然地会面对一些问题。比如随着 AI 写代码的部分越来越多，我们人类对项目的掌控力度是在下降的；在项目初期，我们还能把控完整的上下文；但半年以后，我们基本改不动 AI 写的代码了。比如没有良好的索引，每次 AI 在检索代码库时都要消耗大量的 token；且不同模型的上下文窗口和能力不一致，你也不能指望每个模型从代码反推出的逻辑是一致的。比如同事问你这个功能是怎么实现的，你说不知道，直接问 AI…</p>\n<p>不论如何，以上问题都说明，我们需要一套良好的上下文管理系统，不论是用于提升 AI 编程的效率，还是辅助人类对项目的理解。于是我设计了一套基于 git 的最小化知识循环系统，这套系统不需要你安装任何多余的依赖，只需要引入以下三个 skills 即可很好地运行。</p>\n<h2>概览</h2>\n<p>首先这三个 skills 都是 Codex 版本，因为我目前就职的公司只能使用 Codex（即使我的个人项目使用的是 Claude）。不过这也正好说明了它们身经百战，见得多了，识得唔识得 🐸</p>\n<p>你总是可以在以下链接获取到最新的版本，你也可以让 AI 帮你改成你熟悉的 harness 版本：</p>\n<ul>\n<li><a href=\"https://github.com/mthli/skills/tree/codex/commit-context\" target=\"_blank\" rel=\"noopener noreferrer\">commit-context</a> - 提交当前 diff 并附上相关的对话上下文，以及决策（Decision）</li>\n<li><a href=\"https://github.com/mthli/skills/tree/codex/distill-module\" target=\"_blank\" rel=\"noopener noreferrer\">distill-module</a> - 将 Git Decision 记录蒸馏到 <code class=\"language-text\">.codex/decisions/&lt;id&gt;.md</code></li>\n<li><a href=\"https://github.com/mthli/skills/tree/codex/map-module\" target=\"_blank\" rel=\"noopener noreferrer\">map-module</a> -  用 subagent 研究 + 对抗性验证，产出核实过的 <code class=\"language-text\">.codex/maps/&lt;id&gt;.md</code></li>\n</ul>\n<p>而它们之间的流程关系是这样的：</p>\n<p><figure class=\"gatsby-resp-image-figure\" style=\"\">\n    <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 92.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsSAAALEgHS3X78AAAC/ElEQVQ4y11TaW/jNhClbJ3UfZASRR20RF22LJ+xnWTTrJ1m0aJfix5A///vKGS1m7TAgBgM5s2bgw/M1PC7ARnrTs6qbVYMmpVKeiwbse4kLmIuYs5ohY1KB5V2UEowBp/BgoIx5dvDpd882AEDMhIUDGQMJARkBBQs3E2ERLVSN6zAJ2QoQVJW7fl8fnl5SfJKhESEkQijuRYJaghEH8z98RUDIAW6m3+A701SzaamlzqIKWY8UyNJj+9GNDtlfNssH3h7SBfrD7BwR0o6ERSsmLHlpXaQQYuKkMxUPNf+KU3Srqh3eTmESQtk9MGsmMlcG9trl/35cnp8vFwuZ8vLeL06HPaWnxtestnuDg/n4+myHnayQaAzMStYgvFUJWVNv952q6Fue2hTRMqs6GQjVkzKeJ+yblENJG0E5c4sQbLZP5+fbqfHr17IbVTsji/H89dFtRWUSIRx259OTzdWbgGwgOCqZnp6eovSVrVScJ+HaE6mmFRQQg9nBW82+9Nq2LGi9nGmmglJa1a2NKuyRUOS0g7YXIv+XZiCJX1sG0gojPNV372+/nC7XbtlE1EG5gGhxWa7ef7yZX84FryWZB8A+z8LE2EkKFi1qOFS00ssPzNcqll0pobQyaCTijDK+Xq1OTO+ibPODgoAxj+E5tp4p8kHIpppRIQxEBGQsaQTSb/7Ej4/Xn//469ff/vz20+/oLgGPs5RlDO+jGiJwlyzKI7Loqx53dGsEhQ89ZWwhhX1grfQpmDmgZmnOznI2aLvV+/f3o8PB84Ly0vrbn29vr79eBs2eyCjaa7lejMG366Y8mlNI9i7M5f1OslrP8xkg/gh61ZDv96FcTFTwzmMZkoYhGzZbwveKgYBMhJh5GIOgIxYtX25/nx5fg9Io9mZ5mSTaBQzGSU1phLDY25YaXYGndzyF25YqVbyWVXjwXQ3h05u+ouAtLwZ6na57IcF7+J87WCuO7nu5LJBJ23+X8/jtu9zAhkZbkLSiuaNi9j34CTyKf9v9uBk326EnMMAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Mermaid 画图真不错，嘿嘿\"\n        title=\"Mermaid 画图真不错，嘿嘿\"\n        src=\"/static/2f7f129aadab4456ddf01600d38296c9/302a4/diagram.png\"\n        srcset=\"/static/2f7f129aadab4456ddf01600d38296c9/01bf6/diagram.png 270w,\n/static/2f7f129aadab4456ddf01600d38296c9/07484/diagram.png 540w,\n/static/2f7f129aadab4456ddf01600d38296c9/302a4/diagram.png 1080w,\n/static/2f7f129aadab4456ddf01600d38296c9/0d292/diagram.png 1620w,\n/static/2f7f129aadab4456ddf01600d38296c9/11864/diagram.png 2034w\"\n        sizes=\"(max-width: 1080px) 100vw, 1080px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span>\n    <figcaption class=\"gatsby-resp-image-figcaption\">Mermaid 画图真不错，嘿嘿</figcaption>\n  </figure></p>\n<p>不要慌！我只是想简单表达一下这是个循环（loop）而已。具体使用方式且听我娓娓道来。</p>\n<h2>commit-context</h2>\n<p>需求都是聊出来的。不论你是使用 <a href=\"https://www.aihero.dev/skills-grill-me\" target=\"_blank\" rel=\"noopener noreferrer\">grill-me</a> 还是直接用产品经理产出的文档，你总是要和 AI 对话（Conversation）；在对话和编码过程中，必然涉及到一系列决策（Decisions）；而最终的产物当然就是代码。对话 + 决策 + 代码，有这三者我们就能很好地还原出当时的上下文，而你甚至可以让同事复现 AI 的神迹。</p>\n<p>所以在 AI 写完代码之后，我们只需要运行 <code class=\"language-text\">$commit-context</code>，AI 就会自动把对话和决策写到 git commit message 里，于是我们大概就会看到这样的 git log</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"># Conversation Log\n\n- User:      &lt;关键请求、约束或澄清&gt;\n- Assistant: &lt;关键动作或用户可见的结果&gt;\n\n# Decisions\n\n## Decision 1\n- MODULE:       &lt;来自 .codex/MODULES.md 的精确 ID&gt;\n- WHY:          &lt;一行动机&gt;\n- ALTERNATIVES: &lt;考虑过的方案，用 &quot; / &quot; 分隔&gt;\n- CHOSEN:       &lt;最终实现的方案&gt;\n- TRADEOFFS:    &lt;这个选择放弃了什么&gt;\n- RISKS:        &lt;需要盯着的风险&gt;\n- SUPERSEDES:   &lt;可选：被替代的决策摘要与 commit hash&gt;\n\n# Files Modified\n\n- &lt;路径&gt; — &lt;该暂存改动的语义描述及其目的&gt;\n\n# Token Usage\n\n- Input tokens:            &lt;输入 token 数&gt;\n- Output tokens:           &lt;输出 token 数&gt;\n- Reasoning output tokens: &lt;推理输出 token 数&gt;\n- Cache read tokens:       &lt;缓存读取 token 数&gt;\n- Cache creation tokens:   &lt;缓存创建 token 数&gt;\n- Total tokens:            &lt;总 token 数&gt;\n- Total cost:              &lt;costUSD，保留四位小数；缺失或为零时省略&gt;\n- Models used:             &lt;排序后的模型名&gt;</code></pre></div>\n<p>这里的 <code class=\"language-text\">MODULE</code> 指的是业务模块，比如相机、选图、首页等等。如果 <code class=\"language-text\">$commit-context</code> 发现一个新模块不存在，它会自动辅助你创建一个新模块 ID，并注册到 <code class=\"language-text\">.codex/MODULES.md</code>，且这些模块 ID 在另外两个 skills 里也会同样被引用到（通过模块 ID 将三者关联起来）。</p>\n<p>当然也不是所有改动都要执行 <code class=\"language-text\">$commit-context</code>，你可以酌情简单 commit，只要不是大改动会影响到整个知识循环就行。另外我在这个 skill 里加了一些私心，把 token 消耗也记录上了，毕竟这样我就可以统计到这个需求我花了多少钱，哈哈（你也可以去掉）。</p>\n<h2>distill-module</h2>\n<p>现在所有原始信息（上下文）都记录在 git log 里了，但是让 AI 每次都检索 git log 毕竟是效率低的，所以我们需要定期蒸馏 git log，能让 AI 快速检索出对应模块的改动。</p>\n<p>我一般在完成一个大需求，或者 App 发新版本以后，会运行一次针对所有模块的 <code class=\"language-text\">$distill-module</code>。你将会在 <code class=\"language-text\">.codex/decisions/&lt;id&gt;.md</code> 里看到这样的信息：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"># &lt;模块显示名&gt; Decisions\n\n&gt; 当前共识快照。演化过程见：`git log --grep=&quot;MODULE: &lt;id&gt;&quot;`\n&gt; 最近蒸馏时间：&lt;YYYY-MM-DD&gt;（HEAD = &lt;短 sha&gt;）\n\n## Active\n\n### D1: &lt;改写后的简短标题&gt;\n\n- **What**:      &lt;一句话说明当前采用的做法&gt;\n- **Why**:       &lt;一句话说明动机&gt;\n- **Tradeoffs**: &lt;一句话说明接受了哪些代价&gt;\n- **Watch out**: &lt;一句话说明风险&gt;\n- **Source**:    &lt;短 sha 1&gt;, &lt;短 sha 2&gt;\n\n## Superseded\n\n- ~~&lt;旧决策&gt;~~ → 已被 **D1** 取代，见 &lt;短 sha&gt;（&lt;YYYY-MM-DD&gt;）</code></pre></div>\n<p>为了防止决策文件积累的越来越长，<code class=\"language-text\">$distill-module</code> 也会自动对决策进行压缩，保证 AI 的注意力不会过多分散在历史的长河中 👑</p>\n<h2>map-module</h2>\n<p>嗯，其实如果对于新项目而言，前两个 skills 已经够用了。但我们才刚刚进入 Coding Agent 时代不过短短一年，仍然有很多前 AI 时代的代码仓库需要处理。这显然需要一套探索机制，能尽量准确地摸清历史逻辑，并快速接入我们这套 git 知识循环系统。</p>\n<p>这时我们就需要使用 <code class=\"language-text\">$map-module</code> 对源码进行研究 + 对抗性验证。「对抗性验证」这个概念很好，这是从 Claude Code 的 <a href=\"https://code.claude.com/docs/zh-CN/workflows\" target=\"_blank\" rel=\"noopener noreferrer\">Dynamic Workflows</a> 里借鉴过来的。</p>\n<p>首次运行需要等待较长时间，如果你的项目历史比较悠久，甚至可能需要运行好几个小时，所以推荐在下班时运行，第二天上班时验收。考虑到一个代码仓库有外部依赖，必要时你可以在 prompt 里提供各个依赖的源码路径，<code class=\"language-text\">$map-module</code> 会自动探索对应的路径，并将结论沉淀到 <code class=\"language-text\">.codex/maps/&lt;id&gt;.md</code> 中，格式大概是这样的：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"># &lt;module-id&gt; Map\n&gt; 静态理解快照，不是决策史。\n&gt; 配对的决策史见 `.codex/decisions/&lt;module-id&gt;.md`（若尚不存在，请注明）。\n&gt; Verified: YYYY-MM-DD（验证摘要）\n\n## Responsibilities（职责）\n...\n\n## Key types（关键类型）\n...\n\n## Public entry points（公开入口点）\n...\n\n## Data flow / lifecycle（数据流 / 生命周期）\n...\n\n## Dependencies (inbound / outbound)（依赖：入向 / 出向）\n...\n\n## Invariants and gotchas（不变量与坑）\n...\n\n## Confirmed bugs / technical debt（已确认的 bug / 技术债）\n...\n\n## Open questions（悬而未决的问题）\n...\n\n## To verify（待验证）\n...</code></pre></div>\n<p>可以看到，这里 maps 已经单向关联上了 decisions。</p>\n<h2>循环</h2>\n<p>但是，说了半天，循环呢？别急，接下来就是见证奇迹的时刻。</p>\n<p>相信很多读者都有过维护 AGENTS.md 的经历，朴素地给 AGENTS.md 加规则和上下文，很容易就超过了 200 行（至少 CLAUDE.md 建议是 200 行）。行数越多，模型注意力下降越厉害（Lost in the Middle）。</p>\n<p>但我们其实不需要在 AGENTS.md 里写很多内容，现代模型的指令遵循能力很强，我们只需要让它按照渐进式披露的方式获取上下文就好了。而我们之前所做的动作，都是在对上下文构建索引，使得模型可以很方便地逐级获取上下文。</p>\n<p>当你在第一次执行 <code class=\"language-text\">$commit-context</code> 的时候，它会自动在 AGENTS.md 里注入这段文字：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">## 知识循环约定\n\n### 编写代码之前\n\n1. 通过 `.codex/MODULES.md` 解析出本次改动涉及的每一个模块；ID 中的 `/` 对应子目录。\n2. 对每个受影响的模块，读取存在的 `.codex/maps/&lt;module&gt;.md` 与 `.codex/decisions/&lt;module&gt;.md`。不要加载无关模块的文件。\n3. 对即将改动的文件运行 `git log --oneline -10 -- &lt;path&gt;`。\n4. 若近期提交中含有 `MODULE: &lt;当前模块&gt;`，用 `git show` 查看这些提交的正文。\n\n### 完成任务之后\n\n- 如果实现改动导致现有模块 map 在职责、公开入口点、生命周期或数据流、依赖、不变量、已知局限方面失准，\n  在可用时以定向刷新模式使用 `$map-module`；否则在收尾前报告该 map 已过期。\n  影响范围无法界定时使用全量刷新。若 map 中记录的陈述依然成立，则不要改动它。\n- 使用 `$commit-context` 时，为每条 Decision 填写 `MODULE`、`WHY`、`ALTERNATIVES`、`CHOSEN`、`TRADEOFFS`、`RISKS`。\n- 当一条新 Decision 取代了 `.codex/decisions/` 中的某条决策时，补上 `SUPERSEDES`。</code></pre></div>\n<p>由此，构建出了整个循环。</p>\n<h2>结语</h2>\n<p>这套系统毕竟已经在公司项目 + 个人项目里运行了大半年，按照 API 计价已经烧了 $30000+ tokens，整体还是很健壮的。</p>\n<p>你不需要安装 Obsidian / Notion / 飞书文档 或者其他什么的外挂知识库，所有的知识都存在你的 git log 里，任何一个新同事 git clone 以后就能直接开始干活。你也可以基于这套循环，构建自动化测试等流程。现在测试同学给我提 bug，我也基本可以做到直接转发给 AI 帮我修。甚至因为是基于 git log 的，服务端同学应该也可以直接拉起一个容器，让 agent 自己在代码仓库里跑测试，而不需要引入额外的依赖。</p>\n<p>当然这套架构并不完美，比如还没有处理「模块拆分」等问题，不过这些问题你都可以让 AI 帮你解决（或者等我后续迭代，哈哈，不过目前不是很紧急）。</p>\n<p>我现在感觉非常虚无，仿佛只要有这三个 skills，我就可以胜任任何工作（不是。</p>","frontmatter":{"title":"基于 Git 的最小知识循环系统","date":"August 31, 2026","description":"所有上下文都存在 git log 里 ♾️"}}},"pageContext":{"slug":"/git-knowledge-loop/","previous":{"fields":{"slug":"/pocket-preset/"},"frontmatter":{"title":"Pocket Preset Privacy Policy"}},"next":null}},"staticQueryHashes":["426816048","63159454"]}