RAG(Retrieval-Augmented Generation,检索增强生成)是当前构建 LLM 应用最为广泛的基础架构之一。它通过外部知识库检索 + 大模型生成的组合范式,有效解决了 LLM 的幻觉问题、知识截止问题和私有知识整合问题。本文全面梳理 RAG 的技术体系,从基础原理到高级优化,从工程实践到评估方法。
大语言模型(LLM)虽然能力强大,但存在三个核心缺陷:
RAG 通过让 LLM 在推理时检索外部知识源,从根本上解决了上述问题。相比模型微调(Fine-tuning),RAG 具有以下优势:
| 维度 | RAG | Fine-tuning |
|---|---|---|
| 知识更新 | 即时生效,只需更新知识库 | 需要重新训练或微调 |
| 幻觉控制 | 强(基于检索结果生成) | 弱(依赖模型记忆) |
| 资源成本 | 低(无需 GPU 训练) | 高(需要训练资源) |
| 数据安全 | 可控(知识在本地索引) | 知识嵌入模型参数中 |
| 实现复杂度 | 中等 | 高 |
标准的 RAG 流程可以分为索引阶段和查询阶段:
索引阶段(Indexing Pipeline):
查询阶段(Query Pipeline):
一张图概括 RAG 架构:
Chunking 是 RAG 中最关键也最易被忽视的环节。分块质量直接影响检索效果:
| 策略 | 方法 | 适用场景 | 优缺点 |
|---|---|---|---|
| 固定大小 | 按字符/RAG Token数切分 | 简单文档 | 可能截断语义 |
| 递归分割 | 按段落→句子逐级切分 | 通用 | 最常用,LangChain 默认 |
| 语义分割 | 基于 LLM 识别语义边界 | 复杂长文 | 效果好但成本高 |
| 文档结构分割 | 按标题/章节切分 | 结构化文档(PDF/Markdown) | 保留文档逻辑 |
| 代理分割 | 用 LLM 判断最佳分割点 | 高质量需求 | 延迟高,成本高 |
| Late Chunking | 先编码长文本再切分 | 长文档 | 保留全局上下文 |
实践中推荐参数:
Hugo 的踩坑记录:某次做企业文档检索,固定 512 token 切分导致大量表格被截断,召回率从 85% 掉到 32%。改用按段落分割 + 200 token overlap 后召回恢复至 78%。关键教训:Chunking 策略必须适配文档类型,没有万能方案。
Embedding 模型负责将文本转换为语义向量。选择时关注三个指标:
主流 Embedding 模型对比(2025):
| 模型 | 维度 | MTEB | 语言 | 特点 |
|---|---|---|---|---|
| text-embedding-3-large | 3072 | 64.6 | 多语言 | OpenAI,质量最高但付费 |
| text-embedding-3-small | 1536 | 62.3 | 多语言 | OpenAI,性价比之选 |
| BGE-large-zh-v1.5 | 1024 | 68.6(中文) | 中英 | 中文最优,开源免费 |
| BAAI/bge-m3 | 1024 | 74.6 | 100+语言 | 多语言统一模型 |
| GTE-Qwen2 | 1024 | 76.4 | 中英 | 阿里出品,Qwen 底座 |
| jina-embeddings-v3 | 1024 | 67.1 | 多语言 | 支持多任务,LoRA 适配 |
选型建议:中文场景首选 BGE-m3 或 GTE-Qwen2;预算充足用 OpenAI text-embedding-3-small;需要多语言通用场景用 jina-v3。
向量数据库的核心功能是存储向量并高效执行相似性搜索(ANN)。主流选择:
| 产品 | 运行方式 | 索引算法 | 特点 |
|---|---|---|---|
| Milvus | 分布式部署 | IVF/HNSW | 企业级,支持 GPU 加速 |
| Qdrant | 自部署/托管 | HNSW | Rust 实现,性能极佳 |
| Weaviate | 自部署/托管 | HNSW | 内置向量化模块 |
| Pinecone | 全托管 SaaS | - | 开箱即用,无需运维 |
| Chroma | 嵌入式 | HNSW | 开发友好,适合原型 |
| FAISS | 库(非 DB) | IVF/HNSW | Meta 出品,最核心的 ANN 库 |
| pgvector | PostgreSQL 扩展 | IVFFlat/HNSW | 复用 PG 生态 |
选型参考:
HNSW 索引参数推荐(Hugo 生产经验):
M=16(平衡检索速度与精度)ef_construction=200(构建时的搜索宽度)ef_search=100(检索时的搜索宽度)用户原始查询可能表达模糊,通过 LLM 将查询改写为更适合检索的形式:
原始查询 → LLM → 改写查询
"这个怎么用?" → "如何使用 API 完成用户认证?"
实现方式:
对于多跳问题(Multi-hop Question),需要拆解为多个简单查询:
"2024 年诺贝尔物理学奖得主毕业于哪所大学?"
→ 查询1: "2024 年诺贝尔物理学奖得主是谁"
→ 查询2: "[姓名] 的教育背景 / 毕业院校"
根据查询类型路由到不同的检索策略:
结合**稠密检索(Dense)和稀疏检索(Sparse)**的优势:
混合方法:
# 伪代码示意
dense_score = cosine_similarity(query_emb, doc_emb) # 语义匹配
sparse_score = bm25_score(query, doc_text) # 关键词匹配
final_score = alpha * dense_score + (1-alpha) * sparse_score
alpha 值通常设置为 0.5-0.8,具体看文档类型。代码文档建议 alpha=0.5(关键词精确度高),论文文档建议 alpha=0.8(语义匹配更重要)。
将多个检索结果按排名融合:
其中 通常设为 60, 是文档 在检索系统 中的排名。这种方法简单有效,不需要做分数量纲对齐。
向量检索的 ANN 结果是近似的,需要用更精确的模型进行二次排序。
常用 Re-rank 模型:
| 模型 | 类型 | 特点 |
|---|---|---|
| BGE-Reranker-v2 | Cross-encoder | 中文表现最优 |
| Cohere Rerank | API | 质量高但付费 |
| bge-reranker-v2-m3 | Cross-encoder | 多语言通用 |
| jina-reranker-v2 | API | 支持多粒度重排 |
重要:Cross-encoder 性能远优于 Bi-encoder。向量检索用 Bi-encoder(快),重排序用 Cross-encoder(准)。
Hugo 的经验:某次做法律文档 RAG,使用 BGE 检索 Top-100,然后用 Cross-encoder 重排取 Top-10,最终答案准确率从 72% 提升到 91%。但重排会引入约 50ms 延迟,需要权衡。
由论文《Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection》提出。LLM 在生成过程中自我判断是否检索、检索什么、如何利用检索结果:
查询 → LLM 判断是否需要检索
├─ 否 → 直接生成回答
└─ 是 → 检索文档 → LLM 判断文档相关性
├─ 相关 → 基于文档生成 → 检查是否忠实于文档
└─ 不相关 → 重新检索或拒绝回答
优点:减少不必要的检索调用,提高生成质量和事实一致性。
当检索到的文档质量不高时,不是直接使用,而是进行纠错和补全:
根据问题复杂度动态调整检索策略:
将 RAG 嵌入 Agent 工作流中,让 LLM Agent自主决定搜索计划、搜索时机和搜索策略:
这是 2025 年最主流的 RAG 范式,LangChain、CrewAI 等框架提供完善的 Agentic RAG 支持。
RAG 评估需要从检索质量和生成质量两个层面进行:
| 指标 | 含义 | 计算方式 |
|---|---|---|
| Recall@K | 前 K 个结果中找到相关文档的比例 | 相关文档数 / 总相关文档数 |
| Precision@K | 前 K 个结果中相关文档的比例 | 相关文档数 / K |
| MRR(Mean Reciprocal Rank) | 第一个相关结果的排名倒数的均值 | |
| NDCG(Normalized Discounted Cumulative Gain) | 考虑排序位置的归一化累计增益 | 按排序位置加权求和后归一化 |
| MAP(Mean Average Precision) | 平均精度的均值 | 各查询平均精度的算术平均 |
| 指标 | 含义 | 评估方式 |
|---|---|---|
| Faithfulness(忠实度) | 回答是否基于检索文档 | LLM-as-Judge 或人工 |
| Answer Relevancy | 回答是否回答了问题 | LLM-as-Judge |
| Context Precision | 上下文是否包含必要信息 | 自动计算 |
| Hallucination Rate | 模型编造信息的比例 | LLM-as-Judge |
| Groundedness | 回答是否引用具体来源 | 检测引用来源 |
| 框架 | 特点 | 适用场景 |
|---|---|---|
| Ragas(最推荐) | 开源,自动生成测试集,支持多种指标 | 全流程评估 |
| TruLens | 反馈循环,支持持续监控 | 生产环境 |
| LangSmith | LangChain 生态,可视化监控 | LangChain 用户 |
| DeepEval | 使用简单,L1 评估策略 | 快速评估 |
| Phoenix (Arize) | 开源,支持 LLM 可观测性 | 复杂生产环境 |
Ragas 集成示例:
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall
)
result = evaluate(
dataset=test_dataset, # 包含 question, answer, contexts, ground_truth
metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall
]
)
print(result)
上线后的持续监控至少需要关注以下指标:
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 检索结果不相关 | Chunk 太小 / Embedding 不匹配 | 调整 Chunk 大小 / 更换 Embedding 模型 |
| 答案不完整 | Chunk 截断关键信息 | 增加 Chunk 大小或 Chunk Overlap |
| 答案包含矛盾信息 | Chunk Overlap 太小 / 未去重 | 增加去重机制 |
| 检索延迟高 | 向量索引参数不合理 | 优化 HNSW 参数或升级索引 |
| 频繁幻觉 | 检索质量低 / Context 窗口不足 | 优化检索 + Re-rank 或增加 Context |
| 多跳问题回答错误 | 单次检索无法覆盖 | 切换为 Multi-hop RAG 或 Agentic RAG |
增量更新策略:
知识去重:使用 MinHash 或 SimHash 对相似文档去重,避免检索到几乎相同的内容导致 Token 浪费。
知识时效性标记:给每个 Chunk 添加时间戳元数据,查询时可以根据时间范围过滤。
RAG 系统的端到端延迟需要控制在 2-5 秒:
| 优化方向 | 方法 | 预期提升 |
|---|---|---|
| 向量检索 | 调整 HNSW ef_search |
检索从 10ms → 2ms |
| Embedding 计算 | 用 GPU/API 代替 CPU | 50ms → 10ms |
| LLM 推理 | 使用 vLLM 等推理引擎 | 首 token 延迟从 3s → 0.5s |
| 缓存 | 高频查询向量结果缓存 | 命中时省去检索时间 |
| 流式输出 | 首 token 到达后立即开始输出 | 用户体验显著提升 |
Hugo 的真实案例:某客服 RAG 系统,直接用 llama.cpp 推理延迟高达 8 秒。换成 vLLM + 量化模型后,首 token 延迟降到 600ms,配合 Streaming 输出,用户几乎感觉不到等待。
LLM 的上下文窗口是有限的(Claude 200K、GPT-4o 128K),但 RAG 不应该用完所有窗口。
Context 组织原则:
Prompt 模板 (Hugo 内部实践):
你是一个基于知识库的问答助手。
请基于以下参考资料回答用户的问题。
如果参考资料不足以回答问题,请如实告知「我没有找到相关信息」。
回答时请引用具体来源。
参考资料(按相关度从高到低排列):
{context}
---
用户问题:{question}
回答:
传统的 RAG 只处理纯文本。多模态 RAG 可以同时检索文本和图片、表格、图表。
实现方式:
推荐方式:对于工程实践,方式 1(图转文)最简单有效。方式 2 用于需要图片精确匹配的场景。方式 3 用于高精度多模态场景。
| 框架 | 语言 | 核心优势 | 适用场景 |
|---|---|---|---|
| LangChain | Python/JS | 生态系统最成熟,组件最丰富 | 企业级生产应用 |
| LlamaIndex | Python | 数据索引能力最强,支持 160+ 数据源 | 数据密集型应用 |
| Haystack | Python | 模块化设计,原生支持评估 | 问答系统 |
| Canopy (Pinecone) | Python | Pinecone 原生,简洁高效 | Pinecone 用户 |
| R2R | Python | LLM 原生应用平台,开箱即用 | 中小团队快速搭建 |
Hugo 的使用经验:LangChain 组件丰富但抽象层次太多,调试困难。小项目建议直接用 LlamaIndex 或直接调 API。生产项目用 LangChain 需要建立团队内部的封装层,降低耦合度。
| 框架 | 特点 |
|---|---|
| vLLM | PagedAttention 算法,主流推理引擎,支持多种量化 |
| TGI | HuggingFace 出品,与 HF 生态集成度最高 |
| Ollama | 本地运行模型最简单的方式,适合开发/测试 |
| llama.cpp | 纯 C++ 实现,资源占用最低 |
| TensorRT-LLM | NVIDIA 官方,GPU 利用率最高 |
微软开源的 GraphRAG 将知识图谱引入 RAG,通过构建文档的实体关系图来解决全局性问题。传统 RAG 擅长回答具体事实问题,GraphRAG 擅长回答需要跨文档综合分析的 "宏问题"。
GraphRAG vs 传统 RAG:
Claude 3.5 到 4 系列支持 200K-500K token 上下文窗口,GPT-4-128K 也已经是标配。但长上下文并不意味着 RAG 不再必要:
所以当前共识是:长上下文与 RAG 是互补关系。RAG 负责精确定位相关文档,长上下文负责在同一轮对话中承载更多检索结果。
通过同时检索多个候选文档并行生成候选回答,再由验证器选择最佳回答。在保持质量的同时显著降低延迟。
对于从零开始搭建 RAG 系统的团队,建议按以下顺序迭代:
相关链接:
本文为 AI 知识体系 的核心章节之一,持续更新。