跳转到内容

统一记忆与 LLM 分析

学习目标

理解 CrewAI 的统一记忆系统如何通过 EncodingFlow 和 RecallFlow 两条管线实现 LLM 驱动的记忆管理,以及存储后端的选择策略。

前置知识

下文假设你已理解上述概念,直接聚焦 CrewAI 的具体实现。


项目实践

层次化 Scope

CrewAI 的记忆使用路径式的层次化 Scope:

# 伪代码
scope = MemoryScope("/company/team/user")
slice = MemorySlice([scope1, scope2]) # 组合多个 scope

MemoryScope 支持 .bind() 方法用于检查点恢复。

复合评分

每条记忆通过三维加权评分决定重要性:

score = semantic_weight × 语义相关性(0.5)
+ recency_weight × 时间衰减因子(0.3, 指数衰减)
+ importance_weight × LLM 评估的重要性(0.2)

EncodingFlow:5 步批量编码

batch_embed → intra_batch_dedup → parallel_find_similar → parallel_analyze → execute_plans

A/B/C/D 分组优化:将记忆项按相似度分为四组,相似的项批量处理,减少 LLM 调用次数。去重在批量内部进行,而非逐条比较。

RecallFlow:查询蒸馏 + 并行多路搜索

  1. LLM 将用户查询蒸馏为更适合向量搜索的形式
  2. 生成多个变体查询,并行搜索多个 scope
  3. 基于置信度的路由决策(decide_depth):
    • synthesize:结果足够,直接综合返回
    • explore_deeper:结果不足,迭代使用不同搜索策略
  4. 迭代探索预算:限制最大探索次数

存储后端

后端特点适用场景
LanceDB基于文件的向量存储,跨进程锁,乐观并发重试(5 次)本地部署,小规模
Qdrant Edge写本地/同步中心模式,每进程独立分片多进程,边缘部署

后台写入队列

Memory 类使用后台线程池处理写入(_submit_savedrain_writes),避免阻塞主流程。


问题与规避

进程退出时未 flush 的记忆丢失

  • 后台写入队列中的记忆在进程退出时可能未写入存储
  • 对策:在进程退出前调用 drain_writes() 清空队列

复合评分权重调优困难

  • 默认的 0.5/0.3/0.2 权重不一定适合所有场景
  • 对策:根据实际召回质量调整权重——如果时间因素更重要,提高 recency_weight

查询蒸馏可能丢失原始查询的细微差别

  • LLM 蒸馏过程可能简化原始查询,丢失关键细节
  • 对策:在 RecallFlow 中同时使用原始查询和蒸馏查询进行多路搜索

设计取舍

EncodingFlow 批量处理 vs 逐条编码

  • 批量处理的优势是减少 LLM 调用次数(A/B/C/D 分组),降低延迟
  • 代价是需要积累一定量的记忆后才触发,不适合需要即时编码的场景

LanceDB vs Qdrant

  • LanceDB 更轻量(零依赖,基于文件),适合本地和小规模部署
  • Qdrant 提供更好的并发支持和多进程隔离,适合生产环境

参考来源

  • 源码验证: lib/crewai/src/crewai/memory/encoding_flow.py
  • 源码验证: lib/crewai/src/crewai/memory/recall_flow.py
  • 源码验证: lib/crewai/src/crewai/memory/storage/lancedb_storage.py