高级开发指南
本指南介绍RAG(检索增强生成)系统的高级架构和优化技术,帮助开发者构建更智能、更高效的AI应用。
高级RAG架构模式
多步骤RAG
传统的单步骤RAG在复杂查询中可能不够高效,多步骤RAG通过分解查询-检索-生成过程提高性能:
from langchain.chains import create_retrieval_chain
from langchain.chains.query_constructor.base import AttributeInfo
from langchain.retrievers.self_query.base import SelfQueryRetriever
# 1. 查询理解与分解
def decompose_query(query):
decompose_prompt = f"""
将以下复杂问题分解为2-3个简单的子问题,每个子问题应该能独立回答:
问题: {query}
子问题:
"""
response = llm(decompose_prompt)
# 解析响应获取子问题列表
sub_queries = [q.strip() for q in response.split('\n') if q.strip()]
return sub_queries
# 2. 子查询检索
def retrieve_for_subqueries(subqueries):
all_documents = []
for query in subqueries:
docs = retriever.get_relevant_documents(query)
all_documents.extend(docs)
return all_documents
# 3. 信息综合
def synthesize_answer(query, documents):
# 使用所有检索到的文档和原始查询生成最终答案
synthesize_prompt = f"""
基于以下信息回答问题: {query}
信息:
{documents}
请综合以上信息提供完整回答:
"""
return llm(synthesize_prompt)
# 组合成完整流程
def advanced_rag_query(query):
subqueries = decompose_query(query)
documents = retrieve_for_subqueries(subqueries)
answer = synthesize_answer(query, documents)
return answer
迭代式RAG
迭代RAG通过多轮检索和生成过程提高答案质量:
# 迭代式RAG基本流程
def iterative_rag(query, max_iterations=3):
context = []
answer = ""
for i in range(max_iterations):
# 结合当前上下文优化查询
augmented_query = query
if context:
augmented_query = f"""
原始问题: {query}
已知信息: {context}
基于以上信息,我还需要查询什么以完整回答原始问题?
"""
augmented_query = llm(augmented_query)
# 检索新信息
new_docs = retriever.get_relevant_documents(augmented_query)
# 将新信息添加到上下文
new_content = "\n".join([doc.page_content for doc in new_docs])
context.append(new_content)
# 生成回答
answer_prompt = f"""
基于以下信息回答问题: {query}
信息:
{context}
回答:
"""
answer = llm(answer_prompt)
# 检查答案是否足够完整
completeness_check = f"""
问题: {query}
当前答案: {answer}
这个答案是否已经完整地回答了问题?
回复 "完整" 或 "需要更多信息"。
"""
check_result = llm(completeness_check)
if "完整" in check_result:
break
return answer
检索增强重排序
利用LLM对检索结果进行重排序,提高相关性:
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMRerank
# 创建LLM重排序器
reranker = LLMRerank(
llm=llm,
query_key="query",
document_key="context",
top_n=4 # 保留前4个结果
)
# 创建重排序检索器
rerank_retriever = ContextualCompressionRetriever(
base_retriever=vector_retriever,
base_compressor=reranker
)
# 使用示例
query = "什么是向量数据库的量化技术?"
reranked_docs = rerank_retriever.get_relevant_documents(query)
高级检索技术
混合检索策略
结合多种检索方法可以提高相关性和覆盖面:
# 导入必要库
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain.retrievers.multi_query import MultiQueryRetriever
# 创建关键词检索器
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 5 # 每次检索5个文档
# 创建向量检索器
vector_retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 5})
# 多查询生成器
def generate_queries(question):
prompt = f"""
基于以下问题,生成3 个不同角度的相关查询:
{question}
"""
response = llm(prompt)
queries = [q.strip() for q in response.split('\n') if q.strip()]
return queries
# 创建多查询检索器
multi_query_retriever = MultiQueryRetriever(
retriever=vector_retriever,
llm=llm,
query_generator=generate_queries,
parser_key="lines"
)
# 创建集成检索器
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, multi_query_retriever, vector_retriever],
weights=[0.2, 0.4, 0.4] # 各检索器权重
)
# 使用示例
query = "神经网络如何进行反向传播?"
docs = ensemble_retriever.get_relevant_documents(query)
语义压缩检索
减少检索内容冗余,提高效率:
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.retrievers.document_compressors import DocumentCompressorPipeline
from langchain.retrievers.document_compressors import EmbeddingsFilter
from langchain.retrievers import ContextualCompressionRetriever
# 创建文本分割器
splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=30)
# 创建嵌入相似度 过滤器
embeddings_filter = EmbeddingsFilter(
embeddings=embeddings,
similarity_threshold=0.8 # 相似度阈值
)
# 创建LLM提取器
llm_extractor = LLMChainExtractor.from_llm(llm)
# 创建压缩管道
compressor = DocumentCompressorPipeline(
transformers=[splitter, embeddings_filter, llm_extractor]
)
# 创建压缩检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=vector_retriever
)
高级生成技术
结构化输出生成
引导模型生成特定结构的输出:
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
# 定义输出模式
response_schemas = [
ResponseSchema(name="answer", description="对问题的直接回答"),
ResponseSchema(name="sources", description="用于回答的信息来源"),
ResponseSchema(name="confidence", description="对答案准确性的信心程度,从1-10"),
ResponseSchema(name="follow_up", description="可能的后续问题")
]
# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 获取格式说明
format_instructions = output_parser.get_format_instructions()
# 在提示中使用格式说明
prompt_template = """
基于以下上下文信息回答问题。
上下文信息:
{context}
问题: {question}
{format_instructions}
"""
from langchain.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template(prompt_template)
# 创建链
chain = prompt | llm | output_parser
# 运行链
result = chain.invoke({
"context": "...",
"question": "...",
"format_instructions": format_instructions
})
# 结果是一个字典,包含所有定义的字段
print(f"回答: {result['answer']}")
print(f"信心: {result['confidence']}/10")
多步骤推理生成
通过拆解复杂问题提高回答质量:
# 思维链提示模板
cot_template = """
问题: {question}
让我们一步步思考:
1. 首先,我需要理解问题要求什么。
2. 然后,检查我有哪些相关信息。
3. 根据这些信息,分析可能的答案。
4. 检查我的推理是否合理。
5. 得出最终答案。
上下文信息:
{context}
逐步思考:
"""
# 使用思维链提示
cot_prompt = PromptTemplate(
template=cot_template,
input_variables=["question", "context"]
)
# 创建链
cot_chain = LLMChain(llm=llm, prompt=cot_prompt)
# 运行推理
reasoning = cot_chain.run(question="...", context="...")
# 提取最终答案
final_answer_prompt = f"""
基于以下推理过程,总结一个简洁的最终答案:
{reasoning}
最终答案:
"""
final_answer = llm(final_answer_prompt)
性能优化技术
向量数据库优化
优化向量存储的检索性能:
# FAISS IVF-PQ索引配置示例
import faiss
import numpy as np
# 假设我们有嵌入向量集合
embeddings_array = np.array(embeddings_list).astype('float32')
dimension = embeddings_array.shape[1] # 向量维度
num_vectors = embeddings_array.shape[0] # 向量数量
# 创建IVF-PQ索引
nlist = min(4096, int(np.sqrt(num_vectors))) # 聚类中心数量
m = 16 # 子量化器数量 (通常为维度/2或维度/4)
nbits = 8 # 每个子量化器的位数
quantizer = faiss.IndexFlatL2(dimension) # 用于聚类的量化器
index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, nbits)
# 训练索引 (需要有足够的训练数据)
index.train(embeddings_array)
# 添加向量到索引
index.add(embeddings_array)
# 设置搜索参数
index.nprobe = 64 # 搜索时检查的聚类数量
# 保存优化后的索引
faiss.write_index(index, "optimized_index.faiss")
并行处理
利用并行处理提高RAG系统性能:
import asyncio
from concurrent.futures import ThreadPoolExecutor
from functools import partial
# 并行文档处理
async def process_documents_parallel(documents, chunk_size=1000, max_workers=4):
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size)
# 定义单文档处理函数
def process_single_doc(doc):
chunks = text_splitter.split_text(doc.page_content)
return [Document(page_content=chunk, metadata=doc.metadata) for chunk in chunks]
# 创建线程池
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# 并行处理所有文档
tasks = []
for doc in documents:
tasks.append(
asyncio.get_event_loop().run_in_executor(
executor, partial(process_single_doc, doc)
)
)
# 等待所有任务完成
results = await asyncio.gather(*tasks)
# 合并结果
all_chunks = []
for chunks in results:
all_chunks.extend(chunks)
return all_chunks
# 并行嵌入生成
async def generate_embeddings_parallel(texts, batch_size=64, max_workers=4):
# 分批处理
batches = [texts[i:i+batch_size] for i in range(0, len(texts), batch_size)]
# 定义单批处理函数
def process_batch(batch):
return embeddings.embed_documents(batch)
# 并行处理所有批次
with ThreadPoolExecutor(max_workers=max_workers) as executor:
tasks = []
for batch in batches:
tasks.append(
asyncio.get_event_loop().run_in_executor(
executor, partial(process_batch, batch)
)
)
# 等待所有任务完成
results = await asyncio.gather(*tasks)
# 合并结果
all_embeddings = []
for batch_result in results:
all_embeddings.extend(batch_result)
return all_embeddings