RAG系统进阶:从朴素检索到自适应检索增强

朴素RAG的局限性 标准RAG流程很简单:文档分块→向量化→检索top-k→拼接到prompt→生成回答。但在实际场景中,朴素RAG面临几个核心问题: 检索不准:用户查询与文档语义空间不匹配 排序不佳:向量相似度高≠回答有用 上下文冗余:top-k中可能包含大量无关内容 无法自纠错:检索不到就硬编答案 检索层优化 混合检索 纯向量检索擅长语义匹配但弱于精确关键词。BM25等稀疏检索正好互补。混合检索的实践方案: 向量检索(Dense):召回语义相关段落 关键词检索(Sparse/BM25):召回精确匹配段落 融合排序:RRF(Reciprocal Rank Fusion)算法合并两路结果 def rrf_fusion(dense_results, sparse_results, k=60): scores = {} for rank, doc in enumerate(dense_results): scores[doc.id] = scores.get(doc.id, 0) + 1/(k + rank) for rank, doc in enumerate(sparse_results): scores[doc.id] = scores.get(doc.id, 0) + 1/(k + rank) return sorted(scores.items(), key=lambda x: -x[1]) 查询改写 用户的原始query往往不是最佳检索query。通过LLM对查询进行改写: 查询扩展:生成多个语义变体query,分别检索后合并 HyDE:先让LLM生成一个假设性回答,用该回答的embedding去检索(对长尾问题效果显著) 子问题分解:复杂问题拆成多个子问题分别检索 重排序(Reranking) 向量检索的召回质量参差不齐。在召回后加一个cross-encoder重排层: 向量检索召回top-50(宽召回) Cross-encoder(如bge-reranker-v2)对每对(query, doc)打分 按分数取top-5(精排序) Cross-encoder比bi-encoder准确率高20-30%,但速度慢,所以做两阶段检索。 生成层优化 上下文压缩 检索回来的文档可能很长,需要压缩到LLM能高效处理的篇幅: 提取式:用小模型抽取关键句子 摘要式:LLM对每个文档生成精简摘要 LLMLingua:基于困惑度删除低信息token,可压缩到原长的1/10 引用标注 高质量RAG需要可溯源。实现方式: 在prompt中要求模型标注引用段落编号 后处理时验证引用的段落确实支持该陈述 不支持的引用标记为"未验证" 自适应RAG:让模型决定怎么检索 Self-RAG Self-RAG让模型学会自主决定: 是否需要检索(通过特殊token [Retrieve]/[No Retrieve]) 检索到的段落是否相关([Relevant]/[Irrelevant]) 回答是否被段落支持([Supported]/[Partially Supported]) 这种方式将检索决策内化为模型能力,需要通过强化学习训练。 CRAG(Corrective RAG) CRAG在检索后增加一个"检索评估器": 评估检索结果质量:Correct / Ambiguous / Incorrect 如果Incorrect,触发web搜索补充 如果Ambiguous,将检索结果与web结果合并 对最终结果重排序后生成 Adaptive-RAG 根据查询复杂度自适应选择策略: 简单查询→单次检索 复杂查询→多跳检索+推理 分类器判断查询类型,路由到对应处理流水线 工程实践要点 评估体系 RAG系统必须有量化评估。推荐使用RAGAS框架,四个核心指标: ...

2026-07-16 · 1 min · 119 words · 硅基 AGI 探索者

Self-RAG与Adaptive-RAG:让模型学会何时检索

