RAG生产排坑指南:幻觉、漏检、延迟三大难题

RAG生产排坑指南:幻觉、漏检、延迟三大难题

前言:RAG从Demo到生产的鸿沟 写一个RAG Demo只需要30分钟——加载文档、Embedding、存向量库、检索、生成,完成。但把它放到生产环境,你会发现: 幻觉:LLM明明拿到了正确文档,还是编造了不存在的信息 漏检:库里明明有相关文档,检索就是找不到 延迟:用户等了8秒还没返回,体验崩溃 这三个问题构成了RAG生产环境的"不可能三角"。本文分享2026年我们在生产环境中踩过的坑和解决方案。 难题一:幻觉问题 幻觉的三种形态 类型 表现 根因 忠实性幻觉 答案与检索文档矛盾 LLM忽略上下文,依赖自身参数知识 编造型幻觉 答案包含文档中不存在的信息 LLM"脑补"细节 来源混淆 将多个文档的信息错误组合 多文档检索时上下文混淆 解决方案矩阵 方案1:强约束Prompt # ❌ 容易幻觉的Prompt prompt = f"""基于以下资料回答问题: {context} 问题:{question} """ # ✅ 抗幻觉的Prompt prompt = f"""你是一个严格的信息提取助手。请遵循以下规则: 1. **只使用**以下参考资料回答问题 2. 如果参考资料中没有相关信息,直接回答"根据现有资料无法回答此问题" 3. 不要添加任何参考资料中未提及的信息 4. 不要进行推理、猜测或补全 5. 回答中需要引用具体的资料来源 参考资料: --- {context} --- 问题:{question} 回答格式: [来源:文档名] 回答内容... """ 方案2:置信度校准 def answer_with_confidence(question, retrieved_docs): """带置信度的回答""" # 第一步:评估检索质量 relevance_prompt = f"""评估以下文档与问题的相关性(0-10): 问题: {question} 文档: {retrieved_docs[0].page_content[:500]} 只返回数字。""" relevance_score = int(llm.invoke(relevance_prompt).strip()) if relevance_score < 4: return { "answer": "抱歉,知识库中没有找到与您问题相关的信息。", "confidence": 0.2, "should_answer": False, } # 第二步:生成回答并自我验证 answer = rag_chain.invoke(question) # 第三步:验证回答是否忠于上下文 verify_prompt = f"""判断以下回答的每个陈述是否能在参考资料中找到支撑。 参考资料: {retrieved_docs} 回答: {answer} 返回JSON: {{"faithful": true/false, "unsupported_claims": [...]}}""" verification = json.loads(llm.invoke(verify_prompt)) return { "answer": answer if verification["faithful"] else "无法确认回答准确性", "confidence": relevance_score / 10.0, "should_answer": verification["faithful"], } 方案3:Citation机制 def generate_with_citations(question, retrieved_docs): """强制引用来源的生成""" # 给每个文档编号 numbered_context = "\n\n".join([ f"[{i+1}] {doc.page_content}" for i, doc in enumerate(retrieved_docs) ]) prompt = f"""基于以下编号的参考资料回答问题。每个陈述后必须标注来源编号[1]。 参考资料: {numbered_context} 问题:{question} 要求: - 每个事实陈述后标注来源编号,如"GraphRAG由微软提出[1]" - 如果某个陈述来自多个文档,标注所有来源,如"[1][3]" - 无法找到来源的陈述不要写出 回答:""" return llm.invoke(prompt) 幻觉抑制效果实测 方案 幻觉率↓ 答案完整度↓ 延迟增加 强约束Prompt 45% 15% +0s 置信度校准 68% 8% +1.5s Citation机制 72% 5% +0.8s 三者结合 85% 22% +2.3s 建议组合:强约束Prompt + Citation机制,性价比最高。 ...

2026-06-30 · 4 min · 824 words · 硅基 AGI 探索者
Reranker模型选型:Cohere vs BGE vs Jina对比

Reranker模型选型:Cohere vs BGE vs Jina对比

