mem8
mem8 是面向 AI Agent 的本地、持久化长期记忆 Python 库。Markdown 是记忆内容的真实源,数据库负责元数据、全文检索和向量索引。它支持从对话中提取记忆,也支持接收外部 LLM 已总结好的知识,并通过 BM25、向量检索和 RRF 融合返回相关记忆。
mem8 对外提供稳定、通用的消息与知识模型,核心能力覆盖记忆提取、决策、持久化、检索和维护,各模块通过明确接口协作。
主要能力
- Markdown 文件持久化,数据目录可复制、挂载和备份。
- SQLite、LanceDB、Chroma 三种本地数据库 Backend。
- BM25 + Vector + RRF 混合检索。
- 按 ID 或相对路径查询记忆卡片。
- 支持
text、thinking、tool_call、tool_result、attachment_text消息部件。 - 支持“从对话提取知识”和“直接写入已总结知识”两种更新模式。
- 支持幂等操作、乐观 generation 检查、只读打开和健康检查。
- 检查并修复 Markdown 记忆之间的链接。
环境要求
- Python 3.11 或更高版本。
- 默认 LLM 为 Anthropic,需要设置
ANTHROPIC_API_KEY。 - 至少安装一种 Embedding Provider:Local、OpenAI 或 Voyage。
- Local Embedding 首次运行可能需要下载模型。
当前内置 LLM 实现仅支持 Anthropic。openai extra 提供 OpenAI-compatible Embedding,不提供 OpenAI LLM。
安装
PyPI 分发名称为 mem8-fs,Python 包名仍为 mem8:
pip install mem8-fs
按需安装 Embedding Provider:
pip install "mem8-fs[local]"
pip install "mem8-fs[openai]"
pip install "mem8-fs[voyage]"
SQLite 是默认 Backend,不需要额外数据库依赖。其他 Backend 需安装对应 extra:
pip install "mem8-fs[lancedb]"
pip install "mem8-fs[chroma]"
pip install "mem8-fs[all-databases]"
源码开发环境:
uv sync --extra dev --extra evals --extra local
快速开始
初始化
mem8 init
默认记忆目录是当前工作目录下的 .mem8。也可以通过 CLI 的 --memory-root PATH 或 Python API 的 Memory.open(memory_root=...) 指定目录。
默认 SQLite 目录结构:
<memory_root>/
├── core/ # 只通过 inject_core_card 注入的核心记忆
├── notes/ # Agent 生成和维护的普通记忆
├── mem8.db # SQLite 元数据、FTS5 和向量索引
└── mem8.toml # 配置文件
core/ 和 notes/ 中的 Markdown 是记忆真实源,数据库保存可检查、可重建的索引与运行状态。
检索和查询
mem8 core inject ./seed.md
mem8 retrieve "context overflow" --topk 5 --similarity 0.55
mem8 query --card-id 1
mem8 query --path notes/context.md
更新记忆
从 JSONL 历史对话提取知识,再执行决策和写回:
mem8 update --messages messages.jsonl
{"role":"user","content":"I prefer concise answers."}
{"role":"assistant","content":"Understood."}
外部 LLM 已生成结构化知识时,可跳过提取阶段,直接复用去重、决策和写回链路:
mem8 update-knowledge --knowledge-file knowledges.json
[
{
"claim": "The user prefers concise answers.",
"scope": "communication preferences",
"evidence": ["Please keep answers concise."],
"confidence": 1.0,
"suggested_tags": ["preference", "style"]
}
]
检查和修复记忆链接:
mem8 check
记忆使用时机
以下是接入方可选择的读写时机,不要求每个节点都调用。Turn 指一次输入到响应完成的处理过程;Loop 指 Turn 内的一轮模型推理与后续工具执行(如有),一个 Turn 可以包含多个 Loop。
| 操作 | 时机 | 使用目的与建议 |
|---|---|---|
| 读 | Begin Turn(开始处理输入) | 根据当前请求检索相关历史事实、偏好和经验,为本轮处理提供上下文。 |
| 读 | Begin Loop(开始新一轮推理) | 当目标变化、出现疑问或需要新的背景信息时,按当前问题补充检索,避免每轮重复读取相同内容。 |
| 读 | Post Compact(上下文压缩后) | 按当前目标重新检索仍需使用的长期记忆,补充压缩后缺失的背景;不恢复全部历史对话。 |
| 写 | End Turn(本轮处理结束) | 将本轮已确认、值得跨轮复用的事实、偏好、结论或经验更新到记忆中。 |
| 写 | End Loop(一轮推理与工具执行结束) | 当获得可靠的新事实、纠正已有认知或形成阶段性结论时增量更新,不保存每一步临时推测。 |
| 写 | Pre Compact(上下文压缩前) | 在详细上下文被压缩前,筛选并保存尚未持久化且具有长期价值的信息。 |
| 写 | Dream(离线或周期性整理) | 由接入方组织历史对话或已总结知识,提取、整合并更新可复用记忆;不是重放全部工具操作。 |
- 读取复用
Memory.retrieve,需要展开相关卡片时使用Memory.query;检索结果由接入方放入模型上下文,mem8 不自动注入。 - 写入历史对话使用
Memory.update;已有结构化知识时使用Memory.update_from_knowledge,两者复用同一套决策与写回能力。 - 这些名称是通用生命周期时机,不表示特定 Agent SDK 一定提供对应 Hook。mem8 不内置 Agent Loop、压缩 Hook 或 Dream 调度器,触发和编排由接入方负责。
- 多个时机可能覆盖同一批信息,接入方应控制调用频率,并为同一更新的重试复用
operation_key;新的更新使用新的操作标识。压缩不等于任务结束,记忆写入也不等于完整工作状态备份。
数据库 Backend
选择建议
| Backend | 安装 | 向量存储 | 文本检索 | 适用场景 |
|---|---|---|---|---|
| SQLite | mem8-fs |
sqlite-vec | FTS5 | 默认、依赖最少、单机通用 |
| LanceDB | mem8-fs[lancedb] |
LanceDB | SQLite FTS5 | 本地列式向量存储、数据量增长场景 |
| Chroma | mem8-fs[chroma] |
Chroma | SQLite FTS5 | 已采用 Chroma 或偏好 Collection 模型的应用 |
三个 Backend 保持相同的 Memory API,并提供 hybrid_rrf 检索。当前 V2 为了最小改动和最大复用:
- SQLite 使用
mem8.db保存元数据、FTS5 与 sqlite-vec 向量索引。 - LanceDB/Chroma 保存向量索引,并复用
mem8-meta.db保存元数据、generation、操作回执和 FTS5 投影。 - Markdown 目录、写入约束、RRF 逻辑和上层服务不随 Backend 改变。
- Backend 不能通过修改配置原地切换;已有工作区切换前应显式迁移或重建索引。
LanceDB 目录:
<memory_root>/
├── core/
├── notes/
├── mem8.toml
├── mem8-meta.db
├── lancedb/
└── .mem8-backend.json
Chroma 目录:
<memory_root>/
├── core/
├── notes/
├── mem8.toml
├── mem8-meta.db
├── chroma/
└── .mem8-backend.json
TOML 配置
<memory_root>/mem8.toml:
[database]
provider = "lancedb" # sqlite | lancedb | chroma
path = "lancedb" # memory_root 内的相对路径
distance = "l2" # l2 | cosine
require_hybrid = true
collection = "mem8_cards"
SQLite 默认配置不需要写 [database]。database.path 不能是绝对路径,也不能通过 .. 越过 memory_root。
环境变量配置:
MEM8_DATABASE__PROVIDER=lancedb
MEM8_DATABASE__PATH=lancedb
MEM8_DATABASE__DISTANCE=l2
MEM8_DATABASE__REQUIRE_HYBRID=true
MEM8_DATABASE__COLLECTION=mem8_cards
其他常用变量:
MEM8_LLM__MODELMEM8_LLM__MAX_TOKENSMEM8_EMBEDDING__PROVIDERMEM8_EMBEDDING__MODELMEM8_EMBEDDING__DIMMEM8_STORAGE__DB_FILENAME
环境变量优先于 mem8.toml。LanceDB/Chroma 工作区的 Backend 标识文件会校验 provider、Embedding 维度和距离度量,避免用不兼容配置误开已有工作区。默认 SQLite 和历史工作区继续保持兼容,不强制要求该标识文件。
Python API
检索与对话更新
from mem8 import Memory
from mem8.domain.message import Message
with Memory.open(memory_root="/path/to/memory") as memory:
results = memory.retrieve("user preferences", topk=5, similarity=0.55)
card = memory.query(card_id=results[0].card_id) if results else None
report = memory.update([
Message(role="user", content="I prefer concise answers."),
Message(role="assistant", content="Understood."),
])
check_report = memory.check()
结构化消息
Message.content 继续兼容字符串,也支持厂商无关的结构化消息部件:
from mem8 import (
AttachmentTextPart,
Memory,
Message,
TextPart,
ThinkingPart,
ToolCallPart,
ToolResultPart,
)
messages = [Message(role="assistant", content=[
ThinkingPart(text="private reasoning"),
ToolCallPart(call_id="call-1", name="python_version"),
ToolResultPart(call_id="call-1", content="Python 3.12"),
AttachmentTextPart(
text="project requires Python 3.12",
filename="README.txt",
),
TextPart(text="The project uses Python 3.12."),
])]
with Memory.open() as memory:
memory.update(messages)
默认提取策略排除 thinking、tool_call 和失败的 tool_result;普通文本、成功的文本工具结果和附件提取文本可以作为证据。mem8 不接受二进制附件。
直接写入已总结知识
from mem8 import Knowledge, Memory
knowledges = [Knowledge(
claim="The user prefers concise answers.",
scope="communication preferences",
evidence=["Please keep answers concise."],
confidence=1.0,
suggested_tags=["preference", "style"],
)]
with Memory.open() as memory:
report = memory.update_from_knowledge(
knowledges,
operation_key="memory-intent:example-1",
expected_generation=memory.generation,
)
Memory.update(messages):由 mem8 调用 LLM 提取知识,适合历史对话和后续 dream 流程。Memory.update_from_knowledge(knowledges):接收外部 LLM 已总结的 1~10 条知识,跳过提取阶段。- 两种更新共享决策、写回、文件锁、操作回执和 generation 冲突检查。
- 只读工作区允许检索和查询,但拒绝所有更新操作。
可恢复更新(0.3.4)
两种更新 API 复用同一套 redo journal:先在隔离的元数据/文件视图完成一条知识的决策、卡片构建和 embedding,保存完整计划到 <memory_root>/.mem8-update.json,再写入 Markdown、metadata、关系、vector 和 FTS。计划包含稳定的卡片 ID、关系 ID、内容和向量,恢复不重复生成已准备好的内容。
批次按知识顺序推进,后续知识能检索此前已完成的结果;整个批次完成才提交 generation 和成功回执。它是可恢复的顺序提交,不是跨数据库的原子回滚事务。中断期间,公共检索、读取及维护接口拒绝访问,其他更新不能越过待恢复操作。
with Memory.open(memory_root="/path/to/memory") as memory:
report = memory.recover(operation_key="application-operation-123")
# None:无待恢复操作,也无该 key 成功回执,不能据此宣称修复成功。
# UpdateReport:已恢复完成,或读到此前的成功回执。
- 相同
operation_key、相同输入重试会恢复/返回成功回执,不重复创建卡片;不同输入复用同一 key 会被拒绝。 recover()不指定 key 时恢复目录中唯一的待完成操作。未准备的剩余知识可能调用 LLM;已保存的提取结果不重复提取,已准备计划不重新调用 LLM/embedding。- journal 损坏、存储配置不匹配、generation 冲突会保持隔离并抛出
RecoveryRequiredError,不自动删除数据、切换 backend 或初始化空库。 - 旧调用可以不传 key,但现在也会生成操作 key、记录回执并推进 generation;异常后应调用
recover(),不要用新 key 重做整个批次。 - 三种 backend 共用协议和既有索引适配器。扩展写入动作必须补充显式计划命令和故障注入测试,不得绕过计划修改真实存储。
- journal 含输入消息/知识和卡片正文,需与整个记忆目录一起做访问控制、备份及持久化。只读 API 仍需可用的目录锁文件;不要在更新中复制单个数据库文件。
- 协议依赖文件系统的原子替换、锁和持久化语义,不替代部署方的远程同步/多主协调。不自动修复升级前损坏的数据;
check和核心卡片注入只参与互斥准入,不属于 redo 更新协议。
Backend 状态
with Memory.open(memory_root="/path/to/memory") as memory:
print(memory.database_provider)
print(memory.database_capabilities)
print(memory.database_health())
以上是 V2 新增的只读接口;既有 API 的名称和必填参数保持不变。
API 一览
Memory.open(...)
Memory.retrieve(prompt, topk, similarity) -> list[RetrievalResult]
Memory.query(card_id=..., path=...) -> RetrievalResult
Memory.update(messages) -> UpdateReport
Memory.update_from_knowledge(knowledges, operation_key=..., expected_generation=...) -> UpdateReport
Memory.check() -> CheckReport
Memory.inject_core_card(source_md_path) -> int
Memory.record_eval_run(run) -> int
Memory.list_eval_runs(eval_name) -> list[EvalRun]
Memory.get_baseline_eval_run(eval_name) -> EvalRun | None
Memory.database_provider -> str
Memory.database_capabilities -> DatabaseCapabilities
Memory.database_health() -> DatabaseHealth
Memory.open 支持注入自定义 llm、embedding、tokenizer 和 settings。
数据与写入约束
- Agent 更新只写入
notes/。 - 核心记忆只能通过
inject_core_card或core inject注入。 - Markdown 路径必须位于
memory_root内;绝对路径和目录穿越会被拒绝。 - 单张卡片最多 4096 token、最多 8 个 Markdown 链接,链接按 1 token 计数。
- 修改卡片前会重新计算 token 和链接限制。
- Embedding 维度必须与现有向量索引一致;LanceDB/Chroma 会通过 Backend 标识提前校验。
- 生产环境应持久化整个
memory_root,而不是只持久化数据库子目录。
评测与开发
mem8 eval --suite retrieval
mem8 eval --suite update --record
mem8 eval --suite check --baseline
mem8 eval --suite all --record
源码验证:
uv run pytest
uv run ruff check mem8 evals tests
uv run mypy mem8 evals
可选 Backend 的真实集成测试仅在对应依赖已安装时运行。
发布到 PyPI
仓库使用 GitHub Actions 和 PyPI Trusted Publishing。发布前同时更新 pyproject.toml 与 mem8/__init__.py 中的版本号,合并到 master 后推送匹配的 Tag:
git tag vX.Y.Z
git push origin vX.Y.Z
工作流会校验 Tag 与版本声明、运行测试和静态检查、构建 wheel/sdist,并执行 twine check。发布 Job 使用 pypi GitHub Environment,仓库不保存 PyPI API Token。
文档
README 以当前仓库已实现能力为准。sync、reindex 以及 OpenAI LLM 等仍属于后续能力。recover 是 Python API,尚未提供独立 CLI 子命令。
Metadata
Release files for mem8-fs 0.3.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mem8_fs-0.3.4.tar.gz | 66.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mem8_fs-0.3.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 152.7 kB
Release files / mem8_fs-0.3.4.tar.gz
| Download URL | mem8_fs-0.3.4.tar.gz |
|---|---|
| Size | 66.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fc39c5a635b9917f2428598820b1e2dc50b352ca04a7f21cb44cfb8909044413
|
|
BLAKE2b-256 checksum How to use checksums |
04a75ed6c4574ce082c1bfd1e6a8df5c30dc7c7b2abef03dae61a73b3ceab8d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency logRelease files / mem8_fs-0.3.4-py3-none-any.whl
| Download URL | mem8_fs-0.3.4-py3-none-any.whl |
|---|---|
| Size | 86.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
65d99c1689c05d5fa54b4ba83d44b2770fef42a7e6d40758820f099a6cad0d83
|
|
BLAKE2b-256 checksum How to use checksums |
cfd45e833c200f31535e95e20b09afae08b29142ec382650b8d6140228752dec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency log