LangChain RAG 检索效果从 40% 提到 87%:我用向量重排 查询改写做了这三件事说实话,我一开始是真没把 RAG 检索当回事。项目上 LLM 时,我们团队默认走的就是最标准的向量检索:文档切片 → OpenAI embedding → FAISS 向量库 → top-k 召回 → 丢进 prompt。结果上线一周,业务反馈比没接知识库还离谱:同样的问题,换种问法就答错;专有名词一多,直接开始胡说八道。我用官方示例数据集跑了一遍评估,命中率只有 40%。当时我就意识到:不是模型不行,是检索这一步太糙了。后面三周,我把 LangChain 的检索链路拆开重搭了一遍,从 40% 一路拉到 87%。今天把关键改动和踩坑整理出来,给正在做 RAG 的同学一个参考。先搞清楚:为什么纯向量检索会拉胯RAG 核心逻辑不复杂:把用户问题编码成向量,去知识库找语义最相近的文档片段。问题就出在这个语义相近上。向量检索擅长的是同义转换,但工程文档里有大量它搞不定的东西:缩写和专有名词(比如内部系统代号)数字、版本号、错误码多跳推理(“A 功能在 B 版本后的配置变更”)否定和条件限定更麻烦的是,用户问法和文档写法的分布天然不一致。文档是陈述句,用户是疑问句;文档用全称,用户用简称。只靠 embedding 的语义匹配,召回率根本撑不住。我当时的诊断结论很简单:向量检索不是万能的,得给它配两个搭档–查询改写和重排。第一件事:查询改写,把用户问题翻译成文档语言最直接的问题:用户问怎么接入支付网关,文档里写的是支付网关集成指南。embedding 会觉得它们像,但 top-3 里可能混进别的网关文档。我的做法是加一层 query expansion hyde(假设性文档)。用 LangChain 实现很简单:fromlangchain_openaiimportChatOpenAIfromlangchain.promptsimportPromptTemplate rewrite_promptPromptTemplate.from_template(你是一名搜索专家。请将用户问题改写成 3 个不同版本的检索查询, 要求更接近文档的表述风格,保留核心术语。 用户问题:{question} 输出要求:每行一个查询,不要编号。)llmChatOpenAI(modelgpt-4o-mini,temperature0)defexpand_queries(question:str)-list[str]:textllm.invoke(rewrite_prompt.format(questionquestion)).contentreturn[line.strip()forlineintext.strip().split(\n)ifline.strip()]但这只是多撒网。真正提升召回的是 hyde:让模型先根据问题生成一段理想的参考答案,再用这段答案去检索。hyde_promptPromptTemplate.from_template(请基于你的知识,用一段 100 字左右的文档回答以下问题。 这段回答将用于检索相关文档,所以请尽量包含专业术语。 问题:{question})defhyde_query(question:str)-str:returnllm.invoke(hyde_prompt.format(questionquestion)).content实际组合:原始问题 3 个扩展查询 1 个 hyde 文档,一起拿去检索,然后对结果去重合并。这步单独跑评估,命中率从 40% 提到了 61%。第二件事:混合检索,关键词打底 向量补充向量检索搞不定的,关键词检索反而能兜底。我们用 BM25 做全文检索,和向量检索结果做融合。LangChain 里可以搭一个 ensemble retriever:fromlangchain_community.retrieversimportBM25Retrieverfromlangchain_community.vectorstoresimportFAISSfromlangchain.retrieversimportEnsembleRetriever# 假设 docs 已经切好片bm25_retrieverBM25Retriever.from_documents(docs)bm25_retriever.k5vectorstoreFAISS.from_documents(docs,embedding)vector_retrievervectorstore.as_retriever(search_kwargs{k:5})ensembleEnsembleRetriever(retrievers[bm25_retriever,vector_retriever],weights[0.4,0.6])权重我是用验证集调出来的。BM25 0.4、向量 0.6 这个比例对我们内部的 API 文档最稳。不同领域要自己跑几组对比。这里有个细节:BM25 对中文分词很敏感。LangChain 默认按空格分,中文基本废掉。我换掉了 tokenizer:importjieba bm25_retrieverBM25Retriever.from_documents(docs)bm25_retriever.k5# 在检索时内部会调用 preprocess_funcbm25_retriever.preprocess_funclambdatext: .join(jieba.cut(text))这步上去之后,评估到了 72%。第三件事:重排,把真正相关的片段放到前面召回 10 条,如果不重排,LLM 可能看到第 7 条就已经烦了。特别是上下文窗口有限的时候,前 3 条的质量直接决定答案对不对。我们用的是 cross-encoder 重排模型。LangChain 可以接 sentence-transformers 的 cross-encoder:fromlangchain.retrievers.document_compressorsimportCrossEncoderRerankerfromlangchain_community.cross_encodersimportHuggingFaceCrossEncoder modelHuggingFaceCrossEncoder(model_nameBAAI/bge-reranker-v2-m3)rerankerCrossEncoderReranker(modelmodel,top_n3)fromlangchain.retrieversimportContextualCompressionRetriever compression_retrieverContextualCompressionRetriever(base_compressorreranker,base_retrieverensemble)cross-encoder 会拿 query 和每个候选片段一起打分,比双塔向量模型准得多。bge-reranker-v2-m3 在中文上表现不错,离线也能跑。最终流程变成defretrieve(question:str,top_n:int3):# 1. 查询改写queriesexpand_queries(question)[hyde_query(question),question]# 2. 混合检索召回candidates[]forqinqueries:candidates.extend(ensemble.get_relevant_documents(q))# 去重seenset()unique_docs[]fordincandidates:ifd.page_contentnotinseen:seen.add(d.page_content)unique_docs.append(d)# 3. 重排取 top-nreturnreranker.compress_documents(unique_docs,question)[:top_n]这步加上之后端到端命中率从 72% 拉到 87%top-3 精确率也到了 0.81。完整评估指标别只看命中率很多团队做 RAG 只测“正确答案在不在 top-k 里”也就是 Hitk。但用户体感更敏感的是正确答案排第几。所以我会同时看 MRR 和 NDCG。defmrr(relevant_positions:list[int])-float:returnsum(1.0/pforpinrelevant_positionsifp0)/len(relevant_positions)defdcg(scores:list[float])-float:returnsum((2**s-1)/math.log2(i2)fori,sinenumerate(scores))我们三个版本的对比方案Hit3MRR10NDCG3平均延迟纯向量0.400.320.28120ms查询改写0.610.480.45180ms混合检索0.720.590.56220ms重排0.870.780.74380ms延迟从 120ms 涨到 380ms但对我们的客服机器人场景完全可接受。如果你的场景是实时搜索需要把重排模型换成更小的轻量版或者只做重排不 hyde。评估方式:别用肉眼测,一定要跑数据集我们内部整理了 50 对问题-标准答案片段,格式就是 (question, expected_doc_ids)。评估脚本核心逻辑:defevaluate(retriever,dataset):hit0forq,expected_idsindataset:docsretriever.invoke(q)got_ids{d.metadata[doc_id]fordindocs}ifgot_idsset(expected_ids):hit1returnhit/len(dataset)我对照记录了三个版本:基线向量检索:40%查询改写:61%混合检索:72%重排:87%每次改动单独测,避免把多个变量混在一起。这是做 RAG 优化最容易犯的错。踩坑记录切片粒度太粗:一开始按 1000 token 切,结果重排也救不了。改成 256 token 64 token overlap,效果立刻提升。metadata 没加 doc_id:检索结果去重和评估都依赖 doc_id,前期偷懒没加,后面返工补全。重排模型太大:一开始用 bge-reranker-large,CPU 上 10 条要跑 2 秒。换成 v2-m3,延迟降到 200ms,精度只掉 1%。查询改写生成幻觉查询hyde 偶尔会生成包含虚假术语的段落。解决方式是用温度 0并把 hyde 结果和原问题一起检索而不是只用 hyde。没做版本回归测试第一次优化后效果不错但第二次改分词器时把之前调好的权重又打乱了。后来把评估脚本和 baseline 数据集固化成 GitHub Action每次改检索链路必须跑回归。写在最后RAG 不是接入向量库就完事的活儿。检索链路里的每一环–问题怎么表达、用什么方式召回、怎么排序–都会直接影响 LLM 最终答案的质量。我这三板斧:查询改写、混合检索、重排,都不需要什么 fancy 的模型,LangChain 基本都能串起来。但关键是要跑评估、做 ablation,别靠感觉调。如果你也在做 RAG,建议先用一个小数据集把 baseline 跑出来,然后一项一项加改动。数字不会骗人。
企业数字化 ERP 产品动态
相关推荐
9大网盘直链下载助手终极指南:一键获取真实下载地址,彻底告别限速烦恼 9大网盘直链下载助手终极指南:一键获取真实下载地址,彻底告别限速烦恼 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里… · 2026/11/15 9:07:45
open62541之架构概述 open62541 是 OPC UA(开放平台通信统一架构)的开源实现,旨在从嵌入式微控制器到全尺寸工业服务器的各种环境中运行。系统架构概览本项目遵循严格的分层架构,每一层都向其上层暴露定义良好的接口,且仅依赖于其下层的抽象… · 2026/10/13 19:31:02
macOS虚拟机磁盘空间优化实战指南 1. 虚拟机磁盘空间分配过大的困扰 在macOS平台上使用Parallels Desktop(PD)、VMware或UTM等虚拟机软件时,很多用户都会遇到一个典型问题:初始安装时为虚拟机分配了过多的磁盘空间。我自己的开发机上就躺着几个当初随手设置了200GB… · 2026/10/7 20:35:09
徐州好的电工证培训机构怎么选?电子证书时代怕被中介坑 徐州好的电工证培训机构怎么选?电子证书时代怕被中介坑 不知道去哪报名怕被中介坑,徐州好的电工证培训机构到底怎么找?现在很多人想考电工证,但一听说要找培训机构,就担心被坑,不是多收费就是拿不到电子证书。其实只要你懂流程、找对地方,整个过程不难… · 2026/11/15 9:06:55
莆田电工证报名在哪里真实经历告诉你怎么处理证书过期问题 莆田电工证报名在哪里真实经历告诉你怎么处理证书过期问题 证书过期了不知道怎么复审延期?这种情况我身边好几个朋友都遇到过,有的甚至因为证书过期被单位辞退,有的在项目现场被临时叫停,严重影响了工作进度。今天就从我自己的真实经历出发,带大家详细聊… · 2026/11/15 9:06:55
巩义高压电工证报名费多少?官方报名入口在这里,学历不高也能报! 巩义高压电工证报名费多少?官方报名入口在这里,学历不高也能报! 你是不是也担心,学历不高报不了高压电工证?别急,我来告诉你,其实只要符合年龄和健康要求, 学历并不是高压电工证报名的硬性门槛 。关键是要找到 官方报名入口… · 2026/11/15 9:06:55
塔吊司机特种工教育报名多少钱?别被中介坑了! 塔吊司机特种工教育报名多少钱?别被中介坑了! 你是不是正为 塔吊司机特种工教育 发愁?不知道去哪报名,怕被中介坑,还担心 多少钱 ?别急,这篇文章帮你把关,从报名到证书使用,全流程讲清楚,省心又省钱。 塔吊司机特种工教育到底值不值?… · 2026/11/15 9:06:55
嘉善哪里能考电工证通过率揭秘:电工证考不过真的白花钱 嘉善哪里能考电工证通过率揭秘:电工证考不过真的白花钱 怕考不过白交培训费?嘉善哪里能考电工证?这是很多准备报考电工证的朋友最担心的问题。尤其是现在电工证政策变动频繁,不少考生因为不了解最新要求,结果花了钱还考不过,甚至被培训机构忽悠。这篇文… · 2026/11/15 9:06:55
台州电工证过期了不知道怎么复审延期?复审费用和流程全解析 台州电工证过期了不知道怎么复审延期?复审费用和流程全解析 证书过期了不知道怎么复审延期?别急,这篇文章就是为你准备的。不管是低压电工证还是高压电工证,如果超过有效期不及时复审,不仅影响工作,还可能面临罚款甚至被吊销资格。今天我们就来详细聊聊… · 2026/11/15 9:05:55
长春初级电工证怎么考?通过率揭秘全在这里 长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50
国内电工证报考条件与考试时间 低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50
电工作业时如何断电?电子证书到底能不能全国通用? 电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50
长春初级电工证怎么考?通过率揭秘全在这里 长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50
国内电工证报考条件与考试时间 低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50
电工作业时如何断电?电子证书到底能不能全国通用? 电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 1:51:20
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 4:02:19
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 3:02:05