用SQLite构建本地优先的统一记忆库,让Claude Code、Cursor、Windsurf等23+ AI客户端共享同一记忆数据库。
我平时用 Claude Code 写代码,用 Cursor 做重构,用 Windsurf 做探索。每款工具都有自己独立的记忆。换一款工具,AI 就把之前的事忘得一干二净。
于是我打造了 MemTether——一个本地优先的记忆中心,让 23+ 款 AI 客户端共享同一个物理 SQLite 数据库。
以下是打造它的一些心得。
现有的记忆方案(mem0、cognee、zep)都把记忆当作一种服务来对待。你把记忆发送给它们的云 API,由它们负责存储和检索。这套机制能用,但意味着:
你的记忆存在别人的服务器上
哪怕只是一个本地项目,也需要 API key
你无法直接查看原始数据
我的洞察:如果所有 AI 工具都跑在同一台机器上,你根本不需要什么服务——你只需要一个文件。让它们都指向同一个 SQLite 数据库就够了。
不上云。不收 API 费。没有抽象层。一个 memory.db,23 个客户端读写。
当一条记忆需要更新时,我不会删除旧的那条,而是将它标记为"已覆写"(superseded),再创建一条新版本。这样你随时可以追溯"在学到 X 之前,我们原来相信什么?"
这听起来简单,但它改变了整个系统的工作方式。搜索必须过滤掉已覆写的条目。FTS5 需要触发器来自动同步。投影系统需要优先选用最新版本。
每条记忆有两个时间戳:
T(有效时间):该事实在世界真实成立的时间
T'(记录时间):系统得知该事实的时间
举例:某个 API key 在 9 月 15 日过期,但我到 9 月 18 日才发现。查询"9 月 15 日时我们知道什么?"返回"key 仍然有效"(这是系统当时的认知)。查询"当时实际发生了什么?"返回"已过期"。
没有这个区分,就会出现"回溯性真相偏差"——用今天的知识去评判昨天的决策。
大多数记忆系统的排序依据是"新鲜度"或"语义相似度"。但一条 6 个月前、每天都被用到的记忆,价值显然高于昨天创建却从未被检索过的记忆。
所以我引入了 Q-Value(借鉴自强化学习):每当一条记忆被搜索且确实有用时,它的 Q-Value 就增加。下一次搜索时,它排名就更高。简单、有效,目前没有别人这么做。
原始的语义相似度远远不够。我混合了四个因子:
语义相似度(45%)
类型重要性(10%)
……然后用 z-score + sigmoid 归一化,再以 70/30 与 RRF 分数混合。这修复了纯语义搜索会漏掉的资产查询。
我的第一版是用 Python 代码同步 FTS5 全文索引。代码里到处是 except Exception: pass 包裹着同步调用。结果:254 条过期条目 + 260 条缺失条目。
解决方案:SQLite 触发器。三个触发器(INSERT、DELETE、UPDATE)在 SQL 层面处理。Python 代码无法意外跳过它们。不一致条目数从 514 降到了零。
经验:如果 SQLite 能在 SQL 层面搞定,就别在 Python 里做。
写记忆引擎花了 3 周。让它能正常安装花了 2 个月:
用 wheel 构建时配置正确的 py-modules(扁平布局,不是包)
写 check_packaging.py 检测版本漂移和缺失模块
FTS5 触发器放在正确位置(在 init_db 内部,不要放在 schema 字符串里飘着)
Console 入口点(memtether、memtether-connect)
可选依赖([vector] 对应 chromadb,[server] 对应 fastapi)
一个真正能跑的 Quick Start(我最初写的命令根本不存在)
我是一个人在开发。花在打包上的每一小时,就是没有花在功能上的一小时。但没有打包,功能再好也没人用得了。
我跑了 LongMemEval(500 道题,全量运行):
多会话差距(strict vs judge)是最有趣的发现。当答案需要从多个数据点计算出来时(比如"3 weeks"),严格的子串匹配就会失败,因为计算出的答案不会逐字出现在任何单条记忆里。LLM judge 更宽容一些。
我还实现了一种 E-Hybrid 方法(会话摘要 + 扁平证据),在 15 道题的测试上将多会话 strict 从 48.8% 提升到了 71.4%。样本量小,但有希望。
我不会声称这比 mem0 的 94.4% 更好——不同的测试框架,不同的方法论。但 48.8% strict 已经超过了行业平均水平 27.9%。
MCP Registry 提交(已完成:PR #4946)
社区建设(这篇博客就是其中一部分)
NLPCC 2027 论文提交(CCF C,截稿日期约 2027 年 4 月)
更多示例和更完善的文档
pip install memtether
memtether init
memtether connect --all
GitHub: MemTether/MemTether PyPI: memtether