/2,534 字/阅读约 9 分钟

RAG 链路全解析:从文档入库到混合记忆的实战架构

详述 RAG(检索增强生成)的完整技术链路,包括文档入库、向量化、召回重排、Prompt 拼接,以及基于 Node.js + ChromaDB + SQLite 的三层混合记忆进阶方案。

眠月眠月
joker1point

一套超越传统 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 能够像人一样,拥有"过目不忘"的底片式记忆、"提纲挈领"的摘要记忆,以及"随用随取"的工作记忆。

架构全景图

js
┌─────────────────────────────────────────────────────────────────────────────┐
│                           三层混合记忆架构                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────┐                                                        │
│  │   用户提问       │                                                        │
│  └────────┬────────┘                                                        │
│           │                                                                 │
│           ▼                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                        三层记忆并行检索                               │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │   │
│  │  │  第一层       │  │  第二层       │  │  第三层       │              │   │
│  │  │  全量留存     │  │  滚动摘要     │  │  RAG 记忆    │              │   │
│  │  │  (底片层)     │  │  (摘要层)     │  │  (向量层)     │              │   │
│  │  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘              │   │
│  │         │                 │                 │                       │   │
│  │         ▼                 ▼                 ▼                       │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │   │
│  │  │  SQLite      │  │  每50条      │  │  向量数据库   │              │   │
│  │  │  全量存储    │  │  生成摘要    │  │  ChromaDB    │              │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘              │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│           │                                                                 │
│           ▼                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    三路召回 + RRF 融合排序                            │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │   │
│  │  │  FTS5 关键词 │  │  向量语义    │  │  实体聚合    │              │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘              │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│           │                                                                 │
│           ▼                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    三层 Prompt 动态叠加                               │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │   │
│  │  │  固定人格     │  │  动态情绪    │  │  动态记忆    │              │   │
│  │  │  (角色原型)   │  │  (状态引擎)  │  │  (检索碎片)  │              │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘              │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│           │                                                                 │
│           ▼                                                                 │
│  ┌─────────────────┐                                                        │
│  │   LLM 生成回答  │                                                        │
│  └─────────────────┘                                                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

第一层:全量留存(底片层)

"所有对话,永不删除"

特性说明
存储介质SQLite(better-sqlite3 直连)
写入策略原始消息全量入库
删除策略不做物理删除,作为永远的底层底片
加密方案对敏感字段做加密处理

这一层的价值在于:为未来的审计、分析和模型微调保留了完整的数据基础。你可以随时回溯任意时间点的原始对话,进行数据挖掘或模型训练。

第二层:滚动摘要(摘要层)

"50条消息,一次提炼"

特性说明
触发条件每积累 50 条消息自动触发
生成机制调用 LLM 对 50 条消息生成结构化摘要
存储方式摘要存入 SQLite,与原始消息关联

这一层解决了长期对话中"信息过载"的问题。原始消息数量线性增长,但经过摘要压缩后,关键信息密度大幅提升,为后续检索提供了高效的索引。

第三层:RAG 记忆(向量层)

"碎片提取,向量召回"

这是最核心、最复杂的一层。系统后台有一个专门的异步模块,持续做三件事:

任务说明
事实提取从对话中提取客观事实(如"用户养了一只猫叫Momo")
偏好识别记录用户偏好(如"用户喜欢简洁的回答")
情绪捕捉分析情绪状态(如"用户今天看起来有些焦虑")

提取出的碎片经过向量化,存入 ChromaDB。对话时,系统通过混合检索将这些记忆重新召回。


第三部分:混合检索策略(三路召回 + RRF)

单纯依赖向量检索会丢失很多精确信息。我实现了一个三路召回 + RRF(倒数排序融合) 的混合检索策略:

三路召回通道

js
┌─────────────────────────────────────────────────────────────────┐
│                        三路召回并行执行                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  通道一:FTS5 关键词检索                                        │
│  ├── 基于 SQLite 的全文搜索                                     │
│  ├── 擅长精确匹配(人名、地名、专有名词)                        │
│  └── 返回匹配结果及 BM25 分数                                   │
│                                                                 │
│  通道二:向量语义检索                                           │
│  ├── ChromaDB 向量相似度检索                                    │
│  ├── 擅长语义泛化(近义词、相关概念)                           │
│  └── 返回 TopK 向量及余弦相似度                                 │
│                                                                 │
│  通道三:实体聚合检索                                           │
│  ├── 从对话中提取的实体(人、事、物、情绪标签)                  │
│  ├── 按实体类型和重要性加权                                     │
│  └── 返回关联实体对应的记忆碎片                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RRF 融合排序算法

三路召回的结果通过 RRF(Reciprocal Rank Fusion) 算法进行融合排序:

js
RRF 得分 = Σ (1 / (k + 排名))

其中:
- 排名:某条记忆在单个召回通道中的位置(从1开始)
- k:常数,通常取 60