朴素RAG的致命缺陷 朴素RAG对每个问题都执行检索,这带来两个问题:简单问题浪费检索资源(“1+1等于几"不需要查文档),复杂问题单次检索不够(“对比三家公司五年财报"需要多次检索)。自适应RAG的核心思想是让模型自己决定:是否需要检索、检索几次、检索什么。 Self-RAG:自我反思的检索 核心机制 Self-RAG训练模型输出特殊的反思token来控制检索行为: [Retrieve]:是否需要检索 [Relevant]:检索结果是否相关 [Supported]:生成内容是否被检索结果支持 [Useful]:检索结果是否有用 工作流程 输入问题 → 模型判断[Retrieve] → 是 → 检索Top-K文档 → 模型判断[Relevant] → 过滤不相关文档 → 逐段生成 → [Supported]标注 → 输出 否 → 直接生成 → 输出 训练方法 Self-RAG的训练分为两阶段: 阶段1:训练 critic 模型 收集标注数据训练一个判断模型: 何时需要检索(基于问题类型) 文档是否相关(人工标注) 生成是否被支持(对照检查) class CriticModel: def __init__(self, base_model): self.model = base_model def should_retrieve(self, question): # 简单事实问题不需要检索 # 需要最新信息的问题需要检索 # 需要引用来源的问题需要检索 prompt = f"判断以下问题是否需要检索外部信息:\n{question}" return self.model.generate(prompt) == "yes" def is_relevant(self, question, document): prompt = f"判断文档是否与问题相关:\n问题:{question}\n文档:{document}" return self.model.generate(prompt) == "relevant" 阶段2:训练生成模型 在生成模型中注入反思token的训练: def self_rag_generate(question, retriever, model): # Step 1: 判断是否检索 if model.should_retrieve(question): docs = retriever.search(question, top_k=5) # 过滤不相关文档 relevant_docs = [d for d in docs if model.is_relevant(question, d)] else: relevant_docs = [] # Step 2: 逐段生成 response = "" for segment in model.generate_segments(question, relevant_docs): # 检查是否被来源支持 support_level = model.check_support(segment, relevant_docs) if support_level == "fully_supported": response += segment + " [Supported]" elif support_level == "partially_supported": response += segment + " [Partially Supported]" else: # 无支持的内容触发重新检索 new_docs = retriever.search(segment, top_k=3) response += segment + " [No Support - Retrieved]" return response 效果对比 在多个基准上,Self-RAG相比朴素RAG: ...

2026-07-16 · 3 min · 529 words · 硅基 AGI 探索者

从RAG到GraphRAG:知识检索的范式跃迁

向量检索的天花板 传统RAG系统依赖向量相似度检索,在简单事实问答场景表现出色。但当问题涉及多跳推理、跨文档关联或全局性总结时,纯向量检索就显得力不从心。 比如"公司A的CEO曾在哪家公司任职,那家公司又被谁收购了"这样的问题,需要跨多个文档片段进行链式推理。向量检索只能找到语义相似的片段,无法构建这种实体间的关联路径。 这就是GraphRAG登场的背景。 GraphRAG的核心思路 GraphRAG的核心创新在于:在传统的向量索引之上,叠加一层知识图谱索引。具体流程分为四个阶段: 实体抽取:使用LLM从文档中抽取实体和关系,构建知识图谱。每个实体作为图节点,实体间关系作为边。 社区发现:对知识图谱运行社区检测算法(如Leiden算法),将关联紧密的实体聚类成社区。每个社区生成一个摘要。 混合检索:查询时同时进行向量检索和图遍历。向量检索找到相关文档片段,图遍历沿着实体关系路径发现关联信息。 答案生成:将检索到的文档片段、图路径和社区摘要整合后送入LLM生成最终答案。 微软GraphRAG的实现启示 微软在2024年开源的GraphRAG实现是目前最成熟的参考方案。其架构有几个值得学习的设计: 索引阶段采用两遍处理——第一遍抽取实体和关系,第二遍对社区进行层级摘要。这种分层设计使得系统既能回答细节问题(叶子社区),也能回答宏观问题(根社区)。 查询阶段区分了local search和global search。local search针对具体实体相关问题,从实体邻域出发检索;global search针对全局性问题,直接使用社区摘要进行map-reduce式回答。 实践中的权衡 GraphRAG不是银弹。在实际部署中,我们发现了几个关键的trade-off: 索引成本显著增加。 相比纯向量RAG,GraphRAG的索引阶段需要额外的LLM调用来抽取实体和生成社区摘要。对于一个万级文档的库,索引成本可能增加5-10倍。 维护复杂度上升。 知识图谱需要持续更新。当新文档加入时,不仅要更新向量索引,还要增量更新图结构和重新计算社区归属。 并非所有场景都需要图。 对于简单的FAQ场景,纯向量RAG仍然是最优选择。GraphRAG的价值在多跳推理和全局分析场景中才能充分体现。 从GraphRAG到Agentic RAG GraphRAG代表的是一个更广泛趋势:RAG系统正在从"检索+生成"的简单模式演进为"规划+检索+推理+生成"的Agentic模式。未来的RAG系统不再是被动的检索器,而是主动的知识探索者——它能根据问题复杂度自主选择检索策略,在检索结果不足时自主发起多轮检索,甚至主动构建临时知识图谱来回答复杂问题。 这个方向才刚刚开始,GraphRAG只是第一步。 本文同步发布于 硅基AGI论坛

2026-07-12 · 1 min · 32 words · 硅基 AGI 探索者

从RAG到GraphRAG:知识检索的范式跃迁

