跳转至

记忆与 Sleep

记忆引擎

Riverse 不是 RAG 系统。它不存储原始对话片段再做相似度检索,而是在每次对话结束后运行结构化提取流水线(Sleep),构建一个持续自我修正的个人画像。

提取了什么

每次对话被处理成三种独立的数据结构,各有自己的生命周期:

类型 捕获内容 生命周期
画像事实 持久属性:工作、城市、偏好、健康规律等 置信度驱动,时间衰减,更新时被取代
人际关系 提到的人:姓名、关系、细节、提及次数 每次提及时更新,追踪状态变化
事件 有时效的事件:换工作、搬家、手术等 通过 decay_days 自动过期

事实的生命周期

每条画像事实经历明确的生命周期:

观察(对话中提取的原始陈述)
suspected(猜测) →  confirmed(确认) →  established(稳固)
    ↓                    ↓
  rejected(否定)    closed(关闭,被新事实取代)
  • suspected — 已提取但尚未跨多次会话验证
  • confirmed — 在 2 次以上会话中一致出现,LLM 已交叉验证
  • established — 长期存在、证据充分,不会被单次对话轻易推翻
  • rejected — 标记为错误(手动或 LLM 仲裁)
  • closed — 事实已变化,旧记录保留 end_time,新事实接替

时间衰减

每条事实携带 decay_days 值——该类信息的预估有效期。接近过期的事实在上下文注入时权重降低,过期后从活跃画像中移除,但在时间线中永久保留。

矛盾仲裁

当 Sleep 检测到冲突事实(如"住在东京"vs"搬去大阪")时:

  1. 将两条事实标记为争议对
  2. 携带完整上下文(轨迹、时间线、近期对话)进行 LLM 仲裁
  3. 接受新事实并关闭旧事实,或否定新陈述

证据链

每条事实存储产生它的证据——来自特定对话的观察列表。这意味着:

  • 任何事实都可以追溯到创建它的对话
  • 矛盾仲裁时 LLM 拥有完整上下文
  • 置信度反映支持该事实的观察数量和质量

知识图谱

Sleep 提取事实之间的有类型边,构建个人知识图谱:

  • causes — "压力"导致"睡眠问题"
  • related_to — "换工作"关联"搬迁"
  • supports / contradicts — 事实之间的证据关系

在上下文注入时,知识图谱用于当相关话题出现时,主动关联因果相关的事实。

Sleep — 离线记忆整合

Sleep 是 Riverse 消化对话、更新画像的过程。支持自动触发和手动触发:

触发方式 说明
Telegram 发送 /new — 重置会话并在后台运行 Sleep
CLI 退出时自动执行(quit 或 Ctrl+C)
REST API POST /sleep
定时任务(推荐) 用 cron 设定每晚定时跑,整合一天的对话

cron 示例

每天凌晨 0 点运行 Sleep:

# crontab -e
0 0 * * * cd /path/to/JKRiver && /path/to/python -c "from agent.sleep import run; run()"

14 步流水线

整条流水线在单个数据库事务中原子执行。任何步骤失败,全部回滚——相同的对话会在下次运行时重新处理(至少一次语义)。

阶段一:提取

步骤 1 — 加载初始数据 加载现有用户画像(排除已被取代的事实)和最新的人生轨迹摘要,为后续所有步骤提供上下文。

步骤 2 — 提取会话 对每段未处理的对话,LLM 提取:

  • 观察 — 事实陈述、矛盾、偏好和行为信号。每条观察标记类型和主题。关于第三方(用户提到的人)的观察单独存储。
  • 标签 — 会话级别的主题标签
  • 人际关系 — 提到的人、与用户的关系、细节。已有的关系会合并(提及次数递增,细节更新)。
  • 事件 — 有时效的事件(换工作、搬家、手术等),含重要度和衰减天数

仅包含工具/外包意图的会话会被跳过——不含个人信息。

阶段二:分析

