RAG优化
AIAI Summary (BLUF)
本文系统梳理了RAG(检索增强生成)技术的16种主流实现方案,从最基础的Naive RAG到先进的Agentic RAG,详细讲解了每种方案的原理、适用场景和优缺点,帮助开发者在实际AI应用中更好地选择和使用RAG技术。
核心洞察
市面上 RAGRetrieval-Augmented Generation - an AI framework that combines information retrieval with language generation to produce more accurate and contextually relevant responses. 科普文不少,大多只讲一两个套路。这篇直接铺了 16 种方案,看完能明显感觉到不同方案之间的取舍关系。我最意外的其实是 Adaptive RAG根据问题复杂度动态选择检索策略:简单问题直接生成,中等单次检索,困难多轮检索+深度推理。,加个路由器按问题复杂度分流,简单粗暴但实用。
核心结论
文章梳理了 16 种 RAG 方案,核心取舍集中在检索质量、延迟与成本之间的平衡,不存在适用所有场景的单一最优方案。
Naive RAG基础的RAG框架,包含索引、检索、生成三个核心步骤,但面临检索精度低、生成幻觉等挑战。 的标准流程是“切块 → 向量化 → 检索 Top 5 → 拼接 Prompt 生成”,主要缺陷在于切块可能破坏语义、检索质量过度依赖 Embedding 模型、搜到无关内容时仍会基于错误材料生成答案。
生产级 RAG 的基础配置通常是“语义分块 + Hybrid Search结合词法检索和语义向量检索,通过分数融合或RRF合并结果,兼顾精确匹配和语义理解。 + Reranking重排序,用更精细模型对检索结果打分,过滤噪声。”;典型的级联精排流程是粗检索 150 条 → 轻量 Reranker 筛到 20 条 → Cross-Encoder 精排取 Top 5。
反思型 RAG 的三种代表方案各有明确分工:CRAG 在检索后增加相关性审查并支持 Web 搜索兜底;Self-RAG在 RAG 流程中设置四个自省检查点(是否需要检索、文档相关、答案有据、答案有用),动态调整策略以减少幻觉。 设置“是否需要检索、文档是否相关、回答是否被支撑、是否对用户有用”四个检查点;Adaptive RAG 用路由器按问题复杂度分流,可降低简单场景的开销。
GraphRAG(Microsoft Research 于 2024 年提出)通过 LLM 抽取实体关系构建知识图谱,并用 Leiden 算法做社区划分和摘要生成,在多跳推理与全局语义理解任务上明显优于传统向量 RAG,但图谱构建成本和查询延迟也显著更高。
什么是 RAG?
AI 大模型有几块硬伤:
- 知识有截止日期
- 会一本正经地胡说八道,也就是幻觉
- 看不到私有知识,内部文档的内容一概不知
比如问 DeepSeek 程序员鱼皮的最新项目是什么,它给我扯了个两年前的项目出来,技术栈全不对。
RAG 解决这个问题的思路很直接:先搜再答。让大模型在回答之前先去搜一遍相关资料,再基于搜到的内容组织答案。
就像考试时偷偷翻书,遇到不会的先翻翻书,再根据书里的内容答题。
还是同样的提问,主动给 AI 一些参考资料,回答就靠谱多了。
思路听上去简单,但工程上 RAG 已经演化出很多种实现方式。从最初的"切块 → 搜索 → 生成",到让 AI Agent 自主决策检索策略,复杂度和能力差距很大。
有朋友会问:现在的大模型都支持百万 token 上下文了,还要 RAG 干嘛?
需要,而且用得比以前更多。
把所有文档都塞进上下文窗口,又贵又不靠谱。上下文越长 token 费用越高,大模型还有 "Lost in the Middle" 的问题,对超长上下文中间部分的注意力明显下降。就像听别人讲话,开头和结尾记得清楚,中间的全忘了。
RAG 和长上下文并不互斥。现在的主流做法是先用 RAG 找到精准资料,再靠长上下文做分析推理,两者互补。
背景交代完了,直接进正题。
主流 RAG 方案
标准 RAG 及变体
Naive RAG
Naive 听起来挺高端,其实就是朴素的意思。Naive RAG 是最基础的实现方案。
假设你有一份 200 页的员工手册,怎么让 AI 基于它回答员工提问?
最粗暴的做法是每次提问都把整本手册塞给大模型。但手册几十万字,又贵又慢,还会触发 "Lost in the Middle" 问题。
更合理的思路是:员工问什么,只把相关的几段内容塞给 AI。
那怎么定位到相关段落?
纯靠关键词匹配很容易翻车。员工问"老板不批假怎么办",文档里写的是"请假审批流程",关键词对不上,搜不到。
这时候需要向量。
向量的意思,就是把一段文字转成一串数字,让计算机能够比较语义相似度。
| 文本 | 向量(简化示意) |
|---|---|
| 我喜欢吃鱼 | [0.21, 0.85, 0.13, ...] |
| 我爱吃海鲜 | [0.23, 0.82, 0.15, ...] |
| 今天天气真好 | [0.88, 0.12, 0.41, ...] |
语义越接近的句子,向量在数学空间里离得越近。
把文字转成向量的模型叫 Embedding 模型。存储这些向量并支持相似度搜索的数据库叫向量数据库,比如 Milvus、Chroma、Qdrant。
理解向量之后,Naive RAG 的做法分两步。
第一步,离线索引:
- 把文档切成小块,每块几百字
- 用 Embedding 模型把每个小块转成向量
- 向量和对应原文一起存入向量数据库
第二步,在线查询:
- 把用户问题转成向量
- 在向量库里搜最相似的几个文档块(比如 Top 5)
- 把这几个块和问题拼成 Prompt,交给大模型生成回答
回到员工手册的例子。把手册切成几百个小块并向量化入库,员工问"年假有多少天?",流程是这样的:
- 系统把问题转成向量
- 在向量库里搜到最相似的 5 个文档块(比如某块写着"入职满一年享有 10 天年假,满三年 15 天…")
- 这 5 个块连同问题一起交给大模型
- 大模型回答:"入职满一年享有 10 天年假"
Naive RAG 的缺点也很明显:
- 切块方式粗暴,可能把完整语义从中间截断
- 检索质量完全依赖 embedding 模型,搜不到就没辙
- 搜到垃圾文档也不管,照样输出错误答案
后面的进阶方法,都是冲着解决这些问题去的。
伪代码,不熟悉编程的可以跳过:
离线索引:
# chunk_size=500 表示每块 500 字
# chunk_overlap=50 表示相邻块重叠 50 字,避免关键信息被切断
chunks = split_into_chunks(documents, chunk_size=500, chunk_overlap=50)
for each chunk in chunks:
vector = embedding_model.encode(chunk)
vector_store.insert(vector, chunk)
在线查询:
query_vector = embedding_model.encode(user_query)
top_k_chunks = vector_store.search(query_vector, k=5)
prompt = "基于以下参考资料回答问题:\n" + join(top_k_chunks) + "\n问题:" + user_query
answer = LLM.generate(prompt)
Multi-Query RAG让大模型将原始问题改写成多种表述,分别检索后合并去重,提升召回覆盖。适合用户表述口语化的场景。
用户提问的方式千奇百怪。同样是想知道报销流程,有人问怎么报销,有人问费用审批流程,还有人问花了钱怎么找公司要回来。
文档里可能只写了"报销申请流程"一个表述。用户的措辞和文档差距一大,向量检索就搜不到。
Multi-Query 的思路:让大模型把原始问题改写成多种不同表述,分别去搜,最后合并结果去重。
代价是每次提问要多调一次 LLM 做改写,再多跑 N 次检索,延迟和成本都上去了。如果改写方向跑偏,还会把无关文档带进来。
这个方案适合面向普通用户的客服、电商场景。用户表述口语化,和文档术语差距大,多花这点成本值得。术语规范的专业领域,收益就很有限了。
代码:
# 让 LLM 把原问题改写成多个表述
queries = LLM.generate("请将以下问题改写成 3 个不同的表述:" + user_query)
# 例如 AI 返回: ["报销流程是什么", "费用审批怎么操作", "如何提交报销申请"]
# 每个表述分别走一次向量检索
all_results = []
for each query in queries:
results = vector_store.search(embed(query), k=5)
all_results.append(results)
# 合并去重
merged_chunks = deduplicate(all_results)
answer = LLM.generate(merged_chunks + user_query)
HyDEA technique that generates hypothetical answers to improve query matching in retrieval systems.
AI 回复效果不好,有时候问题出在问法和文档的语义空间不一致。
用户问"KV Cache 是什么?",就这么几个字。文档里关于 KV Cache 的描述是一大段技术解释。一短一长,在 embedding 空间里离得很远,检索就漏了。
HyDE 的做法:让大模型先凭空写一段答案,不必准确,然后用这段假答案的向量去检索。假答案和真文档的文体更接近,在向量空间里离得也近。
还是那个例子。用户问 KV Cache 是什么,LLM 先编一段:"KV Cache 是一种在 Transformer 推理过程中缓存 Key 和 Value 矩阵的优化技术,可以避免重复计算…"
这段假答案不一定全对,但它的向量和真实文档里关于 KV Cache 的描述非常接近,能精准命中。
风险也有:假答案方向跑偏,检索结果会更差。所以更适合 LLM 对问题领域有基本认知的场景,冷门领域或企业私有术语要慎用。
代码:
# 让 LLM 先凭空生成一段假答案
hypothetical_answer = LLM.generate("请回答:" + user_query)
# 用假答案的向量去检索
hyp_vector = embedding_model.encode(hypothetical_answer)
top_k_chunks = vector_store.search(hyp_vector, k=5)
# 真实文档 + 原始问题交给大模型
answer = LLM.generate(top_k_chunks + user_query)
这三种方法解决的是"能不能搜到"的问题。搜到之后资料质量怎么样,看下面。
提升检索质量
语义分块(Semantic Chunking语义分块,根据句子相似度切断文档,保证语义完整。)
Naive RAG 里最粗暴的一步就是切块。每 500 字切一刀,管你是不是正好切在一句话中间。
比如某块文本是"员工请假需要提前 3 天申请,超过 5 天需要",刚好在这里截断,下一块从"部门经理审批"开始。两块单独看都不完整,检索和 AI 理解都会打折。
chunk_overlap 可以缓解一部分问题,但效果有限。
语义分块的做法:先把文档按句子拆开,计算相邻句子的 embedding 相似度。相似度突然下降说明话题变了,就在这里切一刀,尽量保证语义完整。
代价是每句话都要算一次 embedding,成本和耗时比按字数切分高。相似度阈值也很难调,适合结构松散、话题变化快的文档,比如会议纪要、访谈记录。有清晰章节结构的技术手册直接按标题切就行,更便宜。
代码:
sentences = split_into_sentences(document)
chunks = []
current_chunk = [sentences[0]]
for i from 1 to len(sentences) - 1:
similarity = cosine_similarity(embed(sentences[i-1]), embed(sentences[i]))
if similarity < threshold:
chunks.append(join(current_chunk))
current_chunk = []
current_chunk.append(sentences[i])
层级索引(Parent-Child Retrieval父子检索,用小块检索返回大块上下文。)
切块有个天然矛盾。切得小,检索精度高但上下文不足。切得大,上下文丰富,噪声也跟着多。
Parent-Child Retrieval 的策略是两层都要。先把文档切成大块,再把每个大块细分成小块。检索时用小块匹配,命中后返回所属的大块。相当于在书里搜到某句话,读的时候把整个章节都拿过来。
适合长文档场景,比如技术手册、法律合同、产品文档,这些内容需要连带上下文一起看才能理解。
代码:
# 离线:先切大块,再切小块
for each document:
parent_chunks = split_into_sections(document)
for each parent in parent_chunks:
child_chunks = split_into_paragraphs(parent)
# 只对小块建向量索引,但保留属于哪个大块
for each child in child_chunks:
index.insert(embed(child), child, parent_id=parent.id)
# 在线:小块精确匹配,返回大块
matched_children = index.search(embed(query), k=5)
parent_ids = unique([child.parent_id for child in matched_children])
context = [get_parent_chunk(pid) for pid in parent_ids]
answer = LLM.generate(context + query)
Hybrid Search 混合检索
纯向量检索有个缺点,没法精确匹配术语。
用户问"ERROR_CODE_4012 是什么意思?",向量检索会去找语义相似的内容。但这种编码本身没什么语义,向量搜索可能找到一堆讲错误处理的段落,就是找不到精确提到 4012 的那段。
传统关键词搜索擅长精确匹配,但不理解语义。搜"如何退款"搜不到写着"退货及返还货款流程"的文档,类似于数据库的 like 操作。
Hybrid Search 同时跑两种搜索再合并排序。向量搜索负责语义理解,BM25 负责精确匹配,用 RRF 倒数排序融合算法把两边的结果合并成一个排序。
几乎所有生产环境都建议用 Hybrid Search 替代纯向量搜索,尤其技术文档、医疗、法律这些术语密集的领域。
代码:
semantic_results = vector_store.search(embed(query), k=20)
keyword_results = bm25_index.search(query, k=20)
# RRF 融合:1 / (60 + 排名),分数越高越相关
for each doc in (semantic_results ∪ keyword_results):
score = 0
if doc in semantic_results: score += 1 / (60 + rank_in_semantic)
if doc in keyword_results: score += 1 / (60 + rank_in_keyword)
final_results = sort_by_score(all_docs, top_k=5)
answer = LLM.generate(final_results + query)
Reranking 精排
不管向量检索还是 Hybrid Search,候选文档里总混着看起来相关但实际没用的噪声。
Reranking 在检索和生成之间加一个精排步骤,用 Reranker 模型给每对 (query, doc) 重新打分。Embedding 模型是分别算向量再比较距离,快但粗糙。Reranker 把两者拼在一起送进模型打分,慢但精准。
语料库有十万级以上 chunk 时,一般用级联检索方案分层筛选。粗检索先捞 150 个,避免漏掉关键文档。但 150 个全送进 Cross-Encoder 交叉编码器做精确计算,算力扛不住。中间加一层轻量 Reranker 先筛到 20 个,再做精排取 Top 5。
粗检索负责不遗漏,精排负责不掺假,和推荐系统里的粗排精排一个逻辑。
代码:
# 第一层:粗检索
candidates = hybrid_search(query, k=150)
# 第二层:轻量 Reranker 初筛
semi_final = lightweight_reranker.rank(query, candidates, top_k=20)
# 第三层:Cross-Encoder 精排
scored = []
for each doc in semi_final:
score = cross_encoder.score(query, doc)
scored.append((doc, score))
top_docs = top_k(scored, k=5)
answer = LLM.generate(top_docs + query)
到这儿,语义分块、Hybrid Search、Reranking 这三板斧,就是大多数生产级 RAG 系统的基础配置。
前面的方法都在优化检索。但有个更根本的问题:搜到的全是垃圾的话,大模型照样会一本正经地基于垃圾内容生成答案。
像开卷考试带错了书,还照着抄。
接下来看怎么让 RAG 自我纠错。
RAG 反思机制
Corrective RAG(CRAG)
检索总会出岔子。搜不到或者搜歪了的时候,大模型还硬着头皮拿这些内容回答,就会一本正经地胡说八道。
CRAG 的思路:在检索和生成之间插一个质检员,逐个审查检索到的文档是否和问题相关,再根据审查结果走不同分支。
- 打分高,资料靠谱,直接喂给大模型生成答案
- 打分低,内部知识库没找着相关内容,回退到 Web 搜索兜底
- 打分模糊,两边结果合一起送进去
代码:
docs = retriever.search(query, k=5)
relevant_docs = []
for each doc in docs:
score = LLM.judge("这段内容和问题相关吗?", query, doc)
if score > threshold:
relevant_docs.append(doc)
if len(relevant_docs) > 0:
answer = LLM.generate(relevant_docs + query)
else:
new_query = LLM.rewrite(query)
web_results = web_search(new_query)
answer = LLM.generate(web_results + query)
关键是那个 else 分支。内部知识库搜不到有用信息时,自动回退到 Web 搜索,也可以换成其他策略。
Self-RAG
CRAG 管了检索阶段,生成阶段呢?
大模型拿到了正确的参考资料,回答时照样可能夹带私货,掺入参考资料里根本没有的内容。这就是生成阶段的幻觉。
Self-RAG 在整个流程中设了四个检查点,每一步让模型自我审视:
- 这个问题需要检索吗(Retrieve)?
- 检索到的文档相关吗(IsRel)?
- 回答有文档支撑吗(IsSup)?
- 这个答案对用户有用吗(IsUse)?
代码:
need_retrieval = LLM.judge("这个问题需要外部知识吗?", query)
if not need_retrieval:
return LLM.generate(query)
docs = retriever.search(query, k=5)
relevant_docs = filter(docs, where LLM.judge("和问题相关吗?") == true)
answer = LLM.generate(relevant_docs + query)
is_supported = LLM.judge("答案中的每个论断都能在文档中找到依据吗?", answer, relevant_docs)
if not is_supported:
answer = LLM.regenerate(relevant_docs + query + "请严格基于参考资料回答")
第三个检查点价值最高,对抑制幻觉最管用。
Adaptive RAG
CRAG 和 Self-RAG 通过加流程来解决问题,代价是多好几次 LLM 调用,成本上去了。
用户问"你好"或者"今天星期几",也跑完整检索加质检加生成流程,开着坦克去买菜,纯属浪费。
Adaptive RAG 在最前面加了一个路由器,先判断问题的复杂度,再决定走哪条路线。
代码:
complexity = classifier.predict(query)
if complexity == "simple":
answer = LLM.generate(query)
else if complexity == "moderate":
docs = retriever.search(query)
answer = LLM.generate(docs + query)
else:
answer = run_full_crag_pipeline(query)
分类器可以是一个微调的小模型,也可以用 LLM 的 few-shot 少样本提示实现。核心是让简单问题和复杂问题分开处理。
适合流量混杂的场景,既有"公司地址在哪"这种一句话能答的,也有"对比 A 和 B 两个方案的优缺点"这种需要多文档综合分析的。
上面这些方法处理的都是非结构化文本。数据是关系网络或者表格呢?用下面的方法。
结构化知识增强
GraphRAG
前面所有方法都有一个共同问题:答案必须落在某一个文档块里。
现实里有一类问题,答案散落在多个文档中,需要串起来推理。
假设文档库里有两段话:
- 文档 A:"张三是 AI 部门的负责人"
- 文档 B:"AI 部门属于技术中心"
用户问"张三属于哪个中心?"
传统向量检索大概率只能搜到文档 A。要回答这个问题,必须把 A 和 B 连起来推理:张三 → AI 部门 → 技术中心。
这种跨文档的多跳推理,纯向量搜索很难搞定。
GraphRAG 就是干这个的,Microsoft Research 在 2024 年提出的方法。思路是先把文档变成知识图谱,再基于图谱检索和推理。
具体分三步:
- 用 LLM 逐篇读文档,抽取实体(人、部门、产品等)和关系,构建成图谱
- 用 Leiden 算法对图谱做社区划分,把关联紧密的实体聚成一团,让 LLM 为每个社区生成一段摘要
- 提问时先定位到相关实体,沿着关系拿到子图
根据微软的评测,在全局语义理解类问题上,GraphRAG 答案的全面性和多样性明显好于传统向量 RAG。简单事实查询两者差不多,没必要用。
要注意的是,图谱构建成本比向量索引高得多。用 LLM 逐篇抽实体关系,查询延迟也更大。用之前一定要想清楚值不值。
代码:
# 离线:LLM 从每篇文档抽取实体和关系
for each document:
entities, relations = LLM.extract("请抽取文中的实体和关系", document)
knowledge_graph.add(entities, relations)
# Leiden 社区划分 + 社区摘要
communities = leiden_algorithm(knowledge_graph)
for each community:
summary = LLM.summarize(community.entities, community.relations)
# 在线:定位实体,沿关系遍历 2 跳拿子图
relevant_entities = knowledge_graph.search("张三")
subgraph = knowledge_graph.traverse(relevant_entities, hops=2)
answer = LLM.generate(subgraph + community_summaries + query)
Text-to-SQL RAG
数据本身就是结构化表格时,比如销售数据、用户行为日志、财务报表,传统 RAG 不合适。对表格数据做 embedding 效率很低。
用户问"上个月销售额最高的产品是哪个?",这本质上就是一条 SQL。向量搜索对聚合、排序、筛选这类需求完全没招。
Text-to-SQL 的做法:让 LLM 直接把自然语言翻译成 SQL,执行查询,再把查询结果作为上下文来回答。
适合所有数据分析类需求,BI 看板问答、数据库运维助手、财务报表查询,本质上是用 LLM 替代手写 SQL。
生产环境必须注意:LLM 生成的 SQL 不能直接执行。要有只读权限控制、SQL 语法审计、沙盒隔离,防止 SQL 注入。
代码:
schema = "表 sales: product(产品名), amount(金额), month(月份), region(地区)"
sql = LLM.generate("根据以下表结构,将问题转为 SQL:\n" + schema + "\n问题:" + query)
result = database.execute(sql)
answer = LLM.generate("查询结果:" + result + "\n请用自然语言回答:" + query)
到这儿已经讲了不少方法。前面提到的大多数方案都是预定义好的 pipeline,流程写死了,不管什么问题进来,处理方式都差不多。
现实世界的问题千变万化。有的该搜向量库,有的该查数据库,有的该搜 Web,有的根本不需要检索。
有没有一种方法让系统自己判断该怎么做?
有。答案是 Agentic RAG。
智能体驱动 RAG
Agentic RAG
前面每种方法都有擅长场景。Hybrid Search 擅长术语密集的文档,GraphRAG 擅长多跳推理,Text-to-SQL 擅长结构化数据。
真实系统里这些场景可能同时存在。用户问"张三上个月的考勤记录"要查数据库,问"公司的远程办公政策"要搜文档,问"张三属于哪个部门的哪个中心"要走知识图谱。为每种问题硬编码一条 pipeline,太累。
Agentic RAG 的做法:让一个 AI Agent 自动调度,根据问题自主决定每一步怎么做。给它配备一组检索工具,先搜搜看,结果不够就换方式换关键词再搜,够了就生成回答。
代码实现核心是 Agent Loop 循环:
tools = {
"vector_search": query -> vector_store.search(embed(query)),
"web_search": query -> search_engine.search(query),
"sql_query": query -> database.execute(LLM.to_sql(query)),
"graph_traverse": query -> knowledge_graph.traverse(query),
}
context = []
while true:
thought = LLM.reason("问题:" + query + "\n已知信息:" + context +
"\n我应该使用哪个工具?还是信息已经足够可以回答了?")
if thought.action == "answer":
return LLM.generate(context + query)
result = tools[thought.tool](thought.tool_input)
context.append(result)
以前 Agent 概念刚火的时候,很多人还在吵"自主决策靠不靠谱"。现在 Agentic RAG 已经是主流生产范式了。知名的 AI 编程工具 Cursor 用的就是这种方式,AI 自主决定怎么搜集信息。
Multi-Agent RAG
单个 Agent 处理复杂任务时有个问题:要同时兼顾理解意图、选择策略、验证质量、生成答案,Prompt 又长又复杂,决策质量会下降。就像一个人又当程序员、又当篮球教练、又当说唱歌手,忙不过来。
Multi-Agent RAG 拆成多个专职 Agent,各管一摊。Router Agent 负责分发,各 RAG Agent 负责对应领域的检索推理,Verification Agent 负责质检,Generation Agent 负责润色输出。
适合数据源多、权限复杂、语言多样的企业级知识库。每个环节可以独立优化和扩展。
代码:
intent = router_agent.analyze(query)
if intent == "document_qa":
raw_answer = doc_agent.run(query)
else if intent == "data_analysis":
raw_answer = sql_agent.run(query)
else:
raw_answer = graph_agent.run(query)
verified = verifier_agent.check(query, raw_answer)
if not verified.passed:
raw_answer = verifier_agent.suggest_fix(raw_answer)
final_answer = writer_agent.polish(query, raw_answer)
RAG 能力扩展
多模态 RAG(Multimodal RAG)
传统 RAG 只处理文本。企业文档里还有大量图表、流程图、架构图、产品照片。
纯文本 RAG 处理真实文档,流程图和架构图里的信息全丢。
多模态 RAG 的做法:把图片、表格、文本统一到一个向量空间,检索时跨模态匹配。生成阶段用视觉语言模型处理混合模态的上下文,纯文本 LLM 看不懂图片。
代码:
# 离线:文本和图片统一编码
for each page in document:
text_chunks = extract_text(page)
images = extract_images(page)
tables = extract_tables(page)
for each chunk in text_chunks:
index.insert(text_encoder.encode(chunk), chunk, type="text")
for each image in images:
index.insert(vision_encoder.encode(image), image, type="image")
for each table in tables:
index.insert(table_encoder.encode(table), table, type="table")
# 在线:统一检索,跨模态匹配
results = index.search(text_encoder.encode(query), k=5)
# results 中可能混合了文本块、图片、表格
answer = vision_LLM.generate(results + query)
Speculative RAG
普通 RAG 还有个问题:把所有检索到的文档都塞进同一个 Prompt,推理延迟增加,某个文档是噪声的话,整个生成都会带偏。
Speculative RAG 借鉴了推测性解码的思想,核心目标是降低延迟。把检索到的文档分成多个子集,用多个专家小模型从每个子集并行生成候选草稿,最后用一个更强的大模型做验证,选出最佳答案。
有点像团队做项目,多人并行干活,产品经理只需要做最终验证,总时长大幅缩短,问题也更容易被发现。
代码:
docs = retriever.search(query, k=15)
subsets = split_into_subsets(docs, n=5)
drafts = parallel_run(
for each subset in subsets:
draft = small_LM.generate(subset + query)
return { draft, subset, confidence }
)
best = large_LM.verify_and_select(drafts, query)
return best.answer
方法选择
十几种方案看下来,你可能已经晕了。
我该用哪种啊啊啊啊?
别急,一张表直接对照选:
| 你的情况 | 推荐方案 |
|---|---|
| 标准文本知识库,追求基本可用 | Naive RAG |
| 用户提问风格多变、口语化 | Multi-Query RAG 或 HyDE |
| 生产环境,追求检索质量 | Hybrid Search + Reranking |
| 对准确率要求高,不能容忍幻觉 | Corrective RAG 或 Self-RAG |
| 查询复杂度差异大 | Adaptive RAG 路由 |
| 需要跨文档多跳推理 | GraphRAG |
| 数据以结构化表格为主 | Text-to-SQL RAG |
| 文档包含大量图表/图片 | 多模态 RAG |
| 多数据源、多类型混合 | Agentic RAG / Multi-Agent RAG |
| 延迟敏感 | Speculative RAG |
对初学者,建议从简单开始,逐步完善。先跑通 Naive RAG,发现哪一环出了问题,再针对性地叠加方案。
别一上来就 Multi-Agent 加 GraphRAG 加多模态全家桶,实现成本高,效果也不一定更好。
怎么评估 RAG 系统好不好?
有个叫 RAGAS 的评估框架,四个核心指标:
- 忠实度:回答有没有瞎编
- 答案相关性:答的是不是你问的
- 上下文精确率:搜到的有多少是有用的
- 上下文召回率:该搜到的搜到了吗
先评估再优化,别凭感觉调参数。
RAG 相关的主流技术还有编排框架 LangChain / LangGraph、LlamaIndex,一体化平台 Dify、RAGFlow,向量数据库 Chroma、Milvus、Qdrant。感兴趣可以自己去了解。
常见问题(FAQ)
RAG优化有哪些主流方案?
RAG优化方案众多,从基础的Naive RAG到先进的Agentic RAG,共16种。包括改进检索质量的Multi-Query、HyDE、语义分块,以及反思机制、结构化知识增强等。选择时需根据场景权衡,如Adaptive RAG通过路由器按问题复杂度分流,简单实用。
RAG和长上下文有什么关系?
RAG与长上下文并非互斥,而是互补。长上下文虽支持百万token,但费用高且存在"Lost in the Middle"问题。主流做法是先通过RAG精准检索相关资料,再依靠长上下文进行分析推理,两者结合效果更佳。
Naive RAG的缺点有哪些?
Naive RAG作为基础方案,缺点明显:切块方式粗暴,可能截断语义;检索质量完全依赖Embedding模型,搜不到就无解;即使搜到无关文档也会直接用于生成,容易输出错误答案。后续进阶方案多针对这些问题优化。
版权与免责声明:本文仅用于信息分享与交流,不构成任何形式的法律、投资、医疗或其他专业建议,也不构成对任何结果的承诺或保证。
文中提及的商标、品牌、Logo、产品名称及相关图片/素材,其权利归各自合法权利人所有。本站内容可能基于公开资料整理,亦可能使用 AI 辅助生成或润色;我们尽力确保准确与合规,但不保证完整性、时效性与适用性,请读者自行甄别并以官方信息为准。
若本文内容或素材涉嫌侵权、隐私不当或存在错误,请相关权利人/当事人联系本站,我们将及时核实并采取删除、修正或下架等处理措施。也请勿在评论或联系信息中提交身份证号、手机号、住址等个人敏感信息。