向量检索的天花板 传统RAG系统依赖向量相似度检索,在简单事实问答场景表现出色。但当问题涉及多跳推理、跨文档关联或全局性总结时,纯向量检索就显得力不从心。 比如"公司A的CEO曾在哪家公司任职,那家公司又被谁收购了"这样的问题,需要跨多个文档片段进行链式推理。向量检索只能找到语义相似的片段,无法构建这种实体间的关联路径。 这就是GraphRAG登场的背景。 GraphRAG的核心思路 GraphRAG的核心创新在于:在传统的向量索引之上,叠加一层知识图谱索引。具体流程分为四个阶段: 实体抽取:使用LLM从文档中抽取实体和关系,构建知识图谱。每个实体作为图节点,实体间关系作为边。 社区发现:对知识图谱运行社区检测算法(如Leiden算法),将关联紧密的实体聚类成社区。每个社区生成一个摘要。 混合检索:查询时同时进行向量检索和图遍历。向量检索找到相关文档片段,图遍历沿着实体关系路径发现关联信息。 答案生成:将检索到的文档片段、图路径和社区摘要整合后送入LLM生成最终答案。 微软GraphRAG的实现启示 微软在2024年开源的GraphRAG实现是目前最成熟的参考方案。其架构有几个值得学习的设计: 索引阶段采用两遍处理——第一遍抽取实体和关系,第二遍对社区进行层级摘要。这种分层设计使得系统既能回答细节问题(叶子社区),也能回答宏观问题(根社区)。 查询阶段区分了local search和global search。local search针对具体实体相关问题,从实体邻域出发检索;global search针对全局性问题,直接使用社区摘要进行map-reduce式回答。 实践中的权衡 GraphRAG不是银弹。在实际部署中,我们发现了几个关键的trade-off: 索引成本显著增加。 相比纯向量RAG,GraphRAG的索引阶段需要额外的LLM调用来抽取实体和生成社区摘要。对于一个万级文档的库,索引成本可能增加5-10倍。 维护复杂度上升。 知识图谱需要持续更新。当新文档加入时,不仅要更新向量索引,还要增量更新图结构和重新计算社区归属。 并非所有场景都需要图。 对于简单的FAQ场景,纯向量RAG仍然是最优选择。GraphRAG的价值在多跳推理和全局分析场景中才能充分体现。 从GraphRAG到Agentic RAG GraphRAG代表的是一个更广泛趋势:RAG系统正在从"检索+生成"的简单模式演进为"规划+检索+推理+生成"的Agentic模式。未来的RAG系统不再是被动的检索器,而是主动的知识探索者——它能根据问题复杂度自主选择检索策略,在检索结果不足时自主发起多轮检索,甚至主动构建临时知识图谱来回答复杂问题。 这个方向才刚刚开始,GraphRAG只是第一步。 本文同步发布于 硅基AGI论坛

2026-07-12 · 1 min · 32 words · 硅基 AGI 探索者
RAG框架对比

RAG框架对比2026:检索增强生成的最佳选择

引言 RAG(检索增强生成)是企业LLM应用最核心的技术。2026年,RAG框架已经从简单的"检索+生成"发展为包含查询重写、混合检索、重排序、上下文管理等完整技术链的复杂系统。本文将全面对比主流RAG框架。 参评框架 框架 版本 特点 适合场景 Haystack 2.6 企业级,Pipeline架构 企业RAG LlamaIndex 0.6 数据驱动,丰富索引 数据密集型 LangChain 0.3 通用框架,生态丰富 通用应用 RAGFlow 1.2 专注RAG,深度优化 纯RAG场景 DSPy 0.5 编程式RAG 研究型 核心能力对比 文档处理 能力 Haystack LlamaIndex LangChain RAGFlow PDF解析 ★★★★★ ★★★★☆ ★★★☆☆ ★★★★★ 表格识别 ★★★★☆ ★★★☆☆ ★★☆☆☆ ★★★★★ 图文混合 ★★★★☆ ★★★☆☆ ★★☆☆☆ ★★★★☆ 分块策略 ★★★★★ ★★★★★ ★★★☆☆ ★★★★☆ 多格式支持 ★★★★★ ★★★★★ ★★★★☆ ★★★★☆ 检索能力 能力 Haystack LlamaIndex LangChain RAGFlow 稠密检索 ★★★★★ ★★★★★ ★★★★☆ ★★★★☆ 稀疏检索 ★★★★★ ★★★★☆ ★★★☆☆ ★★★★★ 混合检索 ★★★★★ ★★★★☆ ★★★☆☆ ★★★★★ 重排序 ★★★★★ ★★★★☆ ★★★☆☆ ★★★★☆ 多跳检索 ★★★★☆ ★★★★★ ★★★☆☆ ★★★☆☆ 生成质量 使用相同的检索结果,评估各框架的生成质量: ...

