DeerFlow Memory架构

1. 概述

DeerFlow 的 长期记忆(Long-Term Memory) 系统使 Agent 能够在会话之间保留信息。与传统的聊天机器人在会话结束后会忘记一切不同,DeerFlow 会构建用户偏好、上下文和知识的持久记忆。

核心特性:

  • 跨会话持久化
  • 基于 LLM 的自动事实提取
  • 支持按 Agent 独立记忆
  • Token 限制的 System Prompt 注入
  • 防抖异步更新
  • 纠正/强化检测

2. 架构

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                        Memory System Architecture                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────────┐    │
│  │   Frontend   │────▶│  Lead Agent  │────▶│ MemoryMiddleware │    │
│  │   (User)     │     │              │     │  (after_agent)   │    │
│  └──────────────┘     └──────────────┘     └────────┬─────────┘    │
│                                                       │              │
│                                                       ▼              │
│                                              ┌──────────────┐       │
│                                              │ MemoryQueue  │       │
│                                              │ (Debounced)  │       │
│                                              └──────┬───────┘       │
│                                                     │               │
│                                    ┌────────────────┼───────────┐   │
│                                    ▼                ▼           ▼   │
│                             ┌──────────┐    ┌──────────┐  ┌─────┐  │
│                             │ Summarize│    │  Timer   │  │ 30s │  │
│                             │  Hook    │    │(threading│  │wait │  │
│                             └──────────┘    │  Timer)  │  └─────┘  │
│                                            └────────────┘           │
│                                                     │               │
│                                                     ▼               │
│                                              ┌──────────────┐       │
│                                              │MemoryUpdater │       │
│                                              │  (LLM-based) │       │
│                                              └──────┬───────┘       │
│                                                     │               │
│                                                     ▼               │
│                                              ┌──────────────┐       │
│                                              │FileMemory    │       │
│                                              │Storage       │       │
│                                              └──────┬───────┘       │
│                                                     │               │
│                                                     ▼               │
│                                              ┌──────────────┐       │
│                                              │ memory.json  │       │
│                                              └──────────────┘       │
│                                                                      │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────────┐    │
│  │   Frontend   │◀────│  Lead Agent  │◀────│  System Prompt  │    │
│  │   (User)     │     │   (Next      │     │  (Memory         │    │
│  └──────────────┘     │   Request)   │     │   Injection)    │    │
│                       └──────────────┘     └──────────────────┘    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

3. 数据结构

3.1 Memory JSON 结构

存储在 backend/.deer-flow/memory.json

json 复制代码
{
  "version": "1.0",
  "lastUpdated": "2026-04-21T10:30:00Z",

  "user": {
    "workContext": {
      "summary": "字节跳动高级软件工程师,从事 AI 基础设施工作...",
      "updatedAt": "2026-04-21T10:30:00Z"
    },
    "personalContext": {
      "summary": "精通中英文,对分布式系统感兴趣...",
      "updatedAt": "2026-04-21T09:15:00Z"
    },
    "topOfMind": {
      "summary": "目前专注于优化 DeerFlow 的memory系统。同时在探索...",
      "updatedAt": "2026-04-21T10:30:00Z"
    }
  },

  "history": {
    "recentMonths": {
      "summary": "自 2026 年 1 月起从事 DeerFlow 2.0 工作。实现了memory...",
      "updatedAt": "2026-04-20T16:00:00Z"
    },
    "earlierContext": {
      "summary": "之前从事 LangChain 集成工作。构建了多个自定义...",
      "updatedAt": "2026-03-15T11:00:00Z"
    },
    "longTermBackground": {
      "summary": "5 年以上 AI/ML 基础设施经验。强背景...",
      "updatedAt": "2026-01-10T08:00:00Z"
    }
  },

  "facts": [
    {
      "id": "fact_a1b2c3d4",
      "content": "用户更喜欢使用 Python 进行数据处理任务",
      "category": "preference",
      "confidence": 0.92,
      "createdAt": "2026-04-20T14:30:00Z",
      "source": "thread_abc123"
    },
    {
      "id": "fact_e5f6g7h8",
      "content": "用户正在研究 DeerFlow memory优化",
      "category": "context",
      "confidence": 0.88,
      "createdAt": "2026-04-21T10:00:00Z",
      "source": "thread_def456"
    },
    {
      "id": "fact_i9j0k1l2",
      "content": "用户之前对 debounce 机制有误解(避免:假设立即更新)",
      "category": "correction",
      "confidence": 0.95,
      "createdAt": "2026-04-21T09:45:00Z",
      "source": "thread_ghi789",
      "sourceError": "假设memory更新是同步发生的"
    }
  ]
}

