本文系统梳理了RAG的优化策略,帮助提升大模型的准确性和响应速度。核心内容涵盖:LLM当前面临的主要挑战、RAG工作流程及优化概览、查询转换等具体策略及其应用实例。
一、背景
目前LLM虽然已经具备了强大的能力,但在某些场景下仍可能给出不准确的答案。常见的问题集中在以下几个方面:
- 信息偏差/幻觉: 模型有时会生成与事实不符的内容,影响用户信任。
- 知识更新滞后: 基于静态数据集训练,无法及时反映最新信息动态。
- 领域专业知识欠缺: 训练数据多来源于公开领域,在特定专业场景下表现不够理想。
对于基于Transformer架构的大模型,提升生成内容准确性通常遵循三个原则:
- 提供更准确的内容: 输入质量越高,模型越能识别关联信息,输出也就越可靠。
- 让重要内容更靠前: GPT模型的注意力机制对prompt靠前的内容赋予更高权重,越往后权重越低。
- 不传递不相关内容: 缩小每个块的大小,确保每个块只包含关联内容,减少噪声比例。
二、RAG流程简介
RAG并不是一个单一模块,而是一套完整的流水线,工作流程大致分为数据预处理、检索、增强和生成四个阶段:

- 数据处理阶段: 对原始数据清洗、转化,生成检索可用的格式并存入数据库。
- 检索阶段: 将用户问题输入检索系统,从数据库中提取相关信息。
- 增强阶段: 对检索到的信息进行调整和丰富,便于生成模型理解和利用。
- 生成阶段: 将增强后的信息输入大模型,生成最终答案。
一个完整的RAG应用开发,涉及文档加载器、向量数据库、检索器、Prompt、记忆、输出解析器、大语言模型等多个模块,整体结构如下:

通常RAG的优化策略主要从六个方面展开:查询转换、路由、问题构建、索引、检索和生成,如下图所示:

三、RAG优化
3.1 查询转换
3.1.1 查询重写和融合策略
直接用原始问题进行检索,可能因为用户表述偏差而找不到相关文档。多查询重写策略的核心思想是:利用LLM对原始问题进行扩展、分解或抽象,生成多个语义相关但视角不同的子查询,从而提高检索系统对用户意图的覆盖能力。这能有效避免单一查询表述不全或偏差的问题。整体流程如下:

一个简易的prompt示例如下:
你的任务是为给定的用户问题生成3 - 5个语义等价但表述差异化的查询变体,目的是帮助用户克服基于距离的相似性搜索的一些局限性,以便从向量数据库中检索相关文档。
以下是原始问题:
{{question}}
请生成3 - 5个语义与原始问题等价,但表述不同的查询变体,用换行符分隔这些替代问题。
请在<查询变体>标签内写下你的答案。
由于需要转换的问题通常比较简单,对LLM的能力要求并不高,因此在实践中往往采用参数较小的本地模型配合针对性优化的prompt,并将temperature设置为0,确保输出更稳定。
调用样例如下:

