【AI基础篇10】RAG:检索增强生成详解
·
【AI基础篇10】RAG:检索增强生成详解
前言:大模型的知识截止于训练日期,你问它"今天的天气"它不知道,问它"贵公司退货政策"它也不懂。但如果在回答前先查一下天气API、搜一下公司知识库呢?这就是RAG的核心思想——用检索替代记忆,用事实锚定生成。RAG是2024-2026年企业落地AI的第一选择,从客服到法务到医疗,几乎所有需要"私有知识"的场景都在用RAG。本文从基础原理讲到GraphRAG、Agentic RAG等高级范式,一次吃透。
📋 目录
- 一、为什么需要RAG?
- 二、RAG的核心流程:三阶段
- 三、文档处理:知识库构建
- 四、Embedding与向量检索
- 五、检索优化:混合检索与重排序
- 六、RAG的高级范式演进
- 七、RAG评估与调优
- 八、2026年RAG全景:GraphRAG、Agentic RAG、融合架构
- 九、实战:构建一个完整的RAG系统
一、为什么需要RAG?
1.1 大模型的三个致命短板
大模型很强大,但在企业应用中,有三个致命短板:
短板1:知识截止于训练日期
大模型的知识 = 训练数据覆盖的时间范围
训练于2025年 → 不知道2026年的事
你问"今年GDP" → 模型只能"猜"
短板2:不知道你的私有数据
你公司的内部文档、客户记录、产品手册
模型永远没"见过"这些数据
你问"我们公司的退货政策" → 模型只能"编"
短板3:无法保证事实准确性
即使它"知道",也可能记错
即使在标准测试集上表现好
在你自己的数据上也可能出错
RAG = 同时解决这三个问题的方案
1.2 大模型 vs RAG vs 微调
企业知识问答场景下的方案对比:
用户问:"我们公司2026年Q1的营收是多少?"
没有RAG没有微调 ❌
模型不知道公司的私有数据
→ 编造一个数字(幻觉)
→ 即使模型说"我不知道",也等于没用
只微调不RAG ⚠️
模型记住了训练时的营收数据
→ Q1营收是1.2亿(如果训练数据中有)
→ 但如果Q2数据更新了呢?
→ 微调后不能实时更新,除非重新微调
→ 成本和时效性都是问题
RAG(最佳实践) ✅
用户问→检索知识库→找到最新财报→基于财报回答
→ "根据公司2026年Q1财报,营收为1.5亿"
→ 数据更新时→只需要更新知识库→不需要重新微调!
→ 成本低、实时性好、可追溯
一句话对比:
微调是"教会模型记住规则和模式"
RAG是"每次回答前都去查资料"
两者不冲突,可以组合使用
1.3 RAG的适用场景
✅ RAG适合的场景:
客服系统:产品信息、退货政策、FAQ
企业知识库:内部文档、操作手册、制度文件
法律助手:法规条文、判例、合同审查
医疗辅助:诊疗指南、药品说明书、医学文献
教育培训:教材、题库、学习资料
数据分析:报表查询、业务指标、KPI监控
代码助手:公司内部API文档、代码规范
智能搜索:从海量文档中精准找到答案
❌ RAG不适合的场景:
创意写作:不需要"查资料",需要"发挥"
通用聊天:不需要私有知识
简单计算:直接让模型算更快
实时交互应用:多一次检索 → 多几百ms延迟
RAG的本质是"知识增强",不是"能力增强"
它让模型知道它不知道的东西
但不改变模型本身的能力边界
二、RAG的核心流程:三阶段
2.1 三阶段总览
RAG的完整工作流程分为三个阶段:
┌──────────────────────────────────────────────────────┐
│ │
│ 阶段1:索引(Indexing)—— 离线构建 │
│ ┌──────┐ ┌────────┐ ┌───────────┐ │
│ │文档 │ → │分块 │ → │Embedding │ │
│ │收集 │ │Chunking│ │向量化 │ → 存入向量DB│
│ └──────┘ └────────┘ └───────────┘ │
│ │
│ 阶段2:检索(Retrieval)—— 在线查询 │
│ ┌─────┐ ┌──────────┐ ┌──────────┐ │
│ │用户 │ → │问题 │ → │向量检索 │ │
│ │问问题│ │Embedding │ │Top-K文档 │ │
│ └─────┘ └──────────┘ └──────────┘ │
│ │
│ 阶段3:生成(Generation)—— 组装答案 │
│ ┌──────────┐ ┌──────────┐ ┌───────┐ │
│ │检索结果 +│ → │LLM │ → │最终 │ │
│ │用户问题 │ │生成回答 │ │输出 │ │
│ └──────────┘ └──────────┘ └───────┘ │
│ │
└──────────────────────────────────────────────────────┘
2.2 一句话版流程
文档 → 分块 → 向量化 → 存向量数据库
↓
用户问题 → 向量化 → 检索Top-K → 拼接Prompt → LLM生成回答
就这么简单。
2.3 关键参数一览
┌────────────┬──────────────┬──────────────┬─────────────────┐
│ 参数 │ 推荐值 │ 太大/太小 │ 影响 │
├────────────┼──────────────┼──────────────┼─────────────────┤
│ Chunk大小 │ 256-512 token│ 太大:信息混杂 │ 直接影响检索质量 │
│ Chunk重叠 │ 10-20% │ 太小:信息断裂 │ 保证边界信息完整 │
│ Top-K │ 3-5 │ 太多:噪声 │ 召回率 vs 精度 │
│ Embedding │ bge-large-zh │ 小模型准确度低│ 检索质量的核心 │
│ 重排序模型 │ bge-reranker │ 不加可能误检 │ 提升精度10-20% │
│ 温度 │ 0-0.3 │ 太高乱编 │ 事实性任务要低 │
└────────────┴──────────────┴──────────────┴─────────────────┘
三、文档处理:知识库构建
3.1 文档清洗——90%团队忽略的关键
很多团队做RAG,上来就做向量检索。
但真正决定RAG成败的,是**数据摄入层**——文档清洗。
错误的做法:
直接把PDF/Word文档扔进向量数据库
→ PDF解析出错 → 乱码 → 向量化错误 → 检索不到正确内容
正确的数据摄入流程:
Step 1:格式统一
PDF、Word、Excel、HTML、Markdown → 统一转为Markdown
不同格式用不同的解析器:
PDF:PyMuPDF(效果好)或 Azure Document Intelligence(商业)
Word:python-docx
HTML:BeautifulSoup + Readability
扫描件PDF:OCR → PaddleOCR / Tesseract
Step 2:内容清洗
去除页眉页脚、页码、目录 → 噪声
合并跨页的表格 → 避免信息断裂
修复编码问题 → 确保中文不乱码
统一术语 -> 产品名、缩写等前后统一
Step 3:元数据标注
来源文档名、章节标题、创建日期、作者
→ 检索输出时可以附上来源信息
→ 引用时可以直接说"根据[XX文档第X章]"
Step 4:质量过滤
过滤掉太短的块(<50字)
过滤掉纯表格/列表的块(无法向量化)
人工抽检5-10% → 确保清洗质量
3.2 Chunking:分块策略
Chunking是RAG中最关键也最容易被忽视的步骤。
好的Chunk → 检索命中率高
坏的Chunk → 检索不到正确内容
常见的分割方式:
1️⃣ 固定长度分割(最简单)
每256个token切一块
缺点:可能在句子中间切断
用途:通用文本,快速验证
2️⃣ 递归字符分割(LangChain默认)
按\n\n → \n → 句号 → 逗号 依次尝试分割
保证语义完整性
用途:大多数场景都适用
3️⃣ 语义分割(2024-2026新趋势)
用Embedding检测"语义边界"
当连续两句的语义变化超过阈值时切分
效果最好,但需要额外计算
4️⃣ 结构化分割
Markdown/HTML按标题层级分割
H1/H2/H3作为块边界
对文档类场景非常有效
各场景推荐策略:
长文档(书籍/手册):语义分割 + 标题层级
短文本(FAQ/问答):固定512token + 重叠10%
代码文档:按函数/类定义分割
表格数据:整个表格作为一个chunk
3.3 Chunk重叠策略
为什么要重叠?
如果恰好在一个chunk的边界处有重要信息
两个chunk都不完整 → 信息丢失
重叠解决这个问题:
控制参数:
chunk_size = 512
chunk_overlap = 50-100(10-20%)
效果:
文档中"退货政策:7天内可无理由退货"
如果这句话正好在边界
有重叠 → 两个chunk都包含这句话
无重叠 → 可能一个chunk只有"退货政策:",另一个只有"7天内可..."
实践经验:
文本密集:重叠10-15%
表格/列表:重叠15-20%
代码:重叠5-10%(可多分一个整函数)
四、Embedding与向量检索
4.1 Embedding模型选型
Embedding模型决定"检索质量"的上限。
2026年主流Embedding模型对比(中文场景):
┌──────────────────┬────────┬──────────┬──────────┬──────────┐
│ 模型 │ 维度 │ 检索mAP │ 速度 │ 适用场景 │
├──────────────────┼────────┼──────────┼──────────┼──────────┤
│ BAAI/bge-large-zh│ 1024 │ 最佳 │ 中 │ 中文首选 │
│ BAAI/bge-m3 │ 1024 │ 极佳 │ 中 │ 多语言 │
│ text2vec-large │ 1024 │ 优秀 │ 中 │ 中文替代 │
│ OpenAI ada-002 │ 1536 │ 优秀 │ 快 │ 英文最优 │
│ Qwen-Embedding │ 2560 │ 极佳 │ 快(云端)│ 阿里生态 │
│ moka-ai/m3e │ 768 │ 良好 │ 快 │ 轻量部署 │
└──────────────────┴────────┴──────────┴──────────┴──────────┘
选择建议:
中文场景:bge-large-zh-v1.5(开源,效果最好)
多语言场景:bge-m3
英文为主:OpenAI text-embedding-ada-002
快速验证:m3e-base(速度快,性价比高)
阿里生态:Qwen-Embedding(深度整合)
4.2 向量数据库选型
2026年主流向量数据库对比:
┌──────────────┬──────────┬──────────┬──────────┬────────────┐
│ 数据库 │ 部署方式 │ 索引类型 │ 亿级 │ 特点 │
│ │ │ │ 性能 │ │
├──────────────┼──────────┼──────────┼──────────┼────────────┤
│ Milvus │ 集群部署 │ IVF/ │ ✅ │ 企业级, │
│ │ │ HNSW │ │ 功能最全 │
│ Chroma │ 本地嵌入 │ HNSW │ ❌ │ 轻量,适合 │
│ │ │ │ │ 快速原型 │
│ Qdrant │ 单机/集群 │ HNSW │ ✅ │ Rust实现, │
│ │ │ │ │ 性能好 │
│ Weaviate │ 单机/集群 │ HNSW │ ✅ │ 内置MLOps │
│ FAISS │ 库(非DB) │ IVF/ │ ✅ │ 学术首选 │
│ │ │ HNSW │ │ │
│ pgvector │ PostgreSQL│ IVFFlat│ 中 │ 不想引入 │
│ │ 插件 │ HNSW │ │ 新DB │
└──────────────┴──────────┴──────────┴──────────┴────────────┘
选择建议:
小项目/原型:Chroma(一行代码启动)
中等规模:Qdrant 或 pgvector
企业级:Milvus(可扩展,功能全)
Postgres用户:pgvector(零额外运维)
学术研究:FAISS(最灵活)
4.3 向量检索的核心原理
向量检索 = 最大余弦相似度/最小欧氏距离
文本 → [0.12, 0.45, -0.23, 0.89, ..., 0.01] ← 一个高维向量
↓
检索:找一个向量和"用户问题的向量"最像的
常用距离度量:
余弦相似度(最常用):
cos(A, B) = A·B / (|A| × |B|)
只关心方向,不关心长度 → 适合文本
欧氏距离:
d(A, B) = √Σ(A_i - B_i)²
关心绝对距离 → 少用
检索算法(ANN近似最近邻):
HNSW(Hierarchical Navigable Small World,层级导航小世界)
→ 2026年最流行的向量检索算法
→ 构建多层图结构
→ 从顶层快速定位 → 逐层细化
IVF(Inverted File,倒排文件)
→ 先聚类 → 在最近的几个聚类中心里搜索
→ 速度更快但精度略低
五、检索优化:混合检索与重排序
5.1 混合检索——向量+关键词
纯向量检索的问题:
"退货政策"和"退款流程"语义相似 → 向量距离近
但用户问题中出现了精确的关键词 → 向量检索可能忽略
混合检索 = 向量检索 + BM25关键词检索
BM25(关键词检索):
基于词频-逆文档频率的经典算法
擅长:精确匹配特定术语
不擅长:语义相似匹配
向量检索:
基于语义匹配
擅长:同义词、近义词
不擅长:精确匹配专属名词
混合检索方式:
方式1:加权融合
score = α × vector_score + (1-α) × bm25_score
α通常在0.5-0.8之间
方式2:两阶段(推荐)
Step 1:向量检索 Top-100
Step 2:BM25检索 Top-100
Step 3:合并并去重 → 取Top-5
→ 兼顾召回和精度
方式3:RRF(Reciprocal Rank Fusion)
对多个检索结果进行排序融合
RRF_score(d) = Σ 1/(k + rank(d))
不需要调α权重
实践建议:
通用知识:α=0.7(偏向量)
专业术语多:α=0.5(平衡)
代码/编号查询:α=0.3(偏BM25)
5.2 重排序(Re-ranking)
为什么需要重排序?
向量检索是"粗略"的——从百万文档中快速筛出Top-100
但Top-100中只有3-5个是真正相关的
重排序 = 用更精细的模型对Top-100重新打分
重排序模型 vs 检索模型:
检索模型(bge-large-zh):
对整个文档库做检索
速度快(毫秒级)
精度足够筛到Top-100
重排序模型(bge-reranker-large):
只对Top-100做排序
速度慢(但100条只需要几十ms)
精度高(考虑query-doc交互)
如果不加重排序:
用户:公司2026年招聘计划
Top-5:[2026年预算案, 2025年招聘总结, 2026年1月会议纪要, 2026年培训计划, 部门重组方案]
第一个结果不直接相关!
→ LLM会基于不完整的上下文回答
加了重排序后:
Top-5:[2026年招聘计划, 2026年1月会议纪要中提到了招聘, 2026年预算案中的人力资源部分, ...]
→ 排除了不相关项
→ LLM基于高质量上下文回答
效果提升:
不加重排序:检索精度 60-70%
加重排序:检索精度 80-90%
→ 提升15-25个百分点
5.3 查询重写
用户的问题通常不是"检索友好"的:
不好的问题:
"我想问一下,那个退货的事..."
好的检索query:
"退货政策"
查询重写 → 用LLM把用户问题改写为检索友好的格式:
def rewrite_query(user_input):
prompt = f"""将用户的问题改写成适合检索的关键词:
用户输入:{user_input}
检索关键词:"""
response = llm.generate(prompt)
return response
示例:
用户:"帮我看看上次那个关于AI的那篇文章"
改写后:"AI 文章 上次"
检索命中率大幅提升!
六、RAG的高级范式演进
6.1 五代RAG演进
RAG从2020年提出到今天,经历了五代演进:
┌──────────────────────────────────────────────────────┐
│ 2020-2023:Naive RAG(朴素RAG) │
│ 文档 → 分块 → 向量化 → 检索 → 拼接 → 生成 │
│ 问题:检索质量不高,缺乏上下文意识 │
│ │
│ 2023-2024:Advanced RAG(进阶RAG) │
│ + 查询重写 + 重排序 + 混合检索 + 上下文压缩 │
│ 提升检索精度,减少噪声 │
│ │
│ 2024-2025:Modular RAG(模块化RAG) │
│ 自适应检索策略、多跳检索、检索路由 │
│ 不是一个固定流程,而是按需组合模块 │
│ │
│ 2025-2026:Agentic RAG(智能体RAG) │
│ Agent自行决定"什么时候检索、检索什么、怎么检索" │
│ 可以多次检索、多工具组合、多步推理 │
│ │
│ 2026+:融合架构(Fusion Architecture) │
│ RAG + 长上下文模型 + Agent + 记忆系统 │
│ 根据任务自动切换"是直接推理"还是"先检索再回答" │
└──────────────────────────────────────────────────────┘
6.2 Naive RAG(朴素RAG)
最简单的RAG流程:
用户问题 → 向量检索 → Top-K文档 → 拼接Prompt → LLM生成
代码极为简单:
docs = vector_db.similarity_search(query)
prompt = f"基于以下文档回答问题:\n{docs}\n\n问题:{query}"
answer = llm.generate(prompt)
优点:实现简单,一行代码
缺点:
❌ 一次检索,无法多步
❌ 检索质量不稳定
❌ 如果检索不到 → 直接失败
❌ 无法处理复杂查询
使用场景:快速验证、Demo
不适用:生产环境
6.3 Advanced RAG(进阶RAG)
进阶RAG在朴素RAG基础上增加了多个优化模块:
┌──────────────────────────────────────────────────────┐
│ 用户问题 │
│ ↓ │
│ 查询重写 → 转为检索友好的关键词 │
│ ↓ │
│ 混合检索 → 向量检索 + BM25 │
│ ↓ │
│ 合并排序 → RRF融合多路结果 │
│ ↓ │
│ 重排序 → bge-reranker精细排序 │
│ ↓ │
│ 上下文压缩 → 去除冗余、只留关键信息 │
│ ↓ │
│ 生成 → LLM基于高质量上下文回答 │
└──────────────────────────────────────────────────────┘
每个模块的收益:
查询重写:提升检索命中率 10-20%
混合检索:提升召回率 10-15%
重排序:提升精确率 15-25%
上下文压缩:减少token消耗 30-50%,同时减少噪声
进阶RAG解决了朴素RAG的"检索质量差"问题
2026年大多数生产系统处于这个阶段
6.4 Corrective RAG与Self-RAG
Corrective RAG(纠正式RAG,2024):
核心思想:检索后先判断"检索结果是否相关"
如果检索结果不相关 → 修正检索策略
流程:
检索 → 检索质量评估
├─ 质量好 → 正常生成
└─ 质量差 → 重新检索(改写后再查)
├─ 找到 → 正常生成
└─ 找不到 → 诚实说"不知道"
评估方式:用LLM判断或专门的小模型打分
Self-RAG(自省式RAG,2024):
核心思想:检索结果要"引用"和"自评"
流程:
1. 模型自行决定是否需要检索
2. 如果需要,检索并生成带引用的回答
3. 模型自己评估每个引用是否支持回答
4. 如果不支持 → 修正或删除该部分
效果:通过"内部审核"机制,显著降低RAG输出中的幻觉
两者的区别:
Corrective RAG:外部的"检索质量检查"
Self-RAG:模型内部的"回答质量检查"
两者可以组合使用
6.5 Agentic RAG(智能体RAG)
Agentic RAG = Agent + RAG
不再是固定的"检索→生成"流程
而是Agent根据情况自主决策检索策略
Agentic RAG的能力:
1️⃣ 要不要检索?
简单问题:"2+2=?"
→ 不需要检索,直接回答
事实性问题:"公司退货政策"
→ 需要检索,开始查知识库
2️⃣ 从哪里检索?
内部知识库:"产品使用手册"
→ 从向量数据库检索
实时信息:"今天的天气"
→ 调用天气API
结构化数据:"上季度营收"
→ 查询数据库
3️⃣ 检索几次?
单次检索:简单问题,一次性查
多轮检索:复杂问题,查完一次基于结果再查
多轮示例:
Q:"对比GPT-4和Claude 3.5的数学能力"
Round 1:检索"GPT-4数学能力"
Round 2:检索"Claude 3.5数学能力"
Round 3:检索"GPT-4 Claude 3.5 对比"
→ 逐步收敛信息
4️⃣ 怎么组合信息?
从多个文档中提取信息
对比、综合、总结
→ 生成完整回答
Agentic RAG的框架:
LangGraph / CrewAI / AutoGen
→ 用Agent框架编排多步检索策略
七、RAG评估与调优
7.1 RAG评估框架
RAG评估需要分别评估"检索质量"和"生成质量":
┌──────────────────────────────────────────────────────┐
│ 维度 │ 指标 │ 目标值 │
├──────────────────┼─────────────┼──────────────────┤
│ 检索-命中率 │ Hit Rate │ >90% │
│ 检索-精确率 │ Precision@K │ >80% │
│ 检索-MRR │ Mean Reciprocal Rank│ >0.85 │
│ 生成-忠实度 │ Faithfulness │ >90% │
│ 生成-相关性 │ Relevancy │ >85% │
│ 生成-无幻觉 │ No Hallucination │ <5% │
│ 端到端-满意度 │ User Rating │ >4.0/5.0 │
└──────────────────────────────────────────────────────┘
RAGAS(RAG Assessment)框架:
专门为RAG设计的评估框架
包含:忠实度、相关性、上下文精度等指标
使用LLM作为评估器(LLM-as-judge)
测试集构建:
最少需要100-200条测试用例
覆盖:常见问法、边缘情况、复杂查询
每一条包含:问题 + 期望答案 + 知识库中的来源文档
7.2 常见问题与解决方案
RAG系统常见的问题和解决方案:
问题1:检索结果不相关
表现:LLM生成的回答和问题无关
原因:向量检索到的文档并不包含答案
解决:
✅ 加混合检索(向量+BM25)
✅ 加重排序
✅ 检查chunk大小是否合适
✅ 改进嵌入模型
问题2:LLM不遵循上下文
表现:检索到了正确文档,但模型自己编答案
原因:System Prompt不够强硬
解决:
✅ 加防幻觉Prompt:"只基于提供的上下文回答"
✅ 降低temperature到0
✅ 加引用要求:"引用文档编号"
✅ 加拒绝选项:"如果找不到相关信息,说不知道"
问题3:知识库覆盖不全
表现:部分问题总是"找不到信息"
原因:知识库中没有相关文档
解决:
✅ 补充知识库
✅ 加搜索引擎回退
✅ 加"我不知道"处理流程
问题4:延迟太高
表现:用户等太久
原因:重排序 + LLM推理 + 网络消耗
解决:
✅ 使用缓存(相同或相似问题直接返回)
✅ 优化chunk大小(减少上下文token数)
✅ 用更快的Embedding模型
✅ 流式输出(SSE)
问题5:上下文太长(超出模型窗口)
表现:模型截断或丢失信息
原因:Top-K文档加起来太长
解决:
✅ 减小Top-K(从5降到3)
✅ 减小chunk大小
✅ 上下文压缩(去除冗余)
✅ 换更大窗口的模型
7.3 RAG调优路线图
按优先级排序的调优路线:
第一阶段(快速见效,0-1天):
✅ chunk_size调整(256→512→1024对比)
✅ Top-K调整(3→5→10对比)
✅ temperature降到0
✅ 加防幻觉System Prompt
第二阶段(进阶优化,1-3天):
✅ 换更好的Embedding模型(如bge-large-zh)
✅ 加混合检索(向量+BM25)
✅ 加重排序(如bge-reranker)
第三阶段(高级优化,3-7天):
✅ 查询重写
✅ 上下文压缩
✅ 多轮检索
✅ Corrective RAG(检索质量检查)
第四阶段(持续迭代):
✅ 构建测试集
✅ 自动化评估(RAGAS)
✅ A/B测试不同策略
✅ 用户反馈闭环
90%团队忽视的数据摄入层(第一阶段前就应该做好):
✅ 文档清洗(去除PDF乱码/页眉页脚)
✅ 语义分块(非固定长度)
✅ 元数据标注(来源可追溯)
八、2026年RAG全景:GraphRAG、Agentic RAG、融合架构
8.1 GraphRAG:知识图谱+向量检索
传统RAG的问题:
文档分块后 → 块与块之间的"关系"丢失了
"在第3章中提到张三负责项目A"
"在第7章中提到项目A使用了技术B"
→ 两个块之间没有"关系链接"
→ 问"张三用了什么技术?"
→ 单独检索不到这个关系信息
GraphRAG = 知识图谱 + 向量检索
构建过程:
1. 文档分块 → 向量化 → 存入向量DB(传统RAG)
2. 同时提取实体和关系 → 构建知识图谱
提取实体:张三、项目A、技术B
提取关系:张三→负责→项目A
项目A→使用→技术B
3. 检索时:
向量检索 → 找到相关块
图检索 → 找到相关实体和关系
合并 → 提供更完整的上下文
效果:
需要"关系推理"的问题上表现更好
"张三、李四和王五是什么关系?"
→ 图检索直接给出关系路径
→ 传统向量检索很难做到
代价:
构建知识图谱需要额外的计算
需要调用LLM提取实体关系(成本较高)
8.2 Agentic RAG:智能体自主检索
2026年最前沿的RAG范式:
Agentic RAG不是"一个检索流程"
而是"一个能自我决策的检索系统"
核心能力:
Step 1:意图识别
"把发票号INV-2026-001的付款状态发邮件给张三"
→ Agent理解这是一个"查询+发送"任务
→ 需要:查数据库 + 获取邮件地址 + 发送邮件
Step 2:工具选择
Agent决定使用哪些工具:
1. 查询发票数据库(SQL查询)
2. 查找张三的邮件地址(检索通讯录)
3. 发送邮件(调用邮件API)
Step 3:多步执行
Round 1:查询数据库 → 发票状态"已付款"
Round 2:检索通讯录 → zhang@company.com
Round 3:调用邮件API → 发送成功
Step 4:结果综合
"已完成:已查询发票INV-2026-001的付款状态(已付款),
并已将结果发送至zhang@company.com。"
Agentic RAG的代价:
需要更复杂的编排(如LangGraph)
响应时间更长(多步执行)
Agent可能"跑偏"(需要加约束)
8.3 长上下文+RAG融合
2026年的新趋势:
当模型的上下文窗口达到1M token时
还需要RAG吗?
答案是:需要,但用法变了。
长上下文不能解决所有问题:
1M token ≈ 一本厚书
但把整本《三体》放进上下文
→ 模型能够处理,但"注意力被稀释"
→ 问"罗辑的面壁计划" → 模型需要在100万字中找到相关内容
所以RAG + 长上下文结合:
RAG先做"初筛":从1000万字的公司文档中
筛出最相关的2万字的上下文
长上下文再做"精读":在2万字的上下文中
精确定位答案
这叫"分级检索":
第一层:RAG从海量数据快速召回(百万→万级)
第二层:长上下文窗口处理召回结果(万级→答案)
第三层:需要时再深入(多轮追问)
这种融合架构是2026年企业级RAG的趋势方向
8.4 RAG演进全景图
RAG技术演进路线(2020-2026):
2020: Naive RAG
└─ 基础检索+生成
└─ "能用了,但不好用"
2023: Advanced RAG
└─ +查询重写 + 混合检索 + 重排序
└─ "生产可用了"
2024: Corrective RAG / Self-RAG
└─ +检索质量自检 + 生成质量自检
└─ "更可靠了"
2025: GraphRAG
└─ +知识图谱实体关系
└─ "能理解关系了"
2025-2026: Agentic RAG
└─ +Agent自主决策检索策略
└─ "会自己选择了"
2026+: 融合架构
└─ RAG + 长上下文 + Agent + 记忆系统
└─ "按需组合,适应一切场景"
九、实战:构建一个完整的RAG系统
9.1 Step 1:文档处理与索引
import os
from typing import List
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
class DocumentIndexer:
"""文档索引器:加载 → 分块 → 向量化 → 存储"""
def __init__(self, persist_dir: str = "./chroma_db"):
self.persist_dir = persist_dir
# Embedding模型(中文场景首选)
self.embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-large-zh-v1.5",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
)
# 向量数据库
self.vector_store = None
def load_documents(self, docs_dir: str) -> List:
"""加载文档目录中的所有文件"""
# 支持txt、md、pdf等格式
loader = DirectoryLoader(
docs_dir,
glob="**/*.md",
loader_cls=TextLoader,
loader_kwargs={'encoding': 'utf-8'}
)
documents = loader.load()
print(f"加载了 {len(documents)} 个文档")
return documents
def split_documents(self, documents: List) -> List:
"""智能分块"""
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=512, # 每块大小
chunk_overlap=64, # 重叠大小
separators=["\n\n", "\n", "。", "!", "?", ",", " ", ""],
length_function=len,
)
chunks = text_splitter.split_documents(documents)
print(f"分割为 {len(chunks)} 个块")
return chunks
def build_index(self, docs_dir: str):
"""完整索引流程"""
# 1. 加载
docs = self.load_documents(docs_dir)
# 2. 分块
chunks = self.split_documents(docs)
# 3. 向量化并存储
self.vector_store = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory=self.persist_dir
)
self.vector_store.persist()
print(f"索引构建完成!共 {len(chunks)} 个块已存入 {self.persist_dir}")
# 使用
indexer = DocumentIndexer()
indexer.build_index("./company_docs") # 你的文档目录
9.2 Step 2:检索器(混合检索+重排序)
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
class AdvancedRetriever:
"""高级检索器:混合检索 + 重排序"""
def __init__(self, vector_store, docs_chunks):
# 向量检索器
self.vector_retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k": 20} # 先召回20条
)
# BM25关键词检索器
self.bm25_retriever = BM25Retriever.from_documents(
docs_chunks,
k=20
)
# 混合检索器
self.ensemble_retriever = EnsembleRetriever(
retrievers=[self.bm25_retriever, self.vector_retriever],
weights=[0.3, 0.7] # BM25占30%,向量占70%
)
# 重排序模型
self.reranker = HuggingFaceCrossEncoder(
model_name="BAAI/bge-reranker-v2-m3"
)
def retrieve(self, query: str, top_k: int = 5) -> List:
"""检索 + 重排序"""
# 1. 混合检索 → 召回20条
initial_docs = self.ensemble_retriever.invoke(query)
# 2. 重排序 → 选出Top-5
pairs = [[query, doc.page_content] for doc in initial_docs]
scores = self.reranker.predict(pairs)
# 按重排序分数排序
scored_docs = sorted(
zip(initial_docs, scores),
key=lambda x: x[1],
reverse=True
)
# 返回Top-K
return [doc for doc, score in scored_docs[:top_k]]
# 使用
retriever = AdvancedRetriever(vector_store, chunks)
top_docs = retriever.retrieve("公司退货政策是什么")
9.3 Step 3:生成器(带防幻觉System Prompt)
from openai import OpenAI
class RAGGenerator:
"""生成器:基于检索结果生成回答"""
def __init__(self, api_key: str, model: str = "deepseek-chat"):
self.client = OpenAI(
api_key=api_key,
base_url="https://api.deepseek.com" # 或 OpenAI 的 base_url
)
self.model = model
# 防幻觉System Prompt
self.system_prompt = """你是一个基于知识库回答的助手。
核心规则:
1. 只基于"提供的上下文"回答问题
2. 如果上下文没有相关信息,直接说"根据提供的资料,我无法回答这个问题"
3. 绝不编造事实、数据或引用
4. 引用时标注来源文档编号
5. 如果只能部分回答,明确指出哪些有依据、哪些是推断
回答格式:
- 有明确答案:根据[文档X],...
- 部分覆盖:根据资料,我可以回答...,但关于...没有相关信息
- 无法回答:抱歉,资料中没有相关信息。
置信度标注(回答末尾):
{置信度: 高/中/低/无法回答}"""
def generate(self, query: str, context_docs: List) -> str:
"""基于上下文生成回答"""
# 构建带引用的上下文
context = "\n\n".join([
f"[文档{i+1}]: {doc.page_content}"
for i, doc in enumerate(context_docs)
])
# 构造Prompt
user_prompt = f"""请基于以下资料回答问题:
===== 资料 =====
{context}
===== 问题 =====
{query}
===== 回答 ====="""
# 调用LLM(低温度,防幻觉)
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": user_prompt}
],
temperature=0.1, # 低温度
max_tokens=1024,
stream=False
)
answer = response.choices[0].message.content
# 附上来源信息
sources = [f"文档{i+1}" for i in range(len(context_docs))]
return f"{answer}\n\n---\n📚 来源: {', '.join(sources)}"
9.4 Step 4:完整RAG系统
class CompleteRAG:
"""完整的RAG问答系统"""
def __init__(self, api_key: str):
# 索引器
self.indexer = DocumentIndexer()
# 加载已有索引
self.vector_store = Chroma(
persist_directory="./chroma_db",
embedding_function=self.indexer.embeddings
)
# 检索器
all_docs = self.vector_store.get()
# 注意:需要把Chroma文档转回LangChain文档格式
# 此处简化处理
# 生成器
self.generator = RAGGenerator(api_key)
def ask(self, query: str) -> str:
"""完整流程:检索 → 生成"""
# 1. 检索
docs = self.vector_store.similarity_search(query, k=5)
# 2. 检查检索结果
if not docs:
return "抱歉,知识库中没有相关信息。"
# 3. 生成
answer = self.generator.generate(query, docs)
return answer
def ask_with_trace(self, query: str) -> dict:
"""带追踪信息的查询(调试用)"""
docs = self.vector_store.similarity_search(query, k=5)
return {
"query": query,
"retrieved_docs": [
{"content": d.page_content[:100] + "...", "source": d.metadata.get("source", "未知")}
for d in docs
],
"answer": self.generator.generate(query, docs)
}
# 使用
rag = CompleteRAG(api_key="your-api-key")
# 普通查询
print(rag.ask("公司年假政策是什么?"))
# 带追踪的查询
result = rag.ask_with_trace("2026年招聘计划")
print(f"问题: {result['query']}")
print(f"检索来源: {[d['source'] for d in result['retrieved_docs']]}")
print(f"回答: {result['answer']}")
📌 总结
RAG核心要点:
1️⃣ 为什么需要RAG
模型知识截止于训练日期
模型不知道你的私有数据
模型可能编造答案
RAG用"检索替代记忆"
2️⃣ 三代演进
Naive RAG(2020):基础检索+生成
Advanced RAG(2023):+重写+混合+重排序
Agentic RAG(2025-2026):Agent自主决策检索策略
3️⃣ 关键组件
文档清洗 ← 最容易被忽视但最关键
Chunking → 256-512token + 10-20%重叠
Embedding → bge-large-zh(中文首选)
混合检索 → 向量+BM25
重排序 → bge-reranker
4️⃣ 2026年最前沿
GraphRAG:知识图谱+向量检索
Agentic RAG:Agent自动决策
融合架构:RAG+长上下文+Agent+记忆系统
5️⃣ 调优优先级
① 数据清理+分块策略(基础)
② 混合检索+重排序(快速见效)
③ 查询重写+上下文压缩(进一步提升)
④ 构建测试集+自动化评估(持续优化)
🔗 延伸阅读
- 【AI基础篇08】大模型评估指标:困惑度、BLEU、ROUGE
- 【AI基础篇09】大模型幻觉问题:为什么AI会一本正经地胡说八道?
- 【AI基础篇11】大模型部署:从vLLM到ollama(下一篇)
- 【AI基础篇04】Tokenization
觉得有帮助?点赞收藏!基础概念篇10篇完成,下⼀篇我们进入模型架构与应用模块——大模型部署:从vLLM到ollama! 🚀
标签:人工智能、大模型、RAG、检索增强生成、GraphRAG、Agentic RAG、向量检索、知识库
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)