Code外置记忆库
给 Codex 装一块外挂记忆库
如果一个 AI 只能记住当前对话,那它很聪明,但不够“靠谱”。
因为真实项目不是一次性问答。真实项目会反复出现同类问题:今天是音频设备被占用,明天是 AEC 冷启动,后天是 VSCode 里的 Codex 窗口打不开。每一次问题背后都有环境、判断、尝试、失败、修复和验证。如果这些东西只留在某个对话窗口里,等上下文压缩、窗口损坏、换电脑、换线程之后,AI 又会变成“第一次来这个项目”的状态。
所以我给 Codex 增加了一套外挂记忆库。
它不是单纯的聊天记录备份,也不是简单的向量数据库。更准确地说,它是一套围绕项目长期演进设计的外置记忆系统:
人类可读 Markdown 日志
+
SQLite 结构化知识库
+
FTS / 轻量向量 / 可选语义检索
+
Codex Skill 自动工作流
这套东西的目标很简单:
让 Codex 不只回答当前问题,还能主动想起这个项目以前踩过什么坑。
为什么需要外挂记忆
Codex 原本就有上下文,但上下文有几个天然限制。
第一,当前对话会被压缩。压缩以后,大方向通常还在,但很多细节会消失,比如某次改了哪个系统服务、为什么不能再启用 PulseAudio、某个参数为什么不能继续调大。
第二,对话窗口可能损坏或迁移失败。这个项目就遇到过旧 Codex 窗口打不开、远端机器会话太多导致加载卡住、只保留主线程后 Webview 空白等问题。如果所有记忆都押在对话窗口里,风险太高。
第三,长期项目的信息不是线性的。音频链路、系统环境、GitHub 备份、远端迁移、VSCode 扩展、ALSA 配置、DTLN 路线、URES 调参,这些信息分散在不同时间点。如果只靠“我记得好像有这么回事”,非常容易走回错路。
所以外挂记忆库要解决的不是“存更多字”,而是三个更工程化的问题:
- 重要经验要落到项目里,不依赖某一个对话窗口。
- 相似问题要能被重新召回,哪怕用户换了说法。
- 找到历史记录以后,还要能回到原始 Markdown 核对事实。
这就是它和普通聊天历史的区别。
核心思路:Markdown 做事实源,数据库做检索底座
这套记忆库最重要的设计原则是:
Markdown 是事实源,SQLite 是检索底座,向量只是召回增强。
我没有把所有内容直接塞进一个向量库里。原因很现实:向量很适合找“相似”,但不适合保证“精确”。比如一个历史记录里写着:
robot_virtual_speaker
pipewire-pulse.socket
kernel.apparmor_restrict_unprivileged_userns
019db0be-7fb9-7352-837f-e517e238f99d
这些东西不是语义大概相似就行,它们必须准确。路径、设备名、服务名、线程 ID、配置值,一旦错一个字符,后面的判断就可能完全偏掉。
所以这套系统里,Markdown 保留完整上下文,SQLite 负责把它切分、索引、打标签,检索只负责把 Codex 带到正确的历史记录附近。真正做决定前,Codex 仍然要回到 Markdown 原文确认。
这点很关键。
外挂记忆库不是让 AI “凭向量印象办事”,而是让 AI 更快找到证据。
当前项目里的目录布局
这套系统现在放在项目目录里,跟着 Git 和备份走。
核心结构大概是这样:
docs/
问题处理记录.md
问题处理记录/
2026-04-22.md
2026-04-23.md
2026-04-24.md
2026-04-27.md
问题知识库与日切日志说明.md
智能体通用知识记录与检索原则.md
data/
knowledge/
ops_knowledge.db
scripts/
ops_knowledge.py
ops_semantic_session.py
~/.codex/skills/
operation-log-guard/
ops-knowledge-rag/
ops-semantic-session/
这里面每一层分工都很清楚。
docs/问题处理记录.md 是总入口,不再堆所有正文。它更像目录页,告诉人和智能体去哪里看每天的详细记录。
docs/问题处理记录/YYYY-MM-DD.md 是真正的每日问题记录。它保留现场背景、判断过程、操作内容、验证结果和最终结论。人可以直接读,Codex 也可以回看原文。
data/knowledge/ops_knowledge.db 是本地 SQLite 知识库。它不是给人手动看的,而是给检索系统用的。里面有 entries、chunks、全文索引、标签和语义缓存。
scripts/ops_knowledge.py 是维护入口,负责追加记录、重建索引和搜索历史。
scripts/ops_semantic_session.py 是可选的强语义检索服务。它不会开机自启,也不会长期常驻,只在需要更强语义召回时手动启动。
~/.codex/skills/ 里的技能则负责把这套流程变成 Codex 的默认习惯:改东西前先查历史,重大操作前先写日志,做完后再补结果。
一条问题是怎么进入记忆库的
每次遇到值得记录的问题,系统会把它写成一条结构化日志。
一条记录至少包含这些字段:
标题
问题
当前判断
处理
验证
结果
标签
entry_id
比如处理 DGX 上 Codex 空白面板时,记录里会写清楚:
- 用户看到的现象是什么
- 怀疑是不是瘦身导致
- 当前检查到 session_index 和 JSONL 是否可读
- 采用了什么修复方案
- 恢复了哪个备份
- 最后 JSONL 有多少条记录
- 是否仍然只保留主线程
这比一句“修好了”有用得多。
因为下一次再遇到类似问题,Codex 不需要重新猜,它可以先检索:
python scripts/ops_knowledge.py search \
--query "DGX Codex 空白 面板 理解项目布局与背景 瘦身 会话" \
--mode hybrid \
--limit 6
然后它会看到以前的处理记录:哪些判断成立,哪些方案有效,哪些地方是误判。
这就是外挂记忆库最朴素但最有价值的能力:把一次排障变成下次排障的起点。
切分:不是把整篇日志一股脑塞进去
日志写完以后,ops_knowledge.py 会把每日 Markdown 解析成结构化 entry,再切成多个 chunk。
当前主要有两类 chunk。
第一类是 summary chunk。它保留标题、问题、结果和必要处理摘要,适合快速判断“这条记录整体是不是相关”。
第二类是分节 chunk,比如:
problem
analysis
git_backup
approval
action
verification
result
这样切有一个好处:不同类型的问题可以命中不同部分。
如果我搜索“前三秒 AEC 不生效”,很可能命中 problem 或 summary。
如果我搜索“当时到底改了哪个 systemd 服务”,更可能命中 action。
如果我搜索“最后怎么验证的”,就能命中 verification。
这比把一大段 Markdown 整块向量化更可控,也更适合工程排障。
检索:关键词、向量和语义各做各的事
当前系统支持几种检索模式。
fts 是关键词和全文检索。它适合查精确词,比如设备名、报错、服务名、文件路径。
python scripts/ops_knowledge.py search \
--query "robot_virtual_speaker Device or resource busy" \
--mode fts
vector 是轻量相似召回。当前默认模型叫 hashing-zh-en-v1,它不依赖大模型,不需要 torch,只用本地轻量特征做中英文混合匹配。它适合找“说法不完全一样,但现象类似”的记录。
hybrid 是默认推荐模式。它综合:
- FTS 关键词命中
- 轻量向量相似度
- 查询扩展
- 标签重排
- 对知识库自说明记录的轻量降权
也就是说,Codex 平时查历史,优先用 hybrid。
还有 semantic 和 hybrid-semantic。这两种需要手动启动会话级语义服务:
python scripts/ops_semantic_session.py start \
--provider transformers \
--model moka-ai/m3e-small
启动后可以用:
python scripts/ops_knowledge.py search \
--query "现象描述" \
--mode hybrid-semantic \
--semantic-url http://127.0.0.1:8766 \
--limit 6
这层适合更模糊、更语义化的问题,比如“现在是不是又走回了以前那个错误方向”。不过它不是默认常驻服务,用完要关:
python scripts/ops_semantic_session.py stop
这个设计是有意的。外挂记忆库应该帮忙,而不是偷偷变成一个永远运行、占资源、难排查的后台服务。
Skill:让 Codex 真的养成习惯
光有数据库还不够。
如果 Codex 不主动用它,那它就只是一个漂亮的资料柜。
所以我给 Codex 配了几个项目专用 skill。
ops-knowledge-rag 的职责是:遇到历史相关、排障相关、设计相关的问题时,先查本地知识库,再决定怎么回答或怎么改代码。
它要求 Codex 至少先跑一次 hybrid 检索,然后打开命中的 Markdown 原文,比较:
- 症状是否相同
- 硬件路径是否相同
- 服务和进程是否相同
- 配置值是否相同
- 当时的修复是否仍然适用
operation-log-guard 的职责是:改代码、改配置、改系统状态之前,先写操作记录,必要时做 Git 快照。这样后续如果改坏了,至少知道“当时为什么改、改了什么、怎么验证”。
ops-semantic-session 的职责是:当轻量检索不够时,手动启动更强语义检索,并且确保它不会变成开机自启服务。
这几块拼起来以后,Codex 的工作方式就变了。
以前是:
用户提问题 -> Codex 靠当前上下文判断 -> 直接动手
现在是:
用户提问题
-> Codex 查外挂记忆库
-> 回看 Markdown 原文
-> 写操作记录和快照
-> 再动手
-> 做完补结果
这就是“越用越聪明”的关键闭环。
不是因为模型本身变了,而是项目把经验沉淀成了可复用的外部记忆。
它带来的几个明显好处
1. 抗上下文压缩
对话再长也会压缩。压缩后,很多细节会被摘要掉。
外挂记忆库把关键事实落在项目文件里,即使当前对话只剩很短的摘要,Codex 也可以通过检索把旧细节找回来。
这对长期项目非常重要。尤其是系统环境类问题,细节常常比大方向更重要。
2. 不怕换窗口、换机器、换线程
这个项目经历过旧 Codex 线程打不开、远端 DGX 迁移、VSCode 面板空白、只保留主线程等问题。
如果历史只存在某个聊天窗口里,一旦窗口打不开,损失很大。
现在关键经验在仓库文档和本地知识库里。换机器时同步项目目录和 .codex/skills,新的 Codex 也能通过同一套入口检索历史。
这让“记忆”从某个对话窗口里解耦出来,变成项目资产。
3. 能减少重复踩坑
音频项目特别容易反复走回旧路。
比如:
- PulseAudio / PipeWire 是否应该彻底禁用
- AEC 前几秒不生效是不是 startup guard 问题
- DTLN 主增强和默认路线有什么区别
- 播放缓冲改变为什么会影响回声消除
- 远端 Codex 空白到底是会话坏了还是 Webview 挂了
这些问题如果没有记录,过几天又会重新分析一遍。
外挂记忆库能让 Codex 在动手前先看到“这个坑以前踩过”,从而避免在错误方向上继续调参。
4. 人能看,AI 也能用
很多知识库的问题是:给机器看,人看起来很痛苦。
这套系统反过来设计。Markdown 是事实源,人可以直接读;SQLite 是索引层,机器负责用;向量只是召回增强。
所以它不会变成一个只有脚本知道里面有什么的黑盒。
这点对工程项目很重要。真正出问题时,人还是要能打开日志,看清楚当时到底发生了什么。
5. 有审计能力
每次重大修改前,系统会记录:
- 为什么要改
- 当前判断是什么
- 预期风险是什么
- Git 快照在哪里
做完以后再记录:
- 实际改了什么
- 怎么验证
- 结果如何
- 还有什么残余风险
这让项目不是靠“记忆里好像是这样”推进,而是有一条可回溯的决策链。
对音频这种很容易主观判断的系统尤其有用。今天觉得“声音好多了”,明天觉得“又不行了”,如果没有记录,很难区分是参数变了、设备状态变了,还是测试场景变了。
6. 资源可控
这套记忆库没有默认启动一个大模型服务。
平时检索只用 SQLite、FTS 和轻量向量,资源开销很低。
只有当确实需要更强语义召回时,才手动启动 ops_semantic_session.py。而且它有明确规则:
- 不开机自启
- 不写 systemd
- 不长期常驻
- 当前对话结束前关闭
这符合现场机器的需求:音频服务才是主业务,记忆库不能抢资源。
7. 能把“解决问题”变成“训练项目”
这里的训练不是训练模型参数,而是训练项目自身。
每处理一次问题,项目就多一条高质量记录。下次遇到相似问题,Codex 能更快召回。再下次,又能在前一次基础上继续修正。
久而久之,项目会形成自己的经验层:
这个机器有什么硬件习惯
这个服务怎么部署
哪些路线试过但不适合
哪些参数不能再调
哪些修复只适合特定日期和状态
哪些结论已经被后续推翻
这比普通文档更活。普通文档往往写完就老化,而问题记录会随着真实处理不断追加。
为什么不直接保存所有聊天记录
保存所有聊天记录当然有用,但它不是最好的长期记忆形式。
原始对话有几个问题:
- 太长
- 噪声多
- 包含很多中途尝试
- 有些结论后来被推翻
- 加载慢
- 换平台或扩展版本时容易出问题
所以更合理的做法是:聊天记录可以备份,但长期记忆应该提炼成问题记录。
也就是说,真正要留下来的不是“我们聊过的每一句话”,而是:
- 当时的问题是什么
- 做出判断的依据是什么
- 哪个方案有效
- 哪个方案无效
- 当前项目应该继续沿用哪个结论
这就是外挂记忆库和聊天归档的区别。
聊天归档像录像,外挂记忆库像项目病例本。
录像可以留,但医生真正复诊时最需要的是病例本。
它不是万能的
这套系统也有边界。
第一,它不能替代当前运行态检查。历史记录说某个服务以前占用了声卡,不代表今天仍然占用。Codex 还是要查当前进程、当前配置、当前日志。
第二,向量检索只能提示相似,不代表结论正确。尤其是硬件、路径、版本号、线程 ID 这类精确信息,必须回看 Markdown 原文和当前环境。
第三,日志质量决定记忆质量。如果每次只写“修好了”,那检索出来也没用。真正有价值的记录要包含判断、失败尝试、验证方式和边界条件。
第四,外挂记忆库不能消灭人的判断。它能让 Codex 更快进入状态,但不能保证每次历史经验都适合当前场景。
所以这套系统的正确定位是:
它不是自动驾驶,而是给 Codex 配了一套项目级导航和行车记录仪。
最有价值的变化
这套外挂记忆库真正改变的,不是多了一个数据库文件,而是改变了协作节奏。
以前遇到问题时,AI 很容易从当前现象出发,直接给一个看似合理的方案。
现在它会先问自己:
这个项目以前有没有遇到过类似问题?
当时是什么硬件和服务状态?
当时怎么修的?
那个修法后来有没有被推翻?
这次和上次有什么不同?
这会明显减少“越改越差”的概率。
尤其在这个机器人音频项目里,很多问题不是单点问题,而是系统耦合:
- 播放缓冲会影响 AEC 参考延迟
- DTLN 路线会改变启动期表现
- PulseAudio / PipeWire 会影响 ALSA 直通
- Codex 会话瘦身会影响远端加载体验
- VSCode 扩展版本会影响 Webview 能不能打开
没有外置记忆时,这些联系很容易散掉。
有了外挂记忆库以后,Codex 不是只看眼前一帧,而是能带着项目历史一起工作。
一句话总结
这套外挂记忆库的核心不是“给 Codex 多塞一点资料”,而是把项目经验变成可检索、可审计、可迁移、可持续积累的长期记忆。
它的优点可以概括成一句话:
Markdown 保真,SQLite 管理,FTS 精确命中,向量负责想起来,Skill 负责让 Codex 真的用起来。
这就是我现在更喜欢的智能体记忆方式。
不是让 AI 假装永远不会忘,而是给它一个可靠的地方,把重要的事情重新找回来。
更多推荐



所有评论(0)