3.2 Fact 类别

类别 描述 示例
preference 用户偏好的工具、风格、方法 "用户喜欢深色模式"
knowledge 用户的专业知识和技术掌握 "用户精通 PyTorch"
context 背景信息(工作、项目、地点) "用户在字节跳动工作"
behavior 工作模式和沟通习惯 "用户倾向于先问澄清问题"
goal 已声明的目标和项目愿景 "用户想优化 DeerFlow memory"
correction Agent 错误或用户纠正 "用户纠正了 Agent 关于 X 的说法"

3.3 置信度级别confidence

范围 含义 使用场景
0.9 - 1.0 明确陈述的事实 用户说"我从事 X 工作"或"我的角色是 Y"
0.7 - 0.8 从行为强烈暗示 用户持续使用 Python 而非 Java
0.5 - 0.6 推断的模式(谨慎使用) 多次观察到的明确行为模式

3.4 ConversationContext(队列项)

python 复制代码
@dataclass
class ConversationContext:
    thread_id: str                           # 线程标识符
    messages: list[Any]                      # 过滤后的对话消息
    timestamp: datetime                      # 入队时间(默认:现在)
    agent_name: str | None = None            # 按 Agent 记忆(None = 全局)
    correction_detected: bool = False        # 用户纠正了 Agent
    reinforcement_detected: bool = False     # 用户确认 Agent 有帮助

4. 核心组件

4.1 文件结构

复制代码
backend/packages/harness/deerflow/agents/memory/
├── __init__.py
├── storage.py              # MemoryStorage 接口 + FileMemoryStorage 实现
├── queue.py                # 带防抖的 MemoryUpdateQueue
├── updater.py              # MemoryUpdater(基于 LLM 的事实提取)
├── prompt.py               # MEMORY_UPDATE_PROMPT + 注入格式化
├── message_processing.py   # 消息过滤 + 纠正/强化检测
├── summarization_hook.py   # memory_flush_hook() 用于总结集成
└── memory_middleware.py    # MemoryMiddleware(Lead Agent 中间件 #13)

4.2 组件详情

4.2.1 storage.py

职责: 抽象存储接口和基于文件的实现。

关键类:

  • MemoryStorage(ABC):定义 load()reload()save() 接口的抽象基类
  • FileMemoryStorage:基于 JSON 文件的存储,带缓存

FileMemoryStorage 特性:

  • 每个 Agent 名称的线程安全memory缓存
  • 通过文件修改时间(mtime)检查缓存有效性
  • 通过临时文件 + 重命名的原子性保存
  • 支持按 Agent 记忆文件(根据 AGENT_NAME_PATTERN 验证)

默认存储位置:

复制代码
backend/.deer-flow/memory.json              # 全局记忆
backend/.deer-flow/memory_{agent_name}.json # 按 Agent 记忆
4.2.2 queue.py

职责: 用于批处理memory更新的防抖队列。

关键类: MemoryUpdateQueue

特性:

  • 可配置的防抖周期(默认:30 秒)
  • 按线程去重(每个 thread_id 只保留最新对话)
  • 基于线程的定时器延迟处理
  • flush() 用于同步处理,flush_nowait() 用于后台处理

单例模式:

python 复制代码
_memory_queue: MemoryUpdateQueue | None = None

def get_memory_queue() -> MemoryUpdateQueue:
    """获取全局memory更新队列单例。"""
    global _memory_queue
    with _queue_lock:
        if _memory_queue is None:
            _memory_queue = MemoryUpdateQueue()
        return _memory_queue
4.2.3 updater.py

职责: 基于 LLM 的memory更新和事实提取。

关键类: MemoryUpdater

核心方法:

  • update_memory() - 通过 ThreadPoolExecutor 同步更新
  • aupdate_memory() - 在异步上下文中使用的异步更新
  • _prepare_update_prompt() - 使用当前记忆 + 对话构建提示词
  • _finalize_update() - 解析 LLM 响应并持久化更改
  • _apply_updates() - 将结构化更新应用到记忆数据

关键特性:

  • 空白符归一化的事实去重(大小写不敏感、去空格比较)
  • max_facts 限制强制执行(默认:100,保留最高置信度)
  • 上传事件清理,防止临时文件路径进入记忆
  • 带有 sourceError 跟踪的纠正检测