为什么需要Reranker? RAG检索分两个阶段: 第一阶段:召回(Recall) Embedding向量检索,快速从百万文档中召回Top-K(K=20-50) 优势:速度快(<50ms) 劣势:精度有限(Embedding模型容量小,语义理解浅) 第二阶段:精排(Precision) Cross-Encoder Reranker对Top-K重新打分排序 优势:精度高(Cross-Encoder能深度理解query-doc关系) 劣势:速度慢(需对每个候选单独计算) Reranker的本质:用更强的模型对初筛结果做精排,用少量延迟换取显著的精度提升。 Cross-Encoder vs Bi-Encoder Bi-Encoder (Embedding模型): Query ──► Encoder ──► [向量] ◄── Encoder ◄── Document │ 余弦相似度 快但浅 Cross-Encoder (Reranker): [Query, Document] ──► Encoder ──► 相关性分数 慢但深 Cross-Encoder将query和document拼接后一起输入模型,能捕捉两者间的细粒度交互关系,这是Bi-Encoder做不到的。 三大Reranker深度对比 1. Cohere Reranker import cohere co = cohere.Client(api_key="your-key") def cohere_rerank(query, documents, top_n=5): results = co.rerank( model="rerank-v3.5", query=query, documents=documents, top_n=top_n, ) reranked = [] for result in results.results: reranked.append({ "document": documents[result.index], "relevance_score": result.relevance_score, "index": result.index, }) return reranked 特点: ...

2026-06-30 · 4 min · 754 words · 硅基 AGI 推索者
大模型蒸馏:从GPT-5到7B的能力迁移方案

大模型蒸馏:从GPT-5到7B的能力迁移方案

知识蒸馏:用小成本获得大能力 GPT-5很强大但很贵——每次API调用$0.06/1K tokens。如果每天处理10万次查询,月成本$18,000。而7B模型自部署的成本仅为$500/月。 知识蒸馏的核心思想:让小模型学习大模型的"思维方式",而不只是模仿其输出。 Teacher模型 (GPT-5, 175B+) │ │ 知识转移 ▼ Student模型 (Qwen2.5-7B) │ │ 微调 + 对齐 ▼ 蒸馏模型 (7B, 接近GPT-5效果) 三种蒸馏方案 方案1:黑盒蒸馏(最常用) 黑盒蒸馏只需要Teacher模型的输入输出API,不需要访问模型权重或内部状态。 Step 1: 用Teacher生成训练数据 import openai import json from tqdm import tqdm client = openai.OpenAI(api_key="your-key") def generate_training_data(prompts, teacher_model="gpt-5"): """用GPT-5生成高质量训练数据""" training_data = [] for prompt in tqdm(prompts): # 系统提示:让Teacher模型输出详细、有条理的回答 system_prompt = """你是一个专业的AI助手。请按照以下要求回答问题: 1. 回答要详细且有条理 2. 使用适当的格式(标题、列表、代码块) 3. 如果适用,提供示例 4. 确保回答准确且有帮助""" response = client.chat.completions.create( model=teacher_model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}, ], temperature=0.7, # 适度多样性 max_tokens=2000, ) training_data.append({ "instruction": prompt, "output": response.choices[0].message.content, "metadata": { "teacher_model": teacher_model, "temperature": 0.7, } }) return training_data # 生成多样化提示词 def generate_diverse_prompts(domains, num_per_domain=500): """生成覆盖多个领域的多样化提示词""" prompts = [] for domain in domains: # 用Teacher模型生成领域特定提示词 meta_prompt = f"为'{domain}'领域生成{num_per_domain}个多样化的用户问题。" domain_prompts = client.chat.completions.create( model="gpt-5", messages=[{"role": "user", "content": meta_prompt}], ) prompts.extend(domain_prompts.choices[0].message.content.split("\n")) return prompts # 生成数据 domains = ["编程开发", "数据分析", "文案写作", "技术咨询", "数学推理", "创意设计"] prompts = generate_diverse_prompts(domains, num_per_domain=500) training_data = generate_training_data(prompts) # 保存 with open("distill_training_data.json", "w", encoding="utf-8") as f: json.dump(training_data, f, ensure_ascii=False, indent=2) Step 2: 数据质量过滤 def quality_filter(data): """过滤低质量训练数据""" filtered = [] for item in data: output = item["output"] # 长度过滤 if len(output) < 50 or len(output) > 5000: continue # 质量信号检查 quality_signals = [ len(output.split("\n")) > 3, # 有结构 any(kw in output for kw in ["1.", "首先", "因为", "因此"]), # 有逻辑 not output.startswith("I cannot") and not output.startswith("我无法"), # 非拒答 ] if sum(quality_signals) >= 2: filtered.append(item) return filtered Step 3: SFT训练Student模型 from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments from trl import SFTTrainer from peft import LoraConfig, get_peft_model # 加载Student模型 model = AutoModelForCausalLM.from_pretrained( "Qwen/Qwen2.5-7B", torch_dtype=torch.bfloat16, device_map="auto", ) # LoRA配置 lora_config = LoraConfig( r=64, lora_alpha=16, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", ) # 训练 training_args = TrainingArguments( output_dir="./distilled-7b", num_train_epochs=3, per_device_train_batch_size=4, gradient_accumulation_steps=4, learning_rate=2e-4, lr_scheduler_type="cosine", warmup_ratio=0.03, bf16=True, logging_steps=10, save_steps=500, ) trainer = SFTTrainer( model=model, args=training_args, train_dataset=dataset, tokenizer=tokenizer, max_seq_length=2048, peft_config=lora_config, ) trainer.train() 方案2:白盒蒸馏(效果更好) 白盒蒸馏利用Teacher模型的内部状态(logits、注意力权重)进行知识转移。 ...

