Skip to content

架构演进

我们解决的问题

目标: 创建一个记忆系统,使Claude在不同会话中变得更聪明,同时用户不会注意到它的存在。

挑战: 如何观察 AI 代理的行为,智能地压缩它,并在适当的时候返回使用——所有这些都不会减慢或干扰主要工作流程?

这是关于 claude-mem 如何从一个简单的想法发展成可投入生产的系统的故事,以及使其成功的关键架构决策。


v5.x:成熟度与用户体验

在建立了坚实的v4架构之后,v5.x专注于用户体验、可视化和精细化。

v5.1.2:主题切换(2025年11月)

变更内容:在查看器界面添加了明/暗模式主题切换

新功能

  • 用户可选择的主题偏好(浅色、深色、系统)
  • localStorage 中的持久主题设置
  • 平滑的主题过渡
  • 系统偏好检测

实施

typescript
// Theme context with persistence
const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState<'light' | 'dark' | 'system'>(() => {
    return localStorage.getItem('claude-mem-theme') || 'system';
  });

  useEffect(() => {
    localStorage.setItem('claude-mem-theme', theme);
  }, [theme]);

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

重要性:在不同光照条件下工作的用户现在可以自定义查看器以获得舒适体验。

v5.1.1:工作器启动修复(2025年11月)- 现已弃用

注意:本节描述了一种基于 PM2 的历史方法,该方法在后续版本中已被 Bun 取代。

问题:在 Windows 上使用 PM2 时,工作进程启动失败并出现 ENOENT 错误

历史解决方案:使用 PM2 二进制文件的完整路径,而不是依赖 PATH

当前方法:该项目现在使用 Bun 进行进程管理,它提供了更好的跨平台兼容性,并消除了这些与 PATH 相关的问题。

影响:跨平台兼容性已恢复,Windows 用户现在可以无问题使用 claude-mem。

v5.1.0:基于网页的查看器界面(2025年10月)

突破:内存流的实时可视化

我们建立的

  • 基于 React 的网页用户界面位于 http://localhost:37777
  • 用于实时更新的服务器发送事件(SSE)
  • 无限滚动分页
  • 项目筛选
  • 设置持久性(侧边栏状态、所选项目)
  • 带指数退避的自动重连
  • GPU加速动画

新工作端点(新增 8 个):

GET /                    # Serves viewer HTML
GET /stream              # SSE real-time updates
GET /api/prompts         # Paginated user prompts
GET /api/observations    # Paginated observations
GET /api/summaries       # Paginated session summaries
GET /api/stats           # Database statistics
GET /api/settings        # User settings
POST /api/settings       # Save settings

数据库增强

typescript
// New SessionStore methods for viewer
getRecentPrompts(limit, offset, project?)
getRecentObservations(limit, offset, project?)
getRecentSummaries(limit, offset, project?)
getStats()
getUniqueProjects()

React 架构

src/ui/viewer/
├── components/
│   ├── Header.tsx          # Navigation + stats
│   ├── Sidebar.tsx         # Project filter
│   ├── Feed.tsx            # Infinite scroll
│   └── cards/
│       ├── ObservationCard.tsx
│       ├── PromptCard.tsx
│       ├── SummaryCard.tsx
│       └── SkeletonCard.tsx
├── hooks/
│   ├── useSSE.ts           # Real-time events
│   ├── usePagination.ts    # Infinite scroll
│   ├── useSettings.ts      # Persistence
│   └── useStats.ts         # Statistics
└── utils/
    ├── merge.ts            # Data deduplication
    └── format.ts           # Display formatting

构建过程

typescript
// esbuild bundles everything into single HTML file
esbuild.build({
  entryPoints: ['src/ui/viewer/index.tsx'],
  bundle: true,
  outfile: 'plugin/ui/viewer.html',
  loader: { '.tsx': 'tsx', '.woff2': 'dataurl' },
  define: { 'process.env.NODE_ENV': '"production"' },
});

重要性:用户现在可以实时准确地看到正在捕获的内容,使内存系统变得透明且可调试。

v5.0.3:智能安装缓存(2025年10月)

问题: npm install 在每次会话开始时(2-5 秒)运行

洞察:依赖项在各个会话之间很少变化

解决方案:基于版本的缓存