步骤 3 — 行为分析 LLM 结合所有观察、当前画像和轨迹推断行为模式。例如,多次深夜发消息可能意味着用户是夜猫子。推断出的事实以 source_type=inferred 存储。当证据数达到 3 条以上时,生成 clarify 策略,在未来对话中主动求证。

步骤 4 — 分类与整合 核心步骤。LLM 将每条观察与现有画像进行比对分类:

  • support — 支持已有事实 → 追加证据,提及次数递增
  • contradict — 与已有事实矛盾 → 创建新事实并标记 supersedes 链接,形成争议对
  • evidence_against — 削弱已有事实但不主张替代值
  • new — 无匹配事实 → 创建新的画像事实

未被分类的 statement/contradiction 类型观察自动补为 new。整合完成后,为新创建或矛盾的事实生成变更策略(probe 类型)。

步骤 5 — 交叉验证 对猜测事实进行验证:

  • 规则快速通道source_type=statedmention_count ≥ 2 的事实自动确认
  • LLM 验证:其余猜测事实(按提及次数降序,最多 80 条)结合时间线历史、相关对话摘要(近 3 个月)和轨迹上下文进行交叉验证

通过验证的事实从 suspected 升级为 confirmed

步骤 6 — 矛盾仲裁 争议事实对(新事实 supersedes 旧事实但两者均未关闭)连同完整上下文送给 LLM 仲裁。LLM 裁决 accept_new(接受新事实)或 reject_new(驳回新事实)。败诉方被关闭(设置 end_time),其知识图谱边被清理。

阶段三:维护

步骤 7 — 提取边 对本轮所有受影响的事实,LLM 提取有类型的边(因果、时序、层级),构建个人知识图谱。

步骤 8 — 过期处理 超过 expires_at 的事实被关闭。对每条过期事实生成 verify 策略,使 AI 在下次相关对话中自然地询问确认。

步骤 9 — 成熟度衰减 长期存在且证据充分的事实获得更长的生命周期。衰减梯度:

事实年龄 证据数 新 decay_days
≥ 730 天 ≥ 10 730(2 年)
≥ 365 天 ≥ 6 365(1 年)
≥ 90 天 ≥ 3 180(半年)

被轨迹识别为关键锚点的事实(如母语、长期职业)门槛降低 40%——它们成熟得更快。

阶段四:输出

步骤 10 — 用户模型 LLM 从对话中分析沟通风格维度(如直接 vs 委婉、正式 vs 随意、幽默风格)。结果存入 user_model 表,用于调整回复语气。

步骤 11 — 轨迹 当检测到重大变化(事实确认、争议解决、重要类别的矛盾)且距上次更新至少 2 个 session 时,重新生成人生轨迹。轨迹包含:人生阶段、方向、稳定性、关键锚点、不稳定领域和近期势头。

步骤 12 — 整合去重 清理提取和整合过程中产生的重复条目。

步骤 13 — 快照 预编译完整的记忆快照:画像事实 + 用户模型 + 活跃事件 + 人际关系 + 知识图谱边。下次对话直接使用快照,省去从多个表重新拼装上下文的开销。

步骤 14 — 完成 标记所有已处理的对话。这是最后一步——如果流水线在此之前崩溃,事务回滚,相同的对话会被重新处理。

事务后处理

原子事务完成后,两个非关键任务在事务之外运行:

  • 向量嵌入 — 对所有记忆做 embedding,支持语义搜索
  • 记忆聚类 — KMeans 聚类并生成主题标签

知识网络

Sleep 还会构建知识网络 — 用类型化的边连接相关的画像事实(如 causesrelated_tocontradictssupports)。让 AI 看到事实之间的结构关系,而不只是孤立的条目。

当事实被关闭或取代时,相关的边会自动清理。

记忆聚类

开启向量嵌入后,Sleep 还可以对记忆向量做 KMeans 聚类,并为每个簇生成主题标签,提供"鸟瞰"视角了解 AI 对你的认知全貌。

embedding:
  clustering:
    enabled: true
    show_themes: true

语义搜索

开启向量嵌入(BGE-M3)后,Riverse 可以按语义而非关键词检索相关记忆。