2026-07-02 · 2 min · 409 words · 硅基 AGI 探索者
Haystack RAG

Haystack 2026 RAG实践:企业级检索增强生成

引言 Haystack是deepset开发的企业级NLP框架,在RAG领域有着深厚积累。2026年的Haystack已经发展成为一个完整的RAG解决方案框架。本文将分享Haystack在RAG实践中的经验。 Haystack 2026架构 Pipeline设计 from haystack import Pipeline from haystack.components.embedders import OllamaEmbedder from haystack.components.retrievers import ChromaRetriever from haystack.components.generators import OpenAIGenerator # 构建RAG Pipeline pipe = Pipeline() # 添加组件 pipe.add_component("embedder", OllamaEmbedder(model="bge-large-zh")) pipe.add_component("retriever", ChromaRetriever(top_k=5)) pipe.add_component("generator", OpenAIGenerator(model="gpt-5")) # 连接组件 pipe.connect("embedder.embedding", "retriever.query_embedding") pipe.connect("retriever.documents", "generator.documents") 文档处理 from haystack.components.converters import PDFToDocument, MarkdownToDocument from haystack.components.preprocessors import DocumentSplitter, DocumentCleaner # 文档转换pipeline indexing = Pipeline() # 转换器 indexing.add_component("pdf_converter", PDFToDocument()) indexing.add_component("md_converter", MarkdownToDocument()) # 预处理 indexing.add_component("cleaner", DocumentCleaner()) indexing.add_component("splitter", DocumentSplitter( split_by="word", split_length=500, split_overlap=50 )) # 嵌入 indexing.add_component("embedder", OllamaEmbedder(model="bge-large-zh")) indexing.add_component("writer", ChromaDocumentWriter()) # 连接 indexing.connect("pdf_converter.documents", "cleaner.documents") indexing.connect("cleaner.documents", "splitter.documents") indexing.connect("splitter.documents", "embedder.documents") indexing.connect("embedder.documents", "writer.documents") RAG优化实践 实践一:混合检索 from haystack.components.retrievers import ( ChromaRetriever, # 稠密检索 BM25Retriever # 稀疏检索 ) from haystack.components.joiners import DocumentJoiner # 混合检索pipeline hybrid_pipe = Pipeline() # 稠密检索 hybrid_pipe.add_component("dense_embedder", OllamaEmbedder(model="bge-large-zh")) hybrid_pipe.add_component("dense_retriever", ChromaRetriever(top_k=20)) # 稀疏检索 hybrid_pipe.add_component("sparse_retriever", BM25Retriever(top_k=20)) # 融合 hybrid_pipe.add_component("joiner", DocumentJoiner(join_mode="reciprocal_rank_fusion")) # 重排序 hybrid_pipe.add_component("reranker", SentenceTransformersRanker(model="bge-reranker-v2", top_k=5)) 实践二:查询扩展 from haystack.components.generators import OpenAIGenerator # 查询扩展组件 class QueryExpander: def __init__(self, llm): self.llm = llm def expand(self, query): prompt = f"请将以下查询扩展为3个不同表述:\n{query}" response = self.llm.run(prompt) return parse_queries(response) def run(self, query): expanded = self.expand(query) return {"queries": expanded} # 在pipeline中使用 pipe.add_component("expander", QueryExpander(llm=OpenAIGenerator())) 实践三:分块策略优化 from haystack.components.preprocessors import DocumentSplitter # 语义分块(基于段落) splitter = DocumentSplitter( split_by="paragraph", split_length=1, split_overlap=0 ) # 滑动窗口分块 splitter = DocumentSplitter( split_by="word", split_length=300, split_overlap=50 # 50词重叠 ) # 基于标题的分块 class HeadingBasedSplitter: def split(self, document): # 按Markdown标题分块 sections = re.split(r'^#+\s', document.content, flags=re.MULTILINE) return [Document(content=s.strip()) for s in sections if s.strip()] 实践四:上下文管理 # 上下文窗口管理 class ContextWindowManager: def __init__(self, max_tokens=4000): self.max_tokens = max_tokens def select_context(self, documents, query): """选择最相关的上下文,不超过token限制""" selected = [] token_count = 0 for doc in documents: doc_tokens = count_tokens(doc.content) if token_count + doc_tokens > self.max_tokens: # 截断最后一个文档 remaining = self.max_tokens - token_count if remaining > 100: # 至少100 token才包含 doc.content = doc.content[:remaining] selected.append(doc) break selected.append(doc) token_count += doc_tokens return selected 实践五:答案溯源 # 带来源标注的生成 class SourcedGenerator: def __init__(self, llm): self.llm = llm def run(self, query, documents): # 构造带来源编号的提示 context = "" for i, doc in enumerate(documents): context += f"[{i+1}] {doc.content}\n\n" prompt = f""" 基于以下参考信息回答问题。在回答中标注信息来源。 参考信息: {context} 问题:{query} 回答格式:答案内容[来源编号] """ response = self.llm.run(prompt) return {"answer": response} 企业级功能 权限控制 class AccessControlledRetriever: def __init__(self, retriever, acl): self.retriever = retriever self.acl = acl # 访问控制列表 def run(self, query, user_id): # 检索 documents = self.retriever.run(query) # 过滤:只返回用户有权限的文档 accessible = [ doc for doc in documents if self.acl.has_access(user_id, doc.metadata.get("doc_id")) ] return {"documents": accessible} 多租户 class MultiTenantStore: def __init__(self): self.stores = {} # tenant_id -> vector_store def get_store(self, tenant_id): if tenant_id not in self.stores: self.stores[tenant_id] = ChromaStore( collection_name=f"tenant_{tenant_id}" ) return self.stores[tenant_id] 缓存 from haystack.components.cachers import CacheChecker pipe.add_component("cache_checker", CacheChecker( cache_store=RedisCache(), cache_key="{{query}}" )) 2026年新特性 1. 多模态RAG from haystack.components.embedders import CLIPEmbedder # 图文混合RAG pipe.add_component("image_embedder", CLIPEmbedder()) pipe.add_component("text_embedder", OllamaEmbedder(model="bge-large-zh")) 2. 自适应检索 class AdaptiveRetriever: """根据查询复杂度自适应选择检索策略""" def run(self, query): complexity = self.assess_complexity(query) if complexity == "simple": return self.simple_retrieve(query) elif complexity == "medium": return self.hybrid_retrieve(query) else: return self.multi_hop_retrieve(query) 3. 评估集成 from haystack.components.evaluators import ( FaithfulnessEvaluator, AnswerRelevanceEvaluator, ContextRelevanceEvaluator ) # 在pipeline末尾加入评估 pipe.add_component("faithfulness", FaithfulnessEvaluator()) pipe.add_component("relevance", AnswerRelevanceEvaluator()) 性能对比 框架 索引速度 检索延迟 RAG准确率 功能丰富度 Haystack ★★★★☆ ★★★★☆ ★★★★★ ★★★★★ LlamaIndex ★★★★★ ★★★★☆ ★★★★☆ ★★★★☆ LangChain ★★★☆☆ ★★★☆☆ ★★★☆☆ ★★★★★ 结语 Haystack在2026年仍然是企业级RAG的首选框架。其Pipeline架构清晰、组件丰富、可扩展性强,特别适合需要精细控制RAG流程的企业应用。 ...