为什么选择 RRF?

  • 不需要对异构分数(BM25、余弦相似度、实体权重)进行归一化
  • 对离群值不敏感,融合结果鲁棒
  • 计算简单,延迟极低

融合后的 TopK 记忆被动态塞入 system prompt 中,作为 LLM 生成的上下文。


第四部分:动态状态引擎(三层 Prompt 叠加)

传统的角色扮演系统通常只有一个固定的 prompt。我在此基础上做了三层叠加设计:

三层结构详解

层次内容更新频率作用
固定人格角色基础设定(性格、背景、语言风格)永久固定确保角色一致性
动态情绪实时分析的情绪状态(开心/焦虑/疲惫/兴奋)每轮对话更新让回复更有"人情味"
动态记忆从三层记忆中召回的相关碎片每轮对话动态注入提供长期上下文连贯性

情绪状态引擎的实现

这部分参考了 GitHub 上 jiwen 项目的设计思路。引擎实时分析以下维度:

维度检测方法输出示例
基础情绪情感分类模型愉悦/愤怒/悲伤/恐惧/惊讶
情绪强度回归模型打分0-1 之间的强度值
疲劳指数对话轮次 + 时间衰减连续对话超过30轮自动降低"兴奋度"
满意度倾向用户回复的情感分析积极/中性/消极

这些信号最终被合成为一个"情绪状态向量",叠加到 prompt 中。例如:

js
【当前情绪状态】
- 基础情绪:愉悦 (0.82)
- 强度:中高
- 疲劳指数:低(对话第8轮)
- 用户近期满意度:积极

请以关心、温暖的语气回应。

第五部分:完整技术栈

后端核心

组件技术选型理由
应用框架Node.js + Express高 I/O 性能,生态成熟
数据库SQLite + better-sqlite3零配置,同步 API 性能极佳
进程管理PM2稳定可靠的生产级进程管理
外网暴露Cloudflare Tunnel无需公网 IP,自带 SSL,配置简单

AI 与检索层

组件技术选型理由
向量检索服务Python FastAPI + ChromaDBPython 生态对 AI 模型最友好
Embedding 模型Jina v2 base zh (768维)中文效果好,轻量级
推理后端ONNX RuntimeCPU 推理速度快,无需 GPU
混合检索FTS5 + 向量检索 + RRF兼顾精确与语义

数据加密

内容方案
敏感字段应用层加密(AES-256-GCM)
SQLite 文件可选文件系统级加密

第六部分:优化建议与展望

这套架构已经在生产环境中稳定运行,以下几个方向值得进一步探索:

1. 向量库的可扩展性

当前 ChromaDB 在文档量 < 10 万时表现优异。如果知识库持续增长,可以考虑迁移到:

方案适用场景
Qdrant需要高性能、分布式部署
Milvus超大规模(百万级以上)
sqlite-vec希望简化架构,向量与业务数据同库

2. 重排序层(Reranker)的引入

目前 RRF 融合工作在索引级。可以增加一个模型级重排序层:

js
三路召回 → RRF → Top20 → Reranker 模型精排 → Top5

推荐的 Reranker 模型:

  • bge-reranker-base(中文效果优秀)
  • cross-encoder/ms-marco-MiniLM-L-6-v2(英文)

3. SQLite 性能优化

sql
-- 开启 WAL 模式,提升读写并发
PRAGMA journal_mode=WAL;

-- 调整缓存大小
PRAGMA cache_size=-64000;  -- 64MB

-- 启用内存映射
PRAGMA mmap_size=268435456;  -- 256MB

4. 异步写入队列

对于"全量留存"这类非实时操作,可以引入消息队列异步处理:

js
用户对话 → 主流程同步返回 → 写入队列 → 后台批量落库

避免数据库写入阻塞主对话流程。


结语

本文分享的 RAG 架构从一个简单的"文档入库 → 检索 → 生成"链路出发,逐步演进为一个具备长期记忆和情绪感知能力的智能体系统。

核心收获可以总结为三点:

  1. 检索不能只靠向量:FTS5 + 向量语义 + 实体聚合的三路召回,加上 RRF 融合排序,才能应对复杂的对话场景。

  2. 记忆需要分层设计:全量留存(底片)+ 滚动摘要(提纲)+ RAG 记忆(细节),三层各司其职。

  3. Prompt 需要动态合成:固定人格保证角色一致性,动态情绪增加人情味,动态记忆提供上下文连贯性。

这套架构的所有组件都可以在 GitHub 上找到实现参考(如 jiwen 项目的情绪状态引擎)。希望本文能为正在构建类似系统的开发者提供一些实战思路。


附录:参考资源

  • SQLite FTS5 官方文档
  • ChromaDB 向量数据库指南
  • RRF 混合检索算法原理
  • Jina Embeddings 模型介绍
  • Cloudflare Tunnel 配置教程