mem8
mem8 0.2: structured messages and dual update APIs
String message content remains backwards compatible. Rich transcripts can use
vendor-neutral text, thinking, tool_call, tool_result, and
attachment_text parts:
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) # extracts Knowledge, then builds memory
During extraction, thinking, tool_call, and failed tool_result parts are
excluded by default. Text, successful textual tool results, and extracted
attachment text can be used as evidence. Binary attachments are not accepted.
When an external LLM has already summarized the knowledge, skip compression and directly reuse mem8's deduplication, decision, and write-back pipeline:
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)remains the transcript-driven API for future dream workflows.Memory.update_from_knowledge(knowledges)is the preferred API for knowledge already summarized by an external LLM; it accepts 1 to 10 items per call.- Both modes share write logic, locking, operation receipts, and optimistic generation checks. Read-only workspaces reject both modes.
- mem8 has no MCP, agent_runner, admgraiindustry, or vendor transcript SDK dependency. Hosts map SDK events into mem8's generic message parts.
CLI equivalents:
uv run mem8 update --messages messages.jsonl
uv run mem8 update-knowledge --knowledge-file knowledges.json
Installation from PyPI
pip install mem8-fs
The distribution name is mem8-fs; the Python import package remains mem8:
from mem8.api import Memory
mem8 是一个面向 AI Agent 的本地优先长期记忆 Python 包。Markdown 是记忆正文的事实来源;SQLite 保存元数据、链接和评估记录,并通过 FTS5 BM25、sqlite-vec 向量检索及 RRF 融合提供混合检索。LLM 负责从对话中提炼、判断和更新记忆,也用于检查并修复断链。
当前版本为 0.2.0,支持本地 Markdown 记忆、核心记忆注入、按 ID 或路径查询、BM25 与向量混合检索、对话驱动或结构化知识驱动的记忆更新、断链检查修复,以及 retrieval、update、check 评估。默认记忆根目录是当前工作目录下的 .mem8。
环境要求
- Python 3.11 或更高版本。
- 使用 uv 管理依赖、虚拟环境和命令。
- 默认 LLM 为 Anthropic,需要配置
ANTHROPIC_API_KEY。 - 至少安装一种 Embedding Provider:Local、OpenAI 或 Voyage。
- Local Embedding 首次加载模型时可能需要联网下载模型文件。
当前内置 LLM 实现仅支持 Anthropic。openai extra 目前只提供 OpenAI Embedding,不提供 OpenAI LLM。
安装与初始化
安装项目
安装开发、评估和默认 Local Embedding 依赖:
uv sync --extra dev --extra evals --extra local
也可以按需选择 Embedding Provider:
uv sync --extra local # 本地 sentence-transformers,默认配置
uv sync --extra openai # OpenAI Embedding
uv sync --extra voyage # Voyage Embedding
初始化记忆目录
uv run mem8 init
初始化后,mem8 使用以下目录结构:
.mem8/
├── core/ # 用户注入的只读核心记忆,首次注入时创建
├── notes/ # Agent 创建和维护的普通记忆,首次写入时创建
├── mem8.db # SQLite 数据库及索引
└── mem8.toml # Provider 与存储配置
所有卡片路径都相对于记忆根目录,例如 notes/context.md。所有 CLI 命令均可通过 --memory-root PATH 指定其他完整记忆根目录;Python API 则通过 Memory.open(memory_root=...) 指定。mem8 不会在自定义根目录中再创建第二层 .mem8。
打开旧工作区时,如果存在 <memory_root>/.mem8/mem8.toml 或 <memory_root>/.mem8/mem8.db,且根目录不存在同名文件,mem8 会自动将其迁移到根目录。新旧位置同时存在同名文件时会停止迁移,要求人工处理冲突。
journal/ 属于后续恢复机制设计,当前版本不会创建或使用该目录。
CLI 使用
初始化、迁移与配置
# 初始化工作区;重复执行是安全的
uv run mem8 init
# 单独执行幂等数据库迁移
uv run mem8 migrate
# 修改配置
uv run mem8 config set llm.model claude-sonnet-4-6
uv run mem8 config set llm.max_tokens 4096
uv run mem8 config set embedding.provider local
uv run mem8 config set embedding.model all-MiniLM-L6-v2
uv run mem8 config set embedding.dim 384
uv run mem8 config set storage.db_filename mem8.db
配置保存在 <memory-root>/mem8.toml,也可以使用环境变量覆盖:
MEM8_LLM__MODELMEM8_LLM__MAX_TOKENSMEM8_EMBEDDING__PROVIDERMEM8_EMBEDDING__MODELMEM8_EMBEDDING__DIMMEM8_STORAGE__DB_FILENAME
核心记忆、检索与查询
# 注入核心记忆,仅接受 Markdown 文件
uv run mem8 core inject ./seed.md
# BM25 + Vector + RRF 混合检索
uv run mem8 retrieve "context overflow" --topk 5 --similarity 0.55
# 按 ID 或相对路径查询,二者必须且只能提供一个
uv run mem8 query --card-id 1
uv run mem8 query --path notes/context.md
更新与检查
更新命令接收 JSONL 历史对话:
uv run mem8 update --messages messages.jsonl
uv run mem8 check
messages.jsonl 的每个非空行必须包含 role 和 content:
{"role":"user","content":"I prefer concise answers."}
{"role":"assistant","content":"Understood."}
update 执行“压缩 → 决策 → 写回”流程;check 扫描并尝试修复断链。
评估
uv run mem8 eval --suite retrieval
uv run mem8 eval --suite update --record
uv run mem8 eval --suite check --baseline
uv run mem8 eval --suite all --record
--record 只持久化普通评估运行,不会自动将其设为基线。--baseline 仅在数据库已有 is_baseline=True 的显式基线时计算相对差值;门禁指标下降超过 5% 时命令返回非零状态。当前 CLI 尚未提供设置基线的命令,可以通过 Python API 写入基线。
Python API
打开与使用记忆
from mem8 import Memory
from mem8.domain.message import Message
with Memory.open() as memory:
results = memory.retrieve(
"how should context overflow be handled?",
topk=5,
similarity=0.55,
)
if results:
card = memory.query(card_id=results[0].card_id)
update_report = memory.update([
Message(role="user", content="I prefer concise answers."),
Message(role="assistant", content="Understood."),
])
check_report = memory.check()
core_card_id = memory.inject_core_card("seed.md")
Memory.open 支持注入自定义组件,便于测试或替换 Provider:
memory = Memory.open(
memory_root="/path/to/memory",
llm=my_llm,
embedding=my_embedding,
tokenizer=my_tokenizer,
settings=my_settings,
)
公开方法
Memory.retrieve(prompt, topk, similarity) -> list[RetrievalResult]
Memory.query(card_id=..., path=...) -> RetrievalResult
Memory.update(messages) -> 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
retrieve 要求 prompt 非空、topk > 0,且 similarity 位于 [0, 1]。query 必须且只能提供 card_id 或 path 之一。
如需创建评估基线,可构造 is_baseline=True 的 EvalRun:
from mem8.domain.eval_run import EvalRun
memory.record_eval_run(EvalRun(..., is_baseline=True))
写入约束
- Agent 新卡只能写入
notes/。 - 核心记忆只能通过
inject_core_card或core inject注入,更新流程不得修改核心卡。 - 路径必须是安全的根目录相对 Markdown 路径;绝对路径、反斜杠和目录穿越会被拒绝。
- 创建卡片时禁止覆盖已有路径。
- 每张卡片最多 4096 token、最多 8 个 Markdown 出链;链接按 1 token 计数。
- 修改链接前会重新检查来源卡和目标卡的 token 与出链限制。
- 混合检索中任一路结果足够强即可进入 RRF 候选,避免单路弱分误杀结果。
开发指南
质量检查
uv run pytest
uv run ruff check mem8 evals tests
uv run mypy mem8 evals
测试覆盖单元、集成和端到端场景。提交代码前应确保 pytest、Ruff 和 mypy 全部通过。
项目文档
prd.md 是产品要求基线;dev.md 包含当前实现梳理与后续演进设计。README 以当前仓库中实际可运行的公开能力为准。
当前边界
dev.md 中的 audit/repair 分离、sync、reindex、recover、journal 恢复和 OpenAI LLM 等属于后续设计目标,当前公开 API 与 CLI 尚未提供这些入口。
Metadata
Release files for mem8-fs 0.2.0
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.2.0.tar.gz | 56.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mem8_fs-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 129.2 kB
Release files / mem8_fs-0.2.0.tar.gz
| Download URL | mem8_fs-0.2.0.tar.gz |
|---|---|
| Size | 56.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bd99291f40662495f51b41b085c84b569ce5f57c6610dcb0dd8f2d3efa703bfb
|
|
BLAKE2b-256 checksum How to use checksums |
6e682e2afa4e7605a9de239036b62be833bd01f2f8c1986f197c1893930a36ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|
Release files / mem8_fs-0.2.0-py3-none-any.whl
| Download URL | mem8_fs-0.2.0-py3-none-any.whl |
|---|---|
| Size | 73.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
81a272344f467789c96e7275bc50267435e1d709adb441f845851e0018239714
|
|
BLAKE2b-256 checksum How to use checksums |
a18b279aad862e3208f7a2b87734198533abe03fa1f83983290b507e38785226
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|