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的提示词模板。
关键模板:
-
MEMORY_UPDATE_PROMPT- 用于 LLM 分析对话并生成更新:- 输入:当前记忆状态 + 新对话
- 输出:更新 user/history 部分和新事实的结构化 JSON
- 包含用于错误/重试检测的结构化反思说明
-
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)
中间件链中的位置:
- ThreadDataMiddleware
- UploadsMiddleware
- SandboxMiddleware
- DanglingToolCallMiddleware
- LLMErrorHandlingMiddleware
- GuardrailMiddleware
- SandboxAuditMiddleware
- ToolErrorHandlingMiddleware
- SummarizationMiddleware
- TodoListMiddleware
- TokenUsageMiddleware
- TitleMiddleware
- MemoryMiddleware ←
- ViewImageMiddleware
- DeferredToolFilterMiddleware
- SubagentLimitMiddleware
- LoopDetectionMiddleware
- ClarificationMiddleware
after_agent() 流程:
- 从运行时上下文或 LangGraph 配置获取
thread_id - 从状态获取消息
- 过滤为用户输入 + 最终 AI 回复
- 检测纠正/强化信号
- 通过
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():
- 检查记忆是否启用
- 与同一
thread_id的现有上下文合并(保留最新,合并纠正/强化标志) - 重置防抖定时器
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():
- 在
shouldUpdate: true的地方更新 user/history 部分 - 删除
factsToRemove中的事实 - 添加新事实并进行去重(空白符归一化)
- 强制执行
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 |