memoLite 架构解析:SQLite、Kùzu 与向量检索如何组成 Agent 的本地记忆
从一条对话的写入与召回出发,拆解 memoLite 如何用 SQLite 保存事实源、Kùzu 维护 Episode/Derivative 关系、Embedding 与 SQLite 向量表完成检索,并通过 REST、MCP 和 OpenClaw 把本地记忆接回 Agent。
AI Agent 最直观的问题,是它只认识当前上下文。关闭会话、切换工具或超过上下文窗口后,之前说过的偏好、项目约束和历史事件就很难继续使用。
memoLite 的做法不是修改模型,而是在 Agent 外部增加一个本地记忆层:对话结束后保存原始事件并建立检索索引;下一轮开始前先找回相关内容,再把它作为上下文交给模型。
项目的简要介绍已经放在 MemoLite。这篇文章重点拆解它的框架能力和数据流。
整体架构
memoLite 是一个运行在本机的单机服务。上层可以通过 REST、MCP、Python SDK、TypeScript Client 或 OpenClaw 插件访问;中间由 MemoryOrchestrator 统一编排;底层分别使用 SQLite、Kùzu 和向量索引承担不同职责。
这套架构最重要的原则是:SQLite 保存真相,Kùzu 和向量索引保存可以重建的投影。
三种记忆解决不同问题
| 记忆类型 | 保存内容 | 主要用途 |
|---|---|---|
| Short-term | 当前会话的消息窗口与摘要 | 维持眼前对话连续性 |
| Episodic | 用户和 Agent 实际发生过的消息、事件、工具结果 | 回答“以前发生过什么” |
| Semantic | 从历史中提炼出的事实、偏好、分类和标签 | 回答“当前已知事实是什么” |
Episodic 和 Semantic 不是两份互不相关的数据。SemanticFeature 可以通过 citation 指回原始 Episode,因此系统既能快速返回“用户喜欢拉面”,也能解释这条事实来自哪次对话。
SQLite:保存原文和事务状态
默认情况下,memoLite 的主要数据都位于本机的 ~/.memolite/memolite.sqlite3。SQLite 保存:
- project 和 session 的归属信息;
- 原始 Episode 内容、角色、顺序号和元数据;
- SemanticFeature、配置以及 citation;
- 待处理的 semantic ingestion 状态;
- Short-term summary;
- Derivative 和 SemanticFeature 对应的向量 BLOB。
一次事件写入会先提交 SQLite,再生成后续投影。这样即使进程在 Kùzu 或向量写入过程中退出,原始 Episode 仍然存在,可以重新生成派生数据。
Embedding:把文字变成可以比较的数字
Embedding 不负责保存记忆,它只负责把文字编码成固定长度的数字数组。例如:
我最喜欢吃拉面
↓ embedding
[0.12, -0.08, 0.31, ...]写入时为记忆生成向量,查询时为用户问题生成向量。二者使用同一个 Embedder,才可以计算余弦相似度。
memoLite 默认使用 64 维 HashEmbedder:不需要下载模型,速度快,适合本地启动和词语重合检索。需要更真实的语义能力时,可以安装 embeddings 扩展并切换到 Sentence Transformers;向量维度由具体模型在运行时返回。检索结果还可以交给本地 CrossEncoder 重新排序。
sqlite-vec 兼容层:向量仍然在 SQLite 文件里
这个项目没有额外部署 Milvus、Qdrant 或 Pinecone。两类向量分别放在普通 SQLite 表中:
CREATE TABLE derivative_feature_vectors (
feature_id INTEGER PRIMARY KEY,
embedding BLOB NOT NULL
);
CREATE TABLE semantic_feature_vectors (
feature_id INTEGER PRIMARY KEY,
embedding BLOB NOT NULL
);Python 的 float 数组会被打包成二进制 BLOB。表结构本身不声明维度,因此更换 Embedding 模型后必须重建向量;查询向量和存量向量维度不一致时,两者无法比较。
项目把这一层封装成 SqliteVecIndex。按当前实现,它是 sqlite-vec 的兼容层:先用 SQL 读取允许参与搜索的向量,再由 Python 计算余弦相似度并选出 Top-K。也就是说,它具备本地向量存储和检索能力,但当前并没有使用独立向量数据库,也没有把近邻计算交给原生 sqlite-vec 虚拟表。
Kùzu:把命中片段带回原始事件
长消息不适合直接作为一个检索单元。DerivativePipeline 会按句子和换行把 Episode 切成更小的 Derivative:
Episode E1
├── Derivative D1
├── Derivative D2
└── Derivative D3每个 Derivative 都会生成向量。Kùzu 保存 Episode、Derivative 以及下面这条关系:
(Derivative D1)-[:DERIVED_FROM]->(Episode E1)向量搜索命中的是 D1,而用户真正需要的是完整事件 E1。系统先通过 Kùzu 找到 D1 的来源,再回到 SQLite 读取完整原文。Kùzu 在这里承担的是来源关系和回溯,不是向量计算,也不是原始内容的最终存储。
一条记忆如何写进去
以用户说“我最喜欢吃拉面”为例:
最终得到三组相互关联的数据:
- SQLite 中有完整 Episode 和结构化 SemanticFeature;
- SQLite 向量表中有 Derivative 与 SemanticFeature 的 embedding;
- Kùzu 中有 Derivative 到 Episode 的 DERIVED_FROM 关系。
下一轮如何把记忆找回来
当用户问“我喜欢吃什么”时,查询链路分为 Episodic 和 Semantic 两支。
Episodic 检索
- 将问题转换为 Query Embedding。
- 在 Kùzu 中按
session_id找出允许搜索的 Derivative。 - 如果传入角色或事件类型,再通过 SQLite 缩小 Episode 范围。
- 将这些 Derivative 转成 allowed item IDs。
- 只对允许范围内的向量计算相似度。
- 通过 Kùzu 的 DERIVED_FROM 找回 Episode ID。
- 从 SQLite 读取完整 Episode,并按 sequence number 补充前后对话。
- 可选用 CrossEncoder 重排候选。
Semantic 检索
- 先在 SQLite 中按
set_id、category、tag 和 deleted 状态过滤事实。 - 得到允许参与搜索的 SemanticFeature IDs。
- 只在这些向量中计算相似度。
- 按
min_score去掉低相关结果。 - 返回最多
limit条 Feature。
因此范围限制发生在向量计算之前,而不只是搜索后再做过滤:
session_id / set_id / role / category
↓
allowed_item_ids
↓
cosine similarity
↓
min_score + limitOrchestrator 最后把 Short-term、Episodic 和 Semantic 结果合并。OpenClaw 插件在 before_agent_start 阶段把它们放进 <relevant-memories>,模型因此能在新一轮对话中使用过去的信息;成功运行结束后,agent_end 又会捕获新的消息,形成下一次召回的输入。
接入方式
| 接口 | 用途 |
|---|---|
| REST / FastAPI | 项目、会话、记忆、语义配置、健康检查与指标 |
| MCP stdio / HTTP | 让 Codex、Claude 等 Agent 主动调用 add/search/list/delete memory |
| Python SDK | Python 应用以类型化客户端接入 REST 服务 |
| TypeScript Client | Node.js 和前端工具接入 |
| OpenClaw Plugin | 提供自动捕获、自动召回和 memory_* 工具 |
本地启动后,可以直接执行一次混合搜索:
curl -X POST http://127.0.0.1:18731/memories/search \
-H 'content-type: application/json' \
-d '{
"query": "我喜欢吃什么",
"session_id": "session-a",
"semantic_set_id": "user-1",
"mode": "mixed",
"limit": 5,
"min_score": 0.5
}'删除、对账与重建
同时写 SQLite、Kùzu 和向量表意味着一次操作可能只完成一部分。memoLite 将 SQLite Episode 视为恢复锚点,并提供 reconcile、repair、export、import 和 rebuild 工具。
删除 Episode 时,系统先在 SQLite 中标记删除,再通过 Kùzu 找出相关 Derivative,删除对应向量和图节点,同时清理 Semantic citation;如果某个 SemanticFeature 已经没有其他来源,也可以继续清理。
修复时则反过来:读取 SQLite 中仍然有效的 Episode,重新切片、生成 embedding,并重建 Kùzu 节点、关系和 Derivative 向量。这种“主数据 + 可重建投影”的设计,比要求三个存储永远同时成功更适合本地服务。
框架的能力边界
- 它是本地优先、单机运行的记忆基础设施,不是分布式记忆集群。
- 默认 HashEmbedder 更偏轻量词语匹配,真实语义质量取决于选用的 Embedding 模型。
- 当前向量层是 SQLite BLOB 加 Python 相似度计算,适合轻量数据集,不等同于大规模 ANN 向量数据库。
- Kùzu 当前主要保存 Episode 与 Derivative 的来源关系,没有替代 SQLite 的事务数据。
- MCP 提供记忆工具,但自动捕获和自动召回需要宿主生命周期钩子;OpenClaw 插件已经实现这层衔接。
总结
memoLite 的框架价值,不是简单地把 SQLite、Kùzu 和 Embedding 放在一起,而是明确了每一层的数据职责:
SQLite:保存事实和事务状态
Embedding:把文字转换为可比较向量
SQLite 向量表:保存向量并提供本地相似度检索
Kùzu:保存 Derivative 到 Episode 的来源关系
Orchestrator:连接写入、召回、删除和恢复
Agent 插件:在正确的生命周期自动捕获与注入当一条消息能够被保存、索引、召回、追溯、删除并在故障后重建,本地记忆才真正形成闭环。
源码索引
- MemoryOrchestratorMemoLite/src/memolite/orchestrator/memory_orchestrator.py at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.
- DerivativePipelineMemoLite/src/memolite/episodic/derivative_pipeline.py at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.
- EpisodicSearchServiceMemoLite/src/memolite/episodic/search.py at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.
- SqliteVecIndexMemoLite/src/memolite/storage/sqlite_vec.py at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.
- KuzuGraphStoreMemoLite/src/memolite/storage/graph_store.py at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.
- OpenClaw PluginMemoLite/integrations/openclaw/src/index.ts at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.
- Migration and RepairMemoLite/src/memolite/tools/migration.py at e56211913e53af9cc318ba6c9a0a152c094697cf · shaun17/MemoLite。GitHub。Contribute to shaun17/MemoLite development by creating an account on GitHub.