第 3 期:解剖 Claude-Mem 的「大脑」— 数据存储架构全解

⏱ 预计阅读 14 分钟 更新于 2026/5/7
💡 进群学习加 wx: agentupdate
(申请发送: agentupdate)

本期场景:你用 Claude Code 开发博客项目已经两个会话了。Web UI 上显示了一堆 Observations。问题来了:这些数据到底存在哪?长什么样?为什么需要两个数据库?


3.1 数据存储的物理位置

Claude-Mem 的所有数据都存在你本地硬盘的一个目录里:

~/.claude-mem/
├── claude-mem.db          # SQLite 数据库(核心)
├── settings.json          # 配置文件
├── chroma/                # ChromaDB 向量数据库
│   └── ...
└── logs/                  # 运行日志
    └── worker.log

没有任何数据会上传到云端。 你的开发记忆完全属于你自己。


3.2 SQLite — 结构化存储引擎

为什么选 SQLite?

特性 好处
零配置 不需要安装数据库服务器
单文件 整个数据库就是一个 .db 文件,复制就能备份
WAL 模式 Write-Ahead Logging,支持 Hook 和 Worker 同时读写
内置 FTS5 全文搜索引擎,关键词检索飞快

四张核心表

Claude-Mem 的 SQLite 数据库包含四张核心表。让我们逐一解剖:

表 1:sdk_sessions — 会话记录

每次你打开 Claude Code 开始工作,就会创建一条记录。

-- 查看最近 5 个会话
SELECT sdk_session_id, project, status, created_at, completed_at
FROM sdk_sessions
ORDER BY created_at DESC
LIMIT 5;
┌──────────────────┬─────────────┬───────────┬─────────────────────┐
│ sdk_session_id   │ project     │ status    │ created_at          │
├──────────────────┼─────────────┼───────────┼─────────────────────┤
│ sess_abc123      │ my-blog     │ completed │ 2026-04-21 10:30:00 │
│ sess_def456      │ my-blog     │ completed │ 2026-04-20 14:00:00 │
│ sess_ghi789      │ other-proj  │ completed │ 2026-04-19 09:15:00 │
└──────────────────┴─────────────┴───────────┴─────────────────────┘

表 2:observations — 观察记录(核心中的核心)

每当 Claude 执行一个工具操作(读文件、写文件、运行命令),Worker 就会生成一条 Observation。

-- 查看最近的观察
SELECT id, title, type, tool_name, created_at
FROM observations
WHERE session_id = 'sess_abc123'
ORDER BY prompt_number;
┌────┬─────────────────────────────┬──────────┬────────────┬─────────────────────┐
│ id │ title                       │ type     │ tool_name  │ created_at          │
├────┼─────────────────────────────┼──────────┼────────────┼─────────────────────┤
│ 1  │ 读取 prisma schema 文件     │ discovery│ Read       │ 2026-04-21 10:31:00 │
│ 2  │ 添加 Comment 模型          │ feature  │ Write      │ 2026-04-21 10:33:00 │
│ 3  │ 运行 prisma migrate        │ change   │ Bash       │ 2026-04-21 10:34:00 │
│ 4  │ 修复外键约束错误            │ bugfix   │ Write      │ 2026-04-21 10:36:00 │
│ 5  │ 选择级联删除策略            │ decision │ Write      │ 2026-04-21 10:38:00 │
└────┴─────────────────────────────┴──────────┴────────────┴─────────────────────┘

每条 Observation 包含丰富的字段:

字段 含义 示例
title 一句话标题 "修复 JWT 刷新逻辑"
narrative 详细叙述(以第三人称) "开发者发现 refreshToken 函数缺少过期检查..."
facts 提炼出的事实列表 ["使用了 jsonwebtoken 库", "token 有效期 7 天"]
concepts 涉及的概念 ["JWT", "认证", "中间件"]
type 分类(6 种) "bugfix"
tool_name 触发的工具 "Write"
files_read 读取的文件 ["src/auth/jwt.ts"]
files_modified 修改的文件 ["src/auth/jwt.ts"]

表 3:user_prompts — 用户提示词

记录你在每个会话中发送给 Claude 的每一条指令。

SELECT prompt_number, content FROM user_prompts
WHERE session_id = 'sess_abc123'
ORDER BY prompt_number;
┌───────────────┬────────────────────────────────────────────┐
│ prompt_number │ content                                    │
├───────────────┼────────────────────────────────────────────┤
│ 1             │ 帮我给博客加一个评论功能                     │
│ 2             │ 评论要支持 Markdown 格式                    │
│ 3             │ 修一下刚才那个外键报错                      │
└───────────────┴────────────────────────────────────────────┘

表 4:session_summaries — 会话摘要

当会话结束时,AI 自动生成的结构化总结。

