微信扫码
添加专属顾问
我要投稿
告别RAG检索的“找不准”难题,掌握数据分块与查询优化的核心技巧,让AI回答更精准可靠。 核心内容: 1. 智能分块策略:语义分块与句子分块技术详解 2. 父文档检索器:实现精准匹配与完整上下文的双赢方案 3. 文档生成QA对:通过代理问题提升检索召回率的创新方法
from langchain.storage import InMemoryStore
from langchain_core.documents import Document
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
import uuid
docs = [
Document(page_content="RAG-Fusion通过生成多个查询变体并使用RRF算法智能排序来提升检索相关性。", metadata={"doc_id": str(uuid.uuid4())}),
Document(page_content="假设性文档嵌入(HyDE)先让LLM生成一个理想答案,再用该答案的嵌入来检索真实文档。", metadata={"doc_id": str(uuid.uuid4())}),
]
doc_ids = [doc.metadata["doc_id"] for doc in docs]
question_gen_prompt_str = (
"你是一位AI专家。请根据以下文档内容,生成3个用户可能会提出的、高度相关的问题。\n"
"只返回问题列表,每个问题占一行,不要有其他前缀或编号。\n\n"
"文档内容:\n"
"----------\n"
"{content}\n"
"----------\n"
)
question_gen_prompt = ChatPromptTemplate.from_template(question_gen_prompt_str)
question_generator_chain = question_gen_prompt | llm | StrOutputParser()
sub_docs = []
for i, doc in enumerate(docs):
doc_id = doc_ids[i]
generated_questions = question_generator_chain.invoke({"content": doc.page_content}).split("\n")
generated_questions = [q.strip() for q in generated_questions if q.strip()]
for q in generated_questions:
sub_docs.append(Document(page_content=q, metadata={"doc_id": doc_id}))
vectorstore_qa = Chroma.from_documents(documents=sub_docs, embedding=embeddings)
doc_store = InMemoryStore()
doc_store.mset(list(zip(doc_ids, docs)))
multivector_retriever = MultiVectorRetriever(
vectorstore=vectorstore_qa,
docstore=doc_store,
id_key="doc_id",
)
user_query = "RAG-Fusion是怎么工作的?"
retrieved_qa_docs = multivector_retriever.invoke(user_query)
from langchain.retrievers import MultiQueryRetriever# 1. 从LLM和向量数据库创建一个MultiQueryRetriever# 它会自动处理“生成查询 -> 检索 -> 合并去重”的整个流程multiquery_retriever = MultiQueryRetriever.from_llm( retriever=vectorstore.as_retriever(), # 使用我们创建的向量数据库作为基础检索器 llm=llm # 使用我们初始化的LLM来生成子查询)# 2. 使用原始查询进行调用user_query = "如何通过修改问题来改进检索效果?"retrieved_docs = multiquery_retriever.invoke(user_query)# 3. 打印结果print_docs(retrieved_docs, f"查询扩展 (MultiQuery) 对 '{user_query}' 的检索结果")# 深入了解它生成了哪些子查询import logginglogging.basicConfig()logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)retrieved_docs = multiquery_retriever.invoke(user_query)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.documents import Document
import operator
# 1. 定义一个用于生成子查询的链 (Chain)
query_gen_prompt = ChatPromptTemplate.from_messages([
("user", "你是一位AI研究员。请根据以下问题,生成3个不同角度的、语义相似的查询。\n"
"每个查询占一行,不要有其他前缀或编号。\n\n"
"原始问题: {original_question}")
])
generate_queries_chain = query_gen_prompt | llm | StrOutputParser() | (lambda x: x.split("\n"))
# 2. 定义RRF算法函数
def reciprocal_rank_fusion(retrieval_results: list[list[Document]], k=60):
fused_scores = {}
for doc_list in retrieval_results:
for rank, doc in enumerate(doc_list):
doc_id = doc.page_content
if doc_id not in fused_scores:
fused_scores[doc_id] = 0
fused_scores[doc_id] += 1 / (k + rank)
reranked_results = [
next((doc for doc_list in retrieval_results for doc in doc_list if doc.page_content == doc_id), None)
for doc_id, score in sorted(fused_scores.items(), key=operator.itemgetter(1), reverse=True)
]
return [doc for doc in reranked_results if doc is not None]
def rag_fusion_pipeline(original_question: str):
# 生成多个查询
generated_queries = generate_queries_chain.invoke({"original_question": original_question})
all_queries = [original_question] + generated_queries
print(f"生成的查询: {all_queries}")
# 独立检索每个查询
retriever = vectorstore.as_retriever()
retrieval_results = [retriever.invoke(q) for q in all_queries]
# 应用RRF算法对结果进行融合和重排
final_docs = reciprocal_rank_fusion(retrieval_results)
return final_docs
# 4. 调用
user_query = "如何处理用户提问太具体的情况?"
fusion_docs = rag_fusion_pipeline(user_query)
print(fusion_docs, f"RAG-Fusion 对 '{user_query}' 的检索结果")
from langchain_core.runnables import RunnableParallel, RunnablePassthrough# 1. 定义生成“后退一步”问题的Prompt和链step_back_prompt_template = ChatPromptTemplate.from_messages([ ("user", "你是一位善于提炼核心问题的专家。请将以下可能很具体的问题," "抽象成一个更通用、更高层次的“后退一步”的问题。\n\n" "例如:'LangChain的LCEL和Python的asyncio库是如何交互的?' -> 'LangChain LCEL的异步执行机制是怎样的?'\n\n" "原始问题: {original_question}")])step_back_chain = step_back_prompt_template | llm | StrOutputParser()retriever = vectorstore.as_retriever()chain = ( { # 第一个分支:对原始问题进行检索 "original_docs": RunnablePassthrough() | retriever, # 第二个分支:先生成后退问题,再用它进行检索 "step_back_docs": step_back_chain | retriever, } # 将两个分支的结果合并、去重 | (lambda x: remove_duplicates_by_id(x["original_docs"] + x["step_back_docs"])))# 辅助函数去重def remove_duplicates_by_id(documents): seen_ids = set() unique_docs = [] for doc in documents: # 假设 page_content 是唯一标识 if doc.page_content not in seen_ids: unique_docs.append(doc) seen_ids.add(doc.page_content) return unique_docsuser_query = "RAG-Fusion里那个RRF算法的平滑参数k有什么用?"step_back_docs = chain.invoke({"original_question": user_query})
# 示例: 使用 EnsembleRetriever 实现混合搜索from langchain.retrievers import EnsembleRetrieverfrom langchain_community.retrievers import BM25Retrieverfrom langchain.retrievers import EnsembleRetriever# 假设 all_splits 和 vectorstore 已准备好# 1. 初始化关键词检索器 (Sparse Retriever)bm25_retriever = BM25Retriever.from_documents(all_splits)bm25_retriever.k = 3 # 检索3个结果# 2. 初始化向量检索器 (Dense Retriever)vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})# 3. 初始化 EnsembleRetriever,并设置权重# weights 参数决定了最终排序时,两种检索器结果的权重ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, vector_retriever], weights=[0.4, 0.6] # 稍微偏重向量搜索的语义理解能力)# 4. 使用query = "LangChain中的LCEL是什么?"retrieved_docs = ensemble_retriever.invoke(query)print(f"混合搜索召回了 {len(retrieved_docs)} 个文档。")
在本篇文章中,我们探讨了多种用于优化RAG系统的检索机制,包括索引构建的最佳实践、多样的查询转换策略以及混合搜索的实现。这些技术旨在从根本上提升检索的准确性与召回率。
然而,获取初步的文档列表只是整个流程的第一步。这些结果在相关性上可能仍然参差不齐,包含了与问题不直接相关的噪音信息。因此,下一步的关键任务,就是如何对这些初步结果进行有效的后处理与筛选。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-08-28
自适应RAG:用本地 LLM 构建更聪明的检索增强生成系统
2025-08-28
使用RAG构建高质量知识库(四)- 数据检索
2025-08-28
RAG检索后如何应用更有效?
2025-08-28
RAG 不止能检索!它还能在 LangGraph 中当“工具调用大脑”
2025-08-28
RAG进阶神技:让AI自动将“人话”翻译成SQL和Cypher查询!
2025-08-28
如何将 RAG 检索召回率从 50% 提高到 95% 以上
2025-08-28
比RAG提升27.4%,阿里等ComRAG利用“质心式”记忆机制实现实时社区问答
2025-08-27
如何评估RAG系统:给你的AI助手做个"体检"
2025-06-05
2025-06-06
2025-06-05
2025-06-05
2025-06-20
2025-06-20
2025-06-24
2025-07-15
2025-06-24
2025-06-05