在多查询重写策略中,每个子问题都会检索出对应的文档片段。如何合并这些文档?这就引出了多查询结果融合策略,核心思想是对检索结果进行重新排序(reranking)后输出Top K个结果,最后喂给LLM生成最终答案。通常采用的算法是RRF(Reciprocal Rank Fusion),即倒数排名融合算法。公式如下:
- D表示检索到的所有相关文档,d则表示一个子文档。
- R表示所有子问题检索出来的文档列表,R_i表示某个子问题检索出来的列表。需要注意,该列表不仅包含子文档,还体现了子文档按相关度的排序结果。
- rank(d, R_i)表示当前文档d在其子集中的位置。
- k是固定常数60,为实验得到的最优值。
该算法对全集D进行二重遍历:外层遍历文档全集,内层遍历文档子集。在内层遍历时,累积当前文档在其所在子集中的位置并取倒数作为权重。也就是说,子文档在每个子问题中排名越靠前,权重越高。RRF的代码实现如下:
def rrf(results: list[list], k: int = 60) -> list[tuple]:
"""倒数排名融合RRF算法,用于将多个结果生成单一、统一的排名"""
# 1. 初始化一个字典,存储每个唯一文档的得分
fused_scores = {}
# 2. 遍历每个查询对应的文档列表
for docs in results:
# 3. 内层遍历每个文档
for rank, doc in enumerate(docs):
# 4. 将文档用langchain的dump工具转成字符串
doc_str = dumps(doc)
# 5. 若该字符串未出现过,初始化为0
if doc_str not in fused_scores:
fused_scores[doc_str] = 0
# 6. 计算得分:排名越靠前,得分越高
fused_scores[doc_str] += 1 / (rank + k)
# 7. 提取并排序
reranked_results = [
(loads(doc), score)
for doc, score in sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
]
return reranked_results
3.1.2 问题分解策略
当原始问题非常复杂时,无论是直接检索还是生成多个关联子查询,都很难在向量数据库中找到高相关度的文档,导致RAG效果不佳。原因主要有两点:
- 复杂问题通常由多个顺序子步骤组成,相似性搜索面对基础文档块时相似度低,但这些文档在现实中可能具有很强关联(文本嵌入模型的限制:一条向量无法无损保留段落信息)。
- 问题复杂度高或涉及数学推理时,LLM难以一次性完成生成;一次性传入大量相关文档也会压缩生成上下文长度。
问题分解策略就是将复杂问题拆解成多个子问题或子步骤。与查询重写不同的是,分解后的子问题与原始问题是“父子”关系,而查询重写则是“兄弟”关系。
问题分解策略分为串行和并行两种模式:
- 串行模式适用于逻辑依赖较强的问题,保证步骤连贯。例如“RAG都有哪些阶段?”,需先找到阶段,再询问各阶段具体做什么。
- 并行模式适用于独立子任务的高效处理,提升响应速度。例如“如何规划北京到上海的5天旅游行程?”,可同时分解为交通、住宿、景点三个子问题。
两种模式的流程如下:


一个简单的问题分解prompt如下:
你的任务是针对输入的问题生成多个相关的子问题或子查询,将输入问题分解成一组可以独立回答的子问题或子任务。
以下是输入的问题:
{{question}}
请生成3 - 5个与该问题相关的搜索查询,并使用换行符进行分割。生成的子问题/子查询应具有明确的主题和可独立回答的特点。
请在<子问题>标签内写下生成的子问题/子查询。
调用样例如下:

3.1.3 问题回退策略
问题回退策略与分解策略相反——当用户问题非常具体时,可能无法匹配到对应文档,就需要将问题抽象化。例如“李开复在2000年是在哪个公司工作?”可抽象为“李开复的工作经历是什么?”。处理流程如下:

下面是一个执行样例:

- 原始问题:如果理想气体的温度增加2倍,体积增加8倍,压力P会如何变化?
- 直接回答:如果温度增加2倍,体积增加8倍,那么压力将减少16倍
- 回溯问题:这个问题背后的物理原理是什么?
- 回溯答案:理想气体定律:PV=nRT,其中P是压力,V是体积,n是物质的量,R是气体常数,T是温度。
- 最终答案:压力减少了4倍
- 原始问题:1954年8月至11月期间,埃斯特拉·利奥波德就读于哪所学校?
- 1948年,威斯康星大学麦迪逊分校,植物学学士;
- 1950年,加州大学伯克利分校,植物学硕士;
- 1955年,耶鲁大学,植物学博士。
- 直接回答:1954年8月至11月期间,埃斯特拉·利奥波德就读于威斯康星大学麦迪逊分校。
- 回溯问题:埃斯特拉·利奥波德的教育经历是怎样的?
- 回溯答案:(如上所列)
- 最终答案:她1955年就读于耶鲁大学植物学博士项目。因此,1954年8月至11月期间,埃斯特拉·利奥波德最可能就读于耶鲁大学。
应用场景
- 复杂推理任务:如STEM问题(需公式应用)、时间敏感问题(需整合时间线)。
- 多跳推理:通过抽象减少中间步骤的逻辑错误。
prompt举例:
你的任务是分析给定的问题,忽略具体细节,提炼出问题背后涉及的核心概念、原理、知识范畴或通用逻辑。
这是需要分析的问题:
{{question}}
分析时,需要提取出问题的本质,将其转化为对某一概念、原理、知识范畴或通用逻辑的探讨。例如,如果问题是“水加热到100℃为什么会沸腾?”,那么分析后的新问题应该是“分析液体沸腾现象的物理原理(如相变、沸点与气压关系、能量传递机制等)”。
请在<回答>标签内写下你的分析结果。
调用样例如下:

