Vibe Coding 多人游戏(二十三)—— 记忆管理体系

记忆结构

MEMORY.md(核心索引)
├── 33 个锚点词(快速定位到对应文档)
├── 检索协议(怎么查)
└── 分层读取入口(去哪找什么)

memory/
├── 2026-06-07-log.md ← 每日记录(35+ 篇)
├── 2026-06-08-log.md
└── ...

笔记/
├── 项目文档/ ← 规格、规则、方案
├── 决策记录/ ← ADR(40+ 条)
├── 代码笔记/ ← 代码层面的发现
└── daily/ ← 每日日志摘要

MEMORY.md 是整个记忆系统的入口。它不存储具体内容——只存储"到这个锚点词该去读哪个文件"。有点像操作系统的 inode 节点:不存数据,只存指针。


33 个锚点词

记忆检索的核心策略是用锚点词快速定位。这些锚点词是项目里的关键概念:

GTS-Play, OpenCode, E2E, BDD, SCF, TSRPC
room-service, match-service, webpack-dev-server
token-opt, gts-skill, MEMORY-ARCHIVE
重构规则, 代码审核, 验收, gts-acceptance
通知, 飞书, 部署, deploy-scf
状态同步, 绝对状态, 保存, 提交

锚点词的选择有一个迭代过程:

v1(随意命名):凭感觉写锚点词。问题是"SCF部署"和"deploy-scf"同时存在,AI 搜索时不知道用哪个。

v2(英文为主、加连字符):统一英文,用连字符连接。比如 deploy-scftoken-optgts-skill。AI 搜索英文词比中文词更精确——因为 tokenized 后英文词通常是一个完整 token。

v3(三层检索优先级):搜索时按优先级:

锚点词精确命中 > 关键词语义搜索 > 全文搜索

如果搜"部署",先精确匹配锚点词 deploy-scf(命中),再语义搜索"部署"(如果没命中),最后扫全文。这个三层策略的效果是:8 成以上的搜索在第一步就完成了,不需要后面的语义搜索——节省 token。


检索协议

统一命令:openclaw memory search "<关键词>" --max-results 3 --json

规则:

  1. 先匹配锚点词 → 精确命中(优先)
  2. 再匹配关键词 → 扫描索引
  3. 最后语义搜索 → 回退方案

为什么需要统一的检索协议?因为 AI 不会默认用命令去查记忆——它更倾向于直接在对话里问"你还记得上次怎么修的那个 bug 吗?" 但如果这次对话是新开的,AI 确实记不得。

统一命令的好处是:我作为兄弟,不需要教 AI 每个搜索场景怎么做。它自己知道"先跑 openclaw memory search,拿不到结果再问兄弟"。

QMD 的踩坑记录

QMD(Query Markdown)是 OpenClaw 内置的 Markdown 检索引擎。它自动索引 memory/*.md 和 笔记/ 目录下的文件,支持标题精确匹配、关键词搜索和语义搜索。

但引入 QMD 的过程踩了好几个坑,每个坑都改了一次设计。

坑 1:自动重建索引打断对话

现象: 我写 daily log 时(比如记录今天的修复过程),AI 正在分析 bug 根因,QMD 检测到文件变更自动重建索引——对话中断了,"索引重建中"的状态插入到了 bug 分析环节。

分析: QMD 默认的自动重建策略是「文件变更即重建」。但我写 daily log 的频率很高——几乎每次 bug 修复或决策后都会记一笔。一天 10+ 次变更,每次重建索引都消耗当前对话上下文。本来只花了 100 tokens 写一行日志,却触发了 5000+ tokens 的索引重建。

解决:关闭自动重建,改为手动触发。

保存(gts-save-flow / gts-save-memory / gts-submit-save)
  → BDD 编译完成
  → 笔记保存
  →  QMD 索引重建(手动触发)
  → git commit

只有这三个明确的保存指令会触发重建。写 daily log、改笔记、写 ADR——日常操作不触发。

坑 2:索引范围太窄,笔记/目录搜不到

现象: 搜"端逻辑重置"返回空结果。但我知道这条记录在 笔记/项目文档/rules/workflow-rules.md 里——MEMORY.md 的锚点词指向了它,但 QMD 搜不到。

分析: QMD 默认只在 memory/*.md 目录下建立索引。而项目的核心决策记录和规格文档都在 笔记/ 目录下。memory/ 里只存锚点指针,不存具体正文。搜索时索引扫了一遍 memory/ → 空 → 认为没有相关内容。

解决:扩展索引范围,覆盖 笔记/ 目录。

# QMD 索引配置
indexPaths:
  - memory/*.md
  - 笔记/**/*.md        # 新增,覆盖项目文档、ADR、daily log

