Skip to content

RAG工程

更新: 5/5/2026 字数: 0 字 时长: 0 分钟

为什么需要RAG

RAG的诞生是为了解决Agent的两个根本性的局限性——幻觉(编造内容)和知识截至日期(大模型只知道训练集中的内容)

当然,我们也可以使用微调来解决这两个问题,即在私有数据上对模型进行SFT,但实践证明,微调并不适合知识注入,原因深刻:

  • 微调会遗忘:在新数据上微调会损害模型在就数据上的性能,且让AI记住10万页文档的内容需要大量的微调,代价极高
  • 知识更新昂贵:每次微调都需要许多的人力和计算成本
  • 微调不能精确的控制信息来源:新旧知识混合,无法保证大模型一定会用新的知识进行回答
  • 知识密度问题:模型参数的信息存储效率远低于文本本身。一个 70B 模型(140 GB)能存储的”专有知识”远不如直接在推理时给模型看原始文档来得多和准确。

综上所述,预期让模型通过微调记住知识,不如在需要的时候讲相关的知识找出来塞进Prompt

RAG整体流程

一个RAG应该分为两个阶段:离线索引阶段(准备知识库)和在线检索生成阶段(相应查询)

文档解析

我们的原始文件:PDF,Word,HTML等,要先被解析后才可以存到我们的知识库中,这里的解析方式有很多,OCR,直接输入或者大模型解析等等

文档类型解析难度主要工具常见问题
Markdown/纯文本直接读取几乎无
HTML低-中BeautifulSoup, trafilatura噪音(导航栏/广告/脚本)
Word (.docx)python-docx, mammoth样式丢失,嵌入图片
PDF(可搜索)中-高PyMuPDF, pdfminer, pypdf多栏、表格、公式
PDF(扫描件)OCR: Tesseract, PaddleOCR识别精度、布局分析
PowerPointpython-pptx文本框顺序,图表
Excel/CSVpandas表格结构化处理

结构化和非结构化处理

对于表格这种高度结构化的数据——每一行/列都依赖于表头,如果直接讲表格序列化为线性的文本,模型是难以理解的

更好的做法是将其转换为Markdown的形式,亦或者为每一行生成自然语言描述

而对于图表,由于纯文本Embedding模型无法处理图像,因此解决方案有两种:

  • 多模态 Embedding:用多模态 Embedding 模型(如 CLIP)将图像编码为向量,存储在向量库中
  • 图像描述生成:用多模态 LLM(如 GPT-4V)自动生成图像的文字描述,再作为文本索引

文本分块——Chunking策略

Embedding精度问题:Embedding模型将一段文本压缩为一个固定维度的向量,由于向量的维度是固定的,因此文本越长,具体细节越无法被精确的表达,短小精悍的Embedding质量远高于长的Embedding

另一方方面,如果文本过长,我们在进行一次检索的时候,会返回过长的模型给Agent,这回快速的填满模型的上下文,造成回复效果变差

分块的方式