3.1.4 HyDE 混合策略
数据库中存储的通常是完整文档,规模远超用户查询。因此query和doc之间属于不对称检索,能找到的相似文档相对有限。
举个例子:“今天回家的路上看到了美丽的风景,非常开心!想学习python该怎么办?”——前面的风景、开心等与真实需求“学习python”无关,会干扰检索。若直接搜索原始请求,很可能得到不相关甚至无法回答的结果。因此,有必要让查询的语义空间与文档的语义空间保持一致。
整体流程如下:

HyDE将检索过程分解为两个阶段:
- 生成假设文档:利用指令遵循的语言模型(如InstructGPT)根据查询生成虚构但具有相关性的假想文档。生成过程通过自然语言指令(如“写一个回答问题的段落”)引导,无需标注数据。
- 对比编码检索:使用无监督对比学习的编码器(如Contriever)将生成的假想文档编码为向量,在语料库中检索最相似的真实文档。编码器的密集瓶颈可过滤假想文档中的错误细节,使生成内容与实际语料对齐。
关键优势
- 零样本能力:无需相关性标签或微调,直接利用预训练语言模型和对比编码器。
- 跨任务与语言泛化:在Web搜索、问答、事实核查等任务以及斯瓦希里语、韩语、日语等多语言场景中均表现优异,超越无监督基线Contriever,接近有监督微调模型。

prompt参考:
你的任务是实现HyDE零样本检索策略,根据用户输入的查询生成假设文档。生成的内容要反映相关性模式,同时允许存在虚构细节。
以下是用户输入的查询:
<查询>
{{QUERY}}
查询>
在生成假设文档时,请遵循以下要点:
1. 仔细理解查询的核心内容和意图。
2. 围绕查询构建文档,让文档与查询具有明显的相关性。
3. 可以适当添加一些虚构的细节,但不能偏离查询的主题。
4. 输出的文档应具有一定的逻辑性和连贯性。
请在<生成文档>标签内写下你生成的假设文档。
<生成文档>
[在此生成假设文档]
生成文档>
调用样例如下:

局限性:对于doc-doc类型的检索,虽然语义空间保持一致,但在query→doc的过程中,受限于各种因素仍可能产生错误信息。
例如提问“Bel是什么?”,未执行HyDE时直接查询结果如下:
Bel 是由 Paul Graham 在四年的时间里(2015年3月26日至2019年10月12日),用 Arc 语言编写的一种编程语言。它基于 John McCarthy 最初的 Lisp,但添加了额外的功能。它是一个以代码形式表达的规范,旨在成为计算的形式化模型,是图灵机的一种替代方案。
但执行HyDE后生成的假想文档如下:
Bel 是 Paul Graham 的化名,他是这段信息背后的作者,当时需要种子资金以维持生活,并且参与了一项交易,后来成为 Y Combinator 模式的典范。
在这个例子中,HyDE在没有文档上下文的情况下错误地解释了“Bel”,导致完全检索不到相关文档。
3.1.5 混合检索策略
在查询检索中,常见的有两种方式:稀疏检索器和密集检索器:
- 稀疏检索器:基于关键词匹配,利用词频(TF)和逆文档频率(IDF)计算文档与查询的相关性。
- 优点:高效、无需训练,对明确关键词匹配效果好;
- 缺点:无法捕捉语义(如同义词、上下文相关性)。
- 密集检索器:使用深度学习模型生成密集向量,通过向量相似度(如余弦相似度)衡量相关性。
- 优点:捕捉语义信息,解决词汇不匹配问题;
- 缺点:需大量训练数据、计算成本高,对生僻词敏感。
混合检索策略将多种检索方式结合,利用不同算法的优势,获得比单一算法更好的性能,这是目前常用的检索策略。流程如下:

