RAG 整体架构与流程
一个完整的 RAG 系统可以清晰拆成**离线(Offline)和在线(Online)**两个阶段。离线负责把文档变成可检索的向量索引;在线负责把用户问题变成答案。
1. 离线阶段:构建知识索引
离线阶段只需要在文档更新时跑一次(或增量跑),流程如下:
原始文档 (PDF/Word/网页...)
│
▼
[加载 Loader] 读取文本与元数据
│
▼
[拆分 Chunking] 切成合适大小的片段
│
▼
[向量化 Embedding] 每段文本 → 向量
│
▼
[写入向量库] 向量 + 原文 + 元数据持久化关键产物是一个向量数据库,它保存了每段原文的向量表示,供后续相似度搜索使用。
2. 在线阶段:回答用户问题
用户提问时,系统实时执行:
用户问题
│
▼
[问题向量化] 用同一个 Embedding 模型
│
▼
[检索 Retrieval] 在向量库中找 Top-K 相似片段
│
▼
[重排 Rerank] (可选) 用 Cross-Encoder 精排
│
▼
[组装 Prompt] 问题 + 检索片段 + 指令
│
▼
[生成 Generation] LLM 输出最终答案ℹ️两阶段的核心约束
离线阶段和在线阶段必须使用同一个 Embedding 模型。否则「问题向量」和「文档向量」不在同一空间,检索结果会毫无意义。这是新手最常见的坑。
3. 各组件职责一览
| 组件 | 阶段 | 职责 |
|---|---|---|
| Document Loader | 离线 | 把各种格式读成纯文本 |
| Chunking 策略 | 离线 | 决定一段多长、如何切 |
| Embedding 模型 | 离线+在线 | 文本 ↔ 向量 |
| 向量数据库 | 离线+在线 | 存储与相似度检索 |
| Retriever | 在线 | 执行检索(含混合/重排) |
| Prompt 组装 | 在线 | 拼上下文、控制 token 预算 |
| LLM | 在线 | 基于证据生成答案 |
4. 一个最小可跑的伪代码
# 离线
docs = load(file) # 加载
chunks = split(docs) # 拆分
vectors = embed(chunks) # 向量化
store.add(vectors, chunks) # 入库
# 在线
q_vec = embed(question) # 问题向量化
hits = store.search(q_vec, k=5) # 检索 Top-5
prompt = build_prompt(question, hits) # 组装
answer = llm(prompt) # 生成💡先跑通最小闭环
不要一上来就追求高级技巧。先把「加载→切分→向量化→检索→生成」这条最朴素链路打通,再逐步加重排、混合检索、引用溯源等增强项。
🎯练习
画出你目标场景的数据流:源文件在哪、多久更新一次、谁在提问、对延迟的要求。这决定了离线阶段是否需要「增量更新」和在线阶段是否需要「缓存」。
小结
- RAG 分离线(建索引)与在线(答问题)两阶段
- 离线三件套:加载、切分、向量化入库
- 在线三件套:问题向量化、检索、组装 Prompt 后生成
- 离线/在线必须用同一 Embedding 模型
- 下一章从离线第一步「文档加载」讲起 →