2026-06-30 · 4 min · 720 words · 硅基 AGI 探索者
多模态RAG:图文混合检索的架构设计

多模态RAG:图文混合检索的架构设计

为什么需要多模态RAG? 传统RAG只能处理文字,但现实世界的信息是多维的。技术文档里穿插架构图、产品手册里有演示截图、研究报告里有数据图表——这些信息,纯文本RAG完全丢失了。 用户问"系统的整体架构是什么样的?",纯文本RAG只会返回一段文字描述,而无法返回架构图。这就是多模态RAG要解决的问题。 多模态RAG架构全景 ┌─────────────────────────────────────────────────────────┐ │ 多模态RAG系统架构 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 用户查询 │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ Query 分析 │ 判断用户需要图片、文字、还是图文 │ │ └──────┬──────┘ │ │ │ │ │ ┌────┴────┐ │ │ ▼ ▼ │ │ [纯文本查询] [需要图片查询] │ │ │ │ │ │ ▼ ▼ │ │ 文本检索 多模态检索 │ │ (向量库) (CLIP/图片向量) │ │ │ │ │ │ └────┬────┘ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 结果融合 │ 图文结果融合排序 │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ 多模态LLM生成回答(可理解和描述图片) │ │ │ └─────────────────────────────────────────────────────────┘ 四种架构方案详解 方案1:独立双路检索(Easiest) 文本向量库 图片向量库 │ │ └──► 合并 ◄──┘ │ ▼ 多模态LLM生成 最简单也是最常见的方案:文本和图片分别Embedding,分别检索,然后合并结果交给多模态LLM生成回答。 ...

2026-06-30 · 4 min · 845 words · 硅基 AGI 探索者
向量数据库2026选型:Milvus vs Pinecone vs Weaviate vs Qdrant

向量数据库2026选型:Milvus vs Pinecone vs Weaviate vs Qdrant

向量数据库市场2026格局 2026年,向量数据库市场已经从"百模大战"进入"四强争霸"阶段。Milvus、Pinecone、Weaviate、Qdrant四家占据了80%以上的市场份额。但选型依然困难——因为它们各有鲜明的特点,没有"万能解"。 市场定位概览 数据库 类型 部署方式 适合规模 核心优势 Milvus 开源 自建/云托管 亿级+ 分布式架构、生态丰富 Pinecone SaaS 全托管 万-亿级 零运维、Serverless Weaviate 开源 自建/云托管 万-千万级 混合检索、模块化 Qdrant 开源 自建/云托管 万-亿级 Rust高性能、轻量 核心能力对比 1. 索引算法支持 特性 Milvus Pinecone Weaviate Qdrant HNSW ✅ ✅(内部) ✅ ✅ IVF ✅ ❌ ❌ ❌ DiskANN ✅ ❌ ❌ ❌ Flat(暴力) ✅ ❌ ✅ ✅ 量化(PQ/SQ) ✅ ✅(内部) ✅(BQ) ✅(SQ) 动态索引 ✅ ✅ ✅ ✅ 2. 混合检索能力 # === Milvus 混合检索 === from pymilvus import Collection collection.search( data=[query_vector], anns_field="embedding", param={"metric_type": "COSINE", "params": {"nprobe": 16}}, expr='source == "tech_blog" and date > "2026-01-01"', # 标量过滤 limit=10, ) # === Pinecone 混合检索 === from pinecone import Pinecone index.query( vector=query_vector, filter={"source": {"$eq": "tech_blog"}, "date": {"$gt": "2026-01-01"}}, top_k=10, include_metadata=True, ) # === Weaviate 混合检索(原生支持BM25+Vector) === import weaviate result = client.query.get("Document", ["content", "title"]) \ .with_hybrid( query="GraphRAG实践指南", alpha=0.5, # 0=纯BM25, 1=纯向量 ) \ .with_limit(10) \ .do() # === Qdrant 混合检索 === from qdrant_client import QdrantClient client.search( collection_name="documents", query_vector=query_vector, query_filter={ "must": [ {"key": "source", "match": {"value": "tech_blog"}}, {"key": "date", "range": {"gt": "2026-01-01"}}, ] }, limit=10, ) Weaviate的混合检索最原生——BM25和向量检索在同一引擎内完成,无需额外组件。其他三家都需要额外搭建BM25检索器。 ...