- WRRF是RRF的加权版本,通过赋予不同检索器权重,影响文档排序。
在Langchain中,代码实现样例如下:
doc_list = [
"我喜欢苹果",
"我喜欢橙子",
"苹果和橙子是水果",
]
# 初始化 BM25 检索器和 FAISS 检索器
bm25_retriever = BM25Retriever.from_texts(doc_list)
bm25_retriever.k = 2
embedding = OpenAIEmbeddings()
faiss_vectorstore = FAISS.from_texts(doc_list, embedding)
faiss_retriever = faiss_vectorstore.as_retriever(search_kwargs={"k": 2})
# 初始化集成检索器
ensemble_retriever = EnsembleRetriever(retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5])
docs = ensemble_retriever.get_relevant_documents("苹果")
[Document(page_content='我喜欢苹果', metadata={}), Document(page_content='苹果和橙子是水果', metadata={})]
3.2 路由
3.2.1 数据源路由
在RAG开发中,若想根据不同问题检索不同的向量数据库,只需设定对应的prompt,让LLM根据问题返回需要选择的数据库名称,再据此选择不同的检索器即可。整体流程如下:

路由数据源的prompt样例如下:
你是一位擅长将用户问题路由到适当数据源的专家。你的任务是根据问题涉及的编程语言,将问题路由到相关的数据源。
首先,请仔细阅读以下数据源信息:
{{DATA_SOURCES}}
现在,请仔细阅读以下用户问题:
{{QUESTION}}
为了将问题路由到合适的数据源,请按照以下步骤操作:
1. 仔细分析问题,识别其中涉及的编程语言。
2. 查看数据源信息,找出与该编程语言相关的数据源。
3. 如果问题涉及多种编程语言,找出与所有涉及语言都相关或与主要语言相关的数据源。
4. 如果没有合适的数据源,指出“没有合适的数据源”。
请在<回答>标签内写下路由结果。
<回答>
[在此输出路由结果]
回答>
调用样例如下:

3.2.2 prompt路由
在RAG开发中,针对不同场景的问题使用定制化的prompt模板,效果通常比通用模板更好。例如,在教培场景中制作一个物理授课机器人,如果使用通用模板,会导致prompt编写变得非常复杂;若写得过于简单,又可能无法起到良好的回复效果。
如果能根据用户提问的内容——比如数学问题用数学模板、物理问题用物理模板——针对性选择模板,LLM生成的内容会比通用模板更好。下面有两个示例模板:
物理老师:
你将扮演一位非常聪明的物理教授,以简洁易懂的方式回答物理问题。当你不知道问题的答案时,要坦率承认自己不知道。
以下是需要你回答的物理问题:
{{query}}
在回答问题时,请遵循以下指南:
1. 确保回答简洁易懂。
2. 如果不知道问题的答案,直接表明“我不知道这个问题的答案”。
请在<回答>标签内写下你的答案。
数学老师:
你将扮演一位非常优秀的数学家,专门负责回答数学问题。你需要将复杂的问题分解成多个小步骤,回答这些小步骤,然后将它们整合起来回答更广泛的问题。
这是需要你解答的数学问题:
<问题>
{{query}}
问题>
在解答问题时,请按照以下步骤进行:
1. 仔细阅读问题,理解问题的核心。
2. 将问题分解成多个小步骤。
3. 依次解答每个小步骤。
4. 最后将小步骤的解答整合起来,给出完整的答案。
请在<回答>标签内写下你的答案,确保答案清晰、全面且包含每一个关键步骤。
基于文本向量模型,可以根据查询问题的语义,查找相似度最高的prompt模板。语义prompt路由的流程如下:

