核心权衡:召回率 vs 上下文预算 vs 延迟 vs 成本,四者无法同时最优。
实践策略
| 优化点 | 原则 | 常用技术 / 工具 | 控制的关键参数 |
|---|---|---|---|
| 分层存储 | 工作记忆放上下文,长期记忆放外部,按访问频率分层 | LangGraph state、Redis(会话级)、Postgres + pgvector / Qdrant / Weaviate(长期)、Letta(OS 式分层换入换出) | 各层容量上限、换入换出阈值 |
| 写入策略 | 不是所有内容都值得记;显式写入 + LLM 抽取结合 | LLM 抽取 prompt(事实 / 偏好 / 决策)、Mem0 的 add pipeline、importance scoring(参考 Generative Agents) | 抽取频率(每轮 / 每 N 轮 / 会话结束)、importance 阈值 |
| 去重与合并 | 同一事实只保留一份,冲突按时间戳更新 | 嵌入相似度比对(阈值 0.85–0.95)、LLM 判重、Mem0 / Zep 内置 update 逻辑 | 相似度阈值、合并策略(取新 / 合并文本 / 保留版本历史) |
| 检索 | 混合检索优于单一向量检索 | 向量检索(OpenAI / Voyage / BGE 嵌入)+ BM25 + 元数据过滤、Cohere / Voyage reranker、GraphRAG / 知识图谱检索 | top-k、相似度阈值、reranker top-n、元数据过滤条件 |
| 嵌入模型 | 领域相关性 > 通用模型规模 | text-embedding-3-large、Voyage-3、BGE-M3、领域微调嵌入 | 维度(512 / 1024 / 3072)、是否 fine-tune |
| Chunk 粒度 | 语义完整 vs 检索精度的平衡 | 语义分块(按段落 / 主题)、固定窗口 + overlap、LLM 辅助分块 | chunk size(200–800 token)、overlap(10–20%) |
| 上下文压缩 | 超窗时压缩而非截断 | 滚动摘要、层级摘要(细节 → 摘要 → 摘要的摘要)、结构化提取(事实列表替代原文) | 触发阈值(如窗口占用 70%)、压缩比、保留原始消息条数 |
| 遗忘 | 不是所有记忆都该永久保留 | TTL、recency decay(指数衰减)、访问计数淘汰、LLM 周期性 review | 衰减系数、TTL 长度、淘汰阈值 |
| 一致性 / 冲突 | 区分事实与偏好,时间戳决定优先级 | 双时态模型(Zep / Graphiti:fact valid time + system time)、版本化记录 | 冲突解决规则(last-write-wins / 标记冲突 / 人工介入) |
| 检索预算 | 给推理留 token,避免上下文塞满 | 注入 token 上限、动态 k(按 query 复杂度调整)、压缩后注入 | max context tokens、检索结果总 token 上限 |
| 写入性能 | 不阻塞主对话流 | 异步队列(Celery / Redis Queue)、批量嵌入、后台 worker | 队列延迟容忍度、批大小 |
| 可观测性 | 检索命中率是幻觉调试的主线索 | LangSmith、Langfuse、Arize Phoenix、自建 trace 表 | 记录 query / 检索结果 / 是否被引用 / 用户反馈 |
| 评估 | 离线 + 在线双轨 | RAGAS(faithfulness、context precision / recall)、A/B 测试、人工标注 | 召回率、精确率、注入相关性、最终回答质量 |
| 安全 / 隔离 | 多租户场景必须隔离 | 按 user_id / org_id 分 namespace、行级权限、PII 脱敏 | 租户边界、敏感字段过滤规则 |
典型实施路径
- 起步:用 Mem0 或 Zep 跑通最小可用版本,验证业务流程。
- 观察瓶颈:通过可观测性工具找出问题在召回率、延迟还是成本。
- 针对性替换:嵌入模型、reranker、存储后端是最常见的三个替换点。
- 逐步去框架化:当业务复杂度超过框架抽象的承载能力时,迁移到自建。