RAG-检索增强生成

2026-08-08hweihaobo-herbert👁 69 阅读10 分钟阅读📝 1240 字💬 0 评论
RAG-检索增强生成

RAG(检索增强生成):AI 如何结合外部知识库回答问题

LLM 是"大脑",RAG 是给它配了一个"外挂硬盘"。


一、为什么需要 RAG?

1.1 LLM 与生俱来的三个硬伤

硬伤 表现 举例
知识截止 训练数据有截止日期,不知道新信息 “最新的 iOS 版本是什么?” → 胡编
幻觉 不知道的事会自信地编造 “请引用《XX 法》第 3 条” → 编了一条不存在的
无法访问私域数据 只学过公开数据,不懂公司内部文档 “我们的退款政策是什么?” → 编造政策

1.2 RAG 的核心思想

不修改模型本身,而是让模型在回答前"先去查资料"。

传统 LLM:  用户提问 → 模型凭记忆回答(可能忘、可能编)RAG:       用户提问 → 先去知识库搜索相关文档 → 把文档和问题一起给模型 → 模型基于文档回答

就像一个开卷考试:书(知识库)是外部提供的,学生(LLM)负责理解和作答。只要书是对的,答案就不会太离谱。


二、RAG 的完整架构

┌─────────────────────────────────────────────────────┐│                   离线阶段(建库)                    ││                                                      ││  文档 → 切块 → Embedding → 向量数据库                ││  (PDF/网页/数据库)  (chunks)  (向量)  (存储+检索)    ││                                                      │└─────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────┐│                   在线阶段(查询)                    ││                                                      ││  用户提问 → 向量化 → 检索 Top-K 相关文档块           ││       ↓                                              ││  Prompt 拼接: [检索到的文档] + [用户问题]            ││       ↓                                              ││  发给 LLM → 基于文档生成答案 → 返回给用户            ││                                                      │└─────────────────────────────────────────────────────┘

三、分步详解

3.1 文档预处理与切块(Chunking)

RAG 的第一道关卡:把一个长文档切成小块。

为什么不能直接用整个文档?

  • LLM 有上下文长度限制(虽然现在 128K 已很普遍,但不能浪费)
  • 文档太长 → 检索精度下降(大海捞针)
  • 不相关内容占用 Token → 成本浪费

切块策略——这是 RAG 最重要的工程决策之一:

原始文档(5000 字)策略选择┌──────────────────────────────────────────────────┐│ 策略 1:固定大小切块                             ││  每块 512 字,无重叠                             ││  简单但容易把一句话切两半,丢失语义               │├──────────────────────────────────────────────────┤│ 策略 2:滑动窗口重叠切块                         ││  每块 512 字,前后各重叠 50 字                   ││  保证连贯性,但增加存储量                        │├──────────────────────────────────────────────────┤│ 策略 3:语义切块                                 ││  按段落/句子边界切,保证每块是一个完整语义单元    ││  效果最好,但需要 NLP 分句工具或模型辅助          │├──────────────────────────────────────────────────┤│ 策略 4:层级切块                                 ││  小块的 parent 指针指向大块                      ││  检索时先找小块,返回时带上父块上下文             │└──────────────────────────────────────────────────┘

最佳实践:

文档类型 建议策略 块大小
技术文档 固定大小 + 语义边界 256-512 token
法律合同 语义切块 200-400 token
项目代码 按函数/类边界 按需
长篇论文 层级切块 小 256 + 大 1024

3.2 Embedding:把文本变成向量

不是随便什么向量都行,必须让"语义相近的文本向量距离也近"。

"狗" 和 "猫" 的向量距离:近(都是宠物)"狗" 和 "宪法" 的向量距离:远(完全不相关)

常用 Embedding 模型:

