Skip to main content

概述

PAI 的记忆系统为每位用户维护独立的长期记忆库,实现跨会话的信息持久化。无论用户在哪个平台、哪次对话中提及的偏好、事实或目标,都会被自动提取并存储,在后续对话中按相关性注入上下文。

跨会话持久化

记忆存储在数据库中,不随会话结束而丢失

双通道写入

Agent 显式工具调用 + 异步后台提取,双管齐下

相关性检索

基于 token 重叠 + 重要度 + 时效性的综合打分

语义去重

自动识别并合并语义相似的记忆条目

记忆类型

系统支持以下 5 种记忆类型(profile 类型保留给用户档案,不进入长期记忆):
类型说明示例
preference用户偏好与习惯喜欢川菜、偏好简洁回复风格
fact客观事实信息生日 1999-02-07、住在武汉
goal用户的目标与计划年底前考过 N1
project项目相关信息正在开发 PAI 项目
constraint约束规则回复不超过 200 字

数据模型

记忆存储在 long_term_memories 表中:
CREATE TABLE long_term_memories (
    id              SERIAL PRIMARY KEY,
    user_id         INTEGER NOT NULL REFERENCES users(id),
    conversation_id INTEGER REFERENCES conversations(id),
    source_message_id INTEGER REFERENCES messages(id),

    memory_key      VARCHAR(160) NOT NULL,   -- 稳定槽位键,如 profile.birthday
    memory_type     VARCHAR(40) DEFAULT 'fact',
    content         VARCHAR(1000),           -- 记忆值
    importance      INTEGER DEFAULT 3,       -- 1-5 重要度
    confidence      FLOAT DEFAULT 0.8,       -- 0-1 置信度

    is_active       BOOLEAN DEFAULT TRUE,
    last_accessed_at TIMESTAMPTZ,
    expires_at      TIMESTAMPTZ,             -- TTL 过期时间
    created_at      TIMESTAMPTZ NOT NULL,
    updated_at      TIMESTAMPTZ NOT NULL,

    UNIQUE(user_id, memory_key)
);
memory_key 采用点分路径或下划线命名,如 profile.birthdaypreference.sport,保证同一语义槽位的记忆可被覆盖更新而非重复创建。

双通道写入

记忆通过两个独立通道写入系统:

通道一:Agent 显式工具

Agent 在对话过程中可通过以下工具直接操作记忆:
工具功能
memory_save创建或覆盖一条记忆
memory_append追加内容到已有记忆
memory_delete删除指定记忆
memory_list查询用户记忆列表
所有三个管理节点(chat_managerschedule_managerledger_manager)均可使用记忆工具。

通道二:异步提取管道

后台 memory_worker 进程定期扫描未处理的用户消息,自动从对话中提取记忆候选。

三阶段提取流程

异步提取管道分为三个阶段:
1

候选提取 (extract_memory_candidates)

LLM 分析用户输入与完整会话上下文,输出结构化候选记忆数组。每条候选包含:
  • op:操作类型(save / delete)
  • memory_type:记忆类型
  • key:稳定槽位键
  • content:记忆值
  • importance:重要度 1-5
  • confidence:置信度 0-1
  • ttl_days:可选过期天数
2

精炼去重 (_llm_refine_memory_candidates)