加上 笔记/ 后,搜索"端逻辑重置"直接命中 笔记/项目文档/rules/workflow-rules.md 中的 检查项。但这也引入了一个新问题:笔记/ 目录下文件太多(40+ ADR、35+ daily log),重建时间变长了。

坑 3:搜索结果缺少排序

现象: 搜"倒计时"返回了 5 条结果:

  • ADR-036:倒计时乐观锁比较写反(2026-06-28)
  • ADR-038:倒计时结束后游戏不启动(2026-06-30)
  • daily log 6-28:修复倒计时 bug
  • daily log 6-29:重构倒计时逻辑
  • 规格文件:倒计时功能规格

但最相关的是 ADR-036 和 ADR-038,它们排在第三和第五。AI 需要额外处理才能找到真正有用的。

分析: QMD 的排序算法是默认的向量相似度,不考虑时间衰减和引用频率。倒计时关键词在所有文件里都出现了,排序完全随机。

解决:配合 --max-results 3 和手动选择关键词。

不依赖 QMD 的排序,而是用关键词的精确度来筛选。搜"倒计时 乐观锁"而不是"倒计时"——降低信息熵,提高命中率。发现这个规则后,我在 MEMORY.md 的检索协议里加了一条:

search priority: title exact > keyword > semantic

精确匹配比语义搜索省 token 而且更准。现在 AI 搜一个东西会用 2-3 个关键词组合尝试,而不是一个泛词。

坑 4:QMD 索引和 git 不同步

现象: 从 GitHub 拉取更新后,兄弟新写的 ADR 在本地搜不到。跑了一次 git pull 后改动了 5 个文件,但 QMD 索引还是旧的状态。

分析: QMD 索引只检测文件变更事件,不检测 git 操作。git pull 拉下来的文件直接覆盖了磁盘文件,QMD 没有触发重建——因为文件变更事件在 git 文件操作完成后瞬间发生,但 QMD 的检测窗口恰好错过了。

解决:在 git 同步流程中加入索引重建。

gts-git-pull(拉取 GitHub 更新)
  → git fetch + merge
  →  QMD 索引重建
  → 通知兄弟"已同步 + 索引已更新"

每次 git pull 后自动跑索引重建,保证索引和磁盘文件一致。

总结

四个坑对应四个改进:

解决 触发时机
自动重建打断对话 手动触发 只有保存指令时
索引范围太窄 扩展至 笔记/ 单次配置
结果缺少排序 关键词组合 + 精确匹配 检索协议固化
和 git 不同步 拉取后重建 每次 git pull 后

现在 QMD 的索引系统相对稳定了。踩坑过程也帮我形成了一套索引配置经验——什么该索引、什么时候重建、怎么排序——这些经验都固化在了项目的 QMD 配置文件和检索协议中。


QMD(Query Markdown)检索机制

QMD 是支撑整个记忆检索的底层引擎。它不是独立的搜索工具,而是一套索引 + 查询的协议,覆盖了从写入到检索的完整链路。

索引构建

