- Published on
- Word count
- 2,534 字 · 阅读约 9 分钟
RAG 链路全解析:从文档入库到混合记忆的实战架构
- Authors

- Name
- 眠月
一套超越传统 RAG、融合长期记忆与动态状态的智能体架构
引言:为什么需要重新思考 RAG?
传统的 RAG 系统大多遵循一个标准流程:文档切块 → Embedding → 向量库 → TopK 检索 → Prompt 拼接 → LLM 回答。这个链路在处理简单的知识问答场景时表现出色,但当面对需要长期记忆用户偏好、理解对话上下文、感知情绪状态的复杂对话场景时,就显得力不从心了。
本文将分享一套经过实战检验的 RAG 增强架构,它不仅完成了基础的文档检索功能,更重要的是,通过三层记忆混合方案,让 AI 真正具备了"记住"和"感知"的能力。
第一部分:基础 RAG 链路回顾
先来快速回顾一下标准 RAG 的核心流程,这是整个架构的基石:
| 阶段 | 核心任务 | 技术要点 |
|---|---|---|
| 1. 文档入库 | 多源文档清洗与切块 | PDF、网页、Markdown、数据库内容先清洗,再按段落或语义切块 |
| 2. 向量化 | Chunk 转向量并存储 | 通过 Embedding 模型转成向量,写入 Milvus、FAISS、Qdrant、pgvector 等向量库 |
| 3. 用户提问 | 问题向量化 | 用户问题也转成向量,用相似度检索相关 chunk |
| 4. 召回与重排 | 精准筛选相关片段 | 先粗召回 TopK,再用 Reranker 选出最相关片段 |
| 5. 生成答案 | Prompt 组装与 LLM 调用 | 把用户问题、检索片段、回答规则拼成 Prompt,交给 LLM 生成最终回答 |
这个流程解决的是"知识从哪里来"的问题。但对话系统还需要解决"过去说过什么"和"现在什么状态"的问题——这就是三层混合记忆方案登场的时刻。
第二部分:三层混合记忆架构
我设计了一个三层并行的记忆系统,让 AI 能够像人一样,拥有"过目不忘"的底片式记忆、"提纲挈领"的摘要记忆,以及"随用随取"的工作记忆。
架构全景图
┌─────────────────────────────────────────────────────────────────────────────┐
│ 三层混合记忆架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ 用户提问 │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 三层记忆并行检索 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 第一层 │ │ 第二层 │ │ 第三层 │ │ │
│ │ │ 全量留存 │ │ 滚动摘要 │ │ RAG 记忆 │ │ │
│ │ │ (底片层) │ │ (摘要层) │ │ (向量层) │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ SQLite │ │ 每50条 │ │ 向量数据库 │ │ │
│ │ │ 全量存储 │ │ 生成摘要 │ │ ChromaDB │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 三路召回 + RRF 融合排序 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ FTS5 关键词 │ │ 向量语义 │ │ 实体聚合 │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 三层 Prompt 动态叠加 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 固定人格 │ │ 动态情绪 │ │ 动态记忆 │ │ │
│ │ │ (角色原型) │ │ (状态引擎) │ │ (检索碎片) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ LLM 生成回答 │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
第一层:全量留存(底片层)
"所有对话,永不删除"
| 特性 | 说明 |
|---|---|
| 存储介质 | SQLite(better-sqlite3 直连) |
| 写入策略 | 原始消息全量入库 |
| 删除策略 | 不做物理删除,作为永远的底层底片 |
| 加密方案 | 对敏感字段做加密处理 |
这一层的价值在于:为未来的审计、分析和模型微调保留了完整的数据基础。你可以随时回溯任意时间点的原始对话,进行数据挖掘或模型训练。
第二层:滚动摘要(摘要层)
"50条消息,一次提炼"
| 特性 | 说明 |
|---|---|
| 触发条件 | 每积累 50 条消息自动触发 |
| 生成机制 | 调用 LLM 对 50 条消息生成结构化摘要 |
| 存储方式 | 摘要存入 SQLite,与原始消息关联 |
这一层解决了长期对话中"信息过载"的问题。原始消息数量线性增长,但经过摘要压缩后,关键信息密度大幅提升,为后续检索提供了高效的索引。
第三层:RAG 记忆(向量层)
"碎片提取,向量召回"
这是最核心、最复杂的一层。系统后台有一个专门的异步模块,持续做三件事:
| 任务 | 说明 |
|---|---|
| 事实提取 | 从对话中提取客观事实(如"用户养了一只猫叫Momo") |
| 偏好识别 | 记录用户偏好(如"用户喜欢简洁的回答") |
| 情绪捕捉 | 分析情绪状态(如"用户今天看起来有些焦虑") |
提取出的碎片经过向量化,存入 ChromaDB。对话时,系统通过混合检索将这些记忆重新召回。
第三部分:混合检索策略(三路召回 + RRF)
单纯依赖向量检索会丢失很多精确信息。我实现了一个三路召回 + RRF(倒数排序融合) 的混合检索策略:
三路召回通道
┌─────────────────────────────────────────────────────────────────┐
│ 三路召回并行执行 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 通道一:FTS5 关键词检索 │
│ ├── 基于 SQLite 的全文搜索 │
│ ├── 擅长精确匹配(人名、地名、专有名词) │
│ └── 返回匹配结果及 BM25 分数 │
│ │
│ 通道二:向量语义检索 │
│ ├── ChromaDB 向量相似度检索 │
│ ├── 擅长语义泛化(近义词、相关概念) │
│ └── 返回 TopK 向量及余弦相似度 │
│ │
│ 通道三:实体聚合检索 │
│ ├── 从对话中提取的实体(人、事、物、情绪标签) │
│ ├── 按实体类型和重要性加权 │
│ └── 返回关联实体对应的记忆碎片 │
│ │
└─────────────────────────────────────────────────────────────────┘
RRF 融合排序算法
三路召回的结果通过 RRF(Reciprocal Rank Fusion) 算法进行融合排序:
RRF 得分 = Σ (1 / (k + 排名))
其中:
- 排名:某条记忆在单个召回通道中的位置(从1开始)
- k:常数,通常取 60
为什么选择 RRF?
- 不需要对异构分数(BM25、余弦相似度、实体权重)进行归一化
- 对离群值不敏感,融合结果鲁棒
- 计算简单,延迟极低
融合后的 TopK 记忆被动态塞入 system prompt 中,作为 LLM 生成的上下文。
第四部分:动态状态引擎(三层 Prompt 叠加)
传统的角色扮演系统通常只有一个固定的 prompt。我在此基础上做了三层叠加设计:
三层结构详解
| 层次 | 内容 | 更新频率 | 作用 |
|---|---|---|---|
| 固定人格 | 角色基础设定(性格、背景、语言风格) | 永久固定 | 确保角色一致性 |
| 动态情绪 | 实时分析的情绪状态(开心/焦虑/疲惫/兴奋) | 每轮对话更新 | 让回复更有"人情味" |
| 动态记忆 | 从三层记忆中召回的相关碎片 | 每轮对话动态注入 | 提供长期上下文连贯性 |
情绪状态引擎的实现
这部分参考了 GitHub 上 jiwen 项目的设计思路。引擎实时分析以下维度:
| 维度 | 检测方法 | 输出示例 |
|---|---|---|
| 基础情绪 | 情感分类模型 | 愉悦/愤怒/悲伤/恐惧/惊讶 |
| 情绪强度 | 回归模型打分 | 0-1 之间的强度值 |
| 疲劳指数 | 对话轮次 + 时间衰减 | 连续对话超过30轮自动降低"兴奋度" |
| 满意度倾向 | 用户回复的情感分析 | 积极/中性/消极 |
这些信号最终被合成为一个"情绪状态向量",叠加到 prompt 中。例如:
【当前情绪状态】
- 基础情绪:愉悦 (0.82)
- 强度:中高
- 疲劳指数:低(对话第8轮)
- 用户近期满意度:积极
请以关心、温暖的语气回应。
第五部分:完整技术栈
后端核心
| 组件 | 技术选型 | 理由 |
|---|---|---|
| 应用框架 | Node.js + Express | 高 I/O 性能,生态成熟 |
| 数据库 | SQLite + better-sqlite3 | 零配置,同步 API 性能极佳 |
| 进程管理 | PM2 | 稳定可靠的生产级进程管理 |
| 外网暴露 | Cloudflare Tunnel | 无需公网 IP,自带 SSL,配置简单 |
AI 与检索层
| 组件 | 技术选型 | 理由 |
|---|---|---|
| 向量检索服务 | Python FastAPI + ChromaDB | Python 生态对 AI 模型最友好 |
| Embedding 模型 | Jina v2 base zh (768维) | 中文效果好,轻量级 |
| 推理后端 | ONNX Runtime | CPU 推理速度快,无需 GPU |
| 混合检索 | FTS5 + 向量检索 + RRF | 兼顾精确与语义 |
数据加密
| 内容 | 方案 |
|---|---|
| 敏感字段 | 应用层加密(AES-256-GCM) |
| SQLite 文件 | 可选文件系统级加密 |
第六部分:优化建议与展望
这套架构已经在生产环境中稳定运行,以下几个方向值得进一步探索:
1. 向量库的可扩展性
当前 ChromaDB 在文档量 < 10 万时表现优异。如果知识库持续增长,可以考虑迁移到:
| 方案 | 适用场景 |
|---|---|
| Qdrant | 需要高性能、分布式部署 |
| Milvus | 超大规模(百万级以上) |
| sqlite-vec | 希望简化架构,向量与业务数据同库 |
2. 重排序层(Reranker)的引入
目前 RRF 融合工作在索引级。可以增加一个模型级重排序层:
三路召回 → RRF → Top20 → Reranker 模型精排 → Top5
推荐的 Reranker 模型:
bge-reranker-base(中文效果优秀)cross-encoder/ms-marco-MiniLM-L-6-v2(英文)
3. SQLite 性能优化
-- 开启 WAL 模式,提升读写并发
PRAGMA journal_mode=WAL;
-- 调整缓存大小
PRAGMA cache_size=-64000; -- 64MB
-- 启用内存映射
PRAGMA mmap_size=268435456; -- 256MB
4. 异步写入队列
对于"全量留存"这类非实时操作,可以引入消息队列异步处理:
用户对话 → 主流程同步返回 → 写入队列 → 后台批量落库
避免数据库写入阻塞主对话流程。
结语
本文分享的 RAG 架构从一个简单的"文档入库 → 检索 → 生成"链路出发,逐步演进为一个具备长期记忆和情绪感知能力的智能体系统。
核心收获可以总结为三点:
检索不能只靠向量:FTS5 + 向量语义 + 实体聚合的三路召回,加上 RRF 融合排序,才能应对复杂的对话场景。
记忆需要分层设计:全量留存(底片)+ 滚动摘要(提纲)+ RAG 记忆(细节),三层各司其职。
Prompt 需要动态合成:固定人格保证角色一致性,动态情绪增加人情味,动态记忆提供上下文连贯性。
这套架构的所有组件都可以在 GitHub 上找到实现参考(如 jiwen 项目的情绪状态引擎)。希望本文能为正在构建类似系统的开发者提供一些实战思路。
附录:参考资源
- SQLite FTS5 官方文档
- ChromaDB 向量数据库指南
- RRF 混合检索算法原理
- Jina Embeddings 模型介绍
- Cloudflare Tunnel 配置教程