typescript
// Check version marker before installing
const currentVersion = getPackageVersion();
const installedVersion = readFileSync('.install-version', 'utf-8');

if (currentVersion !== installedVersion) {
  // Only install if version changed
  await runNpmInstall();
  writeFileSync('.install-version', currentVersion);
}

缓存检查逻辑

  1. node_modules 存在吗?
  2. .install-versionpackage.json 版本匹配吗?
  3. better-sqlite3 是否存在?(遗留:现在使用 bun:sqlite,无需安装)

影响:

  • SessionStart 钩子:2-5 秒 → 10 毫秒(快 99.5%)
  • 仅在以下情况下安装:首次运行、版本更改、依赖项缺失
  • 借助构建工具提供更好的 Windows 错误信息

v5.0.2:工作人员健康检查(2025年10月)

变更内容:更强大的工作进程启动和监控

新功能

typescript
// Health check endpoint
app.get('/health', (req, res) => {
  res.json({
    status: 'ok',
    uptime: process.uptime(),
    port: WORKER_PORT,
    memory: process.memoryUsage(),
  });
});

// Smart worker startup
async function ensureWorkerHealthy() {
  const healthy = await isWorkerHealthy(1000);
  if (!healthy) {
    await startWorker();
    await waitForWorkerHealth(10000);
  }
}

好处

  • 当工作节点宕机时的优雅降级
  • 自动从崩溃中恢复
  • 用于调试的更好错误信息

v5.0.1:稳定性改进(2025年10月)

变更内容:各种错误修复和稳定性增强

主要修复

  • 修复了观察队列处理中的竞态条件
  • 在 SDK Worker 进程中改进了错误处理
  • 更好地清理过时的工作进程
  • 增强调试日志记录

v5.0.0:混合搜索架构(2025年10月)

演变:SQLite FTS5 Chroma 向量搜索

我们添加的内容:

┌─────────────────────────────────────────────────────────┐
│                    HYBRID SEARCH                         │
│                                                          │
│  Text Query → SQLite FTS5 (keyword matching)            │
│                      ↓                                   │
│            Chroma Vector Search (semantic)               │
│                      ↓                                   │
│              Merge + Re-rank Results                     │
└─────────────────────────────────────────────────────────┘

新依赖项

  • chromadb - 用于语义搜索的向量数据库
  • Python 3.8 - chromadb 所需

MCP 工具增强:

typescript
// Chroma-backed semantic search
search_observations({
  query: "authentication bug",
  useSemanticSearch: true  // Uses Chroma
});

// Falls back to FTS5 if Chroma unavailable

为什么选择混合

  • FTS5:快速关键词匹配,无依赖
  • Chroma:语义理解,寻找相关概念
  • 优雅降级:在没有 Chroma 的情况下工作(仅限 FTS5)

权衡

  • 已添加 Python 依赖(可选)
  • 安装复杂性增加
  • 更好的搜索相关性

MCP 架构简化(2025 年 12 月)

问题:复杂的MCP实现

之前:

9+ MCP tools registered at session start:
- search_observations
- find_by_type
- find_by_file
- find_by_concept
- get_recent_context
- get_observation
- get_session
- get_prompt
- help

Problems:
- Overlapping operations (search_observations vs find_by_type)
- Complex parameter schemas (~2,500 tokens in tool definitions)
- No built-in workflow guidance
- High cognitive load for Claude (which tool to use?)
- Code size: ~2,718 lines in mcp-server.ts

洞察: 渐进式披露应该内置于工具设计中,而不是Claude必须记住的事情。

解决方案:三层工作流程

之后:

4 MCP tools following 3-layer workflow:

1. __IMPORTANT - Workflow documentation (always visible)
   "3-LAYER WORKFLOW (ALWAYS FOLLOW):
    1. search(query) → Get index with IDs
    2. timeline(anchor=ID) → Get context
    3. get_observations([IDs]) → Fetch details
    NEVER fetch full details without filtering first."

2. search - Layer 1: Get index with IDs (~50-100 个 token/result)
3. timeline - Layer 2: Get chronological context
4. get_observations - Layer 3: Fetch full details (~500-1,000 个 token/result)

Benefits:
- Progressive disclosure enforced by tool structure
- No overlapping operations
- Simple schemas (additionalProperties: true)
- Clear workflow pattern
- Code size: ~312 lines in mcp-server.ts (88% reduction)
- ~10x token savings

