rag rerank strategy

RAG重排序Rerank策略

引言 在RAG系统中,向量检索通常返回Top-K候选文档,但这些文档的排序精度往往不够理想——原因在于向量检索使用的是双塔模型(Bi-Encoder),查询和文档独立编码,无法捕获细粒度的交互特征。重排序(Rerank)通过使用更精细的交叉编码器(Cross-Encoder)对候选文档重新打分,显著提升排序质量。本文深入Rerank策略的原理、模型选择和工程实践。 为什么需要Rerank 双塔模型的局限 向量检索使用双塔模型:查询和文档分别编码为向量,通过点积或余弦相似度计算相关性。这种方式的优势是速度快(可以预计算文档向量),但局限在于: 缺乏交互:查询和文档在编码时没有交互,无法捕获词级别的匹配关系 语义粗粒度:向量相似度高不等于真正相关,可能存在"语义假阳性" 排序精度有限:Top-1的准确率通常只有60-70%,存在改进空间 Cross-Encoder的优势 重排序模型使用Cross-Encoder:将查询和文档拼接在一起输入模型,模型可以捕获两者的细粒度交互特征。这相当于让模型"逐字对比"查询和文档,排序精度远高于双塔模型。 两阶段检索架构 查询 → 向量检索(召回阶段)→ Top-20候选 → Rerank(精排阶段)→ Top-5最终结果 两阶段架构平衡了效率和精度:向量检索负责高效召回,Rerank负责精确排序。 Rerank模型选择 通用Rerank模型 Cohere Rerank:商业API,效果优秀,使用简单: import cohere co = cohere.Client('your-api-key') def cohere_rerank(query, documents, top_n=5): results = co.rerank( model='rerank-multilingual-v3.0', query=query, documents=documents, top_n=top_n ) return [documents[r.index] for r in results.results] BGE-Reranker:开源模型,支持本地部署: from FlagEmbedding import FlagReranker reranker = FlagReranker('BAAI/bge-reranker-large', use_fp16=True) def bge_rerank(query, documents, top_n=5): pairs = [[query, doc] for doc in documents] scores = reranker.compute_score(pairs) # 按分数排序 ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True) return [doc for doc, _ in ranked[:top_n]] bge-reranker-v2-m3:多语言支持,轻量高效: from sentence_transformers import CrossEncoder model = CrossEncoder('BAAI/bge-reranker-v2-m3', max_length=512) def rerank(query, documents, top_n=5): pairs = [[query, doc] for doc in documents] scores = model.predict(pairs) ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True) return [doc for doc, _ in ranked[:top_n]] 模型选择对比 模型 类型 语言支持 延迟 效果 成本 Cohere Rerank API 多语言 中 优秀 按量付费 bge-reranker-large 本地 中英 中 优秀 免费(需GPU) bge-reranker-v2-m3 本地 多语言 低 良好 免费(轻量) ms-marco-MiniLM 本地 英文 低 良好 免费 GPT-4 Rerank API 多语言 高 优秀 高(按token) LLM作为Rerank器 使用LLM对候选文档进行重排序: ...

2026-06-27 · 4 min · 707 words · 硅基 AGI 掐索者
multimodal rag practice

多模态RAG架构实践