SELECT request, completed, next_steps FROM session_summaries
WHERE session_id = 'sess_abc123';
{
  "request": "为博客添加评论系统",
  "investigated": ["Prisma 的关联模型语法", "级联删除的几种策略"],
  "completed": ["创建 Comment 模型", "实现评论 API", "修复外键约束"],
  "next_steps": ["添加评论的前端 UI", "实现评论通知功能"]
}

注意 next_steps 的魔力 —— 它会在下一次会话启动时被自动注入 Claude 的上下文,让 AI 知道"上次你还没做完什么"。


3.3 ChromaDB — 语义向量搜索引擎

SQLite 已经有 FTS5 全文搜索了,为什么还需要 ChromaDB?

因为关键词搜索和语义搜索是两种完全不同的能力

搜索类型 引擎 搜索「登录 Bug」时...
关键词搜索 SQLite FTS5 ✅ 匹配含"登录"和"Bug"的记录
❌ 错过"authentication error"的记录
语义搜索 ChromaDB ✅ 匹配"登录 Bug"
✅ 也匹配"authentication error"(语义相近)
✅ 还能匹配"JWT token 过期异常"

ChromaDB 如何工作?

graph LR
    A["新的 Observation:
修复 JWT 刷新逻辑"] --> B["向量化
(文字 → 数字向量)"] B --> C["存入 ChromaDB
[0.23, -0.41, 0.87, ...]"] D["用户搜索:
登录功能的问题"] --> E["向量化
(搜索词 → 数字向量)"] E --> F["向量相似度计算"] C --> F F --> G["返回最相近的记录"] style A fill:#f59e0b,color:#000 style D fill:#6366f1,color:#fff style G fill:#10b981,color:#fff

简单来说:

  • SQLite FTS5 = 精确匹配(像 Ctrl+F 搜索)
  • ChromaDB = 理解含义的匹配(像一个懂你在说什么的同事)

两者结合,就是 Claude-Mem 的混合搜索(Hybrid Search),让你无论用什么关键词都能找到相关的历史记录。


3.4 Observation 的 6 种类型

Worker 在压缩 Observation 时,会自动分类为以下 6 种类型:

类型 含义 博客项目中的例子
decision 架构或设计决策 "选择 Prisma 而不是 TypeORM"
bugfix 修复了一个 Bug "修复文章 slug 重复时的 500 错误"
feature 实现了新功能 "添加文章标签系统"
refactor 重构了代码 "将 API 路由从 pages/ 迁移到 app/"
discovery 发现了新知识 "Prisma 的 findMany 默认不包含关联"
change 通用变更 "更新了 .env 配置文件"

这些类型标签让你可以精准过滤。比如想知道项目中做过哪些架构决策:

search(query="数据库", type="decision")

3.5 数据流全景

让我们把 SQLite 和 ChromaDB 的角色放到完整的数据流中:

graph TB
    A["Claude 执行工具操作
(读文件/写文件/运行命令)"] --> B["PostToolUse Hook 触发"] B --> C["Worker 接收原始工具输出"] C --> D["Claude Agent SDK
压缩提炼"] D --> E["生成结构化 Observation
{title, narrative, facts,
concepts, type}"] E --> F["SQLite"] E --> G["ChromaDB"] F --> F1["INSERT 到 observations 表"] F --> F2["更新 FTS5 全文索引"] G --> G1["文本 → 向量嵌入"] G --> G2["存入向量集合"] H["下次搜索时"] --> I{"搜索类型?"} I -->|"关键词精确匹配"| F I -->|"语义模糊匹配"| G I -->|"混合搜索(默认)"| J["FTS5 + 向量
结果合并排序"] style A fill:#6366f1,color:#fff style F fill:#10b981,color:#fff style G fill:#10b981,color:#fff style J fill:#f59e0b,color:#000

实操练习

  1. 在博客项目中用 Claude Code 工作一个会话(比如创建数据库 Schema)
  2. 结束会话后,用 SQLite 工具直接查看数据:
# 打开数据库
sqlite3 ~/.claude-mem/claude-mem.db

# 查看有多少会话
SELECT COUNT(*) FROM sdk_sessions;

# 查看最近的 Observations
SELECT id, title, type FROM observations ORDER BY created_at DESC LIMIT 10;

# 查看某个会话的摘要
SELECT request, completed, next_steps FROM session_summaries LIMIT 1;

# 退出
.quit
  1. 打开 http://localhost:37777,在 Web UI 中对比你看到的内容和 SQL 查询结果 —— 它们应该是一致的。

下期预告

数据存好了,但数据是怎么"自动"被捕获存进去的?下一期我们揭秘 Claude-Mem 的 5 大生命周期钩子 —— 它们就是那个"偷偷记笔记"的隐形秘书。我们会用一张完整的时序图,追踪从你按下回车到数据入库的每一步。

➡️ 第 4 期:生命周期钩子 — Claude-Mem 如何"偷偷记笔记"