跳转到内容

05 - 记忆蒸馏:Deep Dream 的 LLM 驱动记忆整理

学习目标

理解 CowAgent 的 Deep Dream 机制如何实现定期记忆蒸馏,包括输入材料收集、LLM 蒸馏、输出解析与梦境日记写入。

前置知识

记忆蒸馏的通用原理见 记忆蒸馏:LLM 驱动的记忆整理。本章聚焦 CowAgent 的具体实现。

项目实践

蒸馏触发链路

CowAgent 的 Deep Dream 由每日刷新定时器触发:

每日摘要(Daily Summary)

每日 23:55(带 50-55 分钟的随机抖动),_daily_flush_loop 触发:

  1. Phase 1:对所有活跃 Agent 调用 create_daily_summary()
    • 提取当前 session 的消息
    • LLM 摘要为”用户问了 X → 助手回答了 Y”格式
    • 写入 memory/YYYY-MM-DD.md
  2. Phase 2:选一个 candidate 执行 deep_dream()
    • 读取 MEMORY.md + 最近 N 天的每日记忆
    • LLM 蒸馏输出两部分

Deep Dream 蒸馏细节

# 伪代码 — Deep Dream 核心流程
def deep_dream(self, user_id=None, lookback_days=1, force=False):
# 1. 收集材料
memory_content = self._read_main_memory(user_id) # MEMORY.md
daily_content, has_content = self._read_recent_dailies(user_id, lookback_days)
if not has_content:
return # 无近期日记,跳过
# 2. 去重:同一天相同输入不重复蒸馏
dedup_key = f"{today_str}:{daily_hash}"
if dedup_key == self._last_dream_input_hash and not force:
return
# 3. LLM 蒸馏(动态 max_tokens,基于输入大小)
dream_max_tokens = max(2000, min(input_chars, 8000))
response = self.llm_model.call(request)
# 4. 解析输出
new_memory, dream_diary = self._parse_dream_output(raw)
# 5. 写入 MEMORY.md(覆盖)
main_file.write_text(new_memory)
# 6. 写入梦境日记
if dream_diary:
self._write_dream_diary(dream_diary, user_id)

规则摘要降级

当 LLM 不可用时,_extract_summary_fallback() 使用规则生成摘要:

- 用户: 询问如何部署 Docker → 回复: 提供了 docker compose 配置文件说明
- 用户: 分享了 CowAgent 的架构 → 回复: 分析了三层记忆设计

提取算法:

  1. 提取用户消息的前 120 字符
  2. 提取助手回复的第一条有意义的内容(跳过 markdown 标题、分隔符等噪声)
  3. 格式化为 "- 用户: X → 回复: Y" 的紧凑格式

调度器消息过滤

Deep Dream 在整理记忆时自动过滤调度器注入的消息:

def _strip_scheduler_pairs(cls, messages):
"""Drop scheduler-injected user/assistant pairs from a flush batch."""
# 识别以 "[SCHEDULED]" 开头的用户消息,跳过其配对的助手回复

这避免了定时任务的执行日志(如 “11:28 price=1013, normal”)污染长期记忆。

问题与规避

问题CowAgent 的规避策略
蒸馏后 MEMORY.md 丢失信息蒸馏 prompt 要求”合并提炼”而非”删除”,且保留梦境日记作为审计记录
蒸馏输入无新内容输入哈希去重,相同输入不重复蒸馏
LLM 蒸馏输出格式错误_parse_dream_output() 严格解析 [MEMORY]/[DREAM] 标记,无 [MEMORY] 部分则跳过写入
蒸馏阻塞主回复流每日摘要异步执行(后台线程),Deep Dream 在摘要完成后执行
调度器消息干扰蒸馏_strip_scheduler_pairs() 自动过滤

设计取舍

为什么每日摘要和 Deep Dream 分开执行?

每日摘要记录”今天发生了什么”,Deep Dream 提炼”哪些值得长期记住”。分开执行使得:

  1. 每日摘要轻量(500 tokens max_tokens),每次 trim 都触发
  2. Deep Dream 重量(2000-8000 tokens),每日执行一次
  3. 即使 Deep Dream 失败,每日记忆仍然保留

为什么使用覆盖写入而非追加?

MEMORY.md 需要保持精炼(目标 50 条以内)。追加会导致膨胀,覆盖写入配合 LLM 的合并提炼能力确保密度。代价是如果 LLM 输出不完整,可能丢失旧条目——因此蒸馏 prompt 要求输出”完整的更新后内容”而非”新增条目”。

参考来源