2026-07-02 · 3 min · 494 words · 硅基 AGI 探索者
RAG管线优化

RAG管线优化2026实战

RAG的核心挑战 RAG(检索增强生成)让LLM能够基于私有知识回答问题。但一个简单的RAG原型——文档切块→向量化→相似度检索→拼接到prompt——在实际使用中往往效果不佳。2026年的RAG优化需要从文档处理、检索质量、上下文管理和生成控制四个维度系统提升。 文档处理优化 智能分块 from langchain.text_splitter import RecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter class SmartChunker: def __init__(self, chunk_size=512, chunk_overlap=64): self.chunk_size = chunk_size self.chunk_overlap = chunk_overlap # 通用分割器 self.general_splitter = RecursiveCharacterTextSplitter( chunk_size=chunk_size, chunk_overlap=chunk_overlap, separators=["\n\n", "\n", "。", "!", "?", ".", "!", "?", " ", ""] ) # Markdown分割器 self.md_splitter = MarkdownHeaderTextSplitter( headers_to_split_on=[ ("#", "Header 1"), ("##", "Header 2"), ("###", "Header 3"), ] ) def chunk(self, text, doc_type="auto"): if doc_type == "auto": doc_type = self.detect_type(text) if doc_type == "markdown": # 先按标题分块,再按大小细分 md_chunks = self.md_splitter.split_text(text) final_chunks = [] for chunk in md_chunks: if len(chunk.page_content) > self.chunk_size * 2: sub_chunks = self.general_splitter.split_text(chunk.page_content) for sc in sub_chunks: sc.metadata = chunk.metadata final_chunks.append(sc) else: final_chunks.append(chunk) return final_chunks else: return self.general_splitter.split_text(text) def detect_type(self, text): md_indicators = ["# ", "## ", "- [", "```", "| "] if any(ind in text[:500] for ind in md_indicators): return "markdown" return "text" 表格与代码处理 class TableAwareChunker: """避免在表格中间切分""" def chunk(self, text): # 识别表格区域 table_pattern = r'(\|[^\n]+\|\n)+' chunks = [] last_end = 0 for match in re.finditer(table_pattern, text): # 表格前的文本正常切分 pre_text = text[last_end:match.start()] if pre_text.strip(): chunks.extend(self.split_text(pre_text)) # 表格作为完整块 chunks.append(text[match.start():match.end()]) last_end = match.end() # 剩余文本 if last_end < len(text): chunks.extend(self.split_text(text[last_end:])) return chunks 向量化优化 多向量表示 from sentence_transformers import SentenceTransformer class MultiVectorEncoder: def __init__(self): self.dense_model = SentenceTransformer('BAAI/bge-large-zh-v1.5') # 稀疏向量用于关键词匹配 self.sparse_model = None # 使用BM25或SPLADE def encode(self, text): # 密集向量:语义相似度 dense_vec = self.dense_model.encode(text, normalize_embeddings=True) # 稀疏向量:精确匹配 sparse_vec = self.sparse_model.encode(text) if self.sparse_model else None return { "dense": dense_vec, "sparse": sparse_vec, "text": text } 查询扩展 class QueryExpander: def __init__(self, llm): self.llm = llm async def expand(self, query): """使用LLM扩展查询""" prompt = f"""将以下查询改写为3个不同角度的表述,用于检索: 原始查询:{query} 输出格式: 1. [改写1] 2. [改写2] 3. [改写3]""" response = await self.llm.ainvoke(prompt) expansions = self.parse_expansions(response) expansions.append(query) # 保留原始查询 return expansions def parse_expansions(self, text): lines = text.strip().split('\n') return [line.split('.', 1)[1].strip() for line in lines if '.' in line] 检索优化 混合检索 import numpy as np class HybridRetriever: def __init__(self, vector_store, bm25_store, alpha=0.7): self.vector_store = vector_store # 密集向量检索 self.bm25_store = bm25_store # BM25稀疏检索 self.alpha = alpha # 混合权重 async def retrieve(self, query, k=5): # 密集检索 dense_results = await self.vector_store.asimilarity_search_with_score( query, k=k*2 ) # 稀疏检索 sparse_results = self.bm25_store.search(query, k=k*2) # 分数归一化 dense_scores = self.normalize_scores([s for _, s in dense_results]) sparse_scores = self.normalize_scores([s for _, s in sparse_results]) # 混合排序 combined = {} for (doc, _), score in zip(dense_results, dense_scores): doc_id = doc.metadata["id"] combined[doc_id] = combined.get(doc_id, 0) + self.alpha * score combined.setdefault(f"{doc_id}_doc", doc) for (doc, _), score in zip(sparse_results, sparse_scores): doc_id = doc.metadata["id"] combined[doc_id] = combined.get(doc_id, 0) + (1 - self.alpha) * score combined.setdefault(f"{doc_id}_doc", doc) # 排序返回top-k sorted_ids = sorted( [k for k in combined if not k.endswith("_doc")], key=lambda x: combined[x], reverse=True )[:k] return [combined[f"{did}_doc"] for did in sorted_ids] def normalize_scores(self, scores): if not scores: return [] scores = np.array(scores) if scores.max() > scores.min(): return (scores - scores.min()) / (scores.max() - scores.min()) return np.ones_like(scores) 重排序 from sentence_transformers import CrossEncoder class Reranker: def __init__(self, model_name="BAAI/bge-reranker-large"): self.model = CrossEncoder(model_name) def rerank(self, query, documents, top_k=5): # 构建query-document对 pairs = [(query, doc.page_content) for doc in documents] # 计算相关性分数 scores = self.model.predict(pairs) # 排序 ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True) return [doc for doc, _ in ranked[:top_k]] 上下文管理 动态上下文窗口 class ContextManager: def __init__(self, max_tokens=4096): self.max_tokens = max_tokens def build_context(self, query, retrieved_docs, conversation_history=None): # 预留生成空间 context_budget = self.max_tokens - 512 # 分配:历史对话30%,检索文档70% history_budget = int(context_budget * 0.3) docs_budget = context_budget - history_budget # 构建历史上下文 history_text = self.build_history(conversation_history, history_budget) # 构建文档上下文(按相关性排序) docs_text = self.build_docs(retrieved_docs, docs_budget) # 组装最终prompt context = f""" ## 历史对话 {history_text} ## 相关知识 {docs_text} ## 用户问题 {query} """ return context def build_docs(self, docs, budget): result = [] current_tokens = 0 for i, doc in enumerate(docs): doc_text = f"[{i+1}] {doc.page_content}\n" doc_tokens = len(doc_text) // 4 # 粗略估计 if current_tokens + doc_tokens > budget: break result.append(doc_text) current_tokens += doc_tokens return "\n".join(result) 引用标注 class CitationGenerator: def __init__(self, llm): self.llm = llm async def generate_with_citations(self, query, retrieved_docs): # 为每个文档分配编号 docs_context = "\n\n".join([ f"[{i+1}] {doc.page_content}" for i, doc in enumerate(retrieved_docs) ]) prompt = f"""基于以下参考资料回答问题。在回答中使用 [编号] 标注信息来源。 参考资料: {docs_context} 问题:{query} 要求: 1. 只使用参考资料中的信息 2. 用 [编号] 标注每条信息的来源 3. 如果资料中没有相关信息,说明"根据现有资料无法回答" """ response = await self.llm.ainvoke(prompt) return response 评估与迭代 RAG评估指标 class RAGEvaluator: def __init__(self, llm): self.llm = llm async def evaluate(self, query, response, retrieved_docs, ground_truth=None): metrics = {} # 1. 检索相关性 metrics["retrieval_relevance"] = await self.eval_retrieval( query, retrieved_docs ) # 2. 回答忠实度(是否基于检索内容) metrics["faithfulness"] = await self.eval_faithfulness( response, retrieved_docs ) # 3. 回答完整性 if ground_truth: metrics["completeness"] = await self.eval_completeness( response, ground_truth ) return metrics async def eval_faithfulness(self, response, docs): """评估回答是否忠实于检索内容""" prompt = f"""判断以下回答是否完全基于给定的参考资料。 参考资料:{' '.join(d.page_content[:200] for d in docs)} 回答:{response} 请输出: 1. 忠实/不忠实 2. 不忠实的部分(如有) """ result = await self.llm.ainvoke(prompt) return "忠实" in result 结语 RAG管线优化是一个系统性工程,从文档分块到检索策略、从上下文管理到生成控制,每个环节都需要精心设计。2026年的RAG最佳实践强调混合检索、重排序、动态上下文管理和引用标注——这些技术组合使用可以显著提升RAG系统的准确性和可靠性。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。 ...

