RAG 解决了什么问题
LLM 有两个顽固问题:知识截止(训练数据只到某个日期)和幻觉(编造不存在的事实)。RAG(Retrieval-Augmented Generation)用外部知识库解决了这两个问题——查询时实时检索相关文档,把文档内容作为上下文喂给 LLM。
flowchart TD
A[📄 文档上传] --> B[✂️ 文本分块]
B --> C[🧮 Embedding 向量化]
C --> D[(🗄️ 向量数据库)]
E[❓ 用户提问] --> F[🔍 检索相似文档]
D --> F
F --> G[📋 Top-K 文档]
G --> H[🤖 LLM 生成答案]
H --> I[✅ 带引用的回答]
技术栈选型
一个生产级 RAG 系统需要四个组件,每个都有多种可选方案:
| 组件 | 作用 | 推荐方案 |
|---|---|---|
| 文档处理 | 解析+分块 | Unstructured, LlamaIndex |
| Embedding | 文本转向量 | BGE-M3, text-embedding-3-large |
| 向量数据库 | 存储和检索 | Milvus, Qdrant, Chroma |
| LLM | 生成答案 | GPT-4o, Claude, Qwen |
关键决策一:如何分块
分块策略直接影响检索质量。分太细语义不完整,分太粗噪声太多:
| 策略 | 适用场景 | 示例 |
|---|---|---|
| 固定大小 | 通用文档 | 512 tokens, overlap 64 |
| 语义分块 | 结构化文档 | 按段落/章节分割 |
| 递归分割 | 混合格式 | 先按 \n\n,不够再按句子 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块 500 tokens
chunk_overlap=50, # 相邻块重叠 50 tokens
separators=["\n\n", "\n", "。", ".", " "]
)
chunks = splitter.split_documents(documents)
关键决策二:检索策略
简单的向量相似度检索会漏掉相关文档。生产环境常用混合检索:
# 混合检索 = 向量检索 + BM25 关键词检索
from langchain.retrievers import EnsembleRetriever
dense_retriever = vector_store.as_retriever(search_kwargs={"k": 5})
sparse_retriever = BM25Retriever.from_documents(docs)
hybrid = EnsembleRetriever(
retrievers=[dense_retriever, sparse_retriever],
weights=[0.7, 0.3] # 向量检索权重更高
)
检索后再用重排序模型(如 BGE-Reranker)对 Top-K 文档重新打分,准确率可提升 10-20%。
评估 RAG 系统的好坏
三个关键指标:
- 召回率:相关文档有没有被检索到
- 忠实度:生成的答案是否基于检索到的文档
- 相关性:答案有没有回答用户的问题
RAGAS 是一个流行的 RAG 评估框架,可以自动计算这些指标。
RAG 是目前对抗 LLM 幻觉问题研究现状 中最有效的方案之一。关于个人实践参考 搭建个人 RAG 知识库。