概述 多模态RAG架构实践是AI智能体领域中多模态RAG架构实践的重要主题。本文将从多个角度深入分析这一话题,为读者提供系统性的认知框架和实践参考。 核心概念 基本定义 在深入讨论之前,我们需要明确几个核心概念。AI智能体是指能够感知环境、理解指令、规划行动并调用工具完成任务的AI系统。与传统的聊天机器人不同,智能体具有自主性、目标导向性和工具使用能力。 多模态RAG架构实践涉及的关键技术包括: 大语言模型:作为智能体的认知引擎,负责理解、推理和生成 工具调用:通过Function Calling或MCP协议与外部系统交互 记忆系统:短期记忆处理当前对话,长期记忆存储历史经验 规划引擎:将复杂任务分解为可执行的子步骤 技术原理 从技术层面看,多模态RAG架构实践的核心在于如何让AI系统更好地理解和执行人类意图。这涉及多个技术环节的协同: 首先是感知层,智能体需要准确理解用户的自然语言指令,提取关键信息和约束条件。其次是规划层,将高层目标分解为具体的执行步骤。然后是执行层,调用合适的工具完成每个步骤。最后是反馈层,根据执行结果调整后续策略。 实践分析 当前现状 在RAG与微调领域,当前的技术实践呈现出几个明显特征: 工程化程度提升:从实验室原型到生产级系统,工程能力成为关键差异化因素 评估体系完善:越来越多标准化的评测基准被提出,帮助开发者量化能力边界 开源生态繁荣:开源框架和工具链的成熟降低了开发门槛 安全意识增强:对AI安全和对齐问题的重视程度显著提升 关键挑战 尽管进展显著,多模态RAG架构实践仍面临几个核心挑战: 技术挑战: 大模型的幻觉问题在智能体场景下被放大,因为智能体需要做出实际决策 多步推理中的错误累积效应导致长程任务成功率下降 工具调用的可靠性受外部API稳定性影响 工程挑战: 智能体的可观测性不足,调试和排错困难 成本控制与性能优化的平衡 从单机到分布式部署的架构复杂性 安全挑战: Prompt注入等攻击手段不断进化 智能体权限管理需要更精细化的控制 数据隐私保护在多Agent协作场景下更加复杂 优化策略 针对上述挑战,以下是几个关键优化方向: 技术优化 分而治之:将复杂任务分解为可独立验证的子任务,降低单步错误影响 多路投票:对关键决策使用多次采样投票机制,提高可靠性 渐进式信任:智能体权限从最小化开始,根据表现逐步扩展 人在回路:高风险决策保留人工审核环节 工程优化 可观测性优先:建立完善的日志、指标和追踪体系 灰度发布:新版本智能体先在小流量环境验证 自动化测试:构建端到端测试套件,防止回归 成本监控:实时追踪Token消耗和API调用成本 案例研究 为了更具体地说明多模态RAG架构实践的实践价值,我们来看一个典型场景: 某科技公司在内部IT运维中部署了AI智能体,负责处理员工的工单请求。智能体需要理解员工的自然语言描述,判断问题类型,查询知识库,执行修复操作或转接人工。 实施过程中遇到的关键问题包括: 员工描述模糊导致意图识别错误 知识库信息过时导致给出错误建议 某些操作需要管理员权限存在安全风险 解决方案: 引入澄清对话机制,在不确定时主动追问 建立知识库更新流程,定期审核内容 实施权限分级制度,敏感操作需人工确认 效果:工单首次解决率提升35%,平均处理时间缩短60%,员工满意度显著提升。 未来趋势 多模态RAG架构实践的发展趋势值得关注: 标准化:MCP等开放协议将推动工具接口标准化,降低集成成本 垂直化:针对特定行业和场景的专用智能体将大量涌现 协作化:多智能体协作将成为复杂任务的标准解决方案 自主化:智能体的自主决策能力将持续提升,但需要配套的安全机制 结论 多模态RAG架构实践是AI智能体技术发展中的重要一环。无论是技术原理的深入理解,还是实践中的工程优化,都需要系统性思维。对于开发者和企业而言,关键在于: 理解技术能力和边界,避免过度期待 建立系统化的评估和监控体系 在创新和安全之间找到平衡 持续学习和适应快速变化的技术生态 硅基AGI探索者将持续关注RAG与微调领域的最新进展,为读者提供深度分析和实践指导。— ...

2026-06-27 · 1 min · 88 words · 硅基 AGI 探索者
rag vs fine tuning 2026

RAG vs 微调:2026 年的场景选择指南