一般常见的分块方式分为两种:固定大小分块和语义分块

  • 固定大小分块:根据固定的Token数进行分块,相邻块之间有一定的重叠,保证每个块不会因为固定大小切分而被切断一个完整的语句,或是段落的开头和结尾在不同的块中

  • 语义分块:按段落、按章节、按标题层级

    • 按段落分块:以空行或 \n\n 为边界,每个段落为一个块。适合有清晰段落结构的文档。问题是段落长度差异巨大——有的段落 10 个词,有的 500 个词。
    • 递归字符分块(LangChain 的 RecursiveCharacterTextSplitter):按优先级顺序尝试不同的分隔符(\n\n → \n → . → ),先按段落分,段落太长则按句子分,句子太长则按空格分。这是最实用的分块策略,兼顾了语义完整性和块大小的可控性。
    • 基于 Markdown/HTML 结构分块:如果文档有明确的标题结构(# ## ###),按标题层级切分,每个标题下的内容为一个块,同时在块的 metadata 中记录标题路径(如”第2章 > 2.3节 > 安装配置”)。

块的大小一般没有统一的最优解,需要根据文档类型和检索模式来调整

场景推荐块大小理由
精确问答(如”XX 产品的价格是多少”)128-256 token短块语义更精确,检索相关性高
摘要/综述类问答512-1024 token需要更多上下文来理解主题
代码文档函数级(整个函数)代码语义单元是函数,不应硬切断
法律/合同文档条款级(一个条款)法律条款是语义单元

特别注意的是,块大小是RAG中最容易被忽略的超参数,对于不同的文档,我们实际上应该使用不同的分块大小,然后多次检索,以获得最好的效果

从小到大检索

一种更好的方式是从小到大检索:

  • 小块用于检索(如128Token)——小块的Embedding精度高,检索更加准确
  • 大块用于生成(如512Token)——大块的Embedding包含更多的信息,适合给LLM生成回复

我们通过小块获取其所属的父块,这样既保证了精度,又给了LLM足够的上下文,LlamaIndex 的 NodeWithScore 机制支持这种父子块结构

Embedding模型

Embedding模型是将文本转换成一个固定维度的浮点数向量,语义相似的文本,其Embedding向量在高纬度空间中距离也近

还有一种是非对称Embedding,这里的非对称是指针对查询和文档进行划分,对于查询和文档进行不同的Embedding模式

  • E5 系列:在输入前加 query: 或 passage: 前缀,用不同的前缀引导模型产生适合查询或文档的向量表示
  • BGE 系列:类似机制,加 为这个句子生成表示以用于检索相关文章: 等指令

在实际使用中,如果使用非对称Embedding,那么一定要加上指令,否则可能会让查询效果下降

向量数据库

针对向量这种特殊的数据形式,我们需要一种新的数据库格式拉进行春初,这就是向量数据库

在实际的生产环境中,一个企业级知识库可能包含上百万个文档块,每个块都对应一个1536维的浮点向量,当用户查询到来时,需要在毫秒级找到与之最相关的Top-K个向量———这一过程利用了近似最近邻搜索(ANN)算法

常见的近似最近邻搜索算法

HNSW(Hierarchical Navigable Small World)

HNSW是当前最流行的ANN算法,被Chroma,Milvus,Qdrant,Weaviate,Pgvector等几乎所有的向量库使用

HNSW的核心设计借鉴了六度分隔理论跳表,采用的是多层图结构和贪心搜索的机制

IVF索引

IVF(Inverted File Index) 是另一种常用索引,适合数据量极大(亿级+)的场景。

IVF的内存占用比HNSW低(不存储全图),但召回率通常略低于HNSW,适合显存/内存受限的场景

主流向量数据库对比

数据库部署方式索引类型特色适用规模
Chroma本地/云HNSW轻量,Python 原生,快速原型小-中
Qdrant本地/云HNSWRust 实现,高性能,过滤功能强中-大
Milvus本地/云HNSW/IVF/DiskANN企业级,高可用,多索引支持大型企业
Weaviate本地/云HNSW内置混合搜索,GraphQL API中-大
pgvectorPostgreSQL 扩展HNSW/IVF与 PostgreSQL 生态无缝集成小-中
Pinecone纯云服务私有全托管,零运维任意
Faiss库(非数据库)HNSW/IVF/PQFacebook 出品,底层研究标准本地实验

对于初创团队或快速原型:Chroma 或 pgvector(如果已有 PostgreSQL)是最简单的选择。

对于生产级企业应用:Qdrant 或 Milvus 提供了更好的性能、可用性和管理能力。

检索策略

单独使用向量近似匹配实际上会有搜索不准确的问题,比如我们收缩Iphone15的电池容量,可能会搜索出Iphone14的电池容量,对于这种问题我们必须尝试解决

常见的解决方式是混合搜索,其具体步骤是:

  1. 对查询分别执行向量搜索(返回 Top-K1 个结果)和 BM25搜索(返回 Top-K2 个结果)
  2. 用 RRF(Reciprocal Rank Fusion) 等融合算法合并两个排序列表

另一种方式是使用元数据过滤,只针对限定范围的元数据进行搜索

Reranker

由于Embedding的有损压缩的性质,因此向量搜索必然是一个粗排的过程,我们无法保证真正想要的信息在上方,而我们的大模型又更加熟悉上访的数据,在这个情况下,我们就需要重排序

重排序本身是利用专门的重排序模型进行的,主流 Reranker 模型:bge-reranker-v2-m3(BAAI,多语言)、ms-marco-MiniLM-L-12-v2(微软,英文)、Cohere Rerank API(付费云服务)。

生成阶段

将检索道德文档块(重排序后)和用户的问题组成Prompt:

text
[System]
你是一个专业的知识库助手。根据以下提供的参考文档回答用户的问题。
- 只根据参考文档中的信息作答,不要使用你自己的背景知识
- 如果参考文档中没有足够的信息回答问题,请明确说明"文档中没有相关信息"
- 在答案末尾注明信息来源(文档名称和章节)
[参考文档]
文档1(来源:产品手册第3章):
{chunk_1}
文档2(来源:FAQ-2024.pdf 第15页):
{chunk_2}
文档3(来源:内部Wiki-发布流程):
{chunk_3}
[用户问题]
{user_question}
[回答]

RAG在生成策略的时候也会分为严格RAG和知识增强RAG

  • 严格RAG:模型只使用RAG检索出的内容进行回答,适合专业化要求高的场景(法律,医疗,金融)
  • 知识增强RAG:允许模型在检索结果的基础上调用自身知识进行推理补充。适合对全面性要求更高的场景

来源引用(Citation):生产级 RAG 系统应该在答案中注明信息来源,允许用户验证答案。实现方式:在每个文档块的元数据中存储来源(文件名、页码、章节),检索后将来源信息附在对应的内容上,生成时引导模型以”[来源: XX 文档第 XX 页]“的格式标注。

本站访客数 人次      本站总访问量