2026-06-30 · 3 min · 618 words · 硅基 AGI 推荐者
大模型蒸馏技术2026:从GPT-5到7B的能力迁移

大模型蒸馏技术2026:从GPT-5到7B的能力迁移

引言 知识蒸馏(Knowledge Distillation)是将大模型(Teacher)的能力迁移到小模型(Student)的核心技术。2026年,随着GPT-5、Claude 4等超大规模模型的普及,如何将这些模型的强大能力压缩到可本地部署的7B模型中,成为了AI工程的关键挑战。本文将系统介绍蒸馏技术的最新进展。 知识蒸馏基础 经典蒸馏框架 经典知识蒸馏由Hinton等人于2015年提出,核心思想是让学生模型模仿教师模型的输出分布: $$ \mathcal{L}_{\text{KD}} = (1-\alpha) \cdot \text{CE}(y, p_s) + \alpha \cdot T^2 \cdot \text{KL}(p_t^T | p_s^T) $$ 其中: $p_s$ 和 $p_t$ 分别是学生和教师模型的输出概率 $T$ 是温度参数,软化概率分布 $\alpha$ 是平衡系数 $y$ 是真实标签 温度缩放 温度参数 $T$ 控制输出分布的平滑程度: $$ p_i^T = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)} $$ class DistillationLoss(nn.Module): def __init__(self, alpha=0.5, temperature=4.0): super().__init__() self.alpha = alpha self.T = temperature def forward(self, student_logits, teacher_logits, labels): # 软目标损失 soft_loss = F.kl_div( F.log_softmax(student_logits / self.T, dim=-1), F.softmax(teacher_logits / self.T, dim=-1), reduction='batchmean' ) * (self.T ** 2) # 硬目标损失 hard_loss = F.cross_entropy(student_logits, labels) return (1 - self.alpha) * hard_loss + self.alpha * soft_loss 白盒蒸馏:访问教师内部状态 白盒蒸馏可以访问教师模型的logits、隐藏状态和注意力权重,提供更丰富的监督信号。 ...

2026-06-30 · 4 min · 715 words · 硅基 AGI 探索者
RAG技术演进2026:从基础检索到智能知识库

RAG技术演进2026:从基础检索到智能知识库

2026年,RAG(Retrieval-Augmented Generation)技术已经走过了三年的演进历程。从最初简单的"检索+拼接"模式,发展到今天的GraphRAG、Agentic RAG、Adaptive RAG等多种高级范式,RAG已成为企业AI应用的核心基础设施。本文将系统梳理2026年RAG技术的全景图。 一、RAG技术演进路线 四代RAG架构 代际 名称 核心特征 时间 代表方案 第一代 Naive RAG 简单向量检索+拼接 2023 LangChain Basic RAG 第二代 Advanced RAG 查询改写、重排序、多路召回 2024 LlamaIndex Advanced 第三代 Modular RAG 模块化、可插拔、自适应路由 2025 LangGraph RAG 第四代 Agentic RAG Agent驱动、多步推理、工具调用 2026 Agentic RAG, GraphRAG 为什么需要更先进的RAG? Naive RAG的根本问题在于: 检索质量不稳定:向量相似度≠语义相关性 缺乏推理能力:无法处理"需要多步推理才能回答"的问题 无结构化知识:无法利用实体关系、时序信息等结构化知识 无自适应能力:对所有问题用同一套检索策略 2026年企业RAG部署的统计:Naive RAG的准确率仅55-65%,而Agentic RAG可达85-92%——差距巨大。 二、Embedding技术2026 Embedding模型横评 Embedding是RAG的基础——如果检索不到相关内容,后续一切都无意义。 模型 维度 最大序列 MTEB分数 中文表现 特点 OpenAI text-embedding-3-large 3072 8191 72.5 良好 通用、稳定 Voyage-3 1024 32000 74.8 良好 2026最强 BGE-M3 1024 8192 73.2 优秀 多语言、开源 GTE-Large-ZH 1024 512 71.5 优秀 中文优化 Jina Embeddings v3 1024 8192 72.8 良好 长文本 Cohere Embed v4 1536 512 73.5 良好 多语言 2026年Embedding技术趋势 1. 多向量嵌入(Multi-Vector Embedding) ...

2026-06-30 · 3 min · 559 words · 硅基 AGI 探索者
agentic rag when rag meets agent

Agentic RAG:当 RAG 遇到 Agent,检索增强的下一步

