关于 spomory
Spomory 是一个 MCP 服务,可在不同 AI 客户端和会话间共享持久记忆。它以图结构检索和管理记忆,并提供保存、查找、查看及删除事实的工具。
主要功能
- 01跨客户端和会话共享记忆
- 02增量更新知识图谱
- 03基于图的多跳检索
- 04添加、更新、删除或跳过事实
- 05查看并导出记忆图谱
- 06本地或托管部署
适用场景
- 01跨客户端会话回忆项目细节
- 02在不同客户端复用个人偏好
- 03查看记忆图谱中的关联事实
- 04导出或删除已存记忆
MCP 相关
Spomory 通过 MCP 工具提供记忆操作,包括添加、搜索、删除、查看和导出信息。它既可本地运行,也可作为托管服务运行。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://api.yliuai.com/mcpclaude mcp add --transport http lyf-wxy-spomory https://api.yliuai.com/mcp{"mcpServers":{"lyf-wxy-spomory":{"type":"http","url":"https://api.yliuai.com/mcp"}}}在 Cursor 中打开{"servers":{"lyf-wxy-spomory":{"type":"http","url":"https://api.yliuai.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"lyf-wxy-spomory":{"type":"http","url":"https://api.yliuai.com/mcp"}}}{"mcpServers":{"lyf-wxy-spomory":{"serverUrl":"https://api.yliuai.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
https://api.yliuai.com/mcphttps://api.yliuai.com/mcp-apikey需要授权工具
详细介绍
Spomory
English | 中文
Spomory 为 AI 客户端提供可跨会话持久保存的记忆,并在所有客户端之间共享。只需告诉其中一个客户端一次(例如项目细节、偏好或个人情况),之后任何客户端都能将其回忆起来,无需你重复说明。它是一个 MCP 服务,因此兼容所有 MCP 的客户端:Claude Desktop、Cursor、Codex CLI 和豆包均已通过真实客户端会话完成端到端验证(请参阅下文“它能做什么”);**ModelScope、Coze 和阿里云百炼(Alibaba Cloud Bailian)**也已知兼容,连接方式与其他远程 MCP 客户端相同(使用 Streamable HTTP;百炼目前尚不支持 Streamable HTTP,因此需使用 SSE)。
它以 MCP 服务的形式运行,可在你自己的设备上本地运行(免费,数据不会离开你的电脑),也可作为托管云服务运行(免费注册,记忆可在不同设备间同步)——上述每个客户端都支持这两种方式。本 README 其余部分将介绍本地使用方式(下文“开始使用”介绍的就是这种方式);开始使用云服务最快捷的方式是访问 Web 应用
spomory.yliuai.com/get-started/remote。
每个客户端各自的本地/云端配置详见
docs/mcp_quickstart.en.md(按客户端分节——Claude Desktop/Cursor/Codex CLI/豆包——每节均介绍两种连接方式)。
想先了解它的实际功能,再决定是否安装?无需注册即可在 spomory.yliuai.com体验演示——粘贴一些文本,看看它如何将文本转换为结构化事实。这些事实之后会在你连接的 Claude、Cursor、Codex CLI 及其他所有客户端间同步,并跨会话持久保存,而不是每次重置。
开始使用
需要 Python 3.11+。
1. 安装。 也可以完全跳过这一步——第 3 步的配置可以直接指向 uvx,它会按需获取并运行,无需预先安装:
pip install "spomory[llm,embedding,mcp]"
2. 为它提供一个大模型。 Spomory 使用大模型将你告诉它的内容转换为结构化事实。任何兼容 OpenAI 的 API 都可以——OpenAI、DeepSeek、Qwen 等:
export LLM_API_KEY=sk-...
export LLM_BASE_URL=https://api.deepseek.com # optional, defaults to OpenAI
export LLM_MODEL=deepseek-chat # optional, defaults to gpt-4o-mini
3. 将它连接到你的客户端。 Claude Desktop、Cursor 和 Codex CLI 都需要在配置文件中添加几行,指向 spomory-mcp 命令。具体步骤、每个客户端的配置文件示例,以及我们遇到的一个实际问题(macOS 会阻止运行位于 ~/Documents 下的虚拟环境),请参阅
docs/mcp_quickstart.en.md。
没有配置文件的客户端——Doubao(豆包)、Coze、ModelScope——则通过可点击操作的“自定义连接器”表单连接(URL + 请求头,或用于本地进程的命令 + 参数 + 环境变量);请参阅同一文档中的 Doubao 部分 (现在每个客户端——Claude Desktop、Cursor、Codex CLI、Doubao——都有独立的部分,并在其下按 STDIO/HTTP/OAuth 分类)。
最容易让人踩坑的一点:配置中需要填写
spomory-mcp的绝对路径(运行which spomory-mcp即可查找)——客户端启动它时不一定会设置你的 shell 的PATH。如果command使用uvx,这个问题(以及第 1 步)就都不复存在——具体 JSON 请参阅快速入门指南。
就是这样。默认情况下,数据存储在本地的 ~/.memory-core/(可通过 MEMORY_CORE_DATA_DIR 覆盖)。此外还提供了一个 Dockerfile,适用于从容器镜像部署的 MCP 目录/主机。
连接后还值得立即做两件事:将 skill/spomory/SKILL.md 复制到客户端的技能目录,让它实际调用这些工具,而不是闲置在那里;如果你已经在使用 Claude Code、Codex 或 Cursor,还可以运行 spomory-import-sessions --client claude-code(或 codex/cursor),从真实的会话历史中初始化图谱,而不是从零开始。这两项内容都在快速入门指南中介绍。
想让大模型调用也在本地运行,而不是使用云 API?将 LLM_BASE_URL 指向任意本地 OpenAI 兼容服务端——vLLM、Ollama、llama.cpp 或 MLX 都可以——并设置 EMBEDDING_PROVIDER=openai_compatible,以相同方式处理嵌入,而不是使用本地的 sentence-transformers 模型,从而完全移除 torch 依赖。详情和各引擎的示例请参阅
docs/mcp_quickstart.en.md。
功能介绍
连接后,客户端中即可使用六种工具:
| 工具 | 功能 |
|---|---|
add_memory | 记住你告诉它的内容 |
search_memory | 回忆与问题相关的内容 |
forget_memory | 删除与你要求遗忘的内容最匹配的一项 |
forget_all_memory | 一次调用即可清除整个记忆图谱 |
get_graph | 显示某项内容周围的记忆图谱,供检查 |
export_memory | 将你存储的所有内容导出为 JSON——数据可移植 |
这六种工具都已通过真实的 Claude Desktop、Cursor、Codex CLI 和 Doubao 会话完成端到端验证,涵盖本地和远程场景——各客户端的“验证”具体含义请参阅
docs/mcp_quickstart.en.md。
工作原理(供好奇者了解)
使用 Spomory 并不需要了解以下内容——这里是为想知道底层实际运作方式的人准备的。
- 可插拔的大模型 / 嵌入提供方:默认使用任何兼容 OpenAI 的 API(包括中国市场的大模型提供方)+ 本地
sentence-transformers(默认使用bge-m3,支持中英双语)。 - 双层增量知识图谱:实体和关系作为独立层建模;新数据只会被提取并合并进来,
不会全量重建。完全匹配的填充性输入(“thanks”“好的”“ok”……)会在到达提取大模型调用前被跳过,
因为其中不可能包含可提取的事实——这对于任何未经身份验证的端点都是相关的成本保护措施。默认使用本地
LocalGraphStore(networkx + SQLite);此外还有PostgresGraphStore云端实现,两者共用同一套行为契约测试。 - HippoRAG 2 风格的检索:查询会直接与三元组匹配,而不只是与实体节点匹配;匹配到的种子节点 会通过个性化 PageRank 进行扩散,以实现多跳关联,随后组装成自然语言上下文(包含来源时间戳,因此可以回答 “我什么时候提到过 X”)。此外,排序会随着某条关系越来越久未被检索而降低其相关性;同一事实被重述的 次数越多,相关性就会相应提升(采用对数阻尼,因此不会压过 PPR 排名)——这是下方主动执行的 ADD/UPDATE/DELETE/NOOP 决策之外的一种被动信号。
- 记忆管理:包含 ADD/UPDATE/DELETE/NOOP 操作空间,以及基于规则的默认策略(
RuleBasedPolicy)和完整的 GRPO 训练 流程(memory_manager/train_grpo.py,已在真实 GPU 上实际运行并验证)。 - 记忆护照导出 + 彻底删除:JSON-LD 风格的导出格式、物理删除和审计日志。
- 多模态图像验证:图像描述 → 复用文本提取流程 → CLIP 交叉核验候选三元组。准确来说,这是“验证”, 而非“原生跨模态提取”。
- 云端框架:FastAPI 用户身份验证/API 密钥/配额,以及 Stripe webhook 计费脚手架(仅为框架级别,尚未部署到生产环境)。
测量结果
使用 DeepSeek 对 LoCoMo-10(conv-26,前 150 轮)中的 84 组问答进行真实运行——没有挑选有利样本,目前还无法与更大型项目已发布的结果相媲美:
| 指标 | 值 |
|---|---|
| Recall@10(正确的证据轮次是否进入上下文) | 52.4% |
| 准确率 — 严格子字符串匹配 | 19.0% |
| 准确率 — LLM 评判(标准较宽松,容忍措辞差异) | 44.0% |
此前的一次运行(在修复将日期合并到提取出的谓词中、使“何时”类问题能够回答之前)准确率较低,但召回率较高(62.0%)——这项修复牺牲了一些检索召回率,换来了实际 +14.3 个百分点的准确率提升;我们还进一步查明了具体原因,而不只是报告准确率:日期合并指令有时会误用于没有实际内容的闲聊(“Thanks!” → “thanked on 2023-07-03”),这些低价值三元组会挤占固定的 top-10 检索窗口,让相关三元组无法进入。完整数据、分类别细分结果,以及用于发现这一问题的提取结果并排比较,见 docs/benchmark_smoke_test.md。
LongMemEval(xiaowu0162/longmemeval-cleaned 的 oracle 变体,500 个问题中的前 10 个):
| 指标 | 值 |
|---|---|
| Recall@10 | 100%(10/10) |
| 准确率 — 严格子字符串匹配 | 30% |
| 准确率 — LLM 评判 | 80% |
这里的局限性与数据本身同样重要:
- 仅 10 个问题,并非完整的 500 个——每个问题平均会导入约 27 轮对话(约 27 次实际提取调用,加上一次生成调用和一次评判调用);此环境中的 LLM API 调用需要经过代理,实际延迟较高;完整数据集需要数十小时才能跑完。这是真实运行,并非模拟,但样本量很小,不应将结果视为可推广到完整数据集。
- 这 10 个问题恰好全都是
temporal-reasoning类型——数据集还包含multi-session类型;load_longmemeval(limit=10)按文件顺序取前 10 条,没有进行分层抽样,因此该样本并不代表整个数据集。 - Recall@10 = 100% 很大程度上是 oracle 变体设计造成的结果,并不能有力证明检索能力——oracle 变体会预先筛选每个问题的候选内容,只保留相关会话(没有干扰会话),这比真实部署中的记忆存储(包含数百或数千条无关对话轮次)容易得多。这与完整的(非 oracle)LongMemEval 基准测试并非同一任务,不应直接与其他产品在难度更高的变体上报告的数据进行比较。
- 严格匹配准确率(30%)远低于 LLM 评判准确率(80%),与 LoCoMo 结果中观察到的模式一致——子字符串匹配会系统性地低估内容正确但措辞不同的答案。
原始数据:
benchmarks/results/longmemeval_oracle_subset.json;
运行脚本为
benchmarks/run_longmemeval_subset.py。
贡献者指南:从源代码构建
以下内容适用于希望深入研究内部实现、运行测试套件,或使用 MCP 服务运行所需依赖组之外的其他依赖组(GPU 训练、云 API 骨架、多模态验证)的贡献者。如果你只想使用 Spomory,则无需了解这些内容——请参阅上文的“开始使用”。
项目结构
src/
├── memory_core/
│ ├── graph/ # entity/relation models, storage adapters (local SQLite / cloud Postgres), incremental writes
│ ├── retrieval/ # query→triple matching, personalized PageRank, context assembly
│ ├── memory_manager/ # action space, reward functions, GRPO training script, policy inference
│ ├── multimodal/ # image captioning + CLIP verification
│ ├── mcp_server/ # MCP Server (the distribution entry point)
│ ├── export/ # memory passport export format + true delete
│ ├── llm/ # pluggable LLM/embedding providers
│ ├── audit.py # deletion audit log
│ └── usage.py # retention/usage tracking
└── cloud_api/ # FastAPI cloud service skeleton (auth, quotas, billing)
benchmarks/ # LoCoMo/LongMemEval evaluation harness + multimodal comparison experiments
tests/ # 94+ tests, from unit tests to real LLM/GPU/Postgres end-to-end verification
docs/ # per-epic design notes, verification reports, runbooks (see index below)
设置开发环境
前置条件:Python 3.11+、uv
(没有 uv?可以用 python -m venv + pip install -e 替代下面的
uv 命令)。
git clone <this repo's URL> memory-core && cd memory-core
uv venv --python 3.11 .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Pick dependency groups as needed — they can be combined, no need to install everything:
uv pip install -e ".[dev]" # required to run tests/lint
uv pip install -e ".[llm,embedding]" # required for the "minimal working memory system" (see the demo below)
uv pip install -e ".[mcp]" # extra: connecting to Claude Desktop/Cursor
uv pip install -e ".[rl]" # extra: GRPO training (requires a GPU + CUDA)
uv pip install -e ".[cloud]" # extra: cloud API / Postgres backend
uv pip install -e ".[multimodal]" # extra: image + CLIP verification
embedding 依赖组会在首次使用时从 HuggingFace 下载默认模型 BAAI/bge-m3
(约 2.2GB)——请确保可以访问 huggingface.co
(如果你位于 Great Firewall 后方,运行 export HF_ENDPOINT=https://hf-mirror.com
即可通过镜像访问)。你也可以通过 export EMBEDDING_MODEL=<any sentence-transformers model name>
换用更小的模型。
运行最简示例(不使用 MCP,直接调用 Python)
安装 dev + llm + embedding,并设置好“开始使用”中的三个环境变量后,这个脚本会直接运行完整的“写入记忆 →
检索记忆”流程(逻辑与 mcp_server/server.py 中的 add_memory/search_memory
工具相同,只是直接调用库,而不是通过 MCP 协议层):
# demo.py
from memory_core.graph.local_store import LocalGraphStore
from memory_core.graph.incremental import IncrementalIngestor
from memory_core.llm.openai_compatible import OpenAICompatibleProvider
from memory_core.llm.local_sentence_transformer import SentenceTransformerProvider
from memory_core.memory_manager.policy import RuleBasedPolicy
from memory_core.retrieval.ppr import personalized_pagerank, rank_entities
from memory_core.retrieval.query_match import match_query_to_triples
from memory_core.retrieval.ranker import build_context
store = LocalGraphStore("demo.sqlite3") # a local file; delete it to reset
llm = OpenAICompatibleProvider() # reads LLM_API_KEY etc. from the environment
embedder = SentenceTransformerProvider() # downloads bge-m3 on first run
# 1. Write a memory: the LLM extracts triples, incrementally merged into the graph
ingestor = IncrementalIngestor(store, llm, policy=RuleBasedPolicy())
result = ingestor.ingest("I do AI research at CAS, mostly in Python.", source_id="demo")
print(f"added {result.new_entities} entities, {result.new_relations} relations")
# 2. Retrieve: match the query against triples -> PPR diffusion -> assemble a natural-language context
query = "Where do I work?"
entities, relations = store.all_entities(), store.all_relations()
entities_by_id = {e.id: e for e in entities}
matches = match_query_to_triples(query, relations, entities_by_id, embedder, top_k=10)
seed_ids = {r.relation.subject_id for r in matches} | {r.relation.object_id for r in matches}
scores = personalized_pagerank(entities, relations, seed_entity_ids=list(seed_ids))
ranked_ids = [eid for eid, _ in rank_entities(scores)]
print(build_context(relations, entities_by_id, ranked_ids, top_k=10))
python demo.py
以下是使用 DeepSeek 进行实时运行的实际输出,输入内容与上方完全一致(并非编造,也未清理——这是实际返回的内容):
added 3 entities, 2 relations
I do AI research at CAS (recorded at 2026-09-05 10:40:00).I do AI research mostly in Python (recorded at 2026-09-05 10:40:00).
具体措辞以及实体/关系数量取决于大模型自身的提取结果,并会因运行而异;但只要环境变量设置正确,非空输出就表示整个流程端到端正常运行。
retrieval/ranker.py 会检测关系文本是中文还是其他语言,并相应地渲染(中文不加空格 + 中文时间戳标签,其他语言使用空格分隔单词 + 英文时间戳标签),因此,英文输入不再像这个演示的早期版本那样,输出为一整串连在一起的单词。
测试
pytest # everything
pytest -m "not slow" # skip tests that download models / train — runs in seconds
大多数“耗时较长”的测试都没有使用模拟对象——它们会进行真实调用(真实的大模型 API、真实的本地嵌入模型、真实的 CLIP 模型),因此需要设置相应的环境变量(LLM_API_KEY 等)或已有已下载的模型缓存。
文档索引
| 文档 | 内容 |
|---|---|
| mcp_quickstart.en.md (中文) | MCP 服务安装、配置、连接 Claude Desktop/Cursor/Codex CLI/Doubao,以及实际使用中的注意事项 |
| graph_store_interface.en.md (中文) | 存储适配器接口设计 |
| export_format.en.md (中文) | “记忆护照”导出格式 |
| dataset_format.en.md (中文) | GRPO 训练数据格式,以及真实数据集的生成方式 |
| methodology.en.md (中文) | 技术方法:已验证的内容与仍待验证的内容 |
| benchmark_smoke_test.en.md (中文) | LoCoMo 基准测试的真实结果及失败案例分析 |
| memory_manager_eval.en.md (中文) | 基于规则与经过 GRPO 训练的策略对比,包括调试过程 |
| multimodal_verification.en.md (中文) | 图像 + CLIP 验证实验结果 |
| gpu_training_runbook.en.md (中文) | GPU 训练环境设置记录(包括实际遇到的问题) |
| postgres_setup.en.md (中文) | 云 Postgres 后端部署记录 |
| leaderboard_submission.en.md (中文) | 第三方排行榜调研 |
| mvp_scope.en.md (中文) | MVP 范围定义 |
| privacy_policy_draft.en.md (中文) / product_copy_memory_passport.en.md (中文) | 隐私政策草案 / 面向外部的产品文案 |
| eng_note_cjk_rendering_bug.en.md (中文) | 工程说明:CJK 渲染错误的实际发现→修复→验证过程 |
以上每篇文档现在都有中文版和英文版。
已知限制
- 语音输入的多模态验证(ASR + 音频嵌入)尚未实现。
- GRPO 训练数据集(140 个真实样本)和训练步数仍然较少;
memory_manager_eval.md如实记录了这些因素对训练效果的限制。 - 云 API/计费功能目前仅有基础框架,尚未接入真实的生产环境。
许可证
请参阅 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。