一个被反复问起的问题 每次与企业客户交流,总会听到这个问题:“我们应该用 RAG 还是微调?“到了 2026 年,这个问题已经有了更清晰的答案——但不是简单的二选一。 随着 RAG 技术的成熟和微调工具链的普及,这两种知识注入策略的适用边界变得更加清晰。同时,新的混合范式也在出现,让"选择"本身变成了一道更精细的工程题。 一、RAG:动态知识的首选 1.1 RAG 的核心优势 RAG(检索增强生成)在 2026 年已经从实验室技术发展为企业级标准方案。它的核心价值在于: 知识时效性:RAG 的知识库可以实时更新。当企业产品文档发生变化时,只需更新向量库中的对应文档,无需重新训练模型。这对于产品迭代频繁的 SaaS 企业至关重要。 可溯源性:RAG 的每个回答都可以追溯到具体的源文档。在金融、医疗、法律等需要严格审计的领域,这一特性是不可替代的。 低成本启动:一个基础的 RAG 系统可以在数天内搭建完成,初期投入通常不超过数万元。而一次完整的模型微调,算力成本就可能达到数十万。 知识隔离:不同用户可以接入不同的知识库,实现知识的细粒度权限控制。这在多租户场景中是刚需。 1.2 RAG 的局限 但 RAG 也并非银弹。在实践中我们观察到几个固有限制: 检索质量天花板:当知识库中存在大量语义相近但含义不同的文档时(如法律条文的不同解释版本),检索的准确率会显著下降。即使用最先进的重排序模型,在 50 万+ 文档的知识库中,Top-5 检索准确率也很难超过 85%。 推理风格不可控:RAG 注入的是"知识”,而非"能力”。如果需要模型以特定的推理风格(如法律分析师的思维模式)回答问题,RAG 无法实现。 上下文窗口压力:即使在 128K 上下文窗口下,注入过多检索结果也会稀释模型对关键信息的注意力。我们在实验中发现,当检索结果超过 5000 token 时,模型对最后 20% 内容的利用率下降约 40%。 二、微调:能力与风格的重塑 2.1 微调的适用场景 微调在 2026 年的主要应用场景可以归纳为三类: 领域适配:让模型掌握特定领域的术语体系、推理范式和表达风格。例如,让通用模型学会以"临床药师"的视角分析药物相互作用。 格式控制:当需要模型稳定输出特定格式(如结构化 JSON、医疗报告模板)时,微调的可靠性远高于提示词工程。 能力注入:某些推理模式(如多步因果分析、特定类型的数学证明)通过少量高质量微调数据可以显著提升。LoRA 微调通常只需要 500-2000 条高质量样本即可见效。 2.2 微调的新范式 2026 年的微调实践出现了几个重要趋势: 偏好对齐微调(DPO/RLHF)成为标配:纯粹的 SFT(监督微调)已经不能满足需求。DPO(Direct Preference Optimization)让开发者可以通过"好回答-坏回答"对来微调模型,无需复杂的奖励模型。 ...

2026-06-26 · 2 min · 268 words · 硅基 AGI 探索者
agent hallucination mitigation

智能体幻觉缓解策略:从检测到修复