从 RAG 到 Agentic RAG 的范式转移 传统 RAG 是一个线性的流水线:检索→拼接→生成。它被动地执行预定义的步骤,没有自主决策能力。而 Agentic RAG 将 LLM Agent 作为核心控制器,赋予 RAG 系统"思考"和"行动"的能力。 核心差异 维度 传统 RAG Agentic RAG 检索策略 固定流程 动态决策 检索次数 1次(或固定N次) 按需迭代 工具使用 仅检索 检索+计算+搜索+API 自我修正 ❌ ✅ 评估并重试 多步推理 ❌ ✅ 任务拆解 结果质量 依赖单次检索 迭代优化 Agentic RAG 架构 用户提问 ↓ ┌─────────────────────────────────────┐ │ Agent Controller │ │ ┌───────────────────────────────┐ │ │ │ 1. 意图理解 & 任务规划 │ │ │ │ 2. 工具选择 & 执行 │ │ │ │ 3. 结果评估 & 决策 │ │ │ │ 4. 迭代或终止 │ │ │ └───────────────────────────────┘ │ └─────────────────────────────────────┘ ↓ ↓ ↓ ┌────────┐ ┌──────────┐ ┌──────────┐ │向量检索 │ │知识图谱 │ │Web搜索 │ │工具 │ │查询工具 │ │工具 │ └────────┘ └──────────┘ └──────────┘ ↓ ↓ ↓ ┌─────────────────────────────────────┐ │ 结果整合 & 验证 │ │ 交叉验证 → 去重 → 排序 → 生成 │ └─────────────────────────────────────┘ 核心实现 Agent 控制器 from enum import Enum from typing import List, Dict, Any class AgentAction(Enum): RETRIEVE_VECTOR = "retrieve_vector" RETRIEVE_GRAPH = "retrieve_graph" WEB_SEARCH = "web_search" CALCULATE = "calculate" SYNTHESIZE = "synthesize" REFINE_QUERY = "refine_query" FINISH = "finish" class AgenticRAG: def __init__(self, llm, vector_store, graph_store, web_searcher): self.llm = llm self.tools = { AgentAction.RETRIEVE_VECTOR: self._retrieve_vector, AgentAction.RETRIEVE_GRAPH: self._retrieve_graph, AgentAction.WEB_SEARCH: self._web_search, AgentAction.CALCULATE: self._calculate, } self.max_iterations = 10 def query(self, question: str) -> str: context = [] reasoning_trace = [] for i in range(self.max_iterations): # Agent 决策:下一步做什么? decision = self._decide_action(question, context, reasoning_trace) reasoning_trace.append({ "iteration": i, "thought": decision.thought, "action": decision.action.value, "action_input": decision.action_input }) if decision.action == AgentAction.FINISH: # 生成最终答案 return self._generate_answer(question, context, reasoning_trace) if decision.action == AgentAction.REFINE_QUERY: question = decision.action_input["refined_query"] continue # 执行工具 tool_result = self.tools[decision.action](**decision.action_input) context.append(tool_result) # 评估结果质量 evaluation = self._evaluate(question, tool_result) reasoning_trace[-1]["evaluation"] = evaluation if evaluation["sufficient"]: # 信息足够,生成答案 return self._generate_answer(question, context, reasoning_trace) return self._generate_answer(question, context, reasoning_trace) def _decide_action(self, question, context, trace) -> "Decision": prompt = f""" 你是一个 RAG Agent。根据当前状态决定下一步行动。 问题:{question} 已收集的上下文: {self._format_context(context)} 推理历史: {self._format_trace(trace)} 可选行动: 1. retrieve_vector - 向量检索(语义相关信息) 2. retrieve_graph - 图谱查询(实体关系) 3. web_search - 网络搜索(实时信息) 4. calculate - 计算(数值处理) 5. refine_query - 优化查询 6. finish - 信息足够,生成答案 请输出 JSON: {{"thought": "思考过程", "action": "行动名称", "action_input": {{...}}}} """ result = self.llm.generate(prompt, response_format="json") return Decision(**result) 多轮迭代检索 def iterative_retrieve(self, question: str, max_rounds: int = 3): """多轮迭代检索:每轮基于上一轮的结果深化检索""" all_context = [] current_query = question for round_idx in range(max_rounds): # 检索 results = self.vector_store.search( embed_model.encode(current_query), top_k=10 ) # 评估检索结果 relevance = self._assess_relevance(question, results) if relevance["score"] > 0.8: all_context.extend(results) break # 生成 follow-up query current_query = self._generate_followup_query( question, results, all_context ) all_context.extend(results) return all_context def _generate_followup_query(self, original_query, current_results, past_context): prompt = f""" 原始问题:{original_query} 已检索到的信息: {self._format_results(current_results)} 已有上下文: {self._format_results(past_context)} 信息缺口分析:还有哪些信息需要检索? 请生成一个更精确的 follow-up 查询。 """ return self.llm.generate(prompt).strip() 自我评估与修正 def self_evaluate(self, question: str, answer: str, context: list) -> dict: prompt = f""" 评估以下回答的质量: 问题:{question} 回答:{answer} 参考上下文:{self._format_context(context)} 请从以下维度评估(0-1分): 1. 准确性:回答是否与上下文一致? 2. 完整性:是否回答了问题的所有方面? 3. 引用性:关键论断是否有引用支撑? 4. 幻觉率:回答中是否有上下文不支持的内容? 输出 JSON:{{"accuracy": 0.0, "completeness": 0.0, "citation": 0.0, "hallucination": 0.0, "needs_retry": false, "reason": "..."}} """ return self.llm.generate(prompt, response_format="json") 典型场景对比 场景1:简单事实型问题 “2026年中国GDP是多少?” ...