3.3 问题构建
3.3.1 自查询
检索外部数据时,通常使用的是固定筛选条件(即无附加过滤的相似性搜索)。但用户的原始提问中可能隐含着筛选条件,例如:“请帮我整理下关于2023年全年关于AI的新闻汇总。”
这个提问中隐含了筛选条件year=2023,但在普通的相似性搜索中不会考虑该条件(因为没有添加元数据过滤器,2022年和2023年的数据在高维空间其实很接近),极有可能将其他年份的数据也检索出来。
那么,有没有一种策略,能根据用户传递的原始问题自动构建相应的元数据过滤器?这样在搜索时带上过滤器,不仅能压缩检索范围,还能提升准确性。这个思想就是查询构建,或者称为自查询。
除了向量数据库,类比映射到关系型数据库、图数据库也有同样的操作技巧:
- 关系型数据库自查询:用LLM将自然语言转换成SQL过滤语句。
- 图数据库自查询:用LLM将自然语言转换成图查询语句。
- 向量数据库:用LLM将自然语言转换成元数据过滤器/向量检索器。
在Langchain中,封装了自查询检索器(SelfQueryRetriever),执行流程如下:
将对应prompt翻译后如下所示:
你的任务是根据提供的信息,生成一个符合特定结构的JSON对象。该JSON对象将用于查询和过滤文档。
以下是允许使用的比较器和逻辑运算符:
{{ALLOWED_COMPARATORS}}
{{ALLOWED_OPERATORS}}
现在,请根据以下信息构建JSON对象:
<< Data Source >>
```json
{{{{
"content": "{content}",
"attributes": {attributes}
}}}}
```
在构建JSON对象时,请遵循以下规则:
1. 查询字符串应仅包含预期与文档内容匹配的文本。过滤条件中的任何条件不应在查询中提及。
2. 逻辑条件语句由一个或多个比较和逻辑操作语句组成。
- 比较语句的形式为:`comp(attr, val)`,其中`comp`为允许的比较器,`attr`为要应用比较的属性名称,`val`为比较值。
- 逻辑操作语句的形式为:`op(statement1, statement2, ...)`,其中`op`为允许的逻辑运算符,`statement1`, `statement2`, ... 为比较语句或逻辑操作语句。
3. 仅使用上述列出的比较器和逻辑运算符,不使用其他运算符。
4. 过滤条件仅引用数据源中存在的属性。
5. 过滤条件仅使用应用了函数的属性名称及其函数名。
6. 处理日期数据类型的值时,过滤条件仅使用`YYYY - MM - DD`格式。
7. 过滤条件仅在需要时使用。如果没有要应用的过滤条件,`filter`的值应返回 "NO_FILTER"。
8. `limit`必须始终为整数类型的值。如果该参数没有意义,请留空。
请在<回答>标签内输出符合以下格式的JSON对象:
```json
{
"query": "文本字符串,用于与文档内容进行比较",
"filter": "用于过滤文档的逻辑条件语句",
"limit": 要检索的文档数量
}
```
<<样例>>
Data Source:
```json
{{{{
"content": "Lyrics of a song",
"attributes": {{
"artist": {{
"type": "string",
"description": "Name of the song artist"
}},
"length": {{
"type": "integer",
"description": "Length of the song in seconds"
}},
"genre": {{
"type": "string",
"description": "The song genre, one of "pop", "rock" or "rap""
}}
}}
}}}}
```
User Query:
What are songs by Taylor Swift or Katy Perry about teenage romance under 3 minutes long in the dance pop genre
Structured Request:
```json
{{{{
"query": "teenager love",
"filter": "and(or(eq("artist", "Taylor Swift"), eq("artist", "Katy Perry")), lt("length", 180), eq("genre", "pop"))"
}}}}
3.4 索引
3.4.1 多表征索引
通常我们为一个文档生成一个向量并存入向量数据库。如果能从多个维度记录该文档块的信息,会大大增加其被检索到的概率。多个维度记录信息,相当于为文档块生成多个向量。常见的维度包括:
- 把文档切割成更小的块:将文档块继续拆分成更小的块,通过检索小块定位父文档。
- 存储摘要信息:用LLM生成文档摘要,与原文档一起存入数据库,返回时只返回原文档。
- 假设性问题:用LLM为每个文档块生成适合回答的假设性问题,与原文档一起嵌入或替代,返回时返回原文档。
整体流程如下:
3.4.2 分层索引
传统RAG中,我们通常依赖检索连续的短文本块。但当面对长上下文时,不能简单地将文档分块嵌入或者用上下文填充所有文档。需要找到一种最优的最小化分块方法,这正是RAPTOR的用武之地。RAPTOR均衡了多文档、超长上下文、高准确性、超低成本等特性。
RAPTOR是一种用树状组织检索的递归抽象处理技术,采用自下而上的方法,通过对文本片段进行聚类和归纳形成分层结构。
构建过程如下图所示:
- 对原始文本分块,拆分成合适的大小;
- 对文档块进行嵌入/向量化,目前处于高维空间,并将数据存储到向量数据库;
- 对高维向量降维(例如降到2维或3维),降低运算成本;
- 对降维向量进行聚类,找出同一文档组;
- 合并文档组的文本,用LLM对该合并文本进行摘要汇总,得到新的文本,重复步骤2-5;
- 直到只剩一个文档且长度符合要求,结束流程。
检索策略分为两种:树遍历检索和折叠树检索。
- 树遍历检索流程如下:
- 从根节点开始,计算问题与节点的余弦相似度;
- 选择最相关的前k个节点;
- 将选中节点的子节点放入候选集,重复步骤1-3。
- 折叠树检索流程如下图所示:
- 将所有节点都存入向量数据库,折叠为一层;
- 对原问题检索,选择最相关的前k个节点。
3.4.3 切块优化
3.4.3.1 递归字符分割器
字符分割器根据指定分隔符将文档切分成多个块,通常支持控制块大小以免超出模型上下文限制,同时可控制块与块之间的重叠大小,以保留上下文信息。
但划分过程中可能出现块过大或过小的情况,导致RAG不可控:
- 文档块可能会变得非常大:如果两个分隔符间隔很大,块大小可能超过限制值,极端情况下长度超过LLM上下文限制,该文本块永远不会被引用,相当于数据存储了但丢失了。
- 文档块可能远小于窗口大小:若两个分隔符间隔很小,信息密度太低,即使填充到prompt中,LLM也无法提取有用信息。
递归字符分割器对大块使用更多分隔符使其变小,对小块进行合并以保留更多信息,整体流程如下:
3.4.3.2 语义文档分割器
文档分割器通常使用特定字符拆分文本,虽然考虑了上下文切断问题,但没有考虑句子之间的语义相似性。当需要将长文本分割成语义相关的块以便理解和处理时,语义文档分割器便派上用场。整体流程如下:
3.4.3.3 文档转换器
除了切割,对于结构化数据可直接使用对应的文档转换器,如HTML文档转换器、代码文档转换器。此外还有两种特殊转换器:
- 问答转换器:用LLM提取文档信息并生成问答对,如
{'question': '产品发布活动的日期是什么时候?', 'answer': '7月15日'}。 - 文档翻译器:将文档转换成其他形式,如将英文论文翻译成中文。
3.5 检索
3.5.1 ReRank 重排序
在完成查询改写、路由、索引等优化后,可以进一步优化筛选阶段,主要包括重排序和纠正性RAG两种策略。重排序使用频率最高、性价比最高,通常与混合检索搭配使用,是目前主流的优化策略。
重排序的核心思想顾名思义——对检索到的文档调整顺序。此外,重排序通常还会剔除无关或多余数据,其中RRF就是最基础的一种重排序方法。
3.5.2 CRAG
纠正性检索增强生成(Corrective Retrieval-Augmented Generation,CRAG)是一种旨在提高RAG鲁棒性和准确性的先进技术。CRAG中引入了一个轻量级的检索评估器,用于评估检索文档的质量,并根据评估结果触发不同的知识检索动作,确保生成结果的准确性。整体流程如下图所示:
- 检索文档:基于用户查询执行检索。
- 评估检索质量:CRAG使用轻量级评估器对每个文档进行质量评估,计算置信度分数。
- 触发知识检索动作:根据置信度分数触发以下两个动作之一:
- 正确:若文档高度相关,则采用并进行知识精炼。
- 错误:若文档不相关或误导,则重写新问题,然后利用网络搜索寻找更多知识来源。
- 知识精炼:对评估为正确的文档进行精炼,抽取关键信息并过滤无关内容。
- 问题重写:生成一个相似但优化的问题,改进答案检索。
- 网络搜索:必要时执行网络搜索获取更多高质量知识,纠正或补充检索结果。
- 生成文本:将优化后的知识传递给LLM,生成最终答案。
评估节点prompt:
你是一名评分员,负责评估检索到的文档与用户问题的相关性。你的任务是根据给定的标准,判断文档是否与问题相关,并给出“yes”或“no”的二元评分。
以下是用户的问题:
{{QUESTION}}
以下是检索到的文档:
{{DOCUMENT}}
判断文档是否相关的标准为:如果文档包含与问题相关的关键词或语义含义,则判定为相关。
首先,在<思考>标签中详细分析文档是否包含与问题相关的关键词或语义含义,说明你的分析过程。然后在<回答>标签中给出最终的二元评分(“yes”或“no”)。
<思考>
[在此详细说明你对文档与问题相关性的分析过程]
思考>
<回答>
[在此给出“yes”或“no”的评分]
回答>
问题重写prompt:
你是一个问题改写器,任务是将输入的问题转换为一个更适合网络搜索的优化版本。你需要仔细分析输入问题,挖掘其潜在的语义意图和含义。
以下是需要改写的问题:
{{QUESTION}}
在改写问题时,请遵循以下方法:
1. 去除不必要的修饰词和语气词,使问题简洁明了。
2. 提取问题的核心内容,突出关键信息。
3. 调整语序,使问题更符合网络搜索的习惯。
请在<改写后的问题>标签内写下改写后的问题。
知识精炼prompt:
你是一位信息精炼专家,负责从给定文档中提取与特定主题直接相关的关键事实、数据、观点和结论,过滤掉不相关的背景信息、示例和解释。
请仔细阅读以下文档:
{{DOCUMENT}}
需要围绕的主题是:
{{TOPIC_NAME}}
在精炼信息时,请遵循以下要求:
1. 仅提取与主题直接相关的关键事实、数据、观点和结论。
2. 过滤掉所有不相关的背景信息、示例和解释。
3. 输出尽量保持简洁。
请在<回答>标签内写下精炼后的信息。
RAG-prompt:
你是一个负责回答问题的助手。你的任务是利用提供的检索到的上下文来回答问题。如果不知道答案,就直接表明不知道。回答最多使用三句话,保持简洁。
以下是检索到的上下文:
{{RETRIEVED_CONTEXT}}
这是问题:
{{QUESTION}}
请在<回答>标签内写下你的答案。
<回答>
[在此给出答案]
回答>
3.6 生成
3.6.1 self-RAG
Self-RAG(自我反思RAG)顾名思义,即对原始查询、检索内容、生成内容进行自我反思,根据反思结果执行不同操作:直接输出、重新检索、剔除不相关内容、检测是否存在幻觉、检测是否有帮助等。可以把Self-RAG看作一个拥有自我反思能力的智能体,专门依据知识库回复用户问题,不断迭代直到输出满意结果。SELF-RAG训练了一个任意的LLM,使其能在任务输入时反思自身生成过程,同时输出任务结果和临时的反思标记(检索标记和评论标记),分别表示是否需要检索以及生成质量。流程如下图所示:
一个Self-RAG应用主要由三个步骤组成:
- 按需检索(Retrieval as Needed):通过生成检索标记,评估是否需要从文本中获取信息。若需要,则用检索器获取相关段落;若不需要(例如“写一篇关于Python依赖注入的文章”),则直接生成答案。
- 并行生成(Parallel Generation):模型同时使用prompt和检索内容生成输出,过程中触发多种反思:评估文档是否关联、生成内容是否有幻觉、是否能回答问题。
- 若不关联则重新检索;
- 若存在幻觉或支持不足则重新生成;
- 评估与选择:对步骤2生成的内容进行评估,选择最佳文档段落作为输出。
判断是否有幻觉prompt:
你是一名评分员,负责评估大语言模型(LLM)的生成内容是否有一组检索到的事实作为依据。你的任务是根据给定的事实集,判断生成内容是否能得到事实的支持,并给出“是”或“否”的二元评分。“是”表示答案有事实依据,“否”则表示没有。
首先,请仔细阅读以下检索到的事实集:
<检索到的事实集>
{{RETRIEVED_FACTS}}
检索到的事实集>
现在,请仔细阅读以下大语言模型的生成内容:
<大语言模型生成内容>
{{LLM_GENERATION}}
大语言模型生成内容>
评估这份生成内容时,请考虑生成内容中的所有陈述是否都能在检索到的事实集中找到支持。
在<思考>标签中详细分析你的判断依据,然后在<判断>标签中给出“是”或“否”的判断。例如:
<思考>
[在此详细说明你做出判断的依据]
思考>
<判断>
[在此给出“是”或“否”的判断]
判断>
请现在开始你的评估。
答案评估prompt:
你的任务是评估一个答案是否解决了相应的问题,并给出“yes”或“no”的二元评分。“yes”表示答案解决了问题,“no”表示答案未解决问题。
以下是问题:
{{QUESTION}}
以下是答案:
{{ANSWER}}
在评估时,请仔细对比答案内容与问题,判断答案是否直接回应并解决了问题。
请在<判断>标签内给出你的最终判断,使用“yes”或“no”。
<判断>
[在此给出“yes”或“no”的判断]
判断>
