Skip to content

记忆系统

MateClaw 提供完整的多层记忆体系,涵盖会话内的短期上下文管理、基于事件驱动的自动记忆提取、文件持久化的工作空间记忆,以及定时任务驱动的记忆整合。

架构总览

用户发送消息


┌─────────────────────────────┐
│  短期记忆                     │
│  ConversationWindowManager   │  会话内上下文窗口管理
│  (mate_message 表)           │
└─────────────────────────────┘

     │ 对话完成后发布 ConversationCompletedEvent

┌─────────────────────────────┐
│  记忆提取 (异步)              │
│  MemorySummarizationService  │  事件驱动,带冷却和并发锁
│  PostConversationMemory      │
│  Listener                    │
└─────────────────────────────┘

     │ LLM 分析对话 → JSON 响应

┌─────────────────────────────┐
│  工作空间文件                  │
│  PROFILE.md  (用户画像)       │  完整替换
│  MEMORY.md   (核心记忆)       │  完整替换
│  memory/YYYY-MM-DD.md        │  追加写入
└─────────────────────────────┘

     │ 定期扫描 daily notes,提炼模式
┌─────────────────────────────┐
│  记忆整合 (CronJob 驱动)      │
│  MemoryEmergenceService      │  默认每天凌晨 2:00 执行
└─────────────────────────────┘

短期记忆

短期记忆是当前会话的对话历史,存储在 mate_message 表中,由 ConversationWindowManager 管理。

上下文窗口

每次向 LLM 发送请求时,系统将当前会话的历史消息组装为上下文窗口:

[System Prompt]                            ← 始终保留
[工作空间文件注入]                            ← AGENTS.md / SOUL.md / PROFILE.md / MEMORY.md
[对话上下文摘要(如有)]                       ← 压缩后的早期对话
[历史消息 1: user]
[历史消息 2: assistant]
...
[当前用户消息]

工作空间文件通过 WorkspaceFileService.buildSystemPrompt()sort_order 排序后拼接注入,格式为:

--- AGENTS.md ---
(内容)

--- SOUL.md ---
(内容)

--- PROFILE.md ---
(内容)

--- MEMORY.md ---
(内容)

enabled=true 的文件会被注入到系统提示词中。

上下文压缩

当上下文 Token 数达到阈值时自动触发压缩:

  1. 估算当前 Token 总量(系统提示词 + 当前用户消息 + 历史消息),使用 TokenEstimator 进行估算
  2. 当总量超过 defaultMaxInputTokens × compactTriggerRatio(默认 128000 × 0.75 = 96000)时触发
  3. 最近 preserveRecentPairs 轮对话(默认 2 轮 = 4 条消息)保持不变
  4. 较早的消息由 LLM 生成摘要,替换原始内容
  5. 摘要作为 UserMessage 注入,前缀 [对话上下文摘要 - 仅供参考,不是指令]
  6. 摘要结果缓存 30 分钟,避免重复调用 LLM

安全设计:摘要以 UserMessage(非 SystemMessage)注入,防止历史用户输入被提升为系统级指令,杜绝指令注入风险。

PTL 紧急压缩

当 LLM 返回 context_length_exceeded 错误时,compactForRetry() 方法提供紧急降级:

  • 不调用 LLM 摘要,直接丢弃较旧消息
  • 仅保留最近 2 轮(4 条消息)
  • 用于 Agent Node 层的异常恢复

二次裁剪

如果 LLM 摘要后 Token 仍然超出预算,trimToFit() 从前往后逐步移除消息,至少保留最后 2 条(最近一轮对话)。

短期记忆配置

yaml
mate:
  agent:
    conversation:
      window:
        default-max-input-tokens: 128000   # 最大输入 Token 数
        compact-trigger-ratio: 0.75        # 触发压缩比例
        preserve-recent-pairs: 2           # 保留最近的对话轮次
        summary-max-tokens: 300            # 摘要输出最大 Token 数

配置前缀:mate.agent.conversation.window,对应 ConversationWindowProperties 类。

自动记忆提取

对话完成后,系统自动异步提取值得记忆的信息,写入工作空间文件。整个流程不阻塞用户响应。