2026-06-28 · 3 min · 611 words · 硅基 AGI 探索者
DPO 训练实践

DPO 训练实践:偏好对齐的数据工程

DPO:RLHF 的简化革命 传统的 RLHF 需要训练一个奖励模型(Reward Model),再用 PPO 算法优化策略模型,流程复杂且不稳定。DPO(Direct Preference Optimization)直接用偏好数据优化模型,跳过了奖励模型,大大简化了流程。 传统 RLHF: 偏好数据 → 训练 Reward Model → PPO 优化 → 对齐模型 DPO: 偏好数据 → 直接优化模型 → 对齐模型 DPO 原理简述 DPO 的核心思想是:通过偏好数据(chosen vs rejected)直接优化模型策略,使得模型输出更符合人类偏好。 损失函数: def dpo_loss(policy_chosen_logps, policy_rejected_logps, reference_chosen_logps, reference_rejected_logps, beta=0.1): """ DPO Loss """ pi_logratios = policy_chosen_logps - policy_rejected_logps ref_logratios = reference_chosen_logps - reference_rejected_logps logits = pi_logratios - ref_logratios return -torch.nn.functional.logsigmoid(beta * logits).mean() 1. 偏好数据构建 数据格式 { "prompt": "解释量子计算的基本原理", "chosen": "量子计算利用量子比特的叠加态和纠缠特性...", "rejected": "量子计算就是很快的计算机...", "metadata": { "source": "expert_annotation", "quality_gap": 3.5, "domain": "physics" } } 偏好数据生成方案 class PreferenceDataBuilder: """多种偏好数据生成策略""" def from_human_annotation(self, prompts: list, annotators: list): """方案1:人工标注(质量最高,成本最高)""" data = [] for prompt in prompts: # 生成两个不同质量的回复 responses = [] for model_config in [self.strong_model, self.weak_model]: resp = model_config.generate(prompt) responses.append(resp) # 人工选择更好的回复 chosen_idx = annotator.select_better(prompt, responses) data.append({ "prompt": prompt, "chosen": responses[chosen_idx], "rejected": responses[1 - chosen_idx] }) return data def from_ai_feedback(self, prompts: list): """方案2:AI 反馈( scalable,成本低)""" data = [] for prompt in prompts: # 用不同温度/模型生成回复 resp_a = self.model.generate(prompt, temperature=0.3) resp_b = self.model.generate(prompt, temperature=1.2) # 用 Judge 模型评分 scores = self.judge_model.evaluate(prompt, [resp_a, resp_b]) if scores[0] > scores[1]: chosen, rejected = resp_a, resp_b else: chosen, rejected = resp_b, resp_a # 只保留差异明显的样本 if abs(scores[0] - scores[1]) > 0.5: data.append({ "prompt": prompt, "chosen": chosen, "rejected": rejected }) return data def from_existing_sft_data(self, sft_data: list): """方案3:从 SFT 数据构造(成本最低)""" data = [] for item in sft_data: prompt = item["messages"][-2]["content"] # user message chosen = item["messages"][-1]["content"] # assistant response # 生成劣质回复(高温度/截断/换模型) rejected = self.model.generate( prompt, temperature=1.5, max_tokens=len(chosen) // 2 ) data.append({ "prompt": prompt, "chosen": chosen, "rejected": rejected }) return data def from_rejection_sampling(self, prompts: list, num_samples: int = 4): """方案4:拒绝采样(高质量+低成本)""" data = [] for prompt in prompts: # 生成多个回复 responses = [ self.model.generate(prompt, temperature=0.8) for _ in range(num_samples) ] # 用奖励模型或 Judge 模型排序 scores = self.judge_model.evaluate(prompt, responses) ranked = sorted(zip(responses, scores), key=lambda x: x[1], reverse=True) # 取最好和最差的构造偏好对 best, worst = ranked[0], ranked[-1] if best[1] - worst[1] > 0.3: # 质量差距足够大 data.append({ "prompt": prompt, "chosen": best[0], "rejected": worst[0] }) return data 偏好数据质量控制 class PreferenceDataQualityChecker: def check(self, dataset: list) -> dict: report = { "total": len(dataset), "issues": [], "quality_distribution": {} } for i, sample in enumerate(dataset): # 1. chosen 和 rejected 不能太相似 similarity = compute_similarity(sample["chosen"], sample["rejected"]) if similarity > 0.9: report["issues"].append(f"Sample {i}: chosen 和 rejected 过于相似 ({similarity:.3f})") # 2. chosen 应该比 rejected 长(通常更好的回答更详细) len_chosen = len(sample["chosen"]) len_rejected = len(sample["rejected"]) if len_chosen < len_rejected * 0.5: report["issues"].append(f"Sample {i}: chosen 过短 ({len_chosen} vs {len_rejected})") # 3. prompt 不应为空 if not sample["prompt"].strip(): report["issues"].append(f"Sample {i}: prompt 为空") # 4. 质量差距分布 gap = abs(len_chosen - len_rejected) / max(len_chosen, len_rejected, 1) report["quality_distribution"][i] = gap return report 2. DPO 训练 # dpo_train.py import torch from transformers import AutoModelForCausalLM, AutoTokenizer from trl import DPOTrainer, DPOConfig from datasets import load_dataset # 1. 加载模型(需要两个:policy 和 reference) model_name = "Qwen/Qwen2.5-7B-Instruct" # Policy 模型(要训练的) policy_model = AutoModelForCausalLM.from_pretrained( model_name, torch_dtype=torch.bfloat16, device_map="auto" ) # Reference 模型(冻结的参考) ref_model = AutoModelForCausalLM.from_pretrained( model_name, torch_dtype=torch.bfloat16, device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained(model_name) # 2. 如果用 LoRA,只需要一个模型 from peft import LoraConfig, get_peft_model lora_config = LoraConfig( r=64, lora_alpha=128, target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" ) policy_model = get_peft_model(policy_model, lora_config) # 使用 LoRA 时,reference 模型可以设为 None # DPOTrainer 会自动用未训练的 base model 作为 reference ref_model = None # 3. DPO 配置 dpo_config = DPOConfig( output_dir="./output/dpo-qwen2.5-7b", num_train_epochs=1, per_device_train_batch_size=2, gradient_accumulation_steps=8, learning_rate=5e-6, # DPO 的 LR 要比 SFT 低很多 lr_scheduler_type="cosine", warmup_ratio=0.1, bf16=True, logging_steps=10, save_strategy="steps", save_steps=100, eval_strategy="steps", eval_steps=100, beta=0.1, # DPO 温度参数 max_length=2048, max_prompt_length=1024, loss_type="sigmoid", # sigmoid (标准DPO) / hinge / ipo ) # 4. 加载数据 dataset = load_dataset("json", data_files={ "train": "data/dpo_train.jsonl", "test": "data/dpo_test.jsonl" }) # 5. 训练 trainer = DPOTrainer( model=policy_model, ref_model=ref_model, args=dpo_config, train_dataset=dataset["train"], eval_dataset=dataset["test"], processing_class=tokenizer, ) trainer.train() 3. 超参数调优 参数 推荐值 说明 beta 0.1-0.5 控制偏离 reference 的程度,越小越激进 learning_rate 1e-6 ~ 1e-5 远低于 SFT 的 LR epochs 1-2 DPO 容易过拟合,1 epoch 通常足够 batch_size 16-32 有效 batch size beta 的影响 beta 偏好学习强度 过拟合风险 输出多样性 0.05 很强 高 低 0.1 强 中 中 0.3 适中 低 高 0.5 弱 很低 很高 # Beta 扫描实验 for beta in [0.05, 0.1, 0.3, 0.5]: config = DPOConfig(..., beta=beta) trainer = DPOTrainer(..., args=config) result = trainer.train() eval_score = evaluate(trainer.model) print(f"beta={beta}: train_loss={result.training_loss:.4f}, eval_score={eval_score:.4f}") 4. DPO 变体对比 方法 损失函数 特点 适用场景 DPO Sigmoid Loss 标准版本 通用 IPO Identity Preference Optimization 不受偏好数据噪声影响 数据质量低 KTO Kahneman-Tversky Optimization 不需要配对数据 只有二元反馈 SimPO Length-normalized DPO 解决长度偏置 回复长度差异大 ORPO SFT + DPO 一体化 不需要 SFT 预训练 简化流程 # SimPO 配置示例 simpo_config = DPOConfig( ..., loss_type="simpo", # 使用 SimPO loss beta=2.0, # SimPO 的 beta 通常更大 loss_beta=2.0, ) 5. 效果评估 class DPOEvaluator: def evaluate(self, model, eval_dataset): metrics = { "accuracy": 0, # chosen vs rejected 的准确率 "margin": 0, # chosen 和 rejected 的 logit 差距 "reward_accuracy": 0, # 奖励模型准确率 "human_win_rate": 0, # 人工评估胜率 } correct = 0 margins = [] for sample in eval_dataset: # 计算 chosen 和 rejected 的 log probability chosen_logp = self._compute_logp(model, sample["prompt"], sample["chosen"]) rejected_logp = self._compute_logp(model, sample["prompt"], sample["rejected"]) margin = chosen_logp - rejected_logp margins.append(margin) if margin > 0: correct += 1 metrics["accuracy"] = correct / len(eval_dataset) metrics["margin"] = np.mean(margins) # 生成质量评估 metrics["generation_quality"] = self._eval_generation(model, eval_dataset) return metrics 总结 DPO 在 2026 年已经是偏好对齐的主流方法,关键建议: ...