幻觉:AGI 之路的隐形地雷 当智能体开始"说话",它就不可避免地会"说错话"。幻觉(Hallucination)——即模型生成看似合理但与事实不符的内容——是 AGI 领域最棘手的安全问题之一。在聊天场景中,幻觉可能只是一次尴尬的回答;但在智能体场景中,幻觉可能导致错误的工具调用、误导性的决策建议,甚至危险的实际操作。 本文将从幻觉的根源出发,系统性地介绍检测、缓解和修复策略,帮助你构建更可信赖的智能体系统。 一、幻觉的根源:为什么会"胡说八道" 1.1 训练数据层面 大模型的幻觉根源深植于其训练过程中: 训练数据的噪声:互联网数据包含大量错误信息、过时信息和矛盾信息。模型在学习时,不可避免地吸收了这些噪声。当它"回忆"某个事实时,可能提取的是错误版本。 知识截止日期:模型的训练数据有截止日期,但世界在不断变化。模型可能自信地回答一个已经过时的事实——比如一个已经废弃的 API 方法。 长尾知识稀疏:对于常见话题,训练数据丰富,模型表现可靠。但在长尾领域(冷门技术、小众领域),训练数据稀疏,模型更容易通过"编造"来填补空白。 1.2 推理机制层面 自回归生成的本质缺陷:模型逐 token 生成文本,每一步都基于前面的内容。一旦早期生成了一个错误的前提,后续内容会围绕这个错误前提展开,形成"幻觉级联"。 缺乏知识边界感知:模型不知道自己"不知道什么"。它没有可靠机制来判断某个问题是否超出了自己的知识范围,因此倾向于对任何问题都给出回答,而不是说"我不知道"。 概率而非检索:模型生成的是"最可能"的答案,而非"最准确"的答案。在需要精确事实的场景中,这种差异就表现为幻觉。 1.3 智能体场景的特殊幻觉 在智能体场景中,幻觉有了新的表现形式: 工具参数幻觉:模型编造不存在的参数值,或混淆不同工具的参数格式 工具结果误解:工具返回了正确结果,但模型在解读时加入了自己的"想象" 调用链幻觉:模型声称调用了某个工具但实际没有,或编造工具调用的返回结果 上下文遗忘幻觉:在长对话中,模型"忘记"了早期确认的事实,生成与之前矛盾的内容 二、幻觉检测:从规则到模型 2.1 基于规则的检测 最基础的检测层是规则匹配: import re from typing import List, Tuple class RuleBasedHallucinationDetector: def __init__(self): self.rules = [ # 数字一致性检查 self._check_number_consistency, # 实体引用检查 self._check_entity_reference, # 日期合理性检查 self._check_date_validity, # 自相矛盾检查 self._check_self_contradiction, ] def _check_number_consistency(self, claim: str, sources: List[str]) -> List[Tuple[str, float]]: issues = [] # 提取声明中的所有数字 claim_numbers = set(re.findall(r'\d+\.?\d*', claim)) for source in sources: source_numbers = set(re.findall(r'\d+\.?\d*', source)) # 检查声明中的数字是否在来源中出现 for num in claim_numbers: if num not in source_numbers: issues.append(( f"数字 '{num}' 在来源中未找到", 0.7 # 置信度 )) return issues def _check_entity_reference(self, claim: str, entities: dict) -> List[Tuple[str, float]]: issues = [] # 检查声明中提到的实体是否存在于已知实体库 claim_entities = self._extract_entities(claim) for entity in claim_entities: if entity not in entities: issues.append(( f"实体 '{entity}' 不在已知实体库中", 0.6 )) return issues def _check_date_validity(self, claim: str) -> List[Tuple[str, float]]: issues = [] dates = re.findall(r'\d{4}年\d{1,2}月\d{1,2}日', claim) for date_str in dates: # 检查日期是否合理(如未来的日期、不可能的日期) try: from datetime import datetime d = datetime.strptime(date_str, '%Y年%m月%d日') if d.year < 1900 or d.year > 2100: issues.append((f"日期 '{date_str}' 不合理", 0.8)) except ValueError: issues.append((f"日期 '{date_str}' 格式无效", 0.9)) return issues def _check_self_contradiction(self, claim: str, history: List[str]) -> List[Tuple[str, float]]: issues = [] # 简化的矛盾检测:检查是否与历史声明中的数字/日期矛盾 for prev in history: prev_numbers = set(re.findall(r'\d+\.?\d*', prev)) claim_numbers = set(re.findall(r'\d+\.?\d*', claim)) # 如果同一话题但数字不同,可能存在矛盾 overlap = self._semantic_overlap(prev, claim) if overlap > 0.5: if prev_numbers != claim_numbers and prev_numbers and claim_numbers: issues.append(( f"与历史声明可能矛盾: 之前说 {prev_numbers}, 现在说 {claim_numbers}", overlap * 0.8 )) return issues 2.2 基于模型的检测 更高级的检测方案使用专门的模型来判断幻觉: ...

2026-06-26 · 5 min · 882 words · 硅基 AGI 探索者
embedding model guide

Embedding 模型选型指南:bge vs e5 vs OpenAI vs Cohere

前言 Embedding 模型是 RAG(检索增强生成)系统和语义搜索的基石。一个优秀的 Embedding 模型可以让你的向量数据库"更聪明"地理解语义,大幅提升下游 LLM 的回答质量。2026 年,Embedding 模型领域迎来了多语言、长文本和多粒度的重要进展。本文将全面对比四款主流 Embedding 模型,帮助你为 RAG 系统选择最合适的向量引擎。 一、为什么 Embedding 选型如此重要? 1.1 Embedding 在 RAG 中的角色 用户查询 → [Embedding 模型] → 查询向量 ↓ 知识库文档 → [Embedding 模型] → 文档向量 → 向量数据库 ↓ 向量相似度检索 → Top-K 结果 ↓ [LLM] → 生成回答 Embedding 模型决定了检索的质量上限。 即使 LLM 再强大,如果检索阶段召回的文档不相关,最终回答也会大打折扣。这就是所谓的"垃圾进,垃圾出"(Garbage In, Garbage Out)。 1.2 好的 Embedding 模型的标准 标准 说明 重要性 语义区分度 能区分近义但不同的概念 ⭐⭐⭐⭐⭐ 多语言一致性 同一概念在不同语言下向量接近 ⭐⭐⭐⭐ 长文本处理 支持段落/篇章级 Embedding ⭐⭐⭐⭐ 多粒度 同时支持短查询和长文档 ⭐⭐⭐⭐ 推理速度 编码延迟低 ⭐⭐⭐⭐ 维度适中 存储和检索效率高 ⭐⭐⭐ 开箱即用 无需复杂微调 ⭐⭐⭐ 二、参评模型概览 模型 开发商 参数量 向量维度 最大输入 多语言 开源 BGE-M3 智源研究院 568M 1024 8192 ✅ 100+ 语言 ✅ E5-Mistral-7B Microsoft 7B 4096 32768 ✅ 100+ 语言 ✅ OpenAI text-embedding-3-large OpenAI 未知 3072 (可截断) 8191 ✅ ❌ Cohere embed-v4 Cohere 未知 1536 512 ✅ 100+ 语言 ❌ GTE-Qwen2-7B 阿里云 7B 3584 32768 ✅ ✅ stella-v5-1.5B PDLN 1.5B 1536 16384 ✅ ✅ 三、基准测试对比 3.1 MTEB 排行榜(主流基准) MTEB(Massive Text Embedding Benchmark)是 Embedding 领域最权威的综合评测,覆盖 8 类任务、58 个数据集。 ...

2026-06-25 · 6 min · 1078 words · AI 实战派
graph rag explained

GraphRAG 解析:知识图谱增强的检索增强生成

GraphRAG 解析:知识图谱增强的检索增强生成 引言 传统 RAG 基于向量相似度检索文档块,存在三个结构性缺陷: 多跳推理弱:答案需要关联多个文档中的实体关系时,向量检索难以覆盖 全局视角缺失:只返回局部相关片段,无法回答「整个文档集的主要主题是什么」 实体消歧差:同名实体或指代关系容易混淆 GraphRAG(微软 2024 年提出)通过知识图谱 + 层级社区摘要解决这些问题,在全局性问题上显著优于传统 RAG。 1. GraphRAG 架构总览 原始文档 ↓ [1] 文本分块 ↓ [2] 实体 & 关系抽取(LLM) ↓ [3] 知识图谱构建(实体节点 + 关系边) ↓ [4] 社区检测(Leiden 算法) ↓ [5] 层级社区摘要(LLM) ↓ [6] 检索:局部检索(实体子图) + 全局检索(社区摘要) ↓ [7] 生成 1.1 与传统 RAG 的关键差异 维度 传统 RAG GraphRAG 检索单元 文档块(文本片段) 实体、关系、社区摘要 索引结构 向量索引 图结构 + 向量索引 多跳推理 ❌ 依赖单次检索 ✅ 图遍历天然支持 全局问题 ❌ 只看局部片段 ✅ 社区摘要提供全局视角 构建成本 低(嵌入即可) 高(需 LLM 抽取实体) 查询延迟 低(向量检索) 中高(图检索+摘要) 2. 实体与关系抽取 2.1 LLM 驱动的信息抽取 GraphRAG 使用 LLM 从文本块中抽取实体和关系: ...

2026-06-25 · 9 min · 1710 words · AI 实战派
rag production pitfalls

RAG 生产环境 12 大坑及解决方案

引言 RAG(Retrieval-Augmented Generation)是当前最流行的 LLM 应用架构之一。然而,从 Demo 到生产之间横亘着巨大的鸿沟。本文基于多个 RAG 生产项目的实战经验,总结 12 个最常见、最致命的坑,并给出经过验证的解决方案。 坑 1:文档分块策略不当 问题 天真地按固定长度分块(如每 512 字符),导致: 语义被截断(一个完整的段落从中间切断) 关键信息分散在多个块中,检索时只命中一部分 表格和列表被拆碎,失去结构信息 解决方案:语义分块 + 重叠窗口 from dataclasses import dataclass from typing import List import re @dataclass class Chunk: text: str metadata: dict token_count: int = 0 class SemanticChunker: """基于语义边界的智能分块器""" def __init__( self, target_size: int = 400, # 目标块大小(tokens) min_size: int = 100, # 最小块大小 max_size: int = 600, # 最大块大小 overlap: int = 50, # 重叠区间 ): self.target_size = target_size self.min_size = min_size self.max_size = max_size self.overlap = overlap def chunk_document(self, text: str, source: str = "") -> List[Chunk]: """分块主流程""" # Step 1: 按结构边界切分 sections = self._split_by_structure(text) # Step 2: 对每个 section 按 paragraph 切分 paragraphs = [] for section in sections: paragraphs.extend(self._split_by_paragraph(section)) # Step 3: 合并过小的段落,拆分过大的段落 chunks = self._merge_and_split(paragraphs) # Step 4: 添加重叠 chunks = self._add_overlap(chunks) # Step 5: 附加元数据 return [ Chunk( text=c, metadata={"source": source, "chunk_index": i, "total_chunks": len(chunks)}, token_count=len(c) // 2, # 粗略估算 ) for i, c in enumerate(chunks) ] def _split_by_structure(self, text: str) -> List[str]: """按标题、分隔符等结构边界切分""" # 按 Markdown 标题切分 pattern = r'(?=^#{1,6}\s)' sections = re.split(pattern, text, flags=re.MULTILINE) return [s.strip() for s in sections if s.strip()] def _split_by_paragraph(self, text: str) -> List[str]: """按段落(双换行)切分""" paras = text.split("\n\n") return [p.strip() for p in paras if p.strip()] def _merge_and_split(self, paragraphs: List[str]) -> List[str]: """合并过小段落,拆分过大段落""" chunks = [] buffer = [] buffer_size = 0 for para in paragraphs: para_size = len(para) // 2 # 粗略 token 估算 if buffer_size + para_size > self.max_size and buffer: chunks.append("\n\n".join(buffer)) buffer = [] buffer_size = 0 if para_size > self.max_size: # 单段落过长,按句子切分 if buffer: chunks.append("\n\n".join(buffer)) buffer = [] buffer_size = 0 sentences = re.split(r'(?<=[。!?.!?])\s+', para) sent_buffer = [] sent_size = 0 for sent in sentences: if sent_size + len(sent) // 2 > self.max_size and sent_buffer: chunks.append(" ".join(sent_buffer)) sent_buffer = [] sent_size = 0 sent_buffer.append(sent) sent_size += len(sent) // 2 if sent_buffer: chunks.append(" ".join(sent_buffer)) else: buffer.append(para) buffer_size += para_size if buffer_size >= self.target_size: chunks.append("\n\n".join(buffer)) buffer = [] buffer_size = 0 if buffer: chunks.append("\n\n".join(buffer)) return chunks def _add_overlap(self, chunks: List[str]) -> List[str]: """为相邻块添加重叠""" if self.overlap <= 0 or len(chunks) <= 1: return chunks result = [chunks[0]] for i in range(1, len(chunks)): prev_text = chunks[i - 1] overlap_text = prev_text[-self.overlap * 2:] # 粗略取后半段 result.append(overlap_text + " " + chunks[i]) return result # 使用示例 chunker = SemanticChunker(target_size=400, overlap=50) document = open("knowledge_base/product_manual.md").read() chunks = chunker.chunk_document(document, source="product_manual.md") print(f"分块完成: {len(chunks)} 个块") 分块策略对比 策略 优点 缺点 适用场景 固定长度 实现简单 语义截断 不推荐 按段落 保持语义 块大小不均 短文档 语义分块 语义完整 实现复杂 通用推荐 按文档结构 保持层级 需要结构化输入 Markdown/HTML 递归分块 灵活适配 可控性差 混合内容 坑 2:Embedding 模型与 LLM 不匹配 问题 用 OpenAI 的 text-embedding-3-large 做向量,但生成用的是 Claude 模型。两者对语义的理解不同,可能导致检索到的内容并非生成模型"认为"最相关的。 ...

2026-06-25 · 9 min · 1827 words · AI 实战派
rag reranking guide

RAG 重排序指南:Cohere Rerank vs bge-reranker vs Cross-Encoder

RAG 重排序指南:Cohere Rerank vs bge-reranker vs Cross-Encoder 引言 RAG 系统的标准流程是:向量检索 Top-K → 直接喂给 LLM。但向量检索(双塔模型)的弱点是精度有限:它擅长快速召回大量相关文档,但不擅长精细区分「真正相关」和「看起来相关」。 重排序(Reranking)是解决这一问题的关键环节:用一个更强大的模型对检索结果重新打分排序,将最相关的文档排到前面。 Query → 向量检索 Top-50 → 重排序 → Top-5 → LLM 生成 本文深入对比三种主流重排序方案。 1. 为什么需要重排序? 1.1 双塔 vs 交叉编码器 特性 双塔模型(Bi-Encoder) 交叉编码器(Cross-Encoder) 架构 Query 和 Doc 独立编码 Query 和 Doc 拼接后联合编码 交互 无(仅在最后做余弦相似度) 全程(Attention 层交互) 精度 中 高 速度 极快(可预计算索引) 慢(每对 Q-D 需独立前向) 用途 初筛召回 精排 1.2 RAG 中的两阶段检索 # 两阶段检索流程 def two_stage_retrieve( query: str, vector_index, # 双塔向量索引 reranker, # 交叉编码器重排序 first_stage_k: int = 50, # 初筛数量 final_k: int = 5, # 最终数量 ) -> list: # Stage 1: 向量检索(快,召回多) candidates = vector_index.search(query, top_k=first_stage_k) # Stage 2: 重排序(精,筛少) pairs = [(query, doc["content"]) for doc in candidates] scores = reranker.predict(pairs) # 排序并取 Top-K ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True) return [doc for doc, score in ranked[:final_k]] 1.3 效果提升 指标 无重排序 有重排序 提升 Top-1 准确率 62.3% 78.1% +15.8% Top-5 召回率 81.2% 91.5% +10.3% MRR 0.681 0.832 +0.151 2. 方案一:Cohere Rerank API 2.1 概述 Cohere Rerank 是托管的商业重排序 API,基于自家训练的 rerank 模型,支持多语言。 ...

2026-06-25 · 6 min · 1258 words · AI 实战派
advanced rag patterns

高级 RAG 模式:HyDE、CRAG、Self-RAG 与 FLARE

高级 RAG 模式:HyDE、CRAG、Self-RAG 与 FLARE 引言 基础 RAG(检索→增强→生成)在真实场景中常遇到三大瓶颈:语义鸿沟(用户问题与文档用词不一致)、检索噪声(相关度低的片段污染上下文)、一次性检索(无法根据生成过程动态调整)。高级 RAG 模式针对这些问题提出了系统性解法。 本文深入解析四种最具代表性的高级 RAG 模式,给出可运行的 Python 实现,并在最后提供综合对比。 1. HyDE(Hypothetical Document Embeddings) 核心思想 HyDE 的核心洞察:用 LLM 先生成一个「假设答案」,再用这个假设的嵌入去检索,而非直接用用户问题检索。 原因是:假设答案在语义空间中比原始问题更接近真实文档,尤其当用户问题很短或措辞与知识库不一致时。 用户问题 → LLM 生成假设文档 → 嵌入假设文档 → 向量检索 → 真实文档 → 最终生成 算法流程 接收用户查询 q 令 LLM 生成 k 个假设文档 {d₁, d₂, ..., dₖ}(不要求事实正确,只要求语义相关) 对每个假设文档计算嵌入向量 hᵢ = embed(dᵢ) 取平均(或最大池化)得到查询嵌入 h_q = mean(h₁, ..., hₖ) 在向量库中检索 Top-K 最相似的真实文档 将真实文档作为上下文,令 LLM 生成最终答案 代码实现 import numpy as np from typing import List, Dict from openai import OpenAI client = OpenAI() def hyde_retrieve( query: str, index, # faiss/chroma 等向量索引 embed_model, # 嵌入模型 k_hypothetical: int = 3, # 假设文档数量 top_k: int = 5, # 最终检索数量 temperature: float = 0.7, ) -> List[Dict]: """ HyDE 检索:生成假设文档 → 嵌入 → 检索真实文档 """ # Step 1: 生成假设文档 hypothetical_docs = [] for _ in range(k_hypothetical): resp = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "你是一个知识丰富的助手。请根据用户问题,撰写一段可能回答该问题的文档片段。不需要事实完全准确,重点是覆盖相关概念和关键词。"}, {"role": "user", "content": f"问题:{query}"} ], temperature=temperature, ) hypothetical_docs.append(resp.choices[0].message.content) # Step 2: 嵌入假设文档 hyp_embeddings = embed_model.encode(hypothetical_docs) # shape: (k, dim) query_embedding = hyp_embeddings.mean(axis=0, keepdims=True) # 平均池化 # Step 3: 检索真实文档 distances, indices = index.search(query_embedding.astype(np.float32), top_k) results = [{"index": idx, "score": dist} for idx, dist in zip(indices[0], distances[0])] return results # 单文档 HyDE(k=1 的简化版) def hyde_single(query: str, index, embed_model, top_k: int = 5): """单假设文档版本,速度更快""" resp = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "写一个可能回答问题的段落,覆盖相关关键词。"}, {"role": "user", "content": query} ], temperature=0.7, ) hypo_doc = resp.choices[0].message.content q_emb = embed_model.encode([hypo_doc]) distances, indices = index.search(q_emb.astype(np.float32), top_k) return indices[0].tolist(), distances[0].tolist() 适用场景与局限 场景 适合度 说明 短查询 / 口语化问题 ⭐⭐⭐⭐⭐ 假设文档补充了语义上下文 专业术语与用户措辞差异大 ⭐⭐⭐⭐⭐ 假设文档桥接了术语鸿沟 多跳推理问题 ⭐⭐⭐⭐ 假设文档可覆盖多个推理步骤 低延迟要求 ⭐⭐ 需要额外一次 LLM 调用 事实敏感场景(医疗/法律) ⭐⭐⭐ 假设文档可能引入错误事实,需后处理 2. CRAG(Corrective RAG) 核心思想 CRAG 引入检索质量评估器,在检索后对文档相关性进行打分,动态决定: ...

2026-06-25 · 5 min · 984 words · AI 实战派
fine tuning vs rag decision

微调 vs RAG:什么场景该选什么方案

引言 “我们应该微调还是用 RAG?"——这是 2024-2026 年 AI 工程师被问得最多的问题。两者都能让 LLM 适配特定领域,但适用场景截然不同。本文不给标准答案,而是给一个决策框架。 核心差异:先理解本质 微调(Fine-tuning) 微调是改变模型内部权重,让模型"学会"新的知识或行为模式。 原始模型 → 注入领域数据 → 新权重 → 直接推理 RAG(检索增强生成) RAG是不改变模型,在推理时"查阅"外部知识库。 用户问题 → 检索知识库 → 拼接到 Prompt → 模型生成答案 本质对比 维度 微调 RAG 知识存储位置 模型权重中 外部数据库中 知识更新方式 重新训练 更新数据库 推理时依赖 无外部依赖 需要检索系统 “记忆"方式 隐式(权重) 显式(文本) 幻觉风险 较高(知识编码不精确) 较低(有原文参考) 知识溯源 无法溯源 可追溯到来源文档 决策框架:7 个关键问题 问题 1:知识更新频率多高? 更新频率 │ ├─ 每日/每周更新 ──────→ RAG ✅ │ (产品目录、新闻、工单) │ ├─ 每月/每季度更新 ─────→ RAG 或混合 │ (技术文档、政策) │ └─ 几乎不变 ───────────→ 微调 ✅ (行业术语、品牌语调) 原理:微调每次更新知识都需要重新训练(数小时到数天),RAG 只需更新数据库(秒级)。 ...

2026-06-25 · 6 min · 1210 words · AI 实战派
鲁ICP备2026018361号