04 RAG高级技术与调优
摘要
本笔记深入探讨了RAG(检索增强生成)系统的高级技术与调优策略,涵盖知识库处理(问题生成、对话沉淀、健康度检查、版本管理)、高效召回(多查询、混合检索、重排序、双向改写、Small-to-Big策略)以及GraphRAG的原理与应用,旨在帮助构建更鲁棒、精准的RAG系统。
RAG基础与调优维度
RAG系统由三个核心步骤组成:
- Indexing (索引): 如何更好地将知识存储起来。
- Retrieval (检索): 如何从大量知识中找到一小部分有用的信息供模型参考。
- Generation (生成): 如何结合用户提问和检索到的知识,让模型生成有用的答案。
RAG的调优可以从以下四个主要维度进行:
- 坚实基础:知识库处理 (Knowledge Base Processing)
- 精准雷达:高效召回 (Efficient Retrieval)
- 全局视野:GraphRAG
- 智能决策:Agentic RAG (在提供的资料中,此部分仅有标题,无详细内容展开)
坚实地基:知识库处理
场景1:知识库问题生成与检索优化
核心概念: 当用户提问与知识切片相似度不高时,通过AI为每个知识切片生成可能的问题,从而通过问题与问题的匹配来提高检索准确度。这构建了双重检索索引(原文内容和生成的问题)。
核心功能:
-
自动生成多样化问题: 为每个知识切片生成不同类型、难度和角度的问题。
-
generate_questions_for_chunk(): 生成基础问题。 -
generate_diverse_questions(): 生成更丰富多样化的问题(如8个)。
-
-
构建双重检索索引: 同时构建基于原文内容和生成问题的BM25检索索引。
-
检索评估: 针对两种检索方式进行评估,对比准确率。
代码示例:
generate_questions_for_chunk 的 instruction 示例:
instruction = """
你是一个专业的问答系统专家。给定的知识内容能回答哪些多样化的问题,这些问题可以:
1. 使用不同的问法(直接问、间接问、对比问等)
2. 避免重复和相似的问题
3. 确保问题不超出知识内容范围
请返回JSON格式:
{
"questions": [
{
"question": "问题内容",
"question_type": "问题类型(直接问/间接问/对比问/条件问等)",
"difficulty": "难度等级(简单/中等/困难)"
}
]
}
"""
# ... (调用LLM)
检索评估结果示例:
- BM25原文检索准确率: 66.7%
- BM25问题检索准确率: 100.0%
问题检索方法可以显著提高某些查询的准确率。
场景2:对话知识沉淀
核心概念: 从产品上线后产生的用户对话中提取和沉淀有价值的结构化知识,持续丰富知识库。
核心功能:
- 使用AI模型(通义千问)从对话中提取结构化知识: 支持事实、问题、流程、注意事项等多种知识类型。
- 自动识别用户意图和对话摘要。
- 合并相似知识点: 使用LLM对提取出的知识点进行智能合并。
核心函数:
extract_knowledge_from_conversation(): 从单次对话中提取知识。batch_extract_knowledge(): 批量提取知识。merge_similar_knowledge(): 使用LLM合并相似知识点。
代码示例:
extract_knowledge_from_conversation 的 instruction 示例:
instruction = """
你是一个专业的知识提取专家。请从给定的对话中提取有价值的知识点,包括:
1. 事实性信息(地点、时间、价格、规则等)
2. 用户需求和偏好
3. 常见问题和解答
4. 操作流程和步骤
5. 注意事项和提醒
请返回JSON格式:
{
"extracted_knowledge": [
{
"knowledge_type": "知识类型(事实/需求/问题/流程/注意)",
"content": "知识内容",
"confidence": "置信度(0-1)",
"source": "来源(用户/AI/对话)",
"keywords": ["关键词1", "关键词2"],
"category": "分类"
}
],
"conversation_summary": "对话摘要",
"user_intent": "用户意图"
}
"""
# ... (调用LLM)
知识合并流程示例:
LLM合并提示词要求保留所有重要信息、消除重复、提高准确性和完整性,并返回JSON格式的合并结果。
prompt = f"""
你是一个专业的知识整理专家。请将以下{knowledge_type}类
型的知识点进行智能合并,生成一个更完整、准确的知识点。
### 合并要求:
1. 保留所有重要信息,避免信息丢失
2. 消除重复内容,整合相似表述
3. 提高内容的准确性和完整性
4. 保持逻辑清晰,结构合理
5. 合并后的置信度取所有知识点中的最高值
### 待合并的知识点:
{chr(10).join(knowledge_contents)}
### 请返回JSON格式:
{{
"knowledge_type": "{knowledge_type}",
"content": "合并后的知识内容",
"confidence": 最高置信度值,
"keywords": ["合并后的关键词列表"],
"category": "合并后的分类",
"sources": ["所有来源"],
"frequency": {len(knowledge_group)}
}}
### 合并结果:
"""
# 过滤掉需求和问题类型的知识,因为它们是临时的、个性化的
filtered_knowledge = [
knowledge for knowledge in knowledge_list
if knowledge.get('knowledge_type') not in ['需求', '问题']
]
场景3:知识库健康度检查
核心概念: 对整个知识库进行健康度检查,找出缺少的知识、过期的知识、冲突的知识,确保知识库的质量和可靠性。
核心功能:
- 完整性检查: 评估知识库是否覆盖用户主要查询需求。
- 时效性检查: 识别过期或需要更新的知识内容。
- 一致性检查: 发现知识库中的冲突和矛盾信息。
- 综合评分: 提供量化的健康度评分和改进建议。
代码示例:
LLM用于检查知识库的完整性、时效性和一致性,通过结构化Prompt进行。
完整性检查 instruction 示例:
instruction = """
你是一个知识库完整性检查专家。请分析给定的
测试查询和知识库内容,判断知识库中是否缺少
相关的知识。
请返回JSON格式:
{
"missing_knowledge": [
{
"query": "测试查询",
"missing_aspect": "缺少的知识方面",
"importance": "重要性(高/中/低)",
"suggested_content": "建议的知识内容",
"category": "知识分类"
}
],
"coverage_score": "覆盖率评分(0-1)",
"completeness_analysis": "完整性分析"
}
"""
其他如时效性、一致性检查也采用类似的JSON输出Prompt。
场景4:知识库版本管理与性能比较
核心概念: 对知识库进行版本管理,实现回归测试、上线前验收,并比较不同版本的知识库性能,选择最优版本。
核心功能模块:
-
文本向量化模块: 将文本转换为高维向量(如1024维),使用DashScope Embeddings API。
Pythondef get_text_embedding(text): response = client.embeddings.create( model="text-embedding-v4", input=text, dimensions=1024 ) return response.data[0].embedding -
向量索引构建模块: 构建FAISS向量索引支持高效检索。
Pythondef build_vector_index(self, knowledge_base): # ... 生成向量和元数据 text_index = faiss.IndexFlatL2(1024) text_index.add_with_ids(vectors, ids) return metadata_store, text_index -
版本差异检测模块: 识别版本间的增删改变化,基于ID映射和集合运算。
-
向量检索模块: 基于向量相似度检索相关知识。
-
性能评估模块: 量化评估知识库检索性能(准确率、平均响应时间)。
-
性能比较模块: 对比版本性能并生成建议,基于A/B测试思想。
-
回归测试模块: 确保版本更新不破坏原有功能,通过率=通过测试数/总测试数。
版本性能比较结果示例:
- 版本1性能: 准确率: 60.0%, 平均响应时间: 115.8ms
- 版本2性能: 准确率: 100.0%, 平均响应时间: 120.2ms
- 建议: 推荐使用版本2,准确率提升40.0%,响应时间略有增加但可接受。
精准雷达:高效召回
优化查询扩展: MultiQuery
核心概念: 使用大模型将用户查询改写成多个语义相近的查询,以提升召回多样性,覆盖更广的潜在文档。
代码示例: generate_multi_queries 函数通过LLM生成多个查询变体。
def generate_multi_queries(query: str, llm, num_queries: int = 3) -> List[str]:
prompt = f"""你是一个AI助手,负责生成多个不同视角的搜索查询。
给定一个用户问题,生成{num_queries}个不同但相关的查询,以帮助检索更全面的信息。
每个查询应该从不同角度表达相同的信息需求。
原始问题: {query}
请直接输出{num_queries}个查询,每行一个,不要编号和其他内容:"""
# ... (调用LLM并解析结果)
索引扩展: 混合检索 (BM25 + Vector)
核心概念: 结合BM25(词频-逆文档频率的改进,精确匹配专有名词)和向量检索(Embedding语义相似度,理解同义词和语义)的优势。通过归一化分数和加权融合,提升召回多样性和准确性。
工作流程:
- 输入: 用户查询。
- 并行检索: 同时执行BM25和向量检索。
- 归一化: 将两种分数统一缩放到 [0, 1] 区间。
- 加权融合:
Score_hybrid = α × Score_vector + (1 - α) × Score_BM25。alpha值控制两种方法的权重。 - 输出: 按融合分数排序,返回Top-K结果。
代码示例:
-
BM25检索:
Pythontokenized_query = tokenize_chinese(query) bm25_scores = self.bm25.get_scores(tokenized_query) # 归一化到[0, 1] max_bm25 = max(bm25_scores) if max(bm25_scores) > 0 else 1 bm25_scores_normalized = [s / max_bm25 for s in bm25_scores] -
向量检索:
Pythonvector_results = self.vectorstore.similarity_search_with_score(query, k=len(self.chunks)) # 距离转分数(距离越小 -> 分数越高) for doc, distance in vector_results: vector_scores[idx] = 1 - (distance / max_distance) -
分数融合:
Pythoncombined = alpha _vector_score + (1 - alpha)_ bm25_scoreAlpha 值建议:
-
α = 0.0: 纯BM25,适合专业术语多的文档。 -
α = 0.5: 平衡BM25和向量,通用场景(推荐默认值)。 -
α = 1.0: 纯向量,适合口语化、同义词丰富的查询。
-
精细排序: Rerank 模型
核心概念: 重排序(Rerank)模型用于优化初步检索结果的排序,提高最终输出的相关性或准确性。常见的模型有BGE-Rerank和Cohere Rerank。
-
BGE-Rerank:
Code_特点:_* 开源免费,可本地部署,基于Transformer的Cross-Encoder结构,直接计算查询与文档的交互相关性得分。在中文任务中表现优秀。 _相关性分数:_* 未归一化的对数几率值,通常高相关性在3.0-10.0。 _代码示例:_* ```python from transformers import AutoModelForSequenceClassification, AutoTokenizer tokenizer = AutoTokenizer.from_pretrained('BAAI/bge-reranker-large') model = AutoModelForSequenceClassification.from_pretrained('BAAI/bge-reranker-large') model.eval() pairs = [['query', 'document content']] inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors='pt') scores = model(**inputs).logits.view(-1).float() ``` -
Cohere Rerank:
Code_特点:_* 商业API服务,云端调用,擅长多语言,在英文和多语言任务中表现优异。 _相关性分数:_* 归一化后的相关性分数(如0-1)。
Reranker实现示例:
class Reranker:
def __init__(self, model_name="BAAI/bge-reranker-base", cache_dir="./models"):
# 从ModelScope下载模型并加载
model_dir = snapshot_download(model_name, cache_dir=cache_dir)
self.tokenizer = AutoTokenizer.from_pretrained(model_dir)
self.model = AutoModelForSequenceClassification.from_pretrained(model_dir)
self.model.eval()
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.model.to(self.device)
def rerank(self, query: str, documents: List[Document], top_k: int = None):
pairs = [[query, doc.page_content] for doc in documents]
with torch.no_grad():
inputs = self.tokenizer(pairs, padding=True, truncation=True, max_length=512, return_tensors="pt").to(self.device)
scores = self.model(**inputs).logits.squeeze(-1).cpu().tolist()
scored_docs = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True)
return [doc for doc, _ in scored_docs[:top_k]]
混合查询召回 + Rerank 流程:
def hybrid_multi_query_search_with_rerank(query, hybrid_retriever, reranker, llm, initial_k=10, final_k=4):
# Stage 1: 粗排召回
queries = generate_multi_queries(query, llm)
candidate_docs = []
for q in queries:
docs = hybrid_retriever.search(q, k=initial_k) # 混合检索
candidate_docs.extend(docs)
candidate_docs = deduplicate(candidate_docs) # 去重
print(f"初步召回{len(candidate_docs)} 个候选")
# Stage 2: 精排重排序
reranked_docs = reranker.rerank(query, candidate_docs, top_k=final_k)
print(f"Rerank 后保留{len(reranked_docs)} 个")
return reranked_docs
双向改写 (Query2Doc / Doc2Query)
核心概念:
- Query2Doc: 将短查询改写成类似文档的扩展文本,以更充分表达用户意图,缓解短文本向量化效果差的问题。
- Doc2Query: 为文档生成一组关联查询,增强文档被检索到的可能性。
Small-to-Big 索引策略
核心概念: 一种高效的检索方法,通过小规模内容(如摘要、关键句或段落)建立索引,并链接到大规模内容主体中。用户查询首先匹配小规模内容,然后通过链接获取更详细的大规模内容作为上下文。提高检索效率和答案的逻辑连贯性。
全局视野:GraphRAG
核心概念: GraphRAG 是一种结构化的、分层的RAG方法,通过从原始文本中提取知识图谱、构建社区层级并生成摘要来增强检索生成。它能显著改进复杂信息处理、跨文档理解和综合见解生成的能力,克服基线RAG在连接点缺失和宏观理解上的局限性。
GraphRAG工作流(DAG有向无环图):
-
索引 (Indexing): 将非结构化文本转化为结构化知识。
Code_切片 (Source Text to TextUnits):_* 将文档分割成文本块。 _抽取 (Extract Graph):_* 使用LLM从文本块中提取实体、关系和关键声明 (claims)。 _聚类与摘要 (Community Detection & Summarization):_* 使用Leiden算法对知识图谱进行层次聚类,形成社区,并自下而上地为每个社区生成摘要。 -
查询 (Querying): 利用这些结构为LLM上下文窗口提供材料。
Code_全局搜索 (Global Search):_* 通过社区层级摘要推理语料库的整体问题。 _局部搜索 (Local Search):_* 通过扩展到特定实体的邻居和相关概念来推理特定实体的情况。
GraphRAG索引数据流:
- 第一阶段:组合TextUnits (将输入文档转换为TextUnits)
- 第二阶段:知识图谱提取 (提取实体、关系、主张,并进行合并和概述)
- 第三阶段:知识图谱增强 (社区检测、Node2Vec嵌入)
- 第四阶段:社区总结 (生成社区报告,了解高层次情况)
- 第五阶段:文档处理 (创建文档表,添加额外字段)
- 第六阶段:网络可视化 (UMAP降维用于2D可视化)
GraphRAG方法部署示例 (Microsoft GraphRAG):
-
下载源代码:
git clone https://github.com/microsoft/graphrag.git -
安装依赖并初始化项目:
pip install -e .和graphrag init --root . -
参数文件配置: 配置
settings.yaml(LLM模型、输入输出、向量存储、工作流等) 和.env(API Key)。 -
放置文档: 将待检索文档放入
./input目录下。 -
创建GraphRAG索引:
graphrag index --root .(耗时较长)。 -
进行查询:
Code_全局查询:_* `graphrag query --root . --method global --query "和曹操相关的人物都有哪些?"` _局部查询:_* `python -m graphrag.query --root ./cases --method local "和曹操相关的人物都有哪些?"`
GraphRAG查询模式对比:
对比维度 | Global模式 | Local模式
适用场景 | 回答全局性、概要性问题 (如数据集主要主题) | 回答具体事实、特定实体信息与关系
查询架构 | Map-Reduce架构 | 结合知识图谱结构化信息与原始文档非结构化数据构建上下文
数据来源 | 主要基于社区报告 | 包括知识图谱中的实体、关系、社区报告及原始文本块
LLM调用特点 | 多次调用LLM (为每个社区总结生成答案,再汇总) | 一次调用LLM (将构建好的上下文与原始问题一起输入)
上下文规模 | 较大 (社区报告,Map-Reduce处理) | 相比传统RAG更大 (多种信息构建上下文)
查询成本 | 非常高 (大量上下文,多次LLM调用) | 高 (多种信息构建上下文)
智能决策:Qwen Agent中的RAG
- Level 1: 基础RAG
- Level 2: 并行阅读
- Level 3: 多跳推理
(此部分在资料中仅列出标题,无具体内容)
关键要点
- 知识库的预处理至关重要: 通过LLM生成问题进行检索优化,以及从对话中沉淀和合并知识,能显著提高RAG系统的准确性和覆盖率。定期进行知识库健康度检查,确保知识的完整性、时效性和一致性。
- 高效召回是RAG性能基石: 采用多查询扩展、BM25与向量检索的混合召回,并结合Rerank模型进行精细排序,可以有效提升检索质量。Small-to-Big和双向改写策略能处理长文档和短文本向量化挑战。
- GraphRAG解决复杂推理难题: 相较于基线RAG,GraphRAG通过构建知识图谱和社区摘要,能更好地处理需要跨多个信息点进行综合理解和多跳推理的复杂查询。
- 版本管理与评估不可或缺: 建立知识库版本管理机制,通过性能评估和回归测试,确保新版本知识库的质量和稳定性,持续优化系统表现。
- LLM在RAG全链路发挥核心作用: 从知识抽取、问题生成、知识合并、健康度检查到查询扩展、社区摘要,LLM在RAG高级技术与调优中扮演着不可替代的角色。