2026-07-02 · 4 min · 748 words · 硅基 AGI 探索者
高级RAG模式2026

高级RAG模式2026:超越简单向量检索的架构演进

引言 基础RAG(检索-增强-生成)已经成为了AI应用的标配:用户提问→检索相关文档→LLM基于文档生成回答。但这种简单模式在面对复杂问题时力不从心。 2026年,RAG架构已经演进出多种高级模式:多跳检索、自适应检索、推理增强检索、迭代检索等。这些模式让RAG系统能够处理更复杂的问题、提供更准确的答案。本文将系统介绍这些高级模式。 一、基础RAG的局限 1.1 单次检索不够 复杂问题需要多步推理和多轮检索: 问题: "对比GPT-4和Claude在代码生成任务上的表现" 基础RAG: 一次检索"GPT-4 Claude 代码生成对比" → 可能找不到直接的对比文档 高级RAG: 检索1: "GPT-4 代码生成性能" 检索2: "Claude 代码生成性能" 检索3: "GPT-4 vs Claude benchmark" → 综合多个来源生成对比 1.2 检索质量不稳定 简单向量检索可能返回语义相关但信息不足的文档。 1.3 缺乏推理能力 基础RAG是"检索+拼接",缺乏对检索结果的推理和整合。 二、多跳检索 2.1 原理 多跳检索(Multi-hop Retrieval)通过多轮检索逐步收集信息,每轮检索基于前一轮的结果。 问题: "那位发明了Transformer的作者后来创立了哪家公司?" 跳1: 检索"Transformer论文作者" → 得到作者列表(包括Ashish Vaswani等) 跳2: 检索"Ashish Vaswani 创立公司" → 得到Adept AI 答案: Adept AI 2.2 实现 class MultiHopRetriever: def __init__(self, retriever, llm, max_hops=3): self.retriever = retriever self.llm = llm self.max_hops = max_hops async def retrieve(self, question): accumulated_context = [] for hop in range(self.max_hops): # 1. 根据当前上下文生成下一步检索查询 if hop == 0: query = question else: query = await self.generate_next_query( question, accumulated_context ) if query is None: # 不需要更多检索 break # 2. 执行检索 results = await self.retriever.search(query, top_k=5) # 3. 过滤和评估结果 relevant = await self.filter_relevant(results, question, accumulated_context) accumulated_context.extend(relevant) # 4. 检查是否已有足够信息回答 if await self.has_enough_info(question, accumulated_context): break return accumulated_context async def generate_next_query(self, question, context): """基于当前上下文生成下一步查询""" prompt = f""" 原始问题: {question} 已知信息: {context} 还需要什么信息才能回答问题?请生成一个搜索查询。 如果已经有足够信息,返回"DONE"。 """ response = await self.llm.call(prompt) if "DONE" in response: return None return response.strip() 三、自适应检索 3.1 原理 不是所有问题都需要检索,也不是所有问题都需要相同类型的检索。自适应检索根据问题特征选择最优的检索策略。 ...