第二轮 LLM 调用,结合用户已有记忆做最终裁决:
  • 判断每条候选是否保留(keep
  • 语义等价的候选与已有记忆合并(merge_target_id
  • 归并表述不同但语义相同的候选为规范形式
  • 复用已有 memory_key 避免重复创建
3

写入持久化 (upsert_long_term_memories)

  • 新记忆:插入数据库,自动设置 TTL
  • 合并记忆:更新已有记录的 contentimportanceconfidence
  • 删除记忆:标记 is_active = false
  • 每次写入后清理语义重复项(阈值 0.9)

提取规则

会被提取的内容:
  • 用户明确表达的偏好和习惯
  • 30 天后仍有价值的事实信息
  • 用户说”请记住”或”以后按此执行”的规则
  • 用户的长期目标和计划
会被过滤的内容:
  • 短期状态和一次性任务进度
  • 天气快照、日/周汇总
  • 运维/系统/工具内部信息
  • 身份档案信息(昵称、姓名、助手名、emoji)
  • 原始数据库日志

相关性检索

retrieve_relevant_long_term_memories 函数在每次对话开始时,根据用户输入检索最相关的记忆注入上下文。

打分公式

score = token_overlap * 0.7 + importance_score * 0.2 + recency_score * 0.1
各分量计算方式:
分量计算方法
token_overlap查询 tokens 与记忆 tokens 的重叠比例:overlap / len(query_tokens)
importance_scoremin(5, importance) / 5,归一化到 0-1
recency_score1 / (1 + days_since_update / 30),越新分数越高
检索流程:
  1. 扫描用户所有未过期记忆(上限 retrieve_scan_limit 条)
  2. 按 importance 和 updated_at 降序排列
  3. 对每条记忆计算相关性得分
  4. 优先取词法匹配分 >= 0.12 的条目
  5. 不足时用剩余高分条目补充
  6. 过滤掉身份类记忆
  7. 返回 top-20 条,注入对话上下文

Token 匹配策略

系统同时支持 ASCII 和中文的 token 化:
  • ASCII 词:正则 [a-zA-Z0-9_]{2,} 匹配英文单词
  • 中文 bigram:连续中文字符串按 2-gram 切分(如”武汉大学” -> “武汉”, “汉大”, “大学”)
相似度计算结合两种度量:
  • Jaccard 系数|A & B| / |A | B|
  • Containment 系数max(|A & B|/|A|, |A & B|/|B|) * 0.92
取两者最大值作为最终相似度。

生命周期管理

TTL 过期

  • 默认 TTL:730 天(约 2 年)
  • 可通过 ttl_days 字段自定义每条记忆的过期时间
  • 检索时自动过滤 expires_at 已过期的记忆

语义去重

两个阈值控制去重行为:
阈值用途
SEMANTIC_DUPLICATE_THRESHOLD0.82查找语义重复项时的匹配阈值
SEMANTIC_MERGE_STRICT_THRESHOLD0.9写入后清理严格重复项的阈值

合并 API

系统提供 consolidate API,可批量扫描用户记忆(上限 160 条),通过 LLM 判断是否合并、保留或删除。

消息级追踪

每条用户消息在 messages 表中包含记忆处理状态字段:
字段说明
memory_status处理状态
memory_processed_at处理完成时间
状态流转:
NULL / PENDING → PROCESSED  (成功提取)
NULL / PENDING → FAILED     (提取失败)
NULL / PENDING → SKIPPED    (无需提取)

memory_worker 后台进程

memory_worker 是独立运行的后台进程,负责定期扫描未处理消息并执行记忆提取:
# 运行循环
while True:
    if long_term_memory_enabled and long_term_memory_scan_enabled:
        await scan_unprocessed_memory_messages(
            max_conversations=80,
            max_messages_per_conversation=30,
        )
    await asyncio.sleep(interval_sec)  # 默认 120 秒

配置参数

参数默认值说明
long_term_memory_enabledtrue总开关
long_term_memory_min_confidence0.5最低置信度阈值
long_term_memory_max_write_items6单次最大写入条数
long_term_memory_retrieve_limit20检索返回上限(top-K)
long_term_memory_retrieve_scan_limit80检索扫描上限
long_term_memory_default_ttl_days730默认过期天数
long_term_memory_debounce_sec0写入防抖间隔
long_term_memory_extract_timeout_sec90提取超时
long_term_memory_upsert_timeout_sec90写入超时
long_term_memory_extract_context_max_chars24000提取上下文最大字符数
long_term_memory_extract_message_max_chars200单条消息最大字符数
long_term_memory_scan_enabledtrue后台扫描开关
long_term_memory_scan_run_in_apifalse是否在 API 进程内运行扫描
long_term_memory_scan_interval_sec120扫描间隔(秒)
long_term_memory_scan_max_conversations80每轮最大扫描会话数
long_term_memory_scan_max_messages_per_conversation30每会话最大扫描消息数