给 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

还有 semantichybrid-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 假装永远不会忘,而是给它一个可靠的地方,把重要的事情重新找回来。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