2026-07-02 · 4 min · 807 words · 硅基 AGI 探索者
Agentic RAG

RAG 系统 2026:从基础检索到 Agentic RAG 的演进

引言 检索增强生成(RAG)是2026年最实用的大模型应用架构之一。从基础的"检索-生成"流水线,到Agentic RAG的智能检索代理,RAG技术正在经历深刻的架构演进。本文系统梳理RAG的发展脉络和技术选型。 RAG 的演进阶段 第一阶段:基础 RAG(Naive RAG) 最原始的RAG架构,包含三个步骤: 将文档切分为片段 对片段进行向量化并存储 检索最相关的片段,拼接后输入模型 优点: 简单、快速、易于实现 缺点: 检索质量依赖单一向量相似度,无法处理复杂查询 第二阶段:增强 RAG(Enhanced RAG) 在基础RAG之上增加优化: 查询优化: 查询重写:将用户问题转化为更适合检索的形式 查询分解:将复杂问题拆分为多个子查询 多路检索:同时使用向量检索和关键词检索 后处理: 重排序(Reranking):对检索结果进行精排 上下文压缩:去除冗余片段,保留关键信息 自适应窗口:根据问题类型调整上下文长度 第三阶段:Agentic RAG Agentic RAG的核心思想:让Agent自主决定如何检索、何时检索、检索什么。 ┌─────────────────────────────────────────────┐ │ Agentic RAG 架构 │ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │ Agent │───▶│ 检索 │ │ │ │ 规划器 │ │ 策略 │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ │ │ │ 反思 │◀───│ 多路 │ │ │ │ 与调整 │ │ 检索 │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────────────────┐ │ │ │ 最终生成与验证 │ │ │ └──────────────────────────┘ │ └─────────────────────────────────────────────┘ 主流 RAG 框架对比 LangChain / LangGraph 特点: 生态最丰富,组件最全 适合: 快速原型开发、复杂RAG管线 ...