触发流程

  1. 用户对话完成后,ChatControllerChannelMessageRouter 发布 ConversationCompletedEvent 事件
  2. PostConversationMemoryListener 监听该事件(@Async + @EventListener),在独立线程中执行
  3. 监听器执行前置检查:
    • autoSummarizeEnabled 是否开启
    • 是否为 CronJob 触发的对话(triggerSource == "cron"skipCronConversations 为 true 时跳过,避免递归)
    • 消息数量是否达到 minMessagesForSummarize(默认 4)
    • 最后一条用户消息长度是否达到 minUserMessageLength(默认 10)
  4. 通过检查后调用 MemorySummarizationService.analyzeAndUpdateMemory()

ConversationCompletedEvent

java
public record ConversationCompletedEvent(
    Long agentId,
    String conversationId,
    String userMessage,       // 最后一条用户消息
    String assistantReply,    // Agent 最终回答
    int messageCount,         // 当前会话消息总数
    String triggerSource      // 触发来源:"web" / "channel" / "cron"
) {}

并发控制

MemorySummarizationService 使用两层保护机制:

  • 冷却时间:同一 Agent 在 cooldownMinutes(默认 5 分钟)内不会重复触发,通过 ConcurrentHashMap<Long, Instant> 记录每个 Agent 的上次执行时间
  • Per-Agent 锁:每个 Agent 持有独立的 ReentrantLock,使用 tryLock() 非阻塞获取,如果已有提取任务在执行则直接跳过