4.2.4 prompt.py

职责: 操作memory的提示词模板。

关键模板:

  1. MEMORY_UPDATE_PROMPT - 用于 LLM 分析对话并生成更新:

    • 输入:当前记忆状态 + 新对话
    • 输出:更新 user/history 部分和新事实的结构化 JSON
    • 包含用于错误/重试检测的结构化反思说明
  2. FACT_EXTRACTION_PROMPT - 用于从单条消息提取事实

关键函数:

python 复制代码
def format_memory_for_injection(memory_data: dict, max_tokens: int = 2000) -> str:
    """
    格式化记忆以注入到系统提示词中。

    - 使用 tiktoken 进行精确 token 计数
    - 按置信度排序事实
    - 在 token 预算内包含尽可能多的事实
    - 格式:"- [category | confidence] content"
    """

def format_conversation_for_update(messages: list) -> str:
    """
    格式化对话消息以进行记忆更新。

    - 只过滤 human/ai 消息
    - 从 human 消息中去除 uploaded_files 标签
    - 截断超长消息(>1000 字符)
    """
4.2.5 message_processing.py

职责: 消息过滤和信号检测。

关键函数:

python 复制代码
def filter_messages_for_memory(messages: list) -> list:
    """
    只保留用户输入和最终助手回复。

    - 跳过仅包含文件上传的消息
    - 从内容中去除 uploaded_files 标签
    - 排除工具调用/结果消息
    """

def detect_correction(messages: list) -> bool:
    """
    检测用户明确的纠正。

    模式(英文):
    - "that's wrong", "that's incorrect"
    - "you misunderstood"
    - "try again", "redo"

    模式(中文):
    - "不对", "你理解错了", "你理解有误"
    - "重试", "重新来", "换一种", "改用"
    """

def detect_reinforcement(messages: list) -> bool:
    """
    检测明确的积极强化。

    模式(英文):
    - "yes, exactly", "perfect"
    - "that's right", "that's correct"
    - "keep doing that", "just like that"

    模式(中文):
    - "对,就是这样", "完全正确"
    - "就是这个意思", "正是我想要的"
    - "继续保持"
    """
4.2.6 summarization_hook.py

职责: 与总结系统的集成。

函数: memory_flush_hook(event: SummarizationEvent)

当总结系统即将压缩消息时(以保持在 token 限制内),此钩子确保这些消息首先被刷新到memory队列。这在信息被总结掉之前保留下来。

4.2.7 memory_middleware.py

职责: Lead Agent 中间件集成。