embedding:
  enabled: true
  model: "bge-m3"
  api_base: "http://localhost:11434"

会话记忆(Session Memory)

会话记忆通过三层结构管理单次对话中的上下文:

  1. 滑动摘要 — 旧对话被 LLM 压缩为滚动摘要,保留历史不超 token 限制
  2. 向量召回 — 开启向量嵌入后,根据当前消息的语义相似度召回早期相关对话
  3. 最近轮次 — 最近几轮对话完整保留,提供即时上下文

三层系统让对话可以无限进行而不丢失重要上下文。在 settings.yaml 中配置:

session_memory:
    char_budget: 3000        # 会话上下文总字符预算
    keep_recent: 5           # 保留完整的最近轮次数
    summary_ratio: 0.4       # 摘要占预算的比例
    recall_max: 3            # 向量召回最大条数
    recall_min_score: 0.45   # 召回最低相似度

pgvector 加速

默认情况下,向量以 JSONB 存储,余弦相似度在 Python 中计算。对于大数据集,安装 pgvector 扩展可显著提升性能:

# macOS
brew install pgvector

# Debian/Ubuntu
apt install postgresql-16-pgvector

然后运行迁移脚本:

psql -h localhost -U YOUR_USERNAME -d Riverse -f migrations/001_pgvector.sql

这会创建原生 vector(1024) 列和 IVFFlat 索引,实现快速近似最近邻搜索。应用会自动检测 pgvector 并在可用时使用,无需修改配置。

记忆准确性

Info

目前没有任何 LLM 是专门为个人画像提取训练的,提取结果可能偶尔出现偏差。你可以在 Web 面板中将错误的记忆标记为错误,或手动关闭过期的记忆 — 但记忆不能被删除或直接修改。这是有意为之:河流算法将记忆视为审计记录,错误的记忆就像河流中的泥沙,应该被水流冲走,而不是人工雕刻河床。

如果错误率较高,根本原因通常是 LLM 的理解能力,而非系统 Bug。建议切换更强的模型 — 记忆提取流程本身也是评估你的 LLM 是否适合此场景的实用基准。随着对话积累,算法会通过多轮验证和矛盾检测持续自我修正,画像会越来越准确。

算法先行的设计理念

Riverse 的记忆流水线在架构设计上超前于当前通用 LLM 的能力。14 步 Sleep 整合流程在每一步都需要精确的结构化判断——观察提取、事实分类、交叉验证、矛盾仲裁——且每一步的输出直接驱动下一步。目前准确率的瓶颈是 LLM 在每个环节的输出精度,而非算法本身。

考虑这个级联效应:如果每步 LLM 准确率为 90%(对某些任务已属乐观),六步串联后端到端准确率约 53%。如果换成专用训练的模型达到每步 99%,同样的流水线准确率可达 94%——同一套代码,质的飞跃。

目前没有任何 LLM 是专门为个人记忆整合训练的。理想路径是训练一个专用的记忆 LLM,针对以下能力进行优化:

  • 观察提取精度 — 区分"我住在东京"(陈述)和"我要是住在东京就好了"(假设)
  • 多事实联合推理 — 将一条新观察与 30+ 条现有画像事实进行比对判断(本质是一个受约束的自然语言推理任务,fine-tune 空间很大)
  • 校准的置信度 — 输出可靠的概率分数,让流水线可以按阈值做决策,而不是简单的二元分类

作者对这个模型应该长什么样有清晰的设计,但训练它需要个人开发者无法获得的算力和数据资源。

如果你的公司正在做记忆相关的模型,或者在做个人 AI 方向,有合适的岗位的话,欢迎联系我:mailwangjk@gmail.com

在此之前,算法运行在通用模型之上,并随着每一代更强模型的出现自动提升,无需改动一行代码。流水线的上下文输入(时间线、轨迹、对话摘要、证据链)已经为未来的模型准备了最丰富的信号。

这是一个有意为之的设计选择:先把架构做对,让模型来追赶算法,而不是为了迁就今天的模型能力而简化架构。