迁移:基于技能的搜索已移除

之前: 使用基于技能的搜索

  • 通过自然语言调用的mem-search skill
  • 通过 curl 直接调用的 HTTP API
  • 通过技能加载逐步披露
  • 17 个技能文档文件

现在: 移除了基于技能的方法

  • 仅MCP架构
  • 原生MCP协议(更好的Claude集成)
  • 适用于 Claude Desktop 和 Claude Code
  • 更容易维护(没有技能文件)
  • 已删除所有19个内存搜索技能文件(约2,744行)

关键架构变化

MCP 服务器重构:

之前:

typescript
// Complex parameter schemas
{
  name: "search_observations",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string", description: "..." },
      type: { type: "array", items: { enum: [...] } },
      format: { enum: ["index", "full"] },
      limit: { type: "number", minimum: 1, maximum: 100 },
      // ... many more parameters
    }
  }
}

之后:

typescript
// Simple schemas with workflow guidance
{
  name: "search",
  description: "Step 1: Search memory. Returns index with IDs.",
  inputSchema: {
    type: "object",
    properties: {},
    additionalProperties: true  // Accept any parameters
  }
}

工作流程执行:

之前:克洛德必须记住逐步披露模式

之后:工具结构使得不可能跳过步骤

  • 没有ID就无法从搜索中获取详细信息
  • 在看到__重要提醒之前无法搜索
  • 时间轴提供中间立场(有上下文但没有完整细节)

影响

token 效率:

Traditional: Fetch 20 observations upfront
→ 10,000-20,000 个 token
→ Only 2 observations relevant (90% waste)

3-Layer Workflow:
→ search (20 results): ~1,000-2,000 个 token
→ Review index, identify 3 relevant IDs
→ get_observations (3 IDs): ~1,500-3,000 个 token
→ Total: 2,500-5,000 个 token (50-75% savings)

代码简洁性:

  • MCP 服务器:2,718 行 → 312 行(减少 88%)
  • 已删除:19 个技能文件(约 2,744 行)
  • 净减少:删除约5,150行代码

用户体验:

  • 相同的自然语言交互
  • 更好的 token 效率
  • 更清晰的架构
  • 在 Claude Desktop 和 Claude Code 上工作方式相同

设计理念

通过结构逐步披露:

三层工作流在架构层面体现了渐进式展示:

  1. 层 1(索引) - “什么存在?” - 对选项的廉价调查
  2. 第2层(时间线) - “发生了什么?” - 关于特定点的背景
  3. 第3层(详情) - “告诉我一切” - 仅在有充分理由时提供完整详情

每一层都提供了一个决策点,Claude 可以在此:

  • 如果不相关,请停止
  • 如果不确定,请获取更多上下文
  • 如果有信心就深入潜水

这在结构上使得浪费token变得困难。


v1-v2:天真的方法

第一次尝试:倾倒一切

架构:

PostToolUse Hook → Save raw tool outputs → Retrieve everything on startup

我们学到的:

  • ❌ 上下文污染(数千个无关数据的标记)
  • ❌ 无压缩(原始工具输出内容冗长)
  • ❌ 无搜索(必须线性扫描所有内容)
  • ✅ 证明了概念:跨会话的记忆是有价值的

出了什么问题的例子:

SessionStart loaded:
- 150 file read operations
- 80 grep searches
- 45 bash commands
- Total: ~35,000 tokens
- Relevant to current task: ~500 tokens (1.4%)

v3:智能压缩,错误的架构

突破:人工智能驱动的压缩

新想法: 使用 Claude 本身来压缩观察结果

架构:

PostToolUse Hook → Queue observation → SDK Worker → AI compression → Store insights

我们添加的内容:

  1. Claude 代理 SDK 集成 - 使用 AI 压缩观察结果
  2. 后台Worker 进程 - 不要阻塞主会话
  3. 结构化观察 - 提取事实、决策、洞察
  4. 会话总结 - 生成全面的总结

有效的方法:

  • ✅ 压缩比:10:1 到 100:1
  • ✅ 语义理解(不仅仅是关键词匹配)
  • ✅ 后台处理(钩子保持快速)
  • ✅ 搜索变得有用

