智能体时代RAG:混合检索、长期记忆与生产级工程实践

智能体时代RAG:混合检索、长期记忆与生产级工程实践 1. 项目概述当RAG不再是一条流水线而是一支能思考的工程团队你有没有试过把几十份PDF扔进向量数据库写三行代码调用LLM然后对着返回结果反复刷新页面心里默念“这次应该准了”我干过。2023年那会儿整个行业都像在赶一场技术庙会——Vector DB是香炉Embedding模型是供果LLM是神像我们跪在下面烧香许愿祈祷它别胡说八道。但现实很打脸用户问“上季度华东区客户投诉率最高的三个产品型号”系统却给你列出了2022年华南区的退货政策问“合同第7.2条关于违约金的计算方式”返回内容里混进了另一份协议里关于保密义务的段落。这不是AI不聪明是我们给它喂了一堆没标页码、没分章节、没做索引的“天书”还指望它当法务专家使。这篇文章讲的就是怎么从“烧香式RAG”升级到“工程师式RAG”。核心关键词是Agentic Era智能体时代、hybrid retrieval混合检索、long-term memory长期记忆和production engineering生产级工程——它们不是新名词堆砌而是解决真实线上问题的四把扳手。它适合三类人第一类是已经跑通基础RAG但总被业务方质疑“为什么又错了”的算法工程师第二类是正被老板追问“RAG到底能不能上线”的后端/全栈开发者第三类是技术决策者需要判断该不该砍掉旧Pipeline、重投资源建新架构。它不教你怎么调OpenAI API而是告诉你当用户输入“帮我对比A/B/C三款竞品在售后服务响应时效上的差异”你的系统该启动几个子任务、调用哪些工具、如何交叉验证结果、在哪一步主动拦截错误——这才是2025年真正能落地的RAG。我去年主导重构了某金融知识中台的RAG系统日均查询从800次涨到2.3万次关键指标“首屏答案准确率”从61%提升至94.7%。这个数字背后不是换了个更大参数的LLM而是把原来单线程的“Query→Embed→Search→Prompt→LLM→Output”链条拆解成一个由7个可调度、可监控、可回滚的智能体组成的协作网络。接下来我会带你一层层拆开这个网络为什么必须放弃“一查定音”的幻觉混合检索到底怎么配比语义与关键词权重长期记忆不是加个Redis缓存那么简单它得像人类律师翻卷宗一样记住“上次查过这个条款当时引用的是2023年修订版”而生产级工程意味着你要为一次失败的检索设计熔断策略为LLM的幻觉准备事实核查员甚至为用户一句模糊提问预判出三种可能意图。这不是理论推演每一步我都附上了线上压测数据、配置参数和踩坑时的报错截图——你可以直接抄作业。2. 内容整体设计与思路拆解从“管道思维”到“团队协作”的范式迁移2.1 为什么“User Query → Vector DB → LLM”架构注定失效先说个血淋淋的事实我们在2023年广泛采用的线性RAG架构其底层假设存在根本性缺陷——它默认“用户提问是明确的、文档集合是完备的、向量检索是鲁棒的、LLM是忠实的”。这四个“默认”在真实业务场景中每一个都会被打碎。用户提问的模糊性业务人员问“最近客户反馈多的产品”这个“最近”是7天还是30天“反馈多”指投诉量、咨询量还是社交媒体声量线性架构要求前端强行标准化结果要么漏掉长尾需求要么让用户填一堆筛选条件体验崩坏。文档集合的不完备性企业知识库永远在更新。销售刚签完的合同、法务刚修订的条款、客服刚汇总的FAQ这些增量数据如果等T1同步到向量库用户查“最新签约政策”时看到的就是过期信息。而实时向量化又带来延迟与一致性难题。向量检索的脆弱性向量相似度本质是高维空间的距离计算。当用户问“苹果手机电池续航差”向量库可能召回大量关于“iPhone 15 Pro电池容量”的技术参数但漏掉客服工单里“用户抱怨iOS 17.4更新后待机耗电翻倍”的真实反馈——因为后者文本表述与查询词的向量距离更远。LLM的忠实性陷阱即使检索结果完全正确LLM仍可能因提示词微小偏差或上下文长度限制将“A产品保修期2年”错误生成为“A产品保修期3年”。这不是模型能力问题而是它被设计为“生成器”而非“校对员”。提示我曾用同一份高质量检索结果分别喂给GPT-4、Claude 3和本地Qwen2-72B让它们生成“保修政策摘要”。三者输出中有2个篡改了关键年限1个遗漏了延保购买条件。这证明检索质量≠最终答案质量中间必须插入可验证、可干预的环节。因此2025年的RAG设计起点必须是承认不确定性并构建应对不确定性的机制。我们不再追求“一次检索就命中黄金片段”而是设计一套能自我诊断、自我修正、自我进化的协作流程。这就像组建一支专业服务团队有负责初步理解用户意图的“需求分析师”有擅长多源查证的“情报官”有专注深度推理的“策略顾问”还有最后把关的“合规审查员”。每个角色各司其职通过结构化消息传递协作而非把所有压力压给最后一个LLM节点。2.2 智能体Agent不是给LLM套壳而是定义清晰的职责边界很多人误以为“加个Agent框架升级到Agentic Era”于是用LangChain的AgentExecutor包装一下再塞个ReAct提示词就宣称架构现代化了。这是危险的简化。真正的智能体设计核心在于职责分离Separation of Concerns和契约驱动Contract-Driven。以我们金融中台的“合同条款解析”智能体为例它由4个原子智能体组成每个都有明确定义的输入/输出契约智能体名称输入契约输出契约关键职责技术实现要点意图澄清员原始用户提问如“解释下违约责任”结构化意图JSON{“条款类型”: “违约责任”, “关联主体”: [“甲方”, “乙方”], “需排除条款”: [“不可抗力”]}主动追问模糊点识别隐含约束基于规则小模型轻量分类响应延迟200ms混合检索官意图JSON 用户上下文历史提问、角色权限排序后的候选片段列表每项含来源、置信度、检索方式语义/关键词/图谱并行触发3种检索融合结果并标注依据Pinecone语义检索 Elasticsearch关键词检索 Neo4j关系路径检索事实核查员检索片段 LLM初稿答案校验报告JSON{“关键事实”: [“违约金比例”, “起算时间”], “核查状态”: “已确认/存疑/冲突”, “冲突来源”: [“条款A vs 条款C”]}对答案中的每个事实点反向追溯至原始文档锚点使用Sentence-BERT计算片段与答案子句相似度阈值动态调整合规审查员初稿答案 校验报告最终答案含引用标记或拒绝响应带原因判断答案是否符合监管红线、内部风控规则规则引擎Drools LLM微调分类器双校验看到这里你明白了吗智能体不是让LLM自己决定“下一步做什么”而是由系统根据预设契约将任务精准路由给最合适的执行单元。Agent的本质是分布式工作流编排不是LLM的自主决策。我们禁用了所有ReAct式的“思考-行动”循环因为线上环境要求可预测、可审计、可降级。当“事实核查员”发现冲突时它不会让LLM重新生成而是直接触发“人工审核队列”并将冲突证据打包推送给法务同事——这才是生产环境该有的严谨。2.3 长期记忆不是缓存而是持续演化的知识图谱很多团队把“加长期记忆”理解为“用Redis存用户历史对话”。这完全偏离了目标。真正的长期记忆Long-Term Memory, LTM在2025年RAG中是指系统在与用户交互过程中持续沉淀、结构化、关联并可复用的知识资产。它解决的核心问题是如何让系统记住“用户张三上周查过A产品的售后政策这次他问B产品是否要主动对比差异”我们的LTM实现分三层会话层记忆Session Memory存储当前会话的临时状态如用户已确认的偏好“只看2024年后条款”、已排除的干扰项“不用考虑海外版本”。使用内存数据库Redis TTL15分钟轻量且无状态。用户层记忆User Memory基于用户ID构建个性化知识图谱。例如当销售代表李四多次查询“竞品X的报价策略”系统会自动关联他所在区域、负责行业、历史成交客户形成“李四-竞品X-报价策略”实体关系。图谱节点包含实体竞品X、属性最新报价发布时间、折扣区间、关系李四关注、用于XX客户提案。存储于Neo4j支持复杂路径查询如“找出所有被华东区销售共同关注的竞品”。系统层记忆System Memory这是最关键的创新层。它不记录具体数据而是记录系统自身的决策模式与纠错经验。例如当“事实核查员”连续3次在“违约金计算基数”上发现冲突它会自动生成一条记忆“条款中‘合同总额’表述易与‘订单金额’混淆建议在检索阶段优先匹配含‘本合同约定总价’字样的片段”。这条记忆会被注入到“混合检索官”的权重策略中动态提升相关关键词的匹配分。系统层记忆用向量数据库Weaviate存储但嵌入向量不是文本而是决策日志的结构化摘要如{“问题类型”: “术语歧义”, “高频冲突字段”: [“合同总额”, “订单金额”], “推荐缓解措施”: “增强关键词检索权重”}。注意LTM的更新绝非被动写入。我们设置了严格的准入规则只有经过“合规审查员”确认的、用户未提出异议的答案才允许沉淀为用户层记忆只有被至少5个独立会话验证过的系统层记忆才会生效。这避免了错误知识的雪球效应。3. 核心细节解析与实操要点混合检索、动态权重与生产级容错3.1 混合检索Hybrid Retrieval不是简单拼接而是按需协同混合检索常被误解为“语义检索关键词检索然后取并集”。这种粗暴做法在实践中效果极差——语义检索召回的宽泛片段会淹没关键词检索的精准结果。2025年的混合检索核心是动态路由Dynamic Routing和证据加权Evidence Weighting。我们采用三级路由策略第一级意图驱动路由Intent-Driven Routing由“意图澄清员”输出的结构化意图直接决定检索策略组合。例如当意图含{“条款类型”: “定义条款”}→ 启用精确关键词检索Elasticsearch强制匹配“定义”、“系指”等前缀当意图含{“条款类型”: “责任条款”, “比较操作”: true}→ 启用图谱关系检索Neo4j查找“A产品责任”与“B产品责任”的共性/差异节点当意图含{“模糊度”: “高”}如用户问“大概多少钱” → 启用语义检索重排序Pinecone Cohere Rerank扩大召回面后精细过滤。第二级跨源证据融合Cross-Source Evidence Fusion不同检索源返回的片段不能简单按分数排序。我们设计了证据融合公式综合得分 α × 语义分 β × 关键词分 γ × 图谱分 δ × 时效衰减因子其中α,β,γ不是固定值而是由意图类型动态计算。例如查“最新监管通知”时β0关键词不重要δ权重拉满仅保留30天内文档查“历史判例”时γ0图谱无意义α权重提升。第三级片段级可信度标注Per-Segment Credibility Tagging每个返回片段都附带机器生成的可信度标签来源可信度基于文档元数据如“监管文件”“内部邮件”“员工笔记”内容稳定性该片段在近7天内被多少次检索命中高频命中稳定知识冲突指数该片段与其他高分片段在关键事实上的矛盾程度用BERTScore计算。这套机制让“混合”真正产生化学反应。在压测中针对“跨境支付手续费计算规则”这类复杂查询纯语义检索准确率仅58%纯关键词检索为63%而我们的混合策略达到89.2%。关键提升来自当语义检索召回一份模糊的“参考指南”关键词检索同时命中一份精确的“费率表PDF第3页”系统会自动将后者置顶并在答案中标注“依据《2024跨境支付费率表》v3.2第3页”。3.2 动态权重策略让系统学会“什么时候该相信谁”权重不是玄学而是可量化、可调试的工程参数。我们为每个智能体间的交互定义了信任权重矩阵Trust Weight Matrix它随时间与反馈持续进化。以“意图澄清员”与“混合检索官”的协作为例初始权重澄清员 → 检索官的意图置信度权重设为0.7基于历史数据70%的澄清结果能提升检索精度当某次澄清后检索结果仍导致事实核查失败系统记录为“澄清失效事件”经过10次失效权重自动下调至0.5并触发告警“意图澄清模型在‘时效性’类问题上表现不佳建议优化”同时系统会分析失效案例发现80%发生在用户提问含“最近”“最新”等时间词时于是针对性地为时间词增加规则分支如自动追加“时间范围过去30天”到意图JSON。这种动态权重让系统具备了“经验积累”能力。上线半年后我们的平均意图澄清准确率从72%升至89%而“澄清失效”事件下降了67%。更重要的是权重调整全程可审计——运维后台能清晰看到“权重0.7→0.5触发条件连续10次失效最后修正时间2025-03-17 14:22”。实操心得权重调试切忌“凭感觉”。我们强制要求每次权重调整必须关联到具体的、可复现的bad case。例如某次将检索官 → 事实核查员的片段置信度阈值从0.65调至0.72是因为发现0.65阈值下有3个案例的“冲突指数”高达0.8但因分数略超阈值未被标记导致LLM生成了错误结论。调参不是艺术是故障归因后的精准手术。3.3 生产级容错为每个环节设计“Plan B”线性RAG最大的风险是单点故障——检索挂了整个服务就黑屏LLM超时用户只能看到转圈。2025年的生产级RAG必须为每个环节预设降级方案Fallback Strategy和熔断机制Circuit Breaker。我们为关键环节配置了三级容错环节主流程一级降级毫秒级二级降级秒级熔断条件意图澄清调用微调小模型DistilBERT返回预设模板“请说明您想了解的具体条款类型如付款、违约、保密”调用规则引擎正则匹配关键词连续5次模型响应500ms混合检索并行3源检索仅启用语义检索最快切换至预热缓存最近1小时高频查询结果单源失败率30%持续2分钟事实核查Sentence-BERT细粒度比对启用关键词匹配“违约金”“%”返回原始检索片段标注“未经核查”核查冲突率40%持续5分钟合规审查Drools规则微调分类器仅运行核心规则如禁止泄露客户号直接放行添加水印“此答案未经合规终审”分类器置信度0.6持续10次这套容错体系的价值在去年双十一期间得到验证。当时向量库因流量激增出现间歇性超时熔断器自动触发系统无缝切换至“语义检索关键词降级”模式。虽然首屏答案准确率暂时降至82%但服务可用性保持100%且所有降级操作均记录日志事后我们据此优化了向量库的读写分离策略。生产环境的第一性原理不是“最好”而是“永不中断”。4. 实操过程与核心环节实现从零搭建可验证的智能体RAG4.1 环境准备与依赖安装轻量但精准我们摒弃了动辄20个组件的庞杂框架选择最小可行技术栈确保每个组件都可替换、可监控# Python 3.11 环境推荐使用pyenv管理 pip install torch2.3.0cu121 torchvision0.18.0cu121 --extra-index-url https://download.pytorch.org/whl/cu121 pip install pinecone-client3.3.0 # 向量库客户端 pip install elasticsearch8.13.2 # 关键词检索 pip install neo4j5.21.0 # 图谱检索 pip install cohere5.5.5 # 重排序API pip install sentence-transformers2.7.0 # 本地嵌入与核查 pip install weaviate-client4.4.0 # 系统层记忆注意所有依赖版本均经过线上压测验证。特别提醒不要盲目升级pinecone-client到4.x其异步API在高并发下存在连接池泄漏问题我们已在GitHub提交issue#1287目前稳定使用3.3.0。4.2 混合检索官HybridRetriever核心代码实现以下是HybridRetriever类的关键逻辑展示了如何协调三源检索并融合结果from typing import List, Dict, Any import asyncio from concurrent.futures import ThreadPoolExecutor class HybridRetriever: def __init__(self, pinecone_index, es_client, neo4j_driver): self.pinecone_index pinecone_index self.es_client es_client self.neo4j_driver neo4j_driver async def retrieve(self, intent_json: Dict[str, Any]) - List[Dict[str, Any]]: 主检索入口返回融合后的候选片段列表 # 步骤1根据意图动态选择检索组合 retrieval_tasks self._build_retrieval_tasks(intent_json) # 步骤2并发执行所有任务注意不是简单await要控制并发数 loop asyncio.get_event_loop() with ThreadPoolExecutor(max_workers3) as executor: results await asyncio.gather( *[loop.run_in_executor(executor, task) for task in retrieval_tasks] ) # 步骤3融合结果应用动态权重与可信度标注 fused_results self._fuse_results(results, intent_json) return fused_results def _build_retrieval_tasks(self, intent_json: Dict[str, Any]) - List[callable]: 构建检索任务列表 tasks [] # 语义检索总是启用基础保障 tasks.append(lambda: self._semantic_search(intent_json)) # 按意图动态添加其他任务 if intent_json.get(clause_type) in [definition, scope]: tasks.append(lambda: self._keyword_search(intent_json)) if intent_json.get(compare_operation): tasks.append(lambda: self._graph_search(intent_json)) if intent_json.get(temporal_hint): # 含“最新”“最近”等 tasks.append(lambda: self._temporal_boost(intent_json)) return tasks def _fuse_results(self, raw_results: List[List[Dict]], intent_json: Dict) - List[Dict]: 融合结果的核心算法 all_segments [] for result_list in raw_results: for seg in result_list: # 为每个片段计算综合得分 score self._calculate_fused_score(seg, intent_json) # 添加可信度标签 seg[credibility] self._annotate_credibility(seg) seg[fused_score] score all_segments.append(seg) # 按综合得分排序去重基于片段哈希 sorted_unique sorted( {hash(json.dumps(s)): s for s in all_segments}.values(), keylambda x: x[fused_score], reverseTrue ) return sorted_unique[:10] # 返回Top10 def _calculate_fused_score(self, segment: Dict, intent_json: Dict) - float: 动态权重融合公式 base_score segment.get(score, 0.0) # 获取动态权重系数 weights self._get_dynamic_weights(intent_json) # 时效衰减因子文档越新权重越高 freshness_factor self._calculate_freshness_factor(segment.get(timestamp)) return ( weights[semantic] * segment.get(semantic_score, 0) weights[keyword] * segment.get(keyword_score, 0) weights[graph] * segment.get(graph_score, 0) weights[freshness] * freshness_factor ) def _get_dynamic_weights(self, intent_json: Dict) - Dict[str, float]: 根据意图返回动态权重 if intent_json.get(temporal_hint): return {semantic: 0.3, keyword: 0.2, graph: 0.0, freshness: 0.5} elif intent_json.get(compare_operation): return {semantic: 0.2, keyword: 0.3, graph: 0.4, freshness: 0.1} else: return {semantic: 0.5, keyword: 0.3, graph: 0.1, freshness: 0.1}这段代码的关键在于它把“混合”从静态配置变成了意图驱动的动态决策。当你传入{clause_type: definition, temporal_hint: true}时它会自动启用关键词检索并大幅提升时效权重而不是让你在配置文件里手动开关。4.3 事实核查员FactVerifier的轻量级实现事实核查不必依赖大模型用Sentence-BERT就能做到高精度。以下是核心核查逻辑from sentence_transformers import SentenceTransformer import numpy as np from sklearn.metrics.pairwise import cosine_similarity class FactVerifier: def __init__(self): # 加载轻量级模型仅120MBGPU显存占用1GB self.model SentenceTransformer(all-MiniLM-L6-v2) def verify_fact(self, answer_text: str, retrieved_segments: List[Dict]) - Dict[str, Any]: 核查答案中每个关键事实点 # 步骤1提取答案中的关键事实用规则NER非LLM facts self._extract_facts_from_answer(answer_text) verification_report { facts: [], overall_confidence: 0.0 } for fact in facts: # 步骤2在检索片段中查找支撑该事实的证据 evidence_scores [] for seg in retrieved_segments: # 计算事实与片段的语义相似度 fact_emb self.model.encode([fact]) seg_emb self.model.encode([seg[content]]) sim_score cosine_similarity(fact_emb, seg_emb)[0][0] evidence_scores.append({ segment_id: seg[id], similarity: float(sim_score), source: seg[source] }) # 步骤3按相似度排序取最高分作为支撑证据 best_evidence max(evidence_scores, keylambda x: x[similarity]) # 步骤4设定阈值判断是否“已确认” status 已确认 if best_evidence[similarity] 0.65 else 存疑 verification_report[facts].append({ fact: fact, status: status, evidence: best_evidence, confidence: best_evidence[similarity] }) # 整体置信度 所有事实置信度的几何平均更严格 if verification_report[facts]: confidences [f[confidence] for f in verification_report[facts]] verification_report[overall_confidence] np.prod(confidences) ** (1/len(confidences)) return verification_report def _extract_facts_from_answer(self, text: str) - List[str]: 轻量级事实提取非LLM facts [] # 规则1提取含数字的陈述“违约金为10%”、“保修期2年” import re num_patterns [ r(\d\.?\d*\s*%?)\s*(?:为|是|达|超过|低于)\s*(?:.*?)(?:违约金|利率|比例|费率), r(\d\s*(?:年|月|日|小时))\s*(?:为|是|达|超过|低于)\s*(?:.*?)(?:保修期|响应时间|处理时限) ] for pattern in num_patterns: matches re.findall(pattern, text, re.IGNORECASE) facts.extend(matches) # 规则2提取法律术语组合“不可抗力”、“重大过失”、“书面同意” legal_terms [不可抗力, 重大过失, 书面同意, 事先许可, 合理努力] for term in legal_terms: if term in text: facts.append(term) return list(set(facts)) # 去重这个实现的精妙之处在于它用不到1秒的时间完成了对答案中每个事实点的可验证溯源。上线后“事实核查”环节的平均耗时仅320ms远低于LLM生成的1.2秒真正做到了“快查快验”。而且所有核查过程都可审计——你能清楚看到“为什么认为‘违约金10%’是存疑的”因为它在所有检索片段中的最高相似度只有0.58。4.4 系统层记忆System Memory的自动化沉淀系统层记忆的自动化是我们区别于其他方案的核心。以下是记忆生成与注入的完整流程# system_memory_manager.py from weaviate import Client import json from datetime import datetime class SystemMemoryManager: def __init__(self, weaviate_client: Client): self.client weaviate_client # 初始化系统记忆schema self._init_schema() def _init_schema(self): 定义系统记忆的数据结构 class_obj { class: SystemMemory, description: System-level operational knowledge, vectorizer: text2vec-transformers, properties: [ { name: problem_type, dataType: [string], description: Type of problem encountered (e.g., term_ambiguity) }, { name: trigger_context, dataType: [string], description: Context that triggered this memory (e.g., user query contains \contract amount\) }, { name: recommended_action, dataType: [string], description: Action to mitigate (e.g., boost keyword weight for \contract total\) }, { name: evidence_count, dataType: [int], description: Number of times this pattern was observed }, { name: last_updated, dataType: [date], description: Last time this memory was updated } ] } self.client.schema.create_class(class_obj) def generate_memory_from_failure(self, failure_log: Dict): 从失败日志自动生成系统记忆 # 提取关键模式 problem_type self._infer_problem_type(failure_log) trigger_context self._extract_trigger_context(failure_log) recommended_action self._suggest_action(failure_log) # 构建记忆对象 memory_obj { problem_type: problem_type, trigger_context: trigger_context, recommended_action: recommended_action, evidence_count: 1, last_updated: datetime.now().isoformat() } # 存入Weaviate self.client.data_object.create( data_objectmemory_obj, class_nameSystemMemory ) def _infer_problem_type(self, log: Dict) - str: 推断问题类型 if conflict in log.get(error_type, ): return term_ambiguity elif timeout in log.get(error_type, ): return performance_bottleneck elif empty_result in log.get(error_type, ): return retrieval_gap else: return unknown def _suggest_action(self, log: Dict) - str: 基于失败模式建议行动 if log.get(error_type) term_ambiguity: # 分析冲突的术语 terms log.get(conflicting_terms, []) if len(terms) 2: return fBoost keyword weight for {terms[0]} and {terms[1]} in hybrid retrieval return Review retrieval configuration def inject_to_retriever(self, retriever: HybridRetriever): 将高置信度系统记忆注入检索器 # 查询最近7天内evidence_count5的记忆 result self.client.query.get( SystemMemory, [problem_type, trigger_context, recommended_action] ).with_where({ path: [evidence_count], operator: GreaterThan, valueInt: 5 }).with_additional([id]).do() for item in result[data][Get][SystemMemory]: # 将推荐行动转化为检索器可执行的配置 if item[problem_type] term_ambiguity: retriever.add_keyword_boost(item[trigger_context], weight1.5)这套机制让系统真正拥有了“成长性”。上线三个月后系统自动沉淀了17条高价值记忆其中5条已成功注入检索策略直接提升了对应场景的准确率。比如当系统发现“合同总额”与“订单金额”的混淆频发它会自动在关键词检索中为这两个词加权无需人工干预。5. 常见问题与排查技巧实录那些文档里不会写的血泪教训5.1 典型问题速查表问题现象可能原因排查步骤解决方案我的实操心得检索结果相关性低但向量分数很高1. Embedding模型未针对领域微调2. 文档预处理丢失关键上下文如PDF表格转文本错位3. 查询词过于简短缺乏语义锚点1. 用测试集抽样检查向量距离分布2. 对比原始PDF与入库文本重点查表格、脚注、页眉页脚3. 在意图澄清环节强制要求用户补充背景1. 用领域语料微调bge-small-zh-v1.5准确率提升22%2. 引入unstructured库替代pdfplumber表格解析准确率达98%3. 设计“提问引导模板”“请说明您想了解的[产品名]在[场景]下的[具体问题]”血泪教训曾因PDF页脚“©2023公司名称”被批量嵌入向量导致所有查询都偏向“2023年”相关文档。解决方案预处理时用正则清除页眉页脚且在向量库中为元数据字段单独建立过滤索引。LLM生成答案与检索片段明显矛盾1. 提示词未强制要求“仅基于以下内容回答”2. 检索片段未做去重LLM看到重复信息产生幻觉3. 上下文窗口溢出关键片段被截断1. 检查提示词中是否包含RETRIEVED_CONTENT占位符及明确指令2. 对检索结果做MD5去重3. 监控LLM输入token数设置硬性截断如最多3000 token1. 采用“指令强化模板”你是一个严谨的法律顾问必须且只能依据以下提供的