模型 维度 特点
OpenAI text-embedding-3-small 1536 性价比高,多语言
OpenAI text-embedding-3-large 3072 精度最高
BGE-M3 1024 开源,多语言,支持稀疏+稠密混合检索
Jina Embeddings v2 768 长文本(8K token)支持好
Cohere Embed v3 1024 多语言,分类/检索双模式

生成 Embedding 的注意事项:

  • 输入文本不要直接裸传,加上 prefix(如 BGE 模型要求加 "为这个句子生成表示:..."
  • 中文和多语言场景优先选多语言模型
  • 向量维度越高信息越丰富,但检索越慢,存储越大

3.3 向量数据库:存什么、怎么查

向量数据库的核心能力:在百万、亿级向量中,毫秒级找到最相似的几个。

主流选型:

数据库 类型 适用场景
Milvus 分布式向量库 亿级以上,企业级
Pinecone 托管服务 不想自建,海外场景
Weaviate 开源 + 云 插件生态丰富
Qdrant Rust 高性能 轻量、数据处理灵活
Chroma 轻量嵌入式 原型开发、本地 RAG
pgvector PostgreSQL 插件 已有 PG 的项目,最简单的集成
Elasticsearch 搜索引擎 + 向量 需要混合检索(关键词 + 语义)

衡量标准:

  • QPS(每秒查询数)
  • 召回延迟(P99 < 100ms)
  • 召回率(Recall@K,K=5 时是否召回正确答案)

3.4 检索:找到最相关的文档块

这步是 RAG 的核心——检索质量直接决定回答质量。

基础检索

用户问题 → Embedding → 向量相似度搜索 → 返回 Top-K 文档

纯向量检索有时会"近视"——找出一堆语义相似但不直接相关的文档。混合检索融合关键词匹配(BM25)+ 语义搜索

用户问题:"Python 3.12 中的 dict 类型有什么新特性?"BM25 匹配到:"Python 3.12 release notes dict changes"        ← 精确关键词语义匹配到:"字典合并操作符在最新 Python 版本中的使用指南"    ← 语义相关混合排序 → 取出最靠谱的几个

重排序(Re-ranking)

Top-K 初筛后(比如 K=20),用更强的模型重新精排,再取 Top-3 喂给 LLM:

粗排: 向量检索 → 快速,精度一般 → 返回 20 个精排: Cross-Encoder → 慢但精准 → 对 20 个重新打分 → 取 Top 3

常用 Reranker:Cohere Rerank、BGE-Reranker、Cross-Encoder(cross-encoder/ms-marco-MiniLM-L-6-v2)。

3.5 生成:拼接 Prompt 并调用 LLM

检索到文档后,用以下模板拼接:

markdown
请仅根据以下提供的参考文档回答问题。如果参考文档中不包含相关信息,请直接说"根据已有资料无法回答"。参考文档:---[文档 1]{retrieved_chunk_1}[文档 2]{retrieved_chunk_2}---问题:{user_question}请遵循以下原则:1. 回答必须有引用标注,格式为 [来源: 文档N]2. 不要编造参考文档中不存在的信息3. 如果信息不完整,明确提出"文档未覆盖的部分"

关键设计点:

  • 引用标注:让用户知道答案从哪来的,建立信任
  • "不知道"边界:强制模型承认知识盲区,防止幻觉
  • 角色约束:如需要可以加 System Prompt 限定专业角色

四、RAG 的高级技巧

4.1 查询重写(Query Rewriting)

用户提问往往不够"检索友好":

用户原问题:"上次那个 bug 修好了吗?"  ← "那个"是什么?无法检索重写后:"支付模块订单超时未取消的 bug 修复状态"

可以用 LLM 自动重写:

  1. 把口语变书面语
  2. 把指代消解(“那个”→具体是什么)
  3. 根据对话历史补全上下文
  4. 拆解复合问题成多个子查询

4.2 父文档检索(Parent Document Retrieval)

存储时:  小块(用于检索,精确命中)  大块(作为上下文补充,防止信息断裂)检索时:  找到小块 → 顺便返回它的父文档 → 给 LLM 更完整的上下文

4.3 多跳检索(Multi-Hop Retrieval)

有些问题需要"查询 A 的结果 → 再查询 B"才能回答。

问:"我们公司 CEO 是谁?他的上一家公司叫什么?"Hop 1: 检索"公司 CEO" → 得到"张三"Hop 2: 检索"张三 上一家公司" → 得到"某某科技"

实现方式:迭代 LLM → 检索 → LLM → 检索,直到信息足够。

4.4 摘要索引(Summary Index)

大块文档先生成摘要,检索时先匹配摘要,命中再取原文:

文档 → 每段生成摘要 → 摘要 Embedding查询 → 匹配摘要 → 命中的取原始文档内容 → 回答

4.5 时间衰减加权

知识有时效性,旧文档权重应降低:

相关性得分 = 语义相似度 × e^(-λ × 距今天数)

五、评估 RAG 系统

光看回答"像不像人话"不够,需要量化指标:

指标 含义 计算方式
命中率(Hit Rate) 正确答案是否出现在检索结果中 检索结果包含答案 ÷ 总查询数
MRR 正确答案在检索结果中的排名倒数 1/排名 的平均值
忠实度(Faithfulness) 回答是来自检索文档还是编的 用 LLM 检查回答是否有文档支撑
答案相关性 回答是否真的回应了问题 人工或 LLM 评分
上下文相关性 检索到的文档是否相关 信号噪声比
延迟 检索 + 生成的总时间 P50/P95/P99 毫秒
Token 消耗 每次查询消耗的 Token 成本核算

推荐开源评估工具:

  • Ragas:最流行的 RAG 评估框架,一行代码出报告
  • DeepEval:支持单元测试风格的 pipeline 评估
  • TruLens:可视化追踪 + 评估

六、RAG vs 微调 vs 长上下文

RAG 不是唯一解法,三种方案各有适用场景:

方案 原理 何时用
RAG 检索外部文档注入 Prompt 知识经常更新;私域数据量大;需要引用来源
微调 用私域数据继续训练模型 风格/格式没法学;领域术语需要内化;数据稳定
长上下文 直接塞整个文档进去 文档短(< 50K);一次性任务;延迟不敏感

三者可以组合:用 RAG 检索相关内容 + 用长上下文模型避免切块丢失 + 用微调保证特定风格。


七、开源 RAG 技术栈速览

数据加载:    Unstructured, LlamaIndex Reader, LangChain Document Loader文档切块:    LangChain TextSplitter, LlamaIndex NodeParserEmbedding:   BGE-M3, Jina, text-embedding-3向量库:      Chroma(原型), Qdrant(生产), pgvector(已有 PG)编排框架:    LangChain, LlamaIndex, Haystack评估:        Ragas, DeepEval一站式:      Dify, FastGPT(国内友好)

八、RAG 的常见坑

原因 解法
检索到不相关的文档 Embedding 不够好 / 切块不当 换模型、加混合检索、加 Reranker
检索不到正确的文档 同义词、语言差异 查询重写、HyDE(假设性文档 Embedding)
答案丢失上下文 切块把关键信息打断了 父文档检索、加大块尺寸
答案前后矛盾 多个检索结果互相冲突 给 LLM 加冲突处理指令
速度和成本爆炸 每步都调 LLM 缓存 Embedding、预计算、减少搜索范围

RAG 本质是做了一件事:让 LLM 从"闭卷考试"变成"开卷考试"。卷子(知识库)是你给的,答案准确性的责任就回到了你这边。


延伸阅读:如果 RAG 是你的主要场景,推荐深入学习 LlamaIndex 或 LangChain 的 RAG 模块。从 Chroma + BGE-M3 开始动手,30 分钟就能跑通第一个原型。

hweihaobo-herbert
技术博客作者
1240 字 · 0 评论
2026-08-08

评论 (0)

暂无评论,来写第一条吧

登录后发表评论