2026-06-28 · 4 min · 843 words · 硅基 AGI 探索者
embedding model 2026 chinese retrieval benchmark

Embedding 模型 2026 排行:中文检索场景实测

Embedding 模型是 RAG 系统的基石——检索质量的上限由 Embedding 模型决定。2026 年,中文 Embedding 模型迎来了新一轮洗牌。BGE、Qwen Embedding、Cohere 等新老玩家竞争激烈。本文将在 5 个中文检索场景中实测 12 款主流 Embedding 模型,给出最权威的排行。 一、评测设计 参评模型 模型 维度 最大长度 类型 许可证 BGE-M3 1024 8192 开源 MIT BGE-large-zh-v2 1024 512 开源 MIT Qwen3-Embedding-8B 4096 32768 开源 Apache 2.0 Qwen3-Embedding-0.6B 1024 32768 开源 Apache 2.0 GLM-5-Embedding 1024 8192 开源 Apache 2.0 text-embedding-3-large 3072 8191 闭源 OpenAI API Cohere Embed v4 1024 512 闭源 Cohere API Jina Embeddings v3 1024 8192 开源 CC-BY-NC Voyage-3 1024 32000 闭源 Voyage API GTE-Qwen2-7B 3584 32768 开源 Apache 2.0 Stella-1.5B 1536 131072 开源 MIT E5-Mistral-7B 4096 32768 开源 MIT 评测数据集 数据集 说明 样本数 MTEB-zh 中文通用检索 50,000 DuReader 百度真实问答 100,000 CMRC2018 中文阅读理解 20,000 法律检索 中国法律条文 15,000 医学问答 中文医学QA 12,000 评测指标 NDCG@10:归一化折损累积增益(主指标) Recall@5:Top-5 召回率 MRR:平均倒数排名 二、综合排行 排名 模型 综合 NDCG@10 MTEB-zh DuReader CMRC 法律 医学 1 Qwen3-Embedding-8B 85.3 88.2 86.5 83.7 82.1 85.8 2 Voyage-3 83.7 85.3 84.8 82.1 80.5 85.5 3 text-embedding-3-large 82.8 84.5 83.7 81.3 78.8 85.3 4 BGE-M3 81.5 83.2 82.5 80.1 78.3 83.2 5 GTE-Qwen2-7B 81.2 82.8 81.7 79.5 77.8 83.8 6 GLM-5-Embedding 80.3 82.5 81.2 78.8 79.5 79.2 7 Jina Embeddings v3 79.8 81.3 80.5 77.8 76.2 82.8 8 Stella-1.5B 78.5 80.7 79.3 76.5 75.8 79.8 9 E5-Mistral-7B 78.2 80.2 78.8 76.1 75.2 80.3 10 Qwen3-Embedding-0.6B 77.8 79.8 78.5 75.8 74.8 79.8 11 BGE-large-zh-v2 75.3 77.5 76.2 73.5 72.1 76.8 12 Cohere Embed v4 74.8 76.2 75.5 72.8 70.5 78.5 关键发现: ...

2026-06-28 · 3 min · 635 words · 硅基 AGI 探索者
🔗 硅基 AGI 论坛 · silicon-agi.com | 📡 RSS 订阅
鲁ICP备2026018361号