Appearance
RAG 优化策略与知识库模块功能解析
章节核心学习内容
- LangChain RAG开发多阶段优化策略:掌握查询转换、路由、问题构造、索引、检索、生成6个阶段的优化思路,近20种优化策略的案例实现与Prompt编写,以及复杂RAG应用从流程图到LCEL链的实现思路。
- LLMOps知识库模块功能解析:学习知识库模块UI功能拆解、API文档撰写、数据库表ER图设计;掌握多知识库/多用户/多应用关联的产品设计思路;实现向量数据库元数据结构设计、weaviate数据库复杂条件筛选及数据隔离与同步。
一、RAG开发6个阶段优化策略分析
01. LLM应用中的RAG开发核心目标与优化原则
RAG优化核心目标
提升LLM生成内容的准确性,针对Transformer架构大模型,实现该目标的核心三步骤:
- 传递更准确的内容:让LLM识别到与提问高度关联的信息,提升生成准确性;
- 让重要的内容更靠前:利用GPT模型注意力机制,Prompt中靠前内容权重更高;
- 尽可能不传递不相关内容:缩短文档块大小,减少无关内容占比,提升信息密度。
关键优化注意点
- 优化策略并非越多越好,策略越多单次响应成本越高、性能越差,需根据场景合理选择;
- RAG优化本质是切割合适的文档块、构造更准确的搜索语句、正确排序文档、剔除重复无关检索内容;
- 核心可优化组件:
query(提问查询)、TextSplitter(文本分割器)、VectorStore(向量数据库)、Retriever(检索器)、Prompt(提示词)。
RAG开发6大阶段划分
将RAG流程按功能模块拆分为查询转换、路由、问题构建、索引、检索、生成6个阶段,每个阶段对应不同优化策略,主流策略包括问题转换、多路召回、混合检索、搜索重排、动态路由、图查询、自检索等,策略间相互影响且适用场景不同。
核心:RAG优化与开发框架/编程语言无关,掌握优化思路是核心。
02. RAG开发6个阶段核心优化策略映射
| 开发阶段 | 核心优化策略 |
|---|---|
| 查询转换(Query Translation) | 多查询重写、问题分解、Step-Back回答回退、HyDE混合策略、集成检索 |
| 路由(Routing) | 动态路由、知识库路由、提示词路由 |
| 问题构建(Query Construction) | 关系型查询构建、自然语言查询生成、查询重构 |
| 索引(Indexing) | 切块优化、多表征索引、领域特定Embedding、增量索引 |
| 检索(Retrieval) | 多路召回、混合检索、搜索重排(RRF)、精修RAG、Corrective-RAG/CRAG |
| 生成(Generation) | 自检索(Self-RAG)、RRR、基于“自我思考”的LLM生成控制、检索质量判定与重新检索 |
二、多查询重写策略提升检索准确性
01. Multi-Query多查询策略核心原理
多查询策略(子查询):从多个角度重写用户原始问题,生成多个相关子问题,分别检索后合并去重返回唯一文档,核心解决基于距离的相似性搜索的局限性,提升检索覆盖面。
运行流程
原始问题 → LLM生成多个子问题 → 每个子问题独立检索向量数据库 → 文档列表合并+去重 → 传递给LLM生成答案
LangChain实现:MultiQueryRetriever
LangChain封装了专用检索器MultiQueryRetriever,支持构造函数/from_llm类方法实例化,核心参数:
retriever:基础检索器(必填);llm:大语言模型,用于生成子问题(必填);prompt:子问题生成提示模板(可选,有默认值);parser_key:解析键(已弃用);include_original:是否保留原始问题检索(默认False)。
代码实现示例(基于Weaviate向量数据库)
python
import weaviate
import dotenv
from langchain.retrievers import MultiQueryRetriever
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_weaviate import WeaviateVectorStore
from weaviate.auth import AuthApiKey
dotenv.load_dotenv()
# 1. 构建向量数据库与基础检索器
db = WeaviateVectorStore(
client=weaviate.connect_to_wcs(
cluster_url="https://eftofnujtxqcsa0sn272jw.c0.us-west3.gcp.weaviate.cloud",
auth_credentials=AuthApiKey("21pzYy0or12dx9xCoZ12beuDJNEbB0")
),
index_name="DatasetDemo",
text_key="text",
embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
)
retriever = db.as_retriever(search_type="mmr")
# 2. 创建多查询检索器
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=retriever,
llm=ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0),
)
# 3. 执行检索
docs = multi_query_retriever.invoke("关于LLMOps应用配置的文档有哪些")
print(docs)
print(len(docs))02. 核心注意事项
内置默认Prompt
默认Prompt用于生成3个子问题,基于OpenAI模型调试,效果最优,核心逻辑:
python
DEFAULT_QUERY_PROMPT = PromptTemplate(
input_variables=["question"],
template="You are an AI language model assistant. Your task is to generate 3 different versions of the given user question to retrieve relevant documents from a vector database. By generating multiple perspectives on the user question, your goal is to help the user overcome some of the limitations of distance-based similarity search. Provide these alternative questions separated by newlines.Original question:{question}"
)中文场景适配
国内模型需将Prompt改为中文,避免子问题生成格式错误,示例:
python
from langchain_core.prompts import ChatPromptTemplate
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=retriever,
llm=ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0),
prompt=ChatPromptTemplate.from_template(
"你是一个AI语言模型助手。你的任务是生成给定用户问题的3个不同版本,以从向量数据库中检索相关文档。通过提供用户问题的多个视角,你的目标是帮助用户克服基于距离的相似性搜索的一些限制。请用换行符分隔这些替代问题。原始问题:{question}"
)
)关键使用技巧
- 模型参数设置:生成子问题时将
temperature=0,减少幻觉,保证生成确定性; - 格式兼容:部分模型生成的子问题可能不按
\n分割,需多次测试Prompt,或设置include_original=True,兜底原始问题检索; - 去重逻辑:底层仅通过循环遍历实现简单去重,无权重计算,核心代码:python
def _unique_documents(documents: Sequence[Document])->List[Document]: return [doc for i,doc in enumerate(documents) if doc not in documents[:i]] - 模型选择:子问题生成对LLM能力要求低,可使用轻量本地模型+定制Prompt,降低成本。
三、RAG多查询结果融合策略
01. 多查询结果融合核心问题与RRF算法
多查询重写的局限性
- 合并文档时未考虑数量控制,极端情况会返回大量冗余文档;
- 无文档权重计算,仅按检索顺序合并,高相关性文档可能被后置。
RAG融合核心思想
在Multi-Query基础上,通过RRF(Reciprocal Rank Fusion,倒排序排名算法) 对多轮检索结果重新排序+去重+TopK筛选,再传递给LLM生成答案,解决权重和数量问题。
RRF算法原理
由滑铁卢大学与Google联合开发,核心公式: [R R F_{score }(d \in D)=\sum_{r \in R} \frac{1}{k+r(d)}]
- 参数说明:D为相关文档全集,k为固定常数(最优值60),r(d)为文档d在某一子查询检索结果中的排名;
- 核心特点:高排名文档权重更高,但低排名文档的重要性不会指数级消失,兼顾检索覆盖面和准确性;
- 计算逻辑:二重遍历,外层遍历文档全集,内层遍历各子查询结果,累计文档在不同结果中的倒序排名得分。
RRF算法Python实现
python
from langchain.load import dumps, loads
from langchain_core.documents import Document
def rrf(results:list[list],k:int=60)->list[tuple]:
"""倒排序排名融合RRF算法,合并多检索结果并排序"""
fused_scores = {}
# 遍历每个子查询的检索结果
for docs in results:
# 遍历文档并计算得分
for rank, doc in enumerate(docs):
doc_str = dumps(doc) # 文档序列化
if doc_str not in fused_scores:
fused_scores[doc_str] = 0
fused_scores[doc_str] += 1 / (rank + k) # 累计RRF得分
# 按得分降序排序并反序列化
reranked_results = [
(loads(doc), score)
for doc, score in sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
]
return reranked_results02. 多查询结果融合策略LangChain实现
LangChain无内置融合检索器,需继承MultiQueryRetriever并重写核心方法,实现RRF排序与合并。
核心重写方法
retrieve_documents:重写为返回二维文档列表(每个子查询对应一个子列表);unique_union:重写为基于RRF算法计算得分、排序、去重并返回TopK文档。
完整代码实现
python
from typing import List
import dotenv
import weaviate
from langchain.load import dumps, loads
from langchain.retrievers import MultiQueryRetriever
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_weaviate import WeaviateVectorStore
from weaviate.auth import AuthApiKey
dotenv.load_dotenv()
class RAGFusionRetriever(MultiQueryRetriever):
"""基于RRF的RAG多查询结果融合检索器"""
k: int = 4 # 返回TopK文档
def __init__(self, k: int=4,** kwargs):
super().__init__(**kwargs)
self.k = k
def retrieve_documents(
self, queries: List[str], run_manager: CallbackManagerForRetrieverRun
)->List[List]:
"""重写检索方法,返回二维文档列表"""
documents = []
for query in queries:
docs = self.retriever.invoke(query, config={"callbacks": run_manager.get_child()})
documents.append(docs)
return documents
def unique_union(self, documents:List[List])->List[Document]:
"""重写合并方法,使用RRF算法排序去重"""
fused_scores = {}
for docs in documents:
for rank, doc in enumerate(docs):
doc_str = dumps(doc)
if doc_str not in fused_scores:
fused_scores[doc_str] = 0
fused_scores[doc_str] += 1 / (rank + 60)
# 排序并取TopK
reranked = sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
return [loads(doc) for doc, _ in reranked[:self.k]]
# 1. 构建基础检索器
db = WeaviateVectorStore(
client=weaviate.connect_to_wcs(
cluster_url="https://eftofnujtxqcsa0sn272jw.c0.us-west3.gcp.weaviate.cloud",
auth_credentials=AuthApiKey("21pzYy0or12dx9xCoZ12beuDJNEbB0")
),
index_name="DatasetDemo",
text_key="text",
embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
)
retriever = db.as_retriever(search_type="mmr")
# 2. 创建融合检索器并执行检索
rag_fusion_retriever = RAGFusionRetriever.from_llm(
retriever=retriever,
llm=ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0),
)
docs = rag_fusion_retriever.invoke("关于LLMOps应用配置的文档有哪些")
print(docs)
print(len(docs))四、问题分解策略提升复杂问题检索正确率
01. 复杂问题检索的难点与分解策略核心
复杂问题检索难点
- 复杂问题由多个步骤/子问题组成,向量数据库存储的基础文档与问题相似度低(文本嵌入模型无法无损记录段落信息);
- 问题复杂度高导致LLM无法一次性生成答案,大量相关文档会压缩LLM上下文长度,影响生成效果。
Decomposition问题分解策略核心
将单个复杂问题分解为多个独立子问题,分别检索并生成答案,再通过迭代式或并行式合并子答案得到最终结果,与多查询重写的核心区别:
- 多查询重写:生成同维度的相似问题,并行检索后直接合并文档;
- 问题分解:生成有逻辑关联的子问题,按逻辑处理子答案后合并。
两种实现方案
- 迭代式回答:深度优先,解决完前一个子问题后,将前问题+答案传递给下一个子问题,迭代至最后得到最终答案;
- 并行式回答:所有子问题同时检索并生成答案,最后由LLM汇总所有子答案,生成最终答案。
02. 迭代式回答实现(LangChain自定义链)
LangChain无内置分解检索器,需自定义链实现问题分解+迭代检索+答案合并。
核心步骤
- 构建问题分解链:将复杂问题拆分为多个子问题;
- 构建迭代问答链:基于子问题检索,结合历史问答对生成子答案;
- 循环迭代:遍历所有子问题,累计历史问答对,最终合并为完整答案。
完整代码实现
python
from operator import itemgetter
import dotenv
import weaviate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_weaviate import WeaviateVectorStore
from weaviate.auth import AuthApiKey
dotenv.load_dotenv()
def format_qa_pair(question: str, answer: str)-> str:
"""格式化问题-答案对"""
return f"Question: {question}\nAnswer:{answer}\n\n".strip()
# 1. 构建问题分解链:将复杂问题拆分为子问题
decomposition_prompt = ChatPromptTemplate.from_template("""
你是一个乐于助人的AI助理,可以针对一个输入问题生成多个相关的子问题,
目标是将输入问题分解成一组可以独立回答的子问题或子任务。
生成与以下问题相关的多个搜索查询:{question}
并使用换行符进行分割,输出3个子问题/子查询:
""")
decomposition_chain = (
{"question": RunnablePassthrough()}
| decomposition_prompt
| ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0)
| StrOutputParser()
| (lambda x: x.strip().split("\n"))
)
# 2. 构建向量数据库与基础检索器
db = WeaviateVectorStore(
client=weaviate.connect_to_wcs(
cluster_url="https://mbakeruerziae6psyex7ng.c0.us-west3.gcp.weaviate.cloud",
auth_credentials=AuthApiKey("zltVa9zs0xUcfafelsggGyyH6tnTYQYJVBx")
),
index_name="DatasetDemo",
text_key="text",
embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
)
retriever = db.as_retriever(search_type="mmr")
# 3. 构建迭代问答链:结合子问题、历史问答对、检索上下文生成答案
prompt = ChatPromptTemplate.from_template("""
这是你需要回答的问题: {question}
这是所有可用的背景问题和答案对: {qa_pairs}
这是与问题相关的额外背景信息: {context}
使用上述背景信息和所有可用的背景问题和答案对来回答这个问题: {question}
""")
chain = (
{
"context": itemgetter("question") | retriever,
"question": itemgetter("question"),
"qa_pairs": itemgetter("qa_pairs"),
}
| prompt
| ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0)
| StrOutputParser()
)
# 4. 执行问题分解与迭代回答
question = "关于LLMOps应用配置的文档有哪些"
sub_questions = decomposition_chain.invoke(question)
qa_pairs = ""
for sub_question in sub_questions:
answer = chain.invoke({"question": sub_question, "qa_pairs": qa_pairs})
qa_pairs += "\n---\n" + format_qa_pair(sub_question, answer)
print(f"问题:{sub_question}")
print(f"答案:{answer}\n")并行式回答课后练习提示
使用Runnable.map实现子问题并行检索与回答,替代循环迭代,核心思路:
- 将子问题列表转为可并行处理的输入;
- 用
map方法让问答链并行处理所有子问题; - 构建答案汇总链,将所有子答案合并为最终答案。
五、Step-Back回答回退策略扩大检索范围
01. 前置知识:LangChain少量示例提示模板(Few-shot)
少量示例(Few-shot)是指导LLM生成的高效方式,通过提供示例问题-答案对,降低Prompt复杂度,明确生成规范,LangChain封装了专用模板:
FewShotChatMessagePromptTemplate:适用于聊天模型;FewShotPromptTemplate:适用于文本补全模型。
使用示例
python
import dotenv
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate
from langchain_openai import ChatOpenAI
dotenv.load_dotenv()
# 1. 定义示例模板与示例
example_prompt = ChatPromptTemplate.from_messages([
("human", "{question}"),
("ai", "{answer}"),
])
examples = [
{"question": "帮我计算下20*15等于多少?", "answer": "300"},
{"question": "帮我计算下2+2等于多少?", "answer": "4"},
{"question": "帮我计算下2+3等于多少?", "answer": "5"},
]
# 2. 构建少量示例提示模板
few_shot_prompt = FewShotChatMessagePromptTemplate(
example_prompt=example_prompt,
examples=examples,
)
# 3. 构建最终Prompt并执行
prompt = ChatPromptTemplate.from_messages([
few_shot_prompt,
("system", "你是一个可以计算复杂数学问题的聊天机器人"),
("human", "{question}"),
])
llm = ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0)
chain = prompt | llm | StrOutputParser()
print(chain.invoke("帮我计算下14*15等于多少")) # 输出:21002. Step-Back回答回退策略核心原理
策略概念
Step-Back(后退提示):为复杂问题生成一个更抽象、更通用的前置回退问题,通过回退问题检索扩大范围,再结合回退问题的检索结果+原始问题执行RAG生成,核心解决复杂问题直接检索相关性低的问题。
核心优势
- 回退问题更易检索到相关文档,提升检索覆盖面;
- 仅多调用一次LLM生成回退问题,性能高于问题分解策略;
- 对LLM能力要求低,轻量模型即可实现,无迭代信息丢失风险。
运行流程
原始问题 → 少量示例Prompt → LLM生成回退问题 → 回退问题检索向量数据库 → 文档列表 + 原始问题 → LLM生成最终答案
03. Step-Back检索器自定义实现(LangChain)
继承LangChain基础检索器BaseRetriever,实现回退问题生成+检索核心逻辑。
完整代码实现
python
from typing import List
import dotenv
import weaviate
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from langchain_core.language_models import BaseLanguageModel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate
from langchain_core.retrievers import BaseRetriever
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_weaviate import WeaviateVectorStore
from weaviate.auth import AuthApiKey
dotenv.load_dotenv()
class StepBackRetriever(BaseRetriever):
"""Step-Back回答回退检索器"""
retriever: BaseRetriever
llm: BaseLanguageModel
def _get_relevant_documents(
self, query: str, *, run_manager: CallbackManagerForRetrieverRun
)->List[Document]:
# 1. 构建少量示例Prompt,定义回退问题生成规则
examples = [
{"input": "慕课网上有关于AI应用开发的课程吗?", "output": "慕课网上有哪些课程?"},
{"input": "小课出生在哪个国家?", "output": "小课的个人经历是怎样的?"},
{"input": "司机可以开快车吗?", "output": "司机可以做什么?"},
]
example_prompt = ChatPromptTemplate.from_messages([
("human", "{input}"),
("ai", "{output}"),
])
few_shot_prompt = FewShotChatMessagePromptTemplate(
examples=examples,
example_prompt=example_prompt,
)
# 2. 构建回退问题生成Prompt
system_prompt = """
你是一个世界知识的专家。你的任务是回退问题,将问题转述为更一般或者前置问题,这样更容易回答,请参考示例来实现。
"""
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
few_shot_prompt,
("human", "{question}"),
])
# 3. 构建回退问题生成+检索链
chain = (
{"question": RunnablePassthrough()}
| prompt
| self.llm
| StrOutputParser()
| self.retriever
)
return chain.invoke(query)
# 1. 构建基础检索器
db = WeaviateVectorStore(
client=weaviate.connect_to_wcs(
cluster_url="https://mbakeruerziae6psyex7ng.c0.us-west3.gcp.weaviate.cloud",
auth_credentials=AuthApiKey("21tPVazs0xucfafelsggGyyH6tnTYQYJVBx")
),
index_name="DatasetDemo",
text_key="text",
embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
)
retriever = db.as_retriever(search_type="mmr")
# 2. 创建回退检索器并执行检索
step_back_retriever = StepBackRetriever(
retriever=retriever,
llm=ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0),
)
documents = step_back_retriever.invoke("人工智能会让世界发生翻天覆地的变化吗?")
print(documents)
print(len(documents))策略对比:Step-Back vs 问题分解
| 对比维度 | Step-Back回答回退 | 问题分解(迭代式) |
|---|---|---|
| 性能 | 高(仅多1次LLM调用) | 低(多次迭代检索+生成) |
| LLM要求 | 低(轻量模型即可) | 高(需准确生成/合并子答案) |
| 信息丢失 | 无(无迭代) | 有(迭代中信息逐步丢失,可能偏离原始问题) |
| 实现复杂度 | 低(自定义检索器即可) | 高(需自定义多条链+迭代逻辑) |
| 适用场景 | 复杂描述性问题 | 多步骤/逻辑关联性强的复杂问题 |
六、集成多种检索器算法实现混合检索
01. EnsembleRetriever集成检索器核心原理
核心优势
LangChain封装的EnsembleRetriever支持将多个不同类型的检索器集成,通过RRF算法对各检索器的结果进行重新排序、合并,充分利用不同检索算法的互补优势,提升检索效果。
经典混合检索组合:稀疏+密集检索
- 稀疏检索(如BM25):擅长关键词匹配,对字面相似的问题检索效果好;
- 密集检索(如向量嵌入相似度):擅长语义匹配,对同义不同形的问题检索效果好;
- 混合检索:结合两者优势,覆盖更多检索场景,是Dify、Coze、智谱等平台的主流检索策略。
核心参数
retrievers:检索器列表(必填);weights:各检索器的权重(可选,默认等权重)。
02. 混合检索实现示例(BM25 + FAISS)
前置依赖
安装BM25检索库:
bash
pip install -U rank_bm25完整代码实现
python
import dotenv
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_core.documents import Document
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
dotenv.load_dotenv()
# 1. 准备测试文档列表
documents = [
Document(page_content="笨笨是一只很喜欢睡觉的猫咪", metadata={"page": 1}),
Document(page_content="我喜欢在晚上听音乐。这让我感到放松。", metadata={"page": 2}),
Document(page_content="猫咪在窗台上打盹,看起来非常可爱.", metadata={"page": 3}),
Document(page_content="学习新技能是每个人都应该追求的目标。", metadata={"page": 4}),
Document(page_content="我最喜欢的食物是意大利面,尤其是番茄酱的那种。", metadata={"page": 5}),
Document(page_content="昨晚我做了一个奇怪的梦,梦见自己在太空飞行.", metadata={"page": 6}),
Document(page_content="我的手机突然关机了,让我有些焦虑。", metadata={"page": 7}),
Document(page_content="阅读是我每天都会做的事情,我觉得很充实。", metadata={"page": 8}),
Document(page_content="他们一起计划了一次周末的野餐,希望天气能好。", metadata={"page": 9}),
Document(page_content="我的狗喜欢追球,看起来非常开心.", metadata={"page": 10}),
]
# 2. 构建BM25稀疏检索器(关键词检索)
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 4 # 每次检索返回4个文档
# 3. 构建FAISS密集检索器(语义检索)
faiss_db = FAISS.from_documents(
documents,
embedding=OpenAIEmbeddings(model="text-embedding-3-small")
)
faiss_retriever = faiss_db.as_retriever(search_kwargs={"k": 4})
# 4. 构建集成检索器(等权重融合BM25+FAISS)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.5, 0.5],
)
# 5. 执行混合检索
docs = ensemble_retriever.invoke("除了猫,你养了什么宠物呢?")
print(docs)
print(len(docs))高级用法:运行时动态配置检索器
通过configurable_fields为检索器添加可配置参数,实现运行时动态调整检索参数(如返回数量k),无需修改代码。
python
from langchain_core.runnables import ConfigurableField
# 为FAISS检索器添加可配置的搜索参数
faiss_retriever = faiss_db.as_retriever(search_kwargs={"k": 4}).configurable_fields(
search_kwargs=ConfigurableField(
id="search_kwargs_faiss",
name="搜索参数",
description="要使用的搜索参数",
)
)
# 重新构建集成检索器
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.5, 0.5],
)
# 动态配置:FAISS检索器仅返回1个文档
config = {"configurable": {"search_kwargs_faiss": {"k": 1}}}
docs = ensemble_retriever.invoke("苹果", config=config)七、查询转换阶段优化策略总结
查询转换是RAG优化的核心阶段,主流6种优化策略各有优劣,需根据业务场景选择,核心对比与适用场景如下:
| 优化策略 | 核心逻辑 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 多查询重写 | 生成多个相似子问题,并行检索后简单去重 | 实现简单、性能高、轻量模型可实现 | 无权重计算、可能冗余/遗漏高相关文档 | 简单问题、需提升检索覆盖面的场景 |
| 多查询融合(RRF) | 多查询重写+RRF算法排序/去重/TopK | 兼顾覆盖面和准确性,高相关文档前置 | 略增性能开销,需自定义实现 | 大多数通用场景,替代纯多查询重写 |
| 问题分解(迭代/并行) | 复杂问题拆分为子问题,分别处理后合并答案 | 解决多步骤/高复杂度问题 | 性能低、易信息丢失、LLM要求高 | 逻辑关联性强的复杂问题(如步骤类、数学类) |
| Step-Back回答回退 | 生成抽象回退问题,扩大检索范围 | 性能高、无信息丢失、轻量模型可实现 | 回退问题生成不佳时检索效果差 | 描述性复杂问题、直接检索相关性低的场景 |
| HyDE混合策略 | 将query转为假设性doc,执行doc-doc对称检索 | 提升语义检索相似度,解决query信息不足问题 | 开放性问题/上下文不足时效果差 | 信息明确的具体问题,语义检索效果不佳的场景 |
| 集成检索(稀疏+密集) | 融合多种检索器(如BM25+FAISS),RRF合并 | 结合不同算法优势,检索效果最优 | 实现稍复杂,需调优各检索器权重 | 生产环境核心场景,对检索准确性要求高的场景 |
核心选型建议
- 通用场景:多查询融合(RRF)/ 集成检索(BM25+FAISS);
- 简单问题:纯多查询重写(追求性能);
- 复杂描述性问题:Step-Back回答回退;
- 复杂逻辑步骤问题:问题分解策略;
- 语义检索效果差:HyDE混合策略 + 集成检索。