未奏效的部分:

  • ❌ 仍然一开始就加载所有内容
  • ❌ 会话ID管理损坏
  • ❌ 激进清理中断了摘要
  • ❌ 每个 Claude Code 会话的多个 SDK 会话

关键认识

认识 1:渐进披露

问题: 即使是压缩过的观察,如果你全部加载,也可能污染上下文。

洞察: 人类在开始工作前不会阅读所有内容。人工智能为什么要呢?

解决方案: 首先显示索引,根据需求获取详细信息。

❌ Old: Load 50 observations (8,500 个 token)
✅ New: Show index of 50 observations (800 个 token)
        Agent fetches 2-3 relevant ones (300 个 token)
        Total: 1,100 个 token vs 8,500 个 token

影响:

  • 上下文使用量减少87%
  • 100% 相关性(仅获取所需内容)
  • 代理自治(决定什么是相关的)

领悟 2:会话 ID 混乱

问题: SDK 会话 ID 每次都会变化。

我们所想的:

typescript
// ❌ Wrong assumption
UserPromptSubmit → Capture session ID once → Use forever

现实:

typescript
// ✅ Actual behavior
Turn 1: session_abc123
Turn 2: session_def456
Turn 3: session_ghi789

为什么这很重要:

  • 没有跟踪ID更新无法恢复会话
  • 会话状态在轮次之间丢失
  • 观察被孤立

解决方案:

typescript
// Capture from system init message
for await (const msg of response) {
  if (msg.type === 'system' && msg.subtype === 'init') {
    sdkSessionId = msg.session_id;
    await updateSessionId(sessionId, sdkSessionId);
  }
}

实现 3:优雅清理与激进清理

v3 方法:

typescript
// ❌ Aggressive: Kill worker immediately
SessionEnd → DELETE /worker/session → Worker stops

问题:

  • 摘要生成在处理中途被打断
  • 待处理观察丢失
  • 到处都是竞态条件

v4 方法:

typescript
// ✅ Graceful: Let worker finish
SessionEnd → Mark session complete → Worker finishes → Exit naturally

好处:

  • 摘要完成成功
  • 没有丢失的观测
  • 干净的状态转换

代码:

typescript
// v3: Aggressive
async function sessionEnd(sessionId: string) {
  await fetch(`http://localhost:37777/sessions/${sessionId}`, {
    method: 'DELETE'
  });
}

// v4: Graceful
async function sessionEnd(sessionId: string) {
  await db.run(
    'UPDATE sdk_sessions SET completed_at = ? WHERE id = ?',
    [Date.now(), sessionId]
  );
}

领悟 4:一次会议,而不是多次

问题: 我们在每个 Claude Code 会话中创建了多个 SDK 会话。

我们所想的:

Claude Code session → Create SDK session per observation → 100+ SDK sessions

现实应该是:

Claude Code session → ONE long-running SDK session → Streaming input

为什么这很重要:

  • SDK维护会话状态
  • 上下文会自然积累
  • 效率更高

实施:

typescript
// ✅ Streaming Input Mode
async function* messageGenerator(): AsyncIterable<UserMessage> {
  // Initial prompt
  yield {
    role: "user",
    content: "You are a memory assistant..."
  };

  // Then continuously yield observations
  while (session.status === 'active') {
    const observations = await pollQueue();
    for (const obs of observations) {
      yield {
        role: "user",
        content: formatObservation(obs)
      };
    }
    await sleep(1000);
  }
}

const response = query({
  prompt: messageGenerator(),
  options: { maxTurns: 1000 }
});

v4:有效的架构

核心设计

┌─────────────────────────────────────────────────────────┐
│              CLAUDE CODE SESSION                         │
│  User → Claude → Tools (Read, Edit, Write, Bash)        │
│                    ↓                                     │
│              PostToolUse Hook                            │
│              (queues observation)                        │
└─────────────────────────────────────────────────────────┘
                     ↓ SQLite queue
┌─────────────────────────────────────────────────────────┐
│              SDK WORKER PROCESS                          │
│  ONE streaming session per Claude Code session          │
│                                                          │
│  AsyncIterable<UserMessage>                             │
│    → Yields observations from queue                     │
│    → SDK compresses via AI                              │
│    → Parses XML responses                               │
│    → Stores in database                                 │
└─────────────────────────────────────────────────────────┘
                     ↓ SQLite storage