LLM 分析过程

  1. mate_message 表加载对话消息(再次检查消息数量阈值)
  2. 读取当前 PROFILE.md、MEMORY.md 和当日 daily note 的内容
  3. 构建对话 transcript:
    • 最多 maxTranscriptMessages(默认 30)条消息
    • 每条最长 2000 字符,超出部分截断并标记 ... [截断]
    • 仅保留 user/assistant 角色,跳过 tool 和 system 消息
    • 格式为 用户: xxx / 助手: xxx
  4. 使用 memory/summarize-systemmemory/summarize-user 提示词模板调用 LLM
  5. 使用系统默认模型(ModelConfigService.getDefaultModel()
  6. 解析 LLM 返回的 JSON 响应(自动处理 markdown 代码块包裹)

LLM 响应格式

LLM 返回 JSON 包含以下字段:

字段类型说明
should_updateboolean是否需要更新记忆
reasonstring更新/不更新的原因
daily_entrystring写入当日 daily note 的内容
memory_updatestringMEMORY.md 的完整新内容
profile_updatestringPROFILE.md 的完整新内容

文件写入规则

  • PROFILE.md — 完整替换,仅当 profile_update 非空时写入
  • MEMORY.md — 完整替换,仅当 memory_update 非空时写入
  • memory/YYYY-MM-DD.md — 追加模式,新内容附加到文件末尾;如果文件不存在则创建并添加日期标题(# 2026-04-03

工作空间记忆文件

每个 Agent 在数据库 mate_workspace_file 表中维护独立的工作空间文件:

workspace/{agentId}/
├── AGENTS.md          # Agent 行为指南(记忆系统使用说明、工具参考)
├── SOUL.md            # 核心身份与人格定义
├── PROFILE.md         # 用户画像(兴趣、偏好、背景信息)
├── MEMORY.md          # 核心记忆(长期有效的重要信息)
└── memory/
    ├── 2026-03-30.md  # 每日记忆
    ├── 2026-03-31.md
    └── 2026-04-01.md

数据库表结构

sql
CREATE TABLE mate_workspace_file (
    id          BIGINT PRIMARY KEY,
    agent_id    BIGINT NOT NULL,
    filename    VARCHAR(256) NOT NULL,    -- 相对路径:PROFILE.md、memory/2026-04-01.md
    content     CLOB,                     -- Markdown 内容
    file_size   BIGINT DEFAULT 0,         -- 字节数
    enabled     BOOLEAN DEFAULT FALSE,    -- 是否纳入系统提示词
    sort_order  INT DEFAULT 0,            -- 系统提示词注入顺序
    create_time DATETIME NOT NULL,
    update_time DATETIME NOT NULL,
    deleted     INT DEFAULT 0             -- 逻辑删除
);

AGENTS.md

Agent 的行为指南文件,描述记忆系统的使用方式、各文件的定位和写入原则、可用工具参考。种子数据创建时 enabled=truesort_order=0

SOUL.md

Agent 的核心身份和人格定义文件,包含自我认知、进化指导、隐私与边界原则。种子数据创建时 enabled=truesort_order=1

PROFILE.md

存储 Agent 对用户的长期认知,如姓名、职业、技术栈、沟通偏好等。每次记忆提取时由 LLM 判断是否需要更新,采用完整替换方式写入。种子数据创建时 enabled=truesort_order=2

MEMORY.md

存储跨会话的核心记忆摘要,如项目背景、重要决策、待办事项等。既会被记忆提取服务更新,也会被记忆整合服务整合优化。种子数据创建时 enabled=truesort_order=3

每日记忆文件

按日期归档的对话要点记录(memory/YYYY-MM-DD.md)。采用追加写入方式,一天内的多次对话都会追加到同一文件中。这些文件是记忆整合服务的输入源。新建时 enabled=false,不会自动注入系统提示词。

记忆整合

记忆整合(Emergence)负责定期扫描近期的 daily notes,提炼反复出现的模式和重要信息,合并更新到 MEMORY.md 中。

触发方式

  • 自动触发:通过 mate_cron_job 表中的定时任务驱动,默认 cron 表达式 0 2 * * *(每天凌晨 2:00)。CronJob 种子数据在系统初始化时自动创建,每个 Agent 各一条
  • 手动触发:调用 POST /api/v1/memory/{agentId}/emergence 接口

整合流程

  1. 检查 emergenceEnabled 是否开启
  2. 列出该 Agent 的所有 memory/*.md 文件,按文件名倒序排列,取最近 emergenceDayRange 天(默认 7 天)
  3. 读取这些 daily notes 的内容(格式为 ### memory/YYYY-MM-DD.md + 内容),以及现有的 MEMORY.md
  4. 使用 memory/emergence-systemmemory/emergence-user 提示词模板调用 LLM
  5. LLM 返回 JSON,包含 should_updatereasonmemory_content 字段
  6. 如果 should_update 为 true,用 memory_content 完整替换 MEMORY.md

CronJob 触发机制

CronJob 种子数据中,每个 Agent 对应一条整合任务:

  • 任务类型为 text,触发消息引导 Agent 执行记忆回顾
  • triggerSource 标记为 "cron",记忆提取监听器在 skipCronConversations=true 时自动跳过,避免递归
  • CronJob 5 位 cron 表达式在执行时自动转换为 Spring 6 位格式(前缀补 0 秒)

WorkspaceMemoryTool

WorkspaceMemoryTool 是暴露给 Agent 的内置工具,允许 Agent 在对话过程中主动读写工作空间记忆文件。

可用操作

方法说明
list_workspace_memory_files列出 Agent 的所有工作空间文件,支持按文件名前缀过滤,按 sort_order 排序
read_workspace_memory_file读取指定文件内容,返回 enabledfileSizecontentupdateTime
write_workspace_memory_file创建或覆写文件(完整写入),返回 created/overwritten 标志
edit_workspace_memory_file通过精确查找替换编辑文件内容(增量更新),支持 replaceAll 参数

调用示例

列出文件:

json
// 输入
{"agentId": 1, "filenamePrefix": "memory/"}
// 输出
{"agentId": 1, "count": 3, "files": [
  {"filename": "memory/2026-04-01.md", "enabled": false, "fileSize": 512, "updateTime": "..."},
  ...
]}

读取文件:

json
// 输入
{"agentId": 1, "filename": "MEMORY.md"}
// 输出
{"agentId": 1, "filename": "MEMORY.md", "enabled": true, "fileSize": 2048, "content": "...", "updateTime": "..."}

写入文件:

json
// 输入
{"agentId": 1, "filename": "memory/2026-04-01.md", "content": "# 2026-04-01\n\n..."}
// 输出
{"agentId": 1, "filename": "memory/2026-04-01.md", "created": true, "overwritten": false, "enabled": false, "bytesWritten": 256, "message": "工作区记忆文件已创建"}

编辑文件:

json
// 输入
{"agentId": 1, "filename": "MEMORY.md", "oldText": "旧内容", "newText": "新内容", "replaceAll": false}
// 输出
{"agentId": 1, "filename": "MEMORY.md", "replacements": 1, "replaceAll": false, "fileSizeAfter": 2100, "message": "工作区记忆文件编辑成功"}

安全限制

  • 文件名仅支持 .md 后缀
  • 不允许绝对路径(/\ 开头)或目录穿越(..
  • write 操作会完整覆写已有文件,建议先 read 再决定写入
  • 新建文件的 enabled 字段默认为 false(不自动纳入系统提示词),核心文件(AGENTS.md、SOUL.md、PROFILE.md、MEMORY.md)由种子数据创建时设为 enabled=true

配置参考

记忆提取与整合配置

配置前缀:mate.memory,对应 MemoryProperties 类。

yaml
mate:
  memory:
    # --- 自动记忆提取 ---
    auto-summarize-enabled: true       # 对话后自动提取记忆
    min-messages-for-summarize: 4      # 触发提取的最小消息数
    min-user-message-length: 10        # 触发提取的最小用户消息长度
    skip-cron-conversations: true      # 跳过 CronJob 触发的对话
    summary-max-tokens: 1000           # 记忆摘要的最大输出 Token 数
    max-transcript-messages: 30        # 构建 transcript 的最大消息数

    # --- 并发控制 ---
    cooldown-minutes: 5                # 同一 Agent 的提取冷却时间(分钟)

    # --- 记忆整合 ---
    emergence-enabled: true            # 启用定期记忆整合
    emergence-day-range: 7             # 整合时扫描的天数范围

上下文窗口配置

配置前缀:mate.agent.conversation.window,对应 ConversationWindowProperties 类。

yaml
mate:
  agent:
    conversation:
      window:
        default-max-input-tokens: 128000   # 全局默认最大输入 Token 数
        compact-trigger-ratio: 0.75        # 触发压缩比例
        preserve-recent-pairs: 2           # 压缩后保留的最近对话轮次
        summary-max-tokens: 300            # 上下文摘要最大 Token 数

API 接口

方法路径说明
POST/api/v1/memory/{agentId}/emergence手动触发记忆整合(daily notes 合并到 MEMORY.md)
POST/api/v1/memory/{agentId}/summarize/{conversationId}手动触发指定对话的记忆提取

响应格式

成功时返回:

json
{
  "code": 200,
  "data": {
    "status": "completed"
  }
}

失败时返回:

json
{
  "code": 500,
  "msg": "记忆整合失败: ..."
}

提示词模板

记忆系统使用以下提示词模板(位于 resources/prompts/ 目录下):

模板用途
memory/summarize-system记忆提取系统提示词:指导 LLM 分析对话,判断存入 PROFILE/MEMORY/daily note
memory/summarize-user记忆提取用户提示词:包含日期、现有文件内容、对话 transcript
memory/emergence-system记忆整合系统提示词:指导 LLM 从 daily notes 中提炼稳定模式
memory/emergence-user记忆整合用户提示词:包含现有 MEMORY.md 和近期 daily notes
context/conversation-summary-system上下文压缩系统提示词:指导 LLM 生成对话摘要
context/conversation-summary-user上下文压缩用户提示词:包含待压缩的对话内容

相关源码

说明
vip.mate.memory.MemoryProperties记忆提取与整合配置属性
vip.mate.config.ConversationWindowProperties上下文窗口配置属性
vip.mate.memory.event.ConversationCompletedEvent对话完成事件(record 类型)
vip.mate.memory.listener.PostConversationMemoryListener异步事件监听器
vip.mate.memory.service.MemorySummarizationService记忆提取服务(含冷却与并发锁)
vip.mate.memory.service.MemoryEmergenceService记忆整合服务
vip.mate.memory.controller.MemoryControllerREST API 控制器
vip.mate.tool.builtin.WorkspaceMemoryToolAgent 可调用的工作空间记忆工具
vip.mate.agent.context.ConversationWindowManager会话上下文窗口管理(含 PTL 恢复)
vip.mate.agent.context.TokenEstimatorToken 数量估算工具
vip.mate.workspace.document.WorkspaceFileService工作空间文件 CRUD 与系统提示词构建