2026-06-30 · 2 min · 295 words · 硅基 AGI 探索者
GraphRAG 2026:知识图谱增强检索的实践指南

GraphRAG 2026:知识图谱增强检索的实践指南

引言:为什么传统RAG不够用? 传统向量RAG在处理"全局性"问题时表现糟糕。比如你问"2026年AI芯片市场的主要竞争格局是什么?",基于文档块的向量检索只能返回零散片段,无法构建全局视图。Microsoft Research在2024年提出的GraphRAG正是为解决这一痛点而生,到2026年,这套方法已经成熟并衍生出多种变体。 GraphRAG的核心思想:先从文档中抽取实体和关系构建知识图谱,再用社区检测算法将图谱分层聚类,最后基于社区摘要进行全局检索。 GraphRAG架构总览 ┌─────────────────────────────────────────────┐ │ GraphRAG Pipeline │ ├─────────────────────────────────────────────┤ │ 1. Document Chunking (文档分块) │ │ 2. Entity Extraction (实体抽取) │ │ 3. Relationship Building (关系构建) │ │ 4. Community Detection (社区检测) │ │ 5. Community Summarization (社区摘要) │ │ 6. Query-focused Summarization (查询摘要) │ └─────────────────────────────────────────────┘ 两种检索模式 模式 适用场景 原理 延迟 Local Search 具体实体相关问题 从匹配节点出发,遍历相邻实体和关系 低 (200-500ms) Global Search 全局性、摘要性问题 遍历所有社区摘要,Map-Reduce式汇总 高 (2-5s) 环境搭建与代码实践 安装GraphRAG pip install graphrag==0.6.0 初始化项目 # 创建工作目录 mkdir my_graphrag_project && cd my_graphrag_project # 初始化配置 python -m graphrag.init --root . 初始化后会生成以下结构: ...

2026-06-30 · 2 min · 424 words · 硅基 AGI 探索者
鲁ICP备2026018361号