类: MemoryMiddleware(中间件链中的 #13)

中间件链中的位置:

  1. ThreadDataMiddleware
  2. UploadsMiddleware
  3. SandboxMiddleware
  4. DanglingToolCallMiddleware
  5. LLMErrorHandlingMiddleware
  6. GuardrailMiddleware
  7. SandboxAuditMiddleware
  8. ToolErrorHandlingMiddleware
  9. SummarizationMiddleware
  10. TodoListMiddleware
  11. TokenUsageMiddleware
  12. TitleMiddleware
  13. MemoryMiddleware
  14. ViewImageMiddleware
  15. DeferredToolFilterMiddleware
  16. SubagentLimitMiddleware
  17. LoopDetectionMiddleware
  18. ClarificationMiddleware

after_agent() 流程:

  1. 从运行时上下文或 LangGraph 配置获取 thread_id
  2. 从状态获取消息
  3. 过滤为用户输入 + 最终 AI 回复
  4. 检测纠正/强化信号
  5. 通过 get_memory_queue().add() 入队

5. 更新流程

5.1 完整更新时序

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    Memory Update Sequence Diagram                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  1. 用户交互                                                        │
│  ┌────────┐      ┌──────────────┐      ┌──────────────────────┐    │
│  │ User   │─────▶│  Lead Agent  │─────▶│   MemoryMiddleware   │    │
│  │ Message│      │              │      │     after_agent()     │    │
│  └────────┘      └──────────────┘      └──────────┬───────────┘    │
│                                                     │                │
│  2. 入队 & 防抖                                     ▼                │
│                                          ┌──────────────────┐        │
│                                          │  MemoryQueue     │        │
│                                          │  .add()          │        │
│                                          │  (30s debounce)  │        │
│                                          └────────┬─────────┘        │
│                                                   │                  │
│  3. 定时器到期                                    ▼                  │
│                                          ┌──────────────────┐        │
│                                          │  _process_queue()│        │
│                                          │  (background)    │        │
│                                          └────────┬─────────┘        │
│                                                   │                  │
│  4. LLM 更新                                     ▼                  │
│                                          ┌──────────────────┐        │
│                                          │  MemoryUpdater   │        │
│                                          │  .update_memory()│        │
│                                          └────────┬─────────┘        │
│                                                   │                  │
│  5. 存储                                         ▼                  │
│                                          ┌──────────────────┐        │
│                                          │  FileMemory      │        │
│                                          │  .save()         │        │
│                                          │  (atomic write)  │        │
│                                          └────────┬─────────┘        │
│                                                   │                  │
│  6. 下次交互                                     ▼                  │
│                                          ┌──────────────────┐        │
│                                          │ format_memory    │        │
│                                          │ _for_injection() │        │
│                                          └────────┬─────────┘        │
│                                                   │                  │
│                                                   ▼                  │
│                                          ┌──────────────────┐        │
│                                          │  System Prompt   │        │
│                                          │  <memory> tag    │        │
│                                          └──────────────────┘        │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

5.2 步骤详解

步骤 1:消息收集

每次 Agent 执行后,调用 MemoryMiddleware.after_agent()

python 复制代码
# 获取 thread_id
thread_id = runtime.context.get("thread_id") or get_config().configurable.thread_id

# 获取并过滤消息
messages = state.get("messages", [])
filtered_messages = filter_messages_for_memory(messages)

# 检测信号
correction_detected = detect_correction(filtered_messages)
reinforcement_detected = not correction_detected and detect_reinforcement(filtered_messages)

# 入队等待处理
queue.add(
    thread_id=thread_id,
    messages=filtered_messages,
    agent_name=self._agent_name,
    correction_detected=correction_detected,
    reinforcement_detected=reinforcement_detected,
)
步骤 2:防抖队列

MemoryUpdateQueue.add()

  1. 检查记忆是否启用
  2. 与同一 thread_id 的现有上下文合并(保留最新,合并纠正/强化标志)
  3. 重置防抖定时器
python 复制代码
def _enqueue_locked(self, thread_id, messages, ...):
    # 如果线程已在队列中,用新消息替换
    # 这是"按线程去重" - 只保留最新对话
    self._queue = [c for c in self._queue if c.thread_id != thread_id]
    self._queue.append(ConversationContext(...))
步骤 3:定时器处理

30 秒后(可配置),调用 _process_queue()

python 复制代码
def _process_queue(self):
    with self._lock:
        contexts_to_process = self._queue.copy()
        self._queue.clear()

    for context in contexts_to_process:
        updater = MemoryUpdater()
        updater.update_memory(
            messages=context.messages,
            thread_id=context.thread_id,
            agent_name=context.agent_name,
            correction_detected=context.correction_detected,
            reinforcement_detected=context.reinforcement_detected,
        )
步骤 4:基于 LLM 的事实提取

MemoryUpdater._prepare_update_prompt() 构建提示词:

复制代码
Current Memory State:
<current_memory>
{当前记忆的 JSON}
</current_memory>

New Conversation to Process:
<conversation>
User: 我更喜欢使用 Python 进行数据处理

Assistant: 我会使用 Python 来帮助您处理这个任务...
</conversation>

Instructions:
1. 分析对话中的重要信息
2. 提取相关的事实、偏好和上下文
3. 根据需要更新记忆部分
...

MemoryUpdater._finalize_update() 解析 JSON 响应:

json 复制代码
{
  "user": {
    "workContext": { "summary": "...", "shouldUpdate": true },
    "topOfMind": { "summary": "...", "shouldUpdate": true }
  },
  "history": {
    "recentMonths": { "summary": "...", "shouldUpdate": true }
  },
  "newFacts": [
    { "content": "用户更喜欢使用 Python 进行数据处理", "category": "preference", "confidence": 0.92 }
  ],
  "factsToRemove": []
}
步骤 5:应用更新

_apply_updates()

  1. shouldUpdate: true 的地方更新 user/history 部分
  2. 删除 factsToRemove 中的事实
  3. 添加新事实并进行去重(空白符归一化)
  4. 强制执行 max_facts 限制(保留最高置信度)
步骤 6:原子性保存

FileMemoryStorage.save()

python 复制代码
def save(self, memory_data, agent_name=None):
    # 1. 复制并添加时间戳
    memory_data = {**memory_data, "lastUpdated": utc_now_iso_z()}

    # 2. 写入临时文件
    temp_path = file_path.with_suffix(f".{uuid.uuid4().hex}.tmp")
    with open(temp_path, "w") as f:
        json.dump(memory_data, f, indent=2, ensure_ascii=False)

    # 3. 原子重命名
    temp_path.replace(file_path)

    # 4. 更新缓存
    with self._cache_lock:
        self._memory_cache[agent_name] = (memory_data, mtime)

6. Memory 注入

6.1 注入流程

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    Memory Injection Flow                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  1. 下次用户请求                                                     │
│  ┌────────┐                                                         │
│  │ User   │                                                         │
│  │ Request│                                                         │
│  └───┬────┘                                                         │
│      │                                                              │
│      ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │                   make_lead_agent()                           │    │
│  │                                                             │    │
│  │   ┌─────────────────────────────────────────────────────┐   │    │
│  │   │              apply_prompt_template()               │   │    │
│  │   │                                                      │   │    │
│  │   │   System Prompt:                                      │   │    │
│  │   │   ┌──────────────────────────────────────────────┐   │   │    │
│  │   │   │ <memory>                                    │   │   │    │
│  │   │   │ - [preference | 0.92] 用户更喜欢 Python     │   │   │    │
│  │   │   │ - [knowledge | 0.88] 用户精通 PyTorch       │   │   │    │
│  │   │   │ - [context | 0.85] 用户在字节跳动工作       │   │   │    │
│  │   │   │ </memory>                                   │   │   │    │
│  │   │   └──────────────────────────────────────────────┘   │   │    │
│  │   │                                                      │   │    │
│  │   └─────────────────────────────────────────────────────┘   │    │
│  └─────────────────────────────────────────────────────────────┘    │
│      │                                                              │
│      ▼                                                              │
│  ┌──────────────┐      ┌──────────────┐      ┌──────────────┐       │
│  │  Lead Agent  │─────▶│  LLM Call    │─────▶│   Response   │       │
│  └──────────────┘      └──────────────┘      └──────────────┘       │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

6.2 注入格式

xml 复制代码
<memory>
User Context:
- Work: 字节跳动高级工程师,从事 DeerFlow AI 基础设施工作
- Personal: 精通中英文,对分布式系统感兴趣
- Current Focus: 优化 DeerFlow memory系统,探索基于 LLM 的事实提取

History:
- Recent: 自 2026 年 1 月起从事 DeerFlow 2.0 工作,实现了memory中间件
- Earlier: 之前从事 LangChain 集成,构建了自定义 Agent
- Background: 5 年以上 AI/ML 基础设施经验,分布式系统背景

Facts:
- [preference | 0.92] 用户更喜欢使用 Python 进行数据处理任务
- [knowledge | 0.88] 用户精通 PyTorch 和深度学习框架
- [context | 0.85] 用户在字节跳动从事 AI 基础设施工作
- [behavior | 0.78] 用户倾向于在实施前问澄清问题
- [correction | 0.95] 用户纠正了 Agent 关于 debounce 时序的问题(避免:假设立即更新)
</memory>

6.3 Token 预算

  • 默认:最大 2000 tokens
  • 使用 tiktoken 进行精确计数
  • 按顺序包含部分:User Context → History → Facts
  • 事实按置信度排序(最高优先)
  • 如果超出限制,截断事实

7. 中间件集成

7.1 中间件链位置

复制代码
1.  ThreadDataMiddleware        → 创建按线程的目录
2.  UploadsMiddleware           → 跟踪上传的文件
3.  SandboxMiddleware           → 获取沙盒
4.  DanglingToolCallMiddleware  → 修复中断的工具调用
5.  LLMErrorHandlingMiddleware  → 规范化 provider 错误
6.  GuardrailMiddleware        → 工具调用前授权
7.  SandboxAuditMiddleware     → 安全审计日志
8.  ToolErrorHandlingMiddleware→ 转换工具异常
9.  SummarizationMiddleware    → 上下文缩减
10. TodoListMiddleware          → 任务跟踪
11. TokenUsageMiddleware       → Token 指标
12. TitleMiddleware             → 自动生成线程标题
13. MemoryMiddleware           → ← 将对话排队等待memory更新
14. ViewImageMiddleware         → 为视觉模型注入图像
15. DeferredToolFilterMiddleware → 隐藏延迟的工具
16. SubagentLimitMiddleware    → 强制子代理限制
17. LoopDetectionMiddleware     → 检测重复循环
18. ClarificationMiddleware     → 处理澄清请求

7.2 MemoryMiddleware 生命周期

python 复制代码
class MemoryMiddleware(AgentMiddleware):
    def after_agent(self, state, runtime):
        """每次 Agent 执行后调用。"""
        # 1. 获取 thread_id
        thread_id = runtime.context.get("thread_id") or get_config().configurable.thread_id

        # 2. 获取并过滤消息
        messages = state.get("messages", [])
        filtered = filter_messages_for_memory(messages)

        # 3. 检测信号
        correction = detect_correction(filtered)
        reinforcement = not correction and detect_reinforcement(filtered)

        # 4. 排队等待异步处理
        queue = get_memory_queue()
        queue.add(
            thread_id=thread_id,
            messages=filtered,
            agent_name=self._agent_name,
            correction_detected=correction,
            reinforcement_detected=reinforcement,
        )

        return None  # 无状态更改

7.3 总结钩子

SummarizationMiddleware 即将压缩消息时,首先调用 memory_flush_hook()

python 复制代码
def memory_flush_hook(event: SummarizationEvent):
    """在即将被总结的消息刷新到memory队列。"""
    filtered = filter_messages_for_memory(list(event.messages_to_summarize))

    # 只有在有意义的对话时才处理
    if not user_messages or not assistant_messages:
        return

    correction = detect_correction(filtered)
    reinforcement = not correction and detect_reinforcement(filtered)

    queue = get_memory_queue()
    queue.add_nowait(
        thread_id=event.thread_id,
        messages=filtered,
        agent_name=event.agent_name,
        correction_detected=correction,
        reinforcement_detected=reinforcement,
    )

这确保信息在被总结掉之前被捕获。


8. 存储系统

8.1 存储接口

python 复制代码
class MemoryStorage(ABC):
    @abc.abstractmethod
    def load(self, agent_name: str | None = None) -> dict[str, Any]:
        """加载给定 Agent 的记忆数据。"""
        pass

    @abc.abstractmethod
    def reload(self, agent_name: str | None = None) -> dict[str, Any]:
        """强制重新加载给定 Agent 的记忆数据。"""
        pass

    @abc.abstractmethod
    def save(self, memory_data: dict[str, Any], agent_name: str | None = None) -> bool:
        """保存给定 Agent 的记忆数据。"""
        pass

8.2 FileMemoryStorage

python 复制代码
class FileMemoryStorage(MemoryStorage):
    def __init__(self):
        # 按 Agent 记忆缓存:{agent_name: (memory_data, file_mtime)}
        self._memory_cache: dict[str | None, tuple[dict, float | None]] = {}
        self._cache_lock = threading.Lock()

缓存逻辑:

  • 首次 load() 调用从文件读取
  • 后续调用如果文件 mtime 未变则从缓存返回
  • reload() 强制从文件重新读取,使缓存失效

原子性保存:

python 复制代码
def save(self, memory_data, agent_name=None):
    # 1. 创建带 UUID 后缀的临时文件
    temp_path = file_path.with_suffix(f".{uuid.uuid4().hex}.tmp")

    # 2. 写入临时文件
    with open(temp_path, "w", encoding="utf-8") as f:
        json.dump(memory_data, f, indent=2, ensure_ascii=False)

    # 3. 原子重命名(仅在写入完成时成功)
    temp_path.replace(file_path)

    # 4. 更新缓存
    with self._cache_lock:
        self._memory_cache[agent_name] = (memory_data, file_path.stat().st_mtime)

8.3 按 Agent 记忆

Agent 可以有独立的记忆存储:

python 复制代码
# 全局记忆(默认)
memory = get_memory_storage().load(None)

# 按 Agent 记忆
memory = get_memory_storage().load("agent_name")

文件存储在:

复制代码
backend/.deer-flow/memory.json           # 全局
backend/.deer-flow/memory_agent1.json    # 按 Agent

9. 配置

9.1 MemoryConfig 结构

python 复制代码
class MemoryConfig(BaseModel):
    # 主开关
    enabled: bool = True

    # 存储
    storage_path: str = ""  # "" = 默认为 {base_dir}/memory.json
    storage_class: str = "deerflow.agents.memory.storage.FileMemoryStorage"

    # 更新行为
    debounce_seconds: int = 30  # 1-300 秒

    # 用于基于 LLM 更新的模型(None = 使用默认模型)
    model_name: str | None = None

    # 事实存储限制
    max_facts: int = 100  # 10-500
    fact_confidence_threshold: float = 0.7  # 0.0-1.0

    # 注入设置
    injection_enabled: bool = True
    max_injection_tokens: int = 2000  # 100-8000

9.2 config.yaml 示例

yaml 复制代码
memory:
  enabled: true
  storage_path: ""                          # 使用默认位置
  storage_class: deerflow.agents.memory.storage.FileMemoryStorage
  debounce_seconds: 30                      # 最后一条消息后等待 30 秒
  model_name: null                          # 使用默认模型
  max_facts: 100                            # 保留前 100 个事实
  fact_confidence_threshold: 0.7             # 只存储置信度 >= 0.7 的事实
  injection_enabled: true                   # 注入到系统提示词
  max_injection_tokens: 2000               # 提示词中最多 2000 tokens

10. API 端点

所有端点位于 /api/memory 下。

10.1 端点汇总

端点 方法 描述
/api/memory GET 获取所有记忆数据
/api/memory DELETE 清除所有记忆
/api/memory/reload POST 强制从文件重新加载
/api/memory/facts POST 手动创建事实
/api/memory/facts/{id} DELETE 删除事实
/api/memory/facts/{id} PATCH 更新事实
/api/memory/export GET 导出记忆为 JSON
/api/memory/import POST 从 JSON 导入记忆
/api/memory/config GET 获取记忆配置
/api/memory/status GET 获取配置 + 数据组合

10.2 响应示例

GET /api/memory
json 复制代码
{
  "version": "1.0",
  "lastUpdated": "2026-04-21T10:30:00Z",
  "user": {
    "workContext": { "summary": "字节跳动高级工程师", "updatedAt": "..." },
    "personalContext": { "summary": "精通中英文", "updatedAt": "..." },
    "topOfMind": { "summary": "专注于 DeerFlow memory优化", "updatedAt": "..." }
  },
  "history": {
    "recentMonths": { "summary": "从事 DeerFlow 2.0 工作", "updatedAt": "..." },
    "earlierContext": { "summary": "之前从事 LangChain", "updatedAt": "..." },
    "longTermBackground": { "summary": "5 年以上 AI/ML 基础设施", "updatedAt": "..." }
  },
  "facts": [...]
}
GET /api/memory/status
json 复制代码
{
  "config": {
    "enabled": true,
    "storage_path": "",
    "debounce_seconds": 30,
    "model_name": null,
    "max_facts": 100,
    "fact_confidence_threshold": 0.7,
    "injection_enabled": true,
    "max_injection_tokens": 2000
  },
  "data": { ... }
}
POST /api/memory/facts

请求:

json 复制代码
{
  "content": "用户更喜欢使用 Python 进行数据处理",
  "category": "preference",
  "confidence": 0.92
}

响应:

json 复制代码
{
  "success": true,
  "fact": {
    "id": "fact_a1b2c3d4",
    "content": "用户更喜欢使用 Python 进行数据处理",
    "category": "preference",
    "confidence": 0.92,
    "createdAt": "2026-04-21T10:30:00Z",
    "source": "manual"
  }
}

11. 关键设计决策

11.1 异步 + 同步混合

MemoryUpdater 同时具有同步和异步更新方法:

python 复制代码
def update_memory(self, messages, ...):
    """通过 ThreadPoolExecutor 同步更新。"""
    return _run_async_update_sync(self.aupdate_memory(...))

async def aupdate_memory(self, messages, ...):
    """用于异步上下文的异步更新。"""
    # 为 CPU 密集型的 LLM 调用使用 asyncio.to_thread
    prepared = await asyncio.to_thread(self._prepare_update_prompt, ...)
    response = await model.ainvoke(prompt)
    return await asyncio.to_thread(self._finalize_update, ...)

为什么? 防止阻塞异步事件循环,同时仍支持同步调用点。

11.2 按线程去重

python 复制代码
def _enqueue_locked(self, thread_id, ...):
    # 移除此线程的现有条目
    self._queue = [c for c in self._queue if c.thread_id != thread_id]
    # 添加新条目
    self._queue.append(context)

每个 thread_id 只保留最新对话。这可以防止重复处理并减少 LLM 调用。

11.3 空白符归一化去重

python 复制代码
def _fact_content_key(content):
    """用于去重的大小写折叠、去空格比较。"""
    stripped = content.strip()
    return stripped.casefold()

"User prefers Python" 和 "user prefers python " 被视为重复。

11.4 上传事件清理

python 复制代码
_UPLOAD_SENTENCE_RE = re.compile(
    r"[^.!?]*\b(?:"
    r"upload(?:ed|ing)?(?:\s+\w+){0,3}\s+(?:file|files?|document|...)"
    r"|file\s+upload"
    r"|/mnt/user-data/uploads/"
    r"|<uploaded_files>"
    r")[^.!?]*[.!?]?\s*",
    re.IGNORECASE,
)

def _strip_upload_mentions_from_memory(memory_data):
    """从记忆摘要和事实中去除提及文件上传的句子。"""
    # 清理描述上传事件的事实

上传的文件是会话范围的,在未来的会话中无法访问。记录它们会导致混淆。

11.5 原子性文件写入

python 复制代码
temp_path = file_path.with_suffix(f".{uuid.uuid4().hex}.tmp")
with open(temp_path, "w") as f:
    json.dump(memory_data, f, ...)
temp_path.replace(file_path)  # 在 POSIX 上是原子的

使用临时文件 + 重命名模式。如果进程在写入中间崩溃,原文件保持不变。

11.6 总结前刷新memory

python 复制代码
def memory_flush_hook(event: SummarizationEvent):
    """在消息被总结之前,先刷新到memory。"""
    queue.add_nowait(
        thread_id=event.thread_id,
        messages=filtered_messages,
        ...
    )

即将被总结掉的信息首先被捕获到memory中,然后再压缩。

11.7 带 sourceError 的纠正检测

json 复制代码
{
  "id": "fact_abc123",
  "content": "用户纠正了 Agent 关于 debounce 时序的问题",
  "category": "correction",
  "confidence": 0.95,
  "source": "thread_xyz",
  "sourceError": "假设memory更新是同步发生的"
}

当用户明确纠正 Agent 时,sourceError 字段捕获 Agent 错在哪里,帮助避免同样的错误。

11.8 基于 Token 的注入限制

python 复制代码
def format_memory_for_injection(memory_data, max_tokens=2000):
    # 使用 tiktoken 进行精确 token 计数
    token_count = _count_tokens(result)

    # 如果超出限制,截断
    if token_count > max_tokens:
        char_per_token = len(result) / token_count
        target_chars = int(max_tokens * char_per_token * 0.95)
        result = result[:target_chars] + "\n..."

使用 tiktoken 进行精确 token 计数(不是字符近似)。


附录:文件位置

组件 文件路径
Memory 配置 backend/packages/harness/deerflow/config/memory_config.py
Storage backend/packages/harness/deerflow/agents/memory/storage.py
Queue backend/packages/harness/deerflow/agents/memory/queue.py
Updater backend/packages/harness/deerflow/agents/memory/updater.py
Prompts backend/packages/harness/deerflow/agents/memory/prompt.py
Message Processing backend/packages/harness/deerflow/agents/memory/message_processing.py
Summarization Hook backend/packages/harness/deerflow/agents/memory/summarization_hook.py
Middleware backend/packages/harness/deerflow/agents/middlewares/memory_middleware.py
Memory Router backend/app/gateway/routers/memory.py
默认 Memory 文件 backend/.deer-flow/memory.json

相关推荐
ting94520001 小时前
从零构建大模型实战:数据处理与 GPT-2 完整实现
人工智能
学点程序1 小时前
Manifest:帮个人 AI Agent 降低模型成本的开源路由器
人工智能·开源
可观测性用观测云2 小时前
观测云 x AI Agent:运维智能化的范式跃迁实践
人工智能
数数科技的数据干货2 小时前
ThinkingAI携手华为云,共建企业级AI Agent平台Agentic Engine
人工智能·ai·华为云·agent
人工智能AI技术2 小时前
春招急救:7天面试突击方案
人工智能
2603_954708312 小时前
如何确保微电网标准化架构设计流程的完整性?
网络·人工智能·物联网·架构·系统架构
fanly112 小时前
surging 的Agent插件研发全流程:从定义到落地
微服务·ai·surging
小小AK2 小时前
钉钉与金蝶云星空无缝集成方案
大数据·人工智能·钉钉
不停喝水2 小时前
【AI+Cursor】 告别切图仔,拥抱Vibe Coding: AI + Cursor 开启多模态全栈新纪元 (1)
前端·人工智能·后端·ai·ai编程·cursor