<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Git on UKonA有空</title><link>https://ukona.cn/tags/git/</link><description>Recent content in Git on UKonA有空</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sat, 26 Sep 2026 12:00:00 +0800</lastBuildDate><atom:link href="https://ukona.cn/tags/git/index.xml" rel="self" type="application/rss+xml"/><item><title>把记忆存进Git：一个AI记忆系统的数据模型</title><link>https://ukona.cn/posts/life-064/</link><pubDate>Sat, 26 Sep 2026 12:00:00 +0800</pubDate><guid>https://ukona.cn/posts/life-064/</guid><description>&lt;blockquote&gt;
&lt;p&gt;字数：约2800字 | 阅读时间：8分钟
&lt;strong&gt;&amp;ldquo;索引烧了可以重建，正本烧了就什么都没了。&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;「记忆工程」系列第二篇。上一篇讲了为什么要给 AI 造一个&amp;quot;第二大脑&amp;quot;，这一篇往下挖一层：记忆到底长什么样，为什么必须能 diff，以及四条底线是怎么一条条落进代码里的。&lt;/p&gt;
&lt;h2 id="一先说清楚正本是什么"&gt;一、先说清楚&amp;quot;正本&amp;quot;是什么&lt;/h2&gt;
&lt;p&gt;上一篇发出去之后，被问得最多的问题是：向量库、嵌入式数据库、各种记忆框架都有，为什么偏要从&amp;quot;一堆文件加一个 Git 仓库&amp;quot;开始？&lt;/p&gt;
&lt;p&gt;先给结论：我们要的&lt;strong&gt;不只是&lt;/strong&gt;&amp;ldquo;存得下&amp;rdquo;，更要&amp;quot;毁不掉&amp;quot;。&lt;/p&gt;
&lt;p&gt;所谓正本，就是把所有派生物全删掉之后还剩下的那份东西。embedding 索引删了，可以从 Markdown 重建；缓存删了，可以重新生成。这些都可以坏，坏了重跑就行。但 Markdown 和 Git 历史要是没了，整个系统就只剩一个空壳。反过来，只要这两样在，索引层随便推倒重来，十分钟满血复活。&lt;/p&gt;
&lt;p&gt;这个设计被真实场景检验过。项目进行中，本机的记忆仓库被一次强制重置打翻，AI 在巡检报告里提示了异常。最后我们是靠 Git 的操作日志（reflog）把现场完整恢复的——那些记忆要是存在某个私有数据库里，那次大概率就是永久丢失，连&amp;quot;去哪找&amp;quot;都不知道。&lt;/p&gt;
&lt;p&gt;记忆系统天然处在各种自动化程序的写风险之下：AI 会写错，脚本会写崩，重置会误伤。把正本放在最笨、最老实、二十年不会过时的格式上，就是给整个系统设了一个止损下限。&lt;/p&gt;
&lt;h2 id="二骨架三种记录"&gt;二、骨架：三种记录&lt;/h2&gt;
&lt;p&gt;结论先行：整个记忆库只有三种记录——Topic、Fact、Relation。&lt;/p&gt;
&lt;p&gt;**Topic 是实体节点。**一个项目、一个工具、一次会话、一个设计决策，都是 Topic。它是记忆图里&amp;quot;名词&amp;quot;的部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fact 是关于某个 Topic 的一条离散陈述。&lt;/strong&gt;&amp;ldquo;切片查询默认走三级降级&amp;quot;是一条 Fact，&amp;ldquo;查询接口只监听本机&amp;quot;也是。每条 Fact 独立存在，独立带状态，独立过期。&lt;/p&gt;
&lt;p&gt;**Relation 是带类型的边。**MVP 只留了七种：&lt;code&gt;depends-on&lt;/code&gt;、&lt;code&gt;part-of&lt;/code&gt;、&lt;code&gt;belongs-to&lt;/code&gt;、&lt;code&gt;authored-by&lt;/code&gt;、&lt;code&gt;references&lt;/code&gt;、&lt;code&gt;conflicts-with&lt;/code&gt;、&lt;code&gt;supersedes&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;为什么只留七种？因为实际运行里我们观察到一个现象：关系类型一旦放开，AI 就开始发明关系——&amp;ldquo;somewhat-related-to&amp;quot;这种模糊边一多，图就废了，查询时全是噪音。宁可类型少，也要收敛。&lt;/p&gt;
&lt;p&gt;&lt;img alt="am的数据模型：Topic、Fact、Relation" loading="lazy" src="https://ukona.cn/images/am-02-datamodel.png"&gt;&lt;/p&gt;
&lt;h2 id="三一条事实的解剖"&gt;三、一条事实的解剖&lt;/h2&gt;
&lt;p&gt;空谈模型容易飘，看一条真实的记忆。这是演示库里的一条 Fact（commit 哈希做了截断）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;type&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fact-alpha-getuser-main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;topics&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;project-alpha]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;status&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;active&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;confidence&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;high&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;provenance&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;demo-seed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;repo&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;…/project-alpha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;version&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;commit&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1a2b3c4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;axis&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;subject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Alpha 在 main 分支只提供 getUser(id) 单点查询，无限流。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;前面这几行 frontmatter 是机器读的索引：&lt;code&gt;id&lt;/code&gt; 是唯一编号，&lt;code&gt;topics&lt;/code&gt; 声明这条事实挂在哪些实体上，&lt;code&gt;status&lt;/code&gt; 是生命周期状态（active / expired / superseded / contested / pending-review），&lt;code&gt;confidence&lt;/code&gt; 是置信度，&lt;code&gt;provenance&lt;/code&gt; 记来源。&lt;/p&gt;</description></item><item><title>给AI建一个'第二大脑'：我的记忆外挂立项记</title><link>https://ukona.cn/posts/life-063/</link><pubDate>Wed, 23 Sep 2026 12:00:00 +0800</pubDate><guid>https://ukona.cn/posts/life-063/</guid><description>&lt;blockquote&gt;
&lt;p&gt;字数：约2500字 | 阅读时间：7分钟
&lt;strong&gt;&amp;ldquo;上下文窗口是租来的，记忆得自己盖房。&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一从一次失忆说起"&gt;一、从一次&amp;quot;失忆&amp;quot;说起&lt;/h2&gt;
&lt;p&gt;上个月，我在两台机器上让两个AI协作开发同一个项目。A机上的AI刚做完一轮设计评审，结论写进了它的会话记录；B机上的AI第二天接着干活，对这份结论一无所知，按自己&amp;quot;新想&amp;quot;的方案把接口改了。等我发现时，两边的代码已经分叉，返工花了整整一个晚上。&lt;/p&gt;
&lt;p&gt;这件事之后我盘了盘自己的AI工作流，发现&amp;quot;失忆&amp;quot;无处不在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;会话内失忆&lt;/strong&gt;：上下文窗口一满，早期聊定的决策就被挤出去，AI开始&amp;quot;自作主张&amp;quot;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会话间失忆&lt;/strong&gt;：新会话从零开始，我要么把背景重新粘一遍，要么接受它带着错误的前提干活；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具间失忆&lt;/strong&gt;：A工具记住的东西，B工具看不到。换一个工具，等于换了一个没有经验的实习生；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;机器间失忆&lt;/strong&gt;：我在台式机、笔记本、服务器上各跑着AI助手，它们对同一个项目的认知互不相通。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些问题的根子不在模型。模型的能力一直在涨，但&lt;strong&gt;记忆这件事，从来没有一个正经的架构位置&lt;/strong&gt;——它被默认塞在上下文窗口里，而上下文窗口本质上是租来的临时工位。&lt;/p&gt;
&lt;h2 id="二结论先行做一个外置记忆层"&gt;二、结论先行：做一个&amp;quot;外置记忆层&amp;quot;&lt;/h2&gt;
&lt;p&gt;am（agent memory）想做的事情一句话能讲完：&lt;strong&gt;把&amp;quot;记忆&amp;quot;从AI身体里搬出来，做成一个独立于任何AI、任何工具，人和程序都能读写的知识层。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它不是一个聊天记录归档工具，也不是又一个向量数据库。核心形态是四样东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一堆&lt;strong&gt;纯Markdown文件&lt;/strong&gt;：每个文件记录关于某个&amp;quot;话题&amp;quot;（Topic）的事实（Fact）和关系（Relation）；&lt;/li&gt;
&lt;li&gt;一个&lt;strong&gt;Git仓库&lt;/strong&gt;：每次记忆变更都是一次commit，可diff、可回滚、可审计；&lt;/li&gt;
&lt;li&gt;一层&lt;strong&gt;自动化维护程序&lt;/strong&gt;：监听会话、代码提交、文件变更，自动提取新事实、更新旧事实、标记过期；&lt;/li&gt;
&lt;li&gt;一套&lt;strong&gt;切片查询接口&lt;/strong&gt;：任何AI进入任务前，报上&amp;quot;我是谁、在哪个项目、哪个分支、什么时间&amp;quot;，就能领到一份恰好够用的上下文包。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三四条底线"&gt;三、四条底线&lt;/h2&gt;
&lt;p&gt;设计阶段最纠结的是取舍。最后沉淀下来四条底线，一条都不能让：&lt;/p&gt;
&lt;h3 id="1-明文markdown是唯一正本"&gt;1. 明文Markdown是唯一正本&lt;/h3&gt;
&lt;p&gt;记忆永远以人能直接读的Markdown存在。embedding、索引、缓存都是派生物——删了随时能重建，永远不作为事实来源。这条底线保证的是：哪天这套系统黄了，我剩下的还是一堆能直接翻的笔记，而不会是一把打不开的锁配一个看不懂的库。&lt;/p&gt;
&lt;h3 id="2-每次变更都是一次git-commit"&gt;2. 每次变更都是一次Git commit&lt;/h3&gt;
&lt;p&gt;谁改的、什么时候改的、改了什么——全部留在commit历史里。AI改错了记忆，和改错了代码一样，可以被review、可以revert。这条底线的价值很快就被验证过：项目进行中有一次，一个AI报告&amp;quot;本机仓库曾被外部进程强制重置&amp;quot;，我们就是靠Git的操作日志（reflog）把现场完整恢复的。要是记忆存在某个私有数据库里，那次可能就直接丢了。&lt;/p&gt;
&lt;h3 id="3-工作区隔离"&gt;3. 工作区隔离&lt;/h3&gt;
&lt;p&gt;每个项目的记忆是独立的vault（库），物理隔离，一个项目的记忆污染不能蔓延到另一个项目。多个AI对世界有不同&amp;quot;认知&amp;quot;时，靠Git分支来隔离各自的现实。&lt;/p&gt;
&lt;h3 id="4-跨库一等链接"&gt;4. 跨库一等链接&lt;/h3&gt;
&lt;p&gt;记忆之间用双链语法（类似Obsidian的&lt;code&gt;[[链接]]&lt;/code&gt;）连接，跨项目、跨库的引用是一等公民。真实世界的知识本来就不是树状的：一个&amp;quot;传感器&amp;quot;话题，会同时关联&amp;quot;通信协议&amp;quot;、&amp;ldquo;部署环境&amp;rdquo;，和&amp;quot;那次印象深刻的踩坑&amp;quot;。&lt;/p&gt;
&lt;h2 id="四一条记忆长什么样"&gt;四、一条记忆长什么样&lt;/h2&gt;
&lt;p&gt;空谈架构容易飘，看个简化示例（省略了部分字段）。一条关于项目的事实，在库里就是一个Markdown小节：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### fact-0217 · 切片查询默认走三级降级
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;-&lt;/span&gt; 关于: [[Tool: 切片查询]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;-&lt;/span&gt; 陈述: 检索先走向量近似，超时或预算不足时逐级退回
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; token索引、图遍历，保证任何情况下都有返回。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;-&lt;/span&gt; 版本轴: repo=am-main, branch=main, commit=f40cd48
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;-&lt;/span&gt; 来源: 2026-09-23 基准测试轮 · 置信度: 高
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;-&lt;/span&gt; 状态: 有效
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;机器读它，人也能读它，Obsidian里点开就能改。查询的时候，AI报上&amp;quot;我在哪个仓库、哪个分支、当前时刻&amp;quot;，系统从记忆图里切出这个&amp;quot;世界&amp;quot;下所有有效的条目，渲染成一份上下文包交出去——过期的事实一条都不会混进来。而这一切的每一次变更，都对应Git历史里一行可以追溯的commit。&lt;/p&gt;
&lt;h2 id="五最容易低估的难点时间"&gt;五、最容易低估的难点：时间&lt;/h2&gt;
&lt;p&gt;整个设计里最反直觉、也最值钱的决定，是&lt;strong&gt;给每条记忆标注它属于哪个版本的世界&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;举个例子。一条记忆写着&amp;quot;配置文件的格式是YAML&amp;quot;。三个月后项目重构，格式改成了JSON。这条记忆过期了吗？&lt;/p&gt;
&lt;p&gt;看情况——如果你的服务还跑在旧版本上，它依然有效；如果你在新分支上开发，它已经错了。所以每条事实都必须回答：&amp;ldquo;我在说哪个仓库、哪个分支、哪个提交时刻的世界？&amp;rdquo;&lt;/p&gt;</description></item></channel></rss>