首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
RAG两段式改造:分诊台与拆题术,提升知识库问答准确率
📅 2026/10/5 14:33:50
✍️ 爱科研究院
👁 阅读 3,247
我接手过的RAG项目里十个有八个最后改的不是检索器而是查询入口。用户丢过来一句没头没尾的话系统老老实实去向量库里捞了一堆片段回来生成回答时又凑不齐逻辑。问题不在Embedding选得不好也不在向量库容量不够而在RAG链路最前面的两个环节——判断和规划——几乎被默认跳过了。今天想聊的就是我在实战里反复打磨的分诊台与拆题术让RAG先学会判断这个问题值不值得检索、该检索哪个知识域再学会规划一个大问题怎么拆成几路小问题再合并成完整答案。这套思路适用于所有RAG落地场景尤其是知识库问答、客服助手、企业文档检索这类输入碎片化明显、问题复杂度参差不齐的业务。它不需要你推翻现有RAG架构只是在检索之前加一个判断层在检索之后加一个规划合成层。如果你已经跑通了基础的本地知识库问答想进一步提升回答的准确率和逻辑完整性这篇内容应该能给你一套能直接抄作业的改造方案。1. 普通RAG的翻车现场为什么要给RAG加判断和规划先说个我自己的真实经历。去年我帮一个团队做企业制度文档问答向量库里有几百份制度文件milvus bge-m3检索效果单看召回率还挺像样。结果用户问了句我们请假流程是什么。系统检索出来的片段全是考勤管理加班申请休假类型这些零散内容生成出来的回答把旷工、请假、加班混在一起看得人头疼。问题出在哪里首先是没有判断。一句话里包含了多个可能的检索方向系统不知道用户问的是流程步骤而不是制度条文一股脑全查了。其次是没有规划。请假流程本身是个复合问题它涉及谁审批提前几天需要什么材料和年假怎么对冲等多个子问题模型没拆解直接拿原句去匹配自然只能搜到最表层的文本。1.1 普通RAG的三个典型软肋我后来总结了一下普通RAG答错题基本逃不开这三类情况。第一类是意图模糊导致检索偏移。用户说你们公司对加班怎么看他可能想问加班费也可能想问加班时长限制还可能想问调休政策。模型不去追问也不做意图分层Embedding一算把怎么看这种口语化表达和文档里加班管理细则匹配上结果就不对题。第二类是复合问题被当单问题处理。申请专利需要哪些材料周期多久费用多少——这其实是三个问题材料清单、审批周期、费用标准。普通RAG拿整句去检索向量相似度被三个主题平均掉了每个主题都召回一点又都不完整。第三类是生成阶段缺乏证据约束。检索回来的上下文可能有多个来源大模型编答案时没有哪句话来自哪篇文档的概念经常把A文档的信息和B文档的信息混在一起甚至自己补一段常识进去。用户问的是制度回答却带上了通用法律条文真伪难辨。1.2 分诊台拆题术的本质把RAG改成两段式决策既然问题出在判断和规划上那就在RAG链路上加两个模块一是分诊台二是拆题器。分诊台负责判断。它拿到用户问题后先做一次决策这个问题需不需要检索外部知识如果要检索哪一类知识域有多复杂有没有包含多个子问题判断完之后它给下游输出一个明确的路由指令而不是让检索器盲目搜索。拆题术负责规划。对于复合问题它会把一整句话拆成若干个语义独立、可单独检索的子问题然后逐个执行检索拿到每个子问题的证据块最后再统一交给生成模型组装。这个流程很像医院分诊台先判断你是哪个科室的病急不急需不需要多个科室会诊然后拆成对应检查项目。理解了这个本质再去设计具体实现思路就清晰多了。下面我从分诊台开始讲它是整个链路的地基。2. 分诊台设计先学会判断要不要查、查什么、怎么查分诊台是RAG的第一步也是最容易被忽略的一步。很多RAG项目恨不得所有问题都走检索然后生成这条链路但实际业务里大量问题根本不需要检索。比如你是谁你们公司地址在哪这种高频固定问答直接规则回复或开放生成就行。强行检索反而会因为向量库没有对应内容返回一堆噪音。2.1 分诊粒度怎么定从两分类到多分类路由第一版分诊我做得很简单就是一个二分问题需要检索还是不需要检索。跑了一段时间后发现不够用。同样是需要检索查报销制度和查某位员工的入职时间差别很大前者要搜制度文档后者应该去查结构化数据库。混在一个检索通道里召回效果两头都差。后来我把分诊输出改成三类路由direct_answer直接回答、doc_retrieval文档检索、database_query结构化查询。direct_answer缓存了高频问答不经过RAG链路doc_retrieval进向量库database_query先走SQL再拿结构化结果作为上下文。加了这一层之后日常问答的响应速度明显快了检索的准确率也上来了因为向量库里少了很多不该去的查询。如果你的知识域还分模块比如产品手册和售后政策可以在doc_retrieval里再细分几路对应多个独立的向量集合。分诊模型输出的就不是粗粒度路由而是具体到集合ID。这一步对多知识库场景提升很大能避免跨域文档互相干扰。2.2 规则兜底加模型决策的混合分诊方案纯靠大模型分诊有一个问题费用高且不稳定。我实际跑下来模型对要不要检索的判断偶尔会抽风把明确有答案的简单问题丢进检索链路导致回答变慢甚至被无关文档带偏。更稳的做法是规则兜底加模型决策的混合方案。先跑规则层命中就走规则没命中再交给模型。规则层我用两块一块是关键词白名单比如用户咨询包含怎么如何步骤流程规定是什么这些词时直接判为需要检索包含你是谁联系方式营业时间时直接判为直接回答。另一块是高频问题缓存把历史问答库里TopN高频问题映射到固定答案或固定检索模板完全不走模型。模型层只做规则层覆盖不了的模糊判断。我习惯用少数几个few-shot例子引导模型输出JSON只允许三个取值。Prompt结构大致是这样triage_prompt 你是一个问答系统分诊器。根据用户问题输出以下三种动作之一 - direct_answer: 问题无需检索外部知识可基于常识或固定配置直接回答 - doc_retrieval: 问题需要查询文档库中的非结构化资料 - database_query: 问题需要查询结构化数据库人员、订单、配置等 只输出JSON{action: direct_answer | doc_retrieval | database_query, reason: 简要说明} 示例 用户你们公司支持哪几种支付方式 输出{action: direct_answer, reason: 常见固定问答无需检索} 用户新员工转正需要哪些审批步骤 输出{action: doc_retrieval, reason: 涉及人事制度文档需检索} 用户3号项目的负责人是谁 输出{action: database_query, reason: 项目人员信息在结构化数据库} 用户问题{question} 这个混合方案跑下来大约80%的问题被规则层直接处理延迟从两秒降到几百毫秒模型调用的成本也降了大半。剩下的20%模糊问题交给模型判断准确率比纯规则高得多。2.3 分诊结果的状态映射分诊台输出不只是一个动作还应该包含一个状态描述方便后续模块决定走什么逻辑。我实际用的状态结构长得像这样class TriageState: action: str # direct_answer / doc_retrieval / database_query complexity: str # simple / compound domain: str # 命中的知识域ID空表示不分域 sub_questions: list [] # 拆题结果初始为空complexity字段非常重要。很多RAG系统翻车不是因为检索不好而是因为生成阶段把一个复合问题当成简单问题回答了。分诊阶段判断出这是一个多重需求问题后续拆题器才有依据去拆。domain字段在多知识库系统里作用很大。比如售后系统一批文档是硬件故障排查另一批是软件版本说明用户问设备连不上网分诊应该把domain指向硬件故障排查这样检索时直接在对应向量集合里搜不会把软件说明拉出来干扰。我见过很多团队在分诊阶段只做二元判断结果后续优化难度倍增。我的建议是分诊阶段的粒度宁多勿少哪怕你暂时用不全这些字段后面调整Prompt也比改架构容易。3. 拆题术把复杂问题切成子问题逐条检索再拼装分诊台判断出问题需要检索后第二个关键动作就是拆题。这一步直接决定检索到的内容是不是够用的。只拿原句去检索只有一种情况是合适的——问题本身极其简单且指向单一。只要问题里出现了并列、递进、因果、对比关系不拆题基本都会翻车。3.1 什么样的问题必须拆我总结了一个简单可执行的判断标准问题里有没有多个需要独立检索的语义单元。满足任一条件就拆出现了並列连词或顿号列举比如申请条件、审批流程、所需材料这三个并列成分出现了对比关系比如线下网点和线上渠道有什么区别出现了连带需求比如费用多少多久能办完费用和时限是两个不同维度出现了步骤性需求比如怎么申请需要谁批准多久生效这本质上是一条流程链上的多个节点不拆题时整句Embedding会成为一个语义混合体每个维度都被稀释。拆开后每个子问题独立检索召回的是各自的高相关度片段合并后覆盖度立刻上来了。3.2 拆题Prompt与子查询生成的实操拆题的本质是让大模型做一个问题重组而非问题回答。我用的Prompt核心结构是decompose_prompt 请把用户的问题拆解为多个独立的子问题。每个子问题必须满足 1. 语义独立能单独检索而不依赖其他子问题 2. 覆盖原始问题的所有关键维度 3. 保留原始问题中的限定词如具体产品型号、日期范围 如果用户问题本就是单一维度不要强行拆分输出原句即可。 输出格式JSON数组如[子问题1, 子问题2] 示例 用户办护照需要哪些材料多久能拿到 输出[办护照需要哪些材料, 办护照需要多长时间] 用户A产品和B产品在售后政策上有何不同 输出[A产品的售后政策, B产品的售后政策] 用户路由器无法上网怎么排查 输出[路由器无法上网怎么排查] 用户问题{question} 拆完之后系统会对每个子问题单独执行向量检索取回各自TopK文档。这里有个容易踩的坑子问题过多会导致检索碎片化。我实测里拆出四五个子问题往往会互相干扰上下文长度暴涨生成模型反而抓不住重点。我一般限制拆题数量上限三个超过三个的按维度合并比如材料和时限可以合并成一条综合性子问题重新表述。3.3 子结果聚合与引用对齐拆题之后的聚合阶段问题就变成怎么把多路子结果拼成上下文还不能乱套。我在工程里给每个子问题的检索结果打一个tagretrieval_result { sub_question: 办护照需要哪些材料, tag: Q1, chunks: [...] # 每个chunk保留来源文档ID }合成上下文时把所有chunks按子问题顺序拼接并附上来源标记。生成Prompt最后会加一句约束回答时按证据块内容组织引用内容后标注[来源编号]。这一步能大幅减少张冠李戴。没有这个约束时模型经常把A子问题的文档内容嫁接到B子问题对应的段落上。如果你用的是LangChain或LlamaIndex这类框架拆题模块可以直接包成一个自定义Chain放在Retriever之前。如果你像我自己早期那样是自己撸的RAG流程那就是在查向量库之前多调了一次LLM代码量增加不大效果提升却非常明显。4. 轻量落地方案本地模型加向量库上的两段式编排理论说完了接下来给一套能直接跑起来的轻量方案。我自己的实践环境是本地部署ollama加载模型用bge-m3做Embedding向量库用的chroma整体不依赖外部API数据不出机器。这套组合做RAG改造验证非常方便也适合小团队快速搭原型。4.1 为什么选本地化和这套组合选择ollama做本地推理主要考虑三点数据隐私、成本、离线可验证。企业文档问答场景里用户的制度文件、产品资料往往不能发到外部API去处理本地部署可以规避这个大坑。开发阶段成本几乎为零模型随便试Prompt随便调。bge-m3在中文场景下表现稳检索质量不输商业API而且本地跑完全够快。向量库选chroma单纯是因为它轻pip安装就能用不需要额外运维。如果你已经用了milvus或weaviate改动思路相同只是索引操作换一下API。4.2 主流程骨架分诊到拆题到检索再到合成整个流程我拆成了四个部分每部分可以独立测试。def handle_query(question): # 第一步规则分诊不经过模型 rule_result rule_triage(question) if rule_result direct_answer: return direct_answer(question) # 第二步模型分诊补充规则层覆盖不到的 triage_state llm_triage(question) if triage_state.action database_query: return query_database(triage_state, question) # 第三步拆题复合问题才走简单问题直接用原句 if triage_state.complexity compound: sub_questions llm_decompose(question) else: sub_questions [question] # 第四步逐个子问题检索聚合证据 evidences [] for i, sub_q in enumerate(sub_questions): chunks vector_search(sub_q, top_k3) evidences.append({tag: fQ{i1}, chunks: chunks}) # 第五步合成带引用的答案 return generate_answer(question, evidences)这个骨架你拿去就能用。每个函数内部的具体实现网上有大量现成封装关键是这个编排逻辑——先判断、再规划、再检索、最后合成。很多半成品RAG项目缺的正是这个编排顺序。4.3 实际跑分时的参数和阈值调参是最容易被忽略但影响最大的一环。我踩过一轮之后整理了几个值得关注的点。检索TopK我习惯从3起步。子问题多的时候总chunks数会膨胀我控制在9到12个以内超出部分按相关度截断宁可少一点也别把噪音灌进上下文窗口。相似度阈值要看你用的向量模型。bge-m3的分数一般在0.4到0.8之间我实际跑下来阈值定0.5比较稳。低于这个分数的chunks基本是和问题无关的闲聊段留着只会污染生成结果。上下文窗口的分配也要提前规划。假设模型窗口是8K tokens分诊和拆题的中间输出各占一部分检索结果是重头最后还要给生成留出足够空间。我习惯给检索结果预留5K以内超过就截断。截断策略不是简单砍头尾而是优先保留与子问题相似度最高的top chunks再去掉重复度较高的片段。还有一个小技巧是去重。多个子问题检索出来的chunks可能高度重叠如果某个chunk被多个子问题命中说明它信息密度高保留一份并置于上下文前部即可。我用的是基于文本哈希的简单去重跑下来效果不错还能省不少token。5. 踩坑记录与调优心得分诊误判、拆题过度、引用错位这套方案落地一年多踩过不少坑这里挑几个最有代表性的讲讲希望能帮你少走弯路。5.1 分诊误判案例被模糊提问骗过印象最深的一次误判是用户问你们最近有什么活动。规则层没命中模型层把它判成了doc_retrieval结果向量库里全是去年活动的文档检索回来的内容完全过时。我后来在分诊Prompt里加了一条当问题涉及时间敏感性最近、最新、当前且无法从文档中获取实时信息时action返回direct_answer并提示用户咨询在线客服。这个改动引出一个更通用的经验分诊不只要判断要不要检索还要判断你的知识库有没有能力回答。知识库里没有实时数据时与其检索出过期内容不如直接告诉用户这个信息建议去官网或客服渠道确认。看似少答了一道题实际上避免了更严重的信任损失。5.2 拆题过度的副作用拆题拆多了也有问题。有次用户问优化公司报销流程的建议我拆成了当前报销流程是什么常见痛点有哪些业界最佳实践建议方案四个子问题。结果检索出来的内容特别散合成时模型抓不住主线答案像拼接材料缺乏逻辑主线。后来我调整了拆题的触发条件只有问题中存在明确并列或对比语义才拆存在建议分析评价这类主观生成需求时拆题只做辅助检索不做强制拆分。换句话说拆题的本质是找齐证据不是穷举维度。证据找齐了逻辑组织交给生成模型更合适。5.3 引用错位合成阶段如何约束模型按证据说话引用错位是RAG生成阶段的老大难。模型引用了来源编号可内容根本不是来自那个来源。我试验过几招最有效的是在合成Prompt里加一个硬约束只允许使用证据块中出现的事实不允许使用模型自身知识补充不确定的内容直接写资料中未提及。这个约束牺牲了一点回答的丰富度但换来了可信度的大幅提升。合成Prompt里我还会把每个证据块的来源tag附在块首并提示模型引用时严格对应tag。实践下来引用错位率能降低一半以上。5.4 分诊和拆题本身也有成本不是所有场景都需要最后提醒一句分诊台和拆题术不是免费的。每调用一次模型做分诊要多一次LLM推理拆题也要额外调用。如果你的业务场景里问题普遍简单比如怎么导出报表如何修改密码那加这套机制纯属浪费。我的判断标准是**当RAG回答的错误类型里50%以上是答非所问或逻辑不完整而非事实错误过多时才值得引入分诊和拆题。**事实错误多优先去调Embedding模型、清洗文档、调TopK答非所问和逻辑不完整才是判断与规划环节的问题。以我自己的体会把分诊台和拆题术加进去之后RAG才真正从搜索增强变成了认知增强。搜索只是把相关文本捞出来判断和规划才是让系统理解用户到底想要什么答案的关键。这套东西不复杂本质上就是多两个Prompt构造和一段编排逻辑但它在实际项目里带来的改善往往比换一个更大的模型还要明显。如果你正在做RAG而且感觉效果总差一口气不妨从今天说的这两个环节入手改起。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/5 14:28:49
压力变送器嵌入式C程序设计:硬件耦合与工业可靠性实战
2026/10/5 14:28:49
从零做一个 C 盘大文件夹清理器
2026/10/5 14:28:49
微信小程序【form组件】
2026/10/5 15:18:52
P1131 时态同步【洛谷算法习题】
2026/10/5 15:18:52
AI 写作使用规范 —— 正确使用汇写的态度
2026/10/5 15:18:52
Davinci软件中MCU软件
2026/10/5 15:18:52
采购脆性薄片搬运设备时,如何穿透“样机包装成量产案例“的宣传话术,核验厂家的真实量产成色
2026/10/5 15:18:52
C++ 第 31A 课:先把 ROS2 Publisher 讲成人话
2026/10/5 15:13:52
一个专门适配SurvX的编辑器
2026/10/5 0:02:57
AZ-104题库深度拆解:从刷题到掌握Azure管理员核心考点
2026/10/5 0:02:57
WorkBuddy:基于MCP协议的组织级工作流神经中枢
2026/10/5 0:02:57
大模型 / AI 应用常见面试题及答案汇总(2026 最新版):用 TaoToken 统一 Key 跑通高频考点代码验证
2026/10/5 4:43:56
Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化
2026/10/5 1:10:25
多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系
2026/10/5 13:05:37
hindsight:面向LLM应用的事后可观测性工程实践
2026/10/4 2:41:08
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/4 17:59:15
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/3 15:20:14
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)