1. 先搞清楚这个RAG技术库到底能帮你解决什么问题
如果你正在搭建基于大模型的问答系统、文档分析工具或智能客服,肯定会遇到一个核心问题:模型的知识有局限性,无法访问你的私有数据。RAG(检索增强生成)就是解决这个问题的标准方案,但基础RAG往往效果不稳定——检索不准、回答不相关、无法处理复杂查询。
NirDiamant/RAG_Techniques 这个GitHub仓库收集了42+可运行的RAG技术实现,从最基础的文本检索到复杂的图RAG、自适应检索、多模态处理都有完整代码。它不是理论教程,而是每个技术点都有独立的Jupyter Notebook,可以直接跑起来看效果。
我最看重的是它把RAG拆成了清晰的层次:基础检索→查询增强→上下文优化→高级架构→评估体系。无论你是刚接触RAG的新手,还是已经在生产环境遇到瓶颈的工程师,都能找到对应的解决方案。仓库维护很活跃,最近还加入了MemoRAG(记忆增强检索)和端到端评估等新内容。
2. 环境准备:跑通这些技术需要什么条件
这个仓库主要用Python实现,大部分技术基于LangChain和LlamaIndex框架。如果你要本地运行,我建议先准备以下环境:
基础环境:
- Python 3.8+(推荐3.10或3.11,兼容性更好)
- 至少8GB内存(处理大型文档时需要16GB+)
- 固态硬盘(向量索引文件读写频繁)
关键依赖包:
# 核心框架 pip install langchain llama-index # 向量数据库(按需选择) pip install faiss-cpu # CPU版本 pip install chromadb # 轻量级向量库 # 可选:GPU加速 pip install torch --index-url https://download.pytorch.org/whl/cu118大模型接入:
- OpenAI API密钥(用于GPT系列模型)
- 或本地模型(通过Ollama、vLLM等部署)
- 备用选项:Azure OpenAI、Anthropic Claude等
特别注意事项:
- 首次运行时会下载嵌入模型(如sentence-transformers),约500MB-1GB
- 如果使用重排序(reranking)功能,需要额外计算资源
- 图RAG和复杂架构需要NetworkX、PyVis等图处理库
我一般会先创建一个干净的conda环境,避免与现有项目冲突:
conda create -n rag-techniques python=3.10 conda activate rag-techniques pip install -r requirements.txt # 仓库提供的依赖文件3. 从基础到进阶:如何按顺序验证不同技术方案
3.1 先跑通最简单的RAG流程
不要一上来就尝试最复杂的技术。仓库里的basic_rag目录是最佳起点:
# 基础RAG的核心流程 from langchain.document_loaders import TextLoader from langchain.text_splitter import CharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import FAISS # 1. 加载文档 loader = TextLoader("your_document.txt") documents = loader.load() # 2. 文本分块 text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200) chunks = text_splitter.split_documents(documents) # 3. 创建向量索引 embeddings = OpenAIEmbeddings() vectorstore = FAISS.from_documents(chunks, embeddings) # 4. 检索问答 query = "你的问题" docs = vectorstore.similarity_search(query) # 将检索结果传递给LLM生成答案这个基础版本能帮你确认环境配置正确,同时理解RAG的核心环节:文档加载→分块→向量化→检索→生成。
3.2 查询增强技术:让检索更精准
基础RAG最大的问题是查询与文档不匹配。仓库提供了多种查询增强方案:
查询重写(Query Rewriting):让LLM重新表述问题,使其更符合文档表述方式。
# 示例:将"怎么配置数据库"重写为"MySQL数据库配置步骤" def rewrite_query(original_query): prompt = f"将以下用户问题重写为更符合技术文档表述的形式:{original_query}" return llm.invoke(prompt)HyDE(假设文档嵌入):生成一个假设答案,用这个答案的嵌入去检索。
# 生成假设答案 hypothetical_answer = llm.invoke(f"针对问题'{query}',生成一个假设答案") # 用假设答案的嵌入进行检索 hypothetical_embedding = embeddings.embed_query(hypothetical_answer) results = vectorstore.similarity_search_by_vector(hypothetical_embedding)子查询分解:复杂问题拆成多个简单子问题,分别检索后合并结果。
complex_query = "比较MySQL和PostgreSQL在事务处理方面的差异" sub_queries = [ "MySQL事务处理机制", "PostgreSQL事务处理特性", "MySQL vs PostgreSQL事务性能对比" ]实测时我发现,查询增强对事实性问题的提升最明显,能提高20-30%的检索准确率。
3.3 上下文优化技术:改善生成质量
检索到正确文档后,如何让LLM更好地利用这些信息?仓库提供了多种上下文优化方案:
语义分块(Semantic Chunking):按语义边界而非固定长度分块。
from langchain_experimental.text_splitter import SemanticChunker from langchain.embeddings import OpenAIEmbeddings # 按语义相似度自动分块 text_splitter = SemanticChunker(OpenAIEmbeddings()) chunks = text_splitter.split_documents(documents)上下文压缩:检索后对长文档进行摘要,只保留相关部分。
from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import LLMChainExtractor compressor = LLMChainExtractor.from_llm(llm) compression_retriever = ContextualCompressionRetriever( base_retriever=vectorstore.as_retriever(), base_compressor=compressor )多向量检索:存储文档的多个视图(摘要、关键词、问题等)。
# 为每个文档块生成多个表示 doc_content = "文档内容" summary = llm.invoke(f"为以下内容生成摘要:{doc_content}") questions = llm.invoke(f"针对以下内容生成可能的问题:{doc_content}") # 将所有表示都存入向量库这些技术特别适合处理长文档和技术手册,能显著减少无关信息干扰。
4. 高级架构:应对复杂查询场景
4.1 图RAG:处理多跳推理问题
当用户问题需要连接多个文档片段时,基础RAG就力不从心了。图RAG通过构建知识图谱来解决这个问题:
# 构建实体关系图 entities = extract_entities_from_documents(documents) relationships = extract_relationships(entities) # 图检索流程 def graph_retrieval(query): # 1. 识别查询中的实体 query_entities = extract_entities(query) # 2. 在图中找到相关实体节点 relevant_entities = find_similar_entities(query_entities, knowledge_graph) # 3. 多跳扩展:找到相邻节点 expanded_entities = multi_hop_expansion(relevant_entities, knowledge_graph) # 4. 获取这些实体对应的文档片段 return get_documents_for_entities(expanded_entities)仓库中的Microsoft GraphRAG实现特别完整,适合处理企业级知识库。
4.2 自适应检索:根据问题类型选择策略
不是所有问题都需要相同的检索深度。自适应检索能动态调整策略:
def adaptive_retrieval_strategy(query): # 问题分类 query_type = classify_query(query) if query_type == "factual": # 事实性问题:精确匹配 return exact_match_retrieval(query) elif query_type == "analytical": # 分析性问题:多文档综合 return multi_document_retrieval(query) elif query_type == "creative": # 创意性问题:宽松检索+生成 return creative_retrieval(query)4.3 自我反思RAG(Self-RAG):质量自检
这是仓库里比较高级的技术,让系统自己判断检索和生成的质量:
class SelfRAG: def retrieve_and_generate(self, query): # 1. 决定是否需要检索 need_retrieval = self.should_retrieve(query) if not need_retrieval: return self.generate_directly(query) # 2. 检索并评估相关性 documents = self.retrieve(query) relevance_scores = self.evaluate_relevance(query, documents) # 3. 根据评估结果生成 if max(relevance_scores) < 0.7: # 阈值可调整 return "我找到的信息不够相关,请重新表述问题。" else: return self.generate_with_documents(query, documents)5. 评估体系:如何判断哪种技术适合你的场景
仓库提供了完整的评估方案,这是很多RAG项目忽略的关键环节。
5.1 基础评估指标
from ragas import evaluate from ragas.metrics import ( faithfulness, answer_relevancy, context_precision, ) # 准备测试数据集 test_questions = ["问题1", "问题2", ...] ground_truths = ["标准答案1", "标准答案2", ...] # 运行评估 results = evaluate( dataset=test_dataset, metrics=[faithfulness, answer_relevancy, context_precision], )关键指标解读:
- 忠实度(Faithfulness):生成内容是否基于检索结果,而不是幻觉
- 答案相关性:回答是否直接解决用户问题
- 上下文精确度:检索的文档是否真正相关
5.2 端到端评估流程
我建议按这个顺序评估新技术:
- 单问题测试:用一个典型问题快速验证功能
- 小批量测试:10-20个问题,计算基础指标
- 边界测试:极端情况、复杂问题、模糊查询
- 性能测试:响应时间、资源消耗、并发能力
def rag_evaluation_pipeline(technique_name): print(f"评估技术: {technique_name}") # 1. 功能验证 simple_results = test_simple_queries(technique_name) if not simple_results["basic_functionality"]: print("❌ 基础功能失败,无需继续评估") return # 2. 质量评估 quality_metrics = evaluate_quality(technique_name, test_dataset) print(f"质量得分: {quality_metrics}") # 3. 性能评估 performance = evaluate_performance(technique_name) print(f"性能指标: {performance}") # 4. 适用性判断 suitability = assess_suitability(quality_metrics, performance) print(f"适用场景: {suitability}")6. 生产环境部署的关键考量
6.1 技术选型决策矩阵
| 技术类型 | 适用场景 | 复杂度 | 资源需求 | 维护成本 |
|---|---|---|---|---|
| 基础RAG | 简单问答、概念查询 | 低 | 低 | 低 |
| 查询增强 | 术语不匹配问题 | 中 | 中 | 中 |
| 图RAG | 多跳推理、复杂分析 | 高 | 高 | 高 |
| 自适应检索 | 混合类型查询 | 高 | 中 | 高 |
6.2 性能优化策略
索引优化:
- 分层索引:摘要级+细节级,快速筛选后精读
- 增量更新:避免全量重建,只更新变更部分
- 分布式索引:大数据集采用多节点向量库
检索优化:
- 多路召回:向量检索+关键词检索+图检索,然后融合
- 缓存策略:常见查询结果缓存,减少重复计算
- 提前计算:HyPE等技术在索引阶段预计算查询
6.3 监控与维护
生产环境必须建立监控体系:
class RAGMonitor: def track_performance(self): # 响应时间监控 self.response_time_metrics.append(time_taken) # 质量监控 self.quality_metrics.append({ "retrieval_precision": calculate_precision(), "generation_quality": user_feedback_score }) # 异常检测 if self.detect_anomalies(): self.alert_engineering_team()7. 实际落地时的避坑经验
7.1 文档预处理是关键
很多RAG效果问题根源在文档质量:
- 格式清理:去除HTML标签、特殊字符、乱码
- 结构识别:正确识别标题、段落、列表、表格
- 语言统一:中英文混合文档需要特殊处理
- 质量过滤:去除低质量、重复、过时内容
7.2 分块策略需要反复调试
没有通用的最佳分块大小,必须根据你的文档类型实验:
- 技术文档:300-500字符,保持代码块完整
- 法律合同:200-300字符,按条款划分
- 学术论文:500-800字符,按章节划分
- 对话记录:按对话回合划分
我一般会准备一个分块评估脚本:
def evaluate_chunking_strategy(documents, chunk_sizes=[200, 500, 1000]): results = {} for size in chunk_sizes: splitter = CharacterTextSplitter(chunk_size=size, chunk_overlap=50) chunks = splitter.split_documents(documents) # 评估指标 avg_tokens = np.mean([len(chunk.page_content.split()) for chunk in chunks]) coherence_score = calculate_semantic_coherence(chunks) results[size] = { "chunk_count": len(chunks), "avg_tokens": avg_tokens, "coherence": coherence_score } return results7.3 失败重试机制必不可少
生产环境必须考虑各种失败场景:
class RobustRAGPipeline: def query_with_retry(self, query, max_retries=3): for attempt in range(max_retries): try: # 尝试检索 documents = self.retrieve(query) if self.validate_retrieval(documents): return self.generate_answer(query, documents) else: # 检索结果不理想,尝试查询重写 query = self.rewrite_query(query) continue except Exception as e: logger.error(f"第{attempt+1}次尝试失败: {str(e)}") if attempt == max_retries - 1: return self.fallback_response(query)7.4 成本控制策略
RAG系统可能产生大量API调用成本:
- 本地化部署:使用开源嵌入模型和LLM
- 缓存层:常见问题和检索结果缓存
- 批量处理:离线预处理文档,减少实时计算
- 用量监控:设置预算告警和自动限流
我个人更建议先从最简单的技术开始验证,确保基础流程稳定后再逐步引入复杂功能。这个仓库的价值在于提供了完整的技术光谱,让你能够根据实际需求选择合适的方案,而不是盲目追求最先进的技术。
真正落地时,最该关注的不是技术复杂度,而是输入质量、检索稳定性和失败处理机制。很多团队花了大量时间调试高级功能,最后发现问题的根源是文档预处理不够彻底或者基础检索参数设置不合理。