当记忆被写入 memory/*.md笔记/ 目录时,QMD 会自动建立三层索引:

层级 索引内容 示例
标题索引 文档标题、H1-H6 标题文本 "记忆管理体系" → P23
关键词索引 锚点词、代码标识符、特殊标记 "deploy-scf", "", "yieldMs"
全文索引 所有正文内容的倒排索引 包含"compaction"的所有段落

标题索引最省 token(一次匹配消耗 ~20 tokens),但精准度最高。关键词索引是第二层,覆盖代码专有名词和特殊标记。全文索引是兜底——匹配度低但覆盖面广。

查询优先级

搜索请求进入后,QMD 按以下顺序匹配:

Step 1: 标题精确匹配       → 命中即返回(95% 命中率)
  ↓ 未命中
Step 2: 关键词索引匹配     → 找锚点词 + 代码标识符
  ↓ 未命中  
Step 3: 语义搜索           → 向量相似度匹配
  ↓ 未命中
Step 4: 全文扫描           → 兜底,但消耗最大

前三步的命中率约 98%。第 4 步全文扫描只有在搜索极生僻的词(比如某个临时变量的名字)时才会触发。

为什么这样设计? 因为语义搜索和全文扫描的 token 消耗是标题匹配的 10-20 倍。把高频请求卡在前两步,中低频靠语义,最低频走全文——和 CPU 缓存的多级架构思路一样。

入库触发机制

QMD 的索引不会自动更新——这又是一个坑。最开始我期望它能自动检测文件变更并重建索引,但实际发现自动重建的时机不可控:AI 可能在写 daily log 时触发重建索引,导致当前对话上下文被浪费。

所以索引重建只在保存流程中手动触发:

gts-save-flow / gts-save-memory / gts-submit-save
  → BDD 编译完成
  → 规格文件更新
  → 笔记保存(自动或手动)
  →  QMD 索引重建(触发 CLI 索引命令)
  → git commit

这三个技能(gts-save-flow、gts-save-memory、gts-submit-save)都会触索引重建,保证搜索时能看到最新的笔记内容。

搜索示例

假设兄弟说"看看上次端逻辑重置怎么修的":

1. AI 解析 → 关键词:端逻辑重置
2. QMD Step 1:标题匹配 → 无匹配文档标题
3. QMD Step 2:关键词索引 → 命中 "端逻辑重置"(在 MEMORY.md 的锚点词区索引过)
4. 指向 → 笔记/项目文档/rules/workflow-rules.md 中的  检查项
5. 返回结果 → "End 逻辑未清空跨轮状态"的描述 + 修复文件列表
6. AI 读对应文件 → 找到完整修复方案

整个过程 ~500 tokens,耗时不到 1 秒。如果没有 QMD,AI 需要从头读一遍所有 daily log(~5000 tokens)来找"端逻辑重置"的上下文。

参考资料

如果你对 QMD 的实现细节感兴趣,可以查阅以下资源:

资源 说明 位置
CLI 命令参考 openclaw memory search 的参数和使用示例 OpenClaw 文档(CLI)
索引配置 QMD 的索引路径和重建策略 项目根目录下的 .qmd.yml 或 opencode.yml
检索协议 AI 层的搜索规则和优先级 MEMORY.md - 检索协议
锚点词列表 33 个核心检索词及各自指向的文件 MEMORY.md - 核心锚点词
保存流程 索引重建的触发时机和流程 skills/gts-save-flow/SKILL.md

核心经验:QMD 的搜索能力和索引范围成正比,但必须在稳定性和实时性之间做取舍。 索引范围大意味着搜得准,但重建时间长、容易打断对话。我们的做法是:白天开发只用手动保存触发重建,只在紧急查资料时才临时跑一次全量重建。


保存规则与入库标准

记忆只在明确指令下保存——兄弟说"保存"或"提交"时才写 daily log。不自动保存、不自动提交。

我试过自动保存,但发现几个问题:

  • 每次对话都自动保存 → 日志泛滥,每天产生 5-6 篇无价值的记录
  • AI 不知道什么该记、什么不该记 → 记了一堆无意义的信息
  • 自动提交到 git → commit 日志全是"auto-save",真实的变更历史被淹没了

所以改成手动保存。一条信息是否值得记入 MEMORY.md?满足以下至少 2 条

  • 会影响未来决策(>2 周有效期)
  • 会被重复使用(流程/偏好/规则)
  • 会造成明显损失(忘了会踩坑)
  • 可操作、可验证(不是情绪感受)

Daily Log 格式

日期 + 分类标题 + 结果(✅/❌)
├── 根因分析
├── 修复文件列表
├── 优化入库标记
└── 待继续事项

实际例子:

2026-06-29 修复巨大娘踩踏碰撞减血不触发 ✅
├── 根因:computeCollisionDamage 检查 animationName="running",但 handlePlayerNotMove 无条件设 idle 覆盖
├── 修复:三层防御(isMoving 回退 + 保留 walkAnimTime + 尊重当前状态)
├── 优化入库:rule/workflow 加"End 逻辑重置检查"项
└── 待继续:考虑在 Movement.res 中增加统一的 state 快照机制

"优化入库"这行很关键——它连接了 daily log 和规则体系。如果一个 bug 的根因是"某条规则没覆盖到",那么在修复 bug 的同时,也要更新规则文件,防止同类 bug 再次出现。


保存流程三件套

操作 做什么 推送?
gts-save-flow 审核→BDD→编译→规格→笔记→记忆→提交 GitHub 两段同步
gts-save-memory daily log + commit + 笔记 + commit 不 push
gts-submit-save git commit + 记忆保存 不 push

这三个操作的区分是逐步演化的:

最开始只有一个 gts-save-flow,做全流程:审核代码 → 跑 BDD → 编译检查 → 更新规格 → 更新笔记 → 保存记忆 → git commit → 推送到 GitHub。

但很快发现,这个流程太长了。有时候我只是想"保存今天的讨论记录",不想审核代码、跑 BDD、推送到 GitHub。所以拆出了 gts-save-memory:只保存 daily log + commit,不推送。

后来又发现,有时候 git commit 和记忆保存是两回事——比如改了一个注释,不需要记录到记忆系统。于是又拆出 gts-submit-save:只做 git commit + 记忆保存。

三层技能的核心原则是:粒度足够细,细到每个操作都只做一件事。


记忆系统的实际效果

记忆系统最有价值的一次应用:2026-06-28 修复"倒计时乐观锁比较写反"的 bug。两天后(2026-06-30),同样的场景再次出现——倒计时结束后游戏不启动。AI 通过搜索锚点词 countdown 找到了 6-28 的 ADR,看到"倒计时乐观锁比较写反"的根因分析和修复方案,直接在 6-30 的修复中复用了同样的逻辑。如果没有记忆系统,AI 可能会从头排查一遍,浪费 2-3 个小时。

另一个例子:AI 搜索"端逻辑重置"锚点词,找到了 6-18、6-19、6-29 三个关于场景重入的不完整修复记录。三个记录都指向同一个根因——End 逻辑未清空跨轮状态。后来在 workflow-rules.md 里新增了专门的 检查项。记忆不是只有一个入口,而是多个层次的归档——没有哪条规则是天生的,都是从实际 bug 里凝结出来的。


Obsidian 可视化前端(计划中)

笔记系统积累到一定规模后,纯命令行管理开始不够直观——日志 35+ 篇、ADR 40+ 条、项目文档几十个文件。用 Vim 或 WebChat 翻找某天的 daily log、查看 ADR 的全文、浏览某个规则文件的变更历史,都很费劲。

方案比较

当初对笔记可视化工具做了一轮比较:

方案 优点 缺点
Obsidian 本地优先、Markdown 原生、图谱视图、免费 需要安装客户端
语雀 在线协作、实时保存、搜索好 非 Markdown 原生、依赖网络、导出麻烦
GitBook 在线发布、多人协作 付费、配置重、不适合个人项目
VS Code 直接看 无需额外工具 没有笔记专门功能(图谱、搜索、标签)

最终选择 Obsidian,主要看中三点:

  1. 本地优先 — 笔记文件已经在本地的 笔记/ 目录里了,Obsidian vault 直接指向这个目录就行,不需要迁移数据。如果 Obsidian 有一天不好用了,文件格式没变,随时可以换成别的。
  2. 图谱视图 — ADR 引用 daily log、规则文件引用 ADR、方案文档引用规则——这些引用关系在图谱上一目了然。对于回顾项目演进历史非常有用。
  3. Markdown 原生 — 笔记本身就是 Markdown,和 AI 记忆系统的格式一致。不引入额外的标记语法。

现状:结构就绪,工具未用

选择 Obsidian 的决策促成了 笔记/ 目录的标准化——子目录分类、命名规则、引用格式——都是按照 Obsidian vault 的预期来组织的:

笔记/
├── 项目文档/           ← 规格、规则、方案
├── 决策记录/           ← ADR(40+ 条)
├── 代码笔记/           ← 代码层面的发现
├── 方案/               ← 技术方案文档
├── daily/              ← 每日日志
├── memory/             ← 项目记忆
└── 语雀知识库/         ← 离线备份

事实上我目前还没有真正用上 Obsidian——日常开发中,写 daily log 习惯用 VS Code,检索笔记习惯用 openclaw memory search,整理文档直接在文件管理器中操作。Obsidian 是一个"备用方案":当笔记规模再大几倍、命令行检索不够用时,随时可以打开 Obsidian vault 获得可视化浏览能力。

从某种意义上说,Obsidian 的引入价值不在于它被用上了,而在于它推动了 笔记/ 目录的规范化。 如果当初没有 Obsidian 这个目标,笔记目录可能还是随意命名的文件夹结构。

与 AI 记忆系统的关系

如果以后用上 Obsidian,和 AI 记忆系统的分工应该是:

场景 用谁 原因
AI 自动检索 openclaw memory search 统一命令、锚点词索引、token 友好
人工浏览笔记 Obsidian(备选) 图谱、搜索、实时预览
写 daily log VS Code / 直接文件操作 习惯
整理项目文档 文件管理器 简单直接

核心不变:AI 记忆系统是给 AI 读的,Obsidian 是给人看的。两者不冲突。


下期讲 P24:Agent Brief 与 OpenCode 调度规范——怎么写一个让 AI 不出错的 Brief。

下一篇:Vibe Coding 多人游戏(二十四)—— Agent Brief 与 OpenCode 调度规范

posted @ 2026-07-08 11:38  杨元超  阅读(1)  评论(0)    收藏  举报