Skip to content

Long Term Memory.zh CN

phinn edited this page Sep 18, 2026 · 3 revisions

🌐 Language: English | 中文

长期记忆

KinetAios 自动从每轮对话抽取「关于用户的持久事实」,存进 SQLite,下一轮注入到 prompt。跨引擎、跨会话。

流程

turn N 完成
  ↓
extractMemories():调一次 LLM,从本轮对话抽「持久事实」
  ↓
存进 memories 表(SQLite)
  ↓
turn N+1 开始
  ↓
memoryBlock():检索注入(embedding cosine → FTS5 → recent-N)
  ↓
Direct:作为 history[0] 的 user 消息(_memory 标记)
Claude Code:--append-system-prompt
Codex:拼到 prompt 头

后台异步跑,不阻塞用户继续输入。

抽取(extractMemories)

src/main/TaskManager.ts:282 附近。每个 done 事件触发:

  • 取本轮 user prompt + assistant answer
  • 调 LLM(extractMemories 自己一个独立的小 prompt,不进 directHistory)
  • prompt 引导模型:只抽「关于用户的持久事实」—— 喜好、技能、长期目标、固定约束。不抽一次性任务细节(「这次帮我写个 demo」不算)。
  • 返回的每条 fact 单独 INSERT 进 memories 表

用的是当前会话的模型(同 engine、同 model)。所以 GLM 抽 GLM 的、Claude 抽 Claude 的。

存储(SQLite)

src/main/store.ts:

CREATE TABLE memories (
  id TEXT PRIMARY KEY,
  content TEXT NOT NULL,
  conversation_id TEXT,           -- 抽出这条记忆的会话;NULL = 全局
  created_at INTEGER NOT NULL
);

每条记忆有源会话(供「当前频道」过滤)。

注入(memoryBlock)

src/main/TaskManager.ts:443:

v1.9.0 起,memoryBlock 从全量注入改为检索注入:

memoryBlock(conv)
  → 取最近 1-3 轮用户消息拼成 query(≤500 字)
  → recallForInjection(query):
      1. embedding cosine(score > 0.25, top-15, ≥3 条命中)→ touchMemoryUsed
      2. FTS5 LIKE 从 memories 表搜(≥2 条命中)
      3. recent-N 兜底(最新 15 条)
  → shellSafeMemory 过滤 → 注入为「## 关于用户」块

为什么改检索:记忆多到几百上千条时,全量注入浪费 token 且稀释相关性。检索管线为当前对话选出最相关的 15 条 —— ~500 token 而非 ~2000。

Direct 引擎的特殊处理(v1.0 重构)

memoryBlock 不拼进 systemPrompt,而是作为 history[0] 的 user 消息(带 _memory: true 标记)。理由:

  • Anthropic 的 cache_control 标在整个 system 上
  • memory 拼进 system 时,记忆每变一次(抽取新 fact)就打穿整个 base+rules+context 系统缓存
  • 拆出来后,system 跨轮稳定,缓存命中
  • 记忆失效只影响那条小消息(本就少量 token)

trim / compact 时永远保留 _memory 消息;return 时 dropTransient 过滤掉、不写回 directHistory(下一轮重新注入,防陈旧堆叠)。

详见 Direct-Engine。

🧠 面板

侧边栏 🧠 按钮 → 长期记忆面板:

操作 效果
scope 切换:当前频道 / 全部 按源 conversation_id 过滤
行内编辑 直接改 content,save 进 DB
删除 单条删,确认弹窗

主窗口 modal,不全屏。

导入 / 导出

⚙ → 长期记忆:

  • 导出 JSON —— 写到用户选的路径。结构:{ version: 1, exportedAt: number, memories: Memory[] }
  • 导入 JSON —— 接受上面结构 或 纯 string[]。按 content 去重,已存在的跳过。返回 { imported: N, skipped: N }。

适合:换机器迁移、备份、不同 provider 共享同一份记忆。

recall_memory 工具 vs 长期记忆

不要混淆:

recall_memory 工具 长期记忆
来源 history 表(FTS5 对话原文)+ memories 表(embedding 语义) memories 表(检索注入)
触发 模型主动调 每轮自动注入(top-15 按相关性)
用途 「我们之前怎么解决 X 的?」 「这个用户是谁、喜欢什么」
数据量 所有对话 只挑持久事实

recall_memory 详见 Tools-and-MCP。

已知限制

  • 每轮都抽:每个 turn 多一次 LLM 调用(成本翻倍,虽然小)
  • 抽什么靠模型判断:偶尔会抽出一次性细节(「用户问过 X」)→ 用 🧠 面板手动删
  • embedding 覆盖不全:embedding 只覆盖 memories 表(facts),history 表(对话原文)仍走 FTS5 关键词搜索。全量语义召回是 roadmap 项。
  • 跨语言不统一:中文抽中文、英文抽英文,不翻译

后续 roadmap 见 IMPROVEMENTS.md。

Clone this wiki locally