┌─────────────────────────────────────────────────────────┐
│              NEXT SESSION                                │
│  SessionStart Hook                                       │
│    → Queries database                                    │
│    → Returns progressive disclosure index               │
│    → Agent fetches details via MCP                      │
└─────────────────────────────────────────────────────────┘

五钩架构

**Purpose:** Inject context from previous sessions

**Timing:** When Claude Code starts

**What it does:**
- Queries last 10 session summaries
- Formats as progressive disclosure index
- Injects into context via stdout

**Key change from v3:**
- ✅ Index format (not full details)
- ✅ Token counts visible
- ✅ MCP search instructions included



**Purpose:** Initialize session tracking

**Timing:** Before Claude processes prompt

**What it does:**
- Creates session record
- Saves raw user prompt (v4.2.0+)
- Starts worker if needed

**Key change from v3:**
- ✅ Stores raw prompts for search
- ✅ Auto-starts worker service



**Purpose:** Capture tool observations

**Timing:** After every tool execution

**What it does:**
- Enqueues observation in database
- Returns immediately

**Key change from v3:**
- ✅ Just enqueues (doesn't process)
- ✅ Worker handles all AI calls



**Purpose:** Generate session summaries

**Timing:** Worker-triggered (mid-session)

**What it does:**
- Gathers observations
- Sends to Claude for summarization
- Stores structured summary

**Key change from v3:**
- ✅ Multiple summaries per session
- ✅ Summaries are checkpoints, not endings



**Purpose:** Graceful cleanup

**Timing:** When session ends

**What it does:**
- Marks session complete
- Lets worker finish processing

**Key change from v3:**
- ✅ Graceful (not aggressive)
- ✅ No DELETE requests
- ✅ Worker finishes naturally

数据库模式演化

v3 架构:

sql
-- Simple, flat structure
CREATE TABLE observations (
  id INTEGER PRIMARY KEY,
  session_id TEXT,
  text TEXT,
  created_at INTEGER
);

v4 架构:

sql
-- Rich, structured schema
CREATE TABLE observations (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  session_id TEXT NOT NULL,
  project TEXT NOT NULL,

  -- Progressive disclosure metadata
  title TEXT NOT NULL,
  subtitle TEXT,
  type TEXT NOT NULL,  -- decision, bugfix, feature, etc.

  -- Content
  narrative TEXT NOT NULL,
  facts TEXT,  -- JSON array

  -- Searchability
  concepts TEXT,  -- JSON array of tags
  files_read TEXT,  -- JSON array
  files_modified TEXT,  -- JSON array

  -- Timestamps
  created_at TEXT NOT NULL,
  created_at_epoch INTEGER NOT NULL,

  FOREIGN KEY(session_id) REFERENCES sdk_sessions(id)
);

-- FTS5 for full-text search
CREATE VIRTUAL TABLE observations_fts USING fts5(
  title, subtitle, narrative, facts, concepts,
  content=observations
);

-- Auto-sync triggers
CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN
  INSERT INTO observations_fts(rowid, title, subtitle, narrative, facts, concepts)
  VALUES (new.id, new.title, new.subtitle, new.narrative, new.facts, new.concepts);
END;

变化内容:

  • ✅ 结构化字段(标题、副标题、类型)
  • ✅ FTS5 全文搜索
  • ✅ 项目范围查询
  • ✅ 用于渐进式显示的丰富元数据

Worker 服务重新设计

v3 Worker:

typescript
// Multiple short SDK sessions
app.post('/process', async (req, res) => {
  const response = await query({
    prompt: buildPrompt(req.body),
    options: { maxTurns: 1 }
  });

  for await (const msg of response) {
    // Process single observation
  }

  res.json({ success: true });
});

v4 Worker:

typescript
// ONE long-running SDK session
async function runWorker(sessionId: string) {
  const response = query({
    prompt: messageGenerator(),  // AsyncIterable
    options: { maxTurns: 1000 }
  });

  for await (const msg of response) {
    if (msg.type === 'text') {
      parseObservations(msg.content);
      parseSummaries(msg.content);
    }
  }
}

好处:

  • 保持会话状态
  • SDK会自动处理上下文
  • 更高效(更少的 API 调用)
  • 自然多轮对话

途中关键修复

修复 1:上下文注入污染 (v4.3.1)

问题: SessionStart 钩子输出被 npm install 日志污染

bash
# Hook output contained:
npm WARN deprecated ...
npm WARN deprecated ...
{"hookSpecificOutput": {"additionalContext": "..."}}

它为什么坏了:

  • Claude Code 期望干净的 JSON 或纯文本
  • npm install 的标准错误/标准输出与钩子输出混合
  • 上下文未正确注入

解决方案:

json
{
  "command": "npm install --loglevel=silent && node context-hook.js"
}

结果: 清洁的 JSON 输出,上下文注入有效

修复 2:双 Shebang 问题 (v4.3.1)

问题: 钩子可执行文件有重复的 shebang

javascript
#!/usr/bin/env node
#!/usr/bin/env node  // ← Duplicate!

// Rest of code...

为什么会发生:

  • 源文件有 shebang
  • esbuild 在构建过程中添加了另一个 shebang

解决方案:

typescript
// Remove shebangs from source files
// Let esbuild add them during build

结果: 可执行文件干净,无解析错误

修复 3:FTS5 注入漏洞(v4.2.3)

问题: 用户输入直接传递到 FTS5 查询

typescript
// ❌ Vulnerable
const results = db.query(
  `SELECT * FROM observations_fts WHERE observations_fts MATCH '${userQuery}'`
);

攻击:

typescript
userQuery = "'; DROP TABLE observations; --"

解决方案:

typescript
// ✅ Safe: Use parameterized queries
const results = db.query(
  'SELECT * FROM observations_fts WHERE observations_fts MATCH ?',
  [userQuery]
);

修复 4:NOT NULL 约束违规 (v4.2.8)

问题: 当提示为空时会话创建失败

sql
INSERT INTO sdk_sessions (claude_session_id, user_prompt, ...)
VALUES ('abc123', NULL, ...)  -- ❌ user_prompt is NOT NULL

解决方案:

typescript
// Allow NULL user_prompts
user_prompt: input.prompt ?? null

模式更改:

sql
-- Before
user_prompt TEXT NOT NULL

-- After
user_prompt TEXT  -- Nullable

性能改进

优化 1:预处理语句

之前:

typescript
for (const obs of observations) {
  db.run(`INSERT INTO observations (...) VALUES (?, ?, ...)`, [obs.id, obs.text, ...]);
}

之后:

typescript
const stmt = db.prepare(`INSERT INTO observations (...) VALUES (?, ?, ...)`);
for (const obs of observations) {
  stmt.run([obs.id, obs.text, ...]);
}
stmt.finalize();

影响: 批量插入速度快 5 倍

优化 2:FTS5 索引

之前:

typescript
// Manual full-text search
const results = db.query(
  `SELECT * FROM observations WHERE text LIKE '%${query}%'`
);

之后:

typescript
// FTS5 virtual table
const results = db.query(
  `SELECT * FROM observations_fts WHERE observations_fts MATCH ?`,
  [query]
);

影响: 在大型数据集上搜索速度提高100倍

优化 3:索引格式默认值

之前:

typescript
// Always return full observations
search_observations({ query: "hooks" });
// Returns: 5,000 个 token

之后:

typescript
// Default to index format
search_observations({ query: "hooks", format: "index" });
// Returns: 200 个 token

// Fetch full only when needed
search_observations({ query: "hooks", format: "full", limit: 1 });
// Returns: 150 个 token

影响: 平均搜索结果大小减少25倍


我们学到了什么

第1课:上下文是宝贵的

原则: 你放入上下文窗口的每个标记都会消耗注意力。

应用:

  • 渐进式披露减少了87%的浪费
  • 索引优先方法赋予代理控制权
  • token 计数让成本显而易见

第2课:会话状态很复杂

原则: 分布式状态很困难。SDK处理它比我们更好。

应用:

  • 使用 SDK 内置的会话恢复
  • 不要尝试手动重建状态
  • 从初始化消息跟踪会话ID

第3课:优雅胜于激进

原则: 让进程在终止前完成其工作。

应用:

  • 优雅的清理可以防止数据丢失
  • Worker 完成重要操作
  • 干净的状态转换可以减少错误

第4课:人工智能是压缩器

原则: 不要手动压缩。让人工智能进行语义压缩。

应用:

  • 10:1 到 100:1 的压缩比
  • 语义理解,而非关键词提取
  • 结构化输出(XML解析)

第5课:渐进的一切

原则: 首先显示元数据,按需获取详细信息。

应用:

  • 上下文注入中的渐进披露
  • 搜索结果中的索引格式
  • 第1层(标题)→ 第2层(摘要)→ 第3层(完整详情)

前方的道路

计划:自适应索引大小

typescript
SessionStart({ source: "startup" }):
  → Show last 10 sessions (normal)

SessionStart({ source: "resume" }):
  → Show only current session (minimal)

SessionStart({ source: "compact" }):
  → Show last 20 sessions (comprehensive)

计划:相关性评分

typescript
// Use embeddings to pre-sort index by semantic relevance
search_observations({
  query: "authentication bug",
  sort: "relevance"  // Based on embeddings
});

计划:多项目环境

typescript
// Cross-project pattern recognition
search_observations({
  query: "API rate limiting",
  projects: ["api-gateway", "user-service", "billing-service"]
});

计划:协作记忆

typescript
// Team-shared observations (optional)
createObservation({
  title: "Rate limit: 100 req/min",
  scope: "team"  // vs "user"
});

迁移指南:v3 → v5

步骤 1:备份数据库

bash
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem-v3-backup.db

步骤 2:更新插件

bash
cd ~/.claude/plugins/marketplaces/thedotmack
git pull

步骤 3:更新插件

bash
/plugin update claude-mem

自动发生的事情:

  • 依赖更新(包括像 v5.0.0 的 chromadb 这样的新依赖)
  • 数据库模式迁移会自动运行
  • Worker 服务使用新代码重新启动
  • 智能安装缓存已激活(v5.0.3)

步骤4:测试

bash
# Start Claude Code
claude

# Check that context is injected
# (Should see progressive disclosure index with v5 viewer link)

# Open viewer UI (v5.1.0+)
open http://localhost:37777

# Submit a prompt and watch real-time updates in viewer

第5步:探索新功能

bash
# View memory stream in browser (v5.1.0+)
open http://localhost:37777

# Toggle theme (v5.1.2+)
# Click theme button in viewer header

# Check worker health
npm run worker:status
curl http://localhost:37777/health

关键指标

v3 性能

指标数值
每次会话的上下文使用量约 25,000 个标记
相关上下文约2,000个标记(8%)
钩子执行时间~200毫秒
搜索延迟~500毫秒(LIKE 查询)

v4 性能

指标数值
每次会话的上下文使用量约 1,100 个标记
相关上下文约1,100个标记(100%)
钩子执行时间~45毫秒
搜索延迟~15毫秒 (FTS5)

v5 性能

指标数值
每次会话的上下文使用量约 1,100 个标记
相关内容~1,100 个标记 (100%)
钩子执行时间~10毫秒(缓存安装)
搜索延迟~12毫秒(FTS5)或 ~25毫秒(混合)
查看器界面加载时间~50毫秒(打包的HTML)
SSE 更新延迟约5毫秒(实时)

v3 → v4 改进:

  • 上下文浪费减少96%
  • 相关性提高12倍
  • 速度快4倍的钩子
  • 搜索速度快 33 倍

v4 → v5 改进:

  • 钩子速度提升78%(智能缓存)
  • 实时可视化(查看器界面)
  • 更好的搜索相关性(混合型)
  • 增强的用户体验(主题切换、持久化)

结论

从v3到v5的旅程就是要理解这些基本的真理:

  1. 上下文是有限的 - 渐进式显示尊重注意力预算
  2. 人工智能是压缩器 - 语义理解胜过关键词提取
  3. 代理人很聪明 - 让他们决定去获取什么
  4. 状态管理很困难 - 使用 SDK 的内置机制
  5. 优雅退出 - 让进程干净地结束

结果是一个既强大又隐形的记忆系统。用户从未注意到它在工作——Claude只是随着时间变得更聪明。

v5 增加了可见性:现在用户如果愿意可以看到内存系统的工作情况(通过查看器 UI),但它仍然不具侵入性。


进一步阅读


这种架构的演变反映了数百小时的实验、数十次的失败尝试,以及在现实使用中获得的宝贵经验。v5 是从理解实际有效的内容中产生的架构——并将其呈现给用户。