[{"data":1,"prerenderedAt":465},["ShallowReactive",2],{"note:\u002Fprojects\u002Frag-knowledge-base\u002F04-意图识别与检索策略":3},{"id":4,"title":5,"body":6,"date":444,"description":445,"draft":446,"extension":447,"featured":446,"kind":448,"lastmod":444,"meta":449,"navigation":326,"path":453,"planned":454,"section":455,"seo":456,"source":457,"stem":458,"tags":459,"toc":326,"weight":463,"__hash__":464},"notes\u002Fprojects\u002Frag-knowledge-base\u002F04-意图识别与检索策略.md","意图识别与检索策略",{"type":7,"value":8,"toc":434},"minimark",[9,13,16,20,28,39,43,46,57,63,69,73,84,123,134,137,192,196,203,209,220,227,231,238,244,254,284,291,295,302,344,347,350,386,399,402,427,430],[10,11,12],"p",{},"用户的问法只有那么几种，但系统要做的决定一点不少：\n这句话该直答、该查 FAQ、该检索文档，还是该先追问一句？",[10,14,15],{},"如果所有问题都直接丢给向量库，会出现两种典型事故：用户发一句「你好」也被检索，\n模型硬着头皮拿无关文档回答；用户搜一个具体编号，语义检索却召不回。",[17,18,19],"h2",{"id":19},"先给结论",[10,21,22,23,27],{},"这套项目的意图链路是三段式：",[24,25,26],"strong",{},"规则候选 + BERT 模型 + 网关仲裁","。",[29,30,36],"pre",{"className":31,"code":33,"language":34,"meta":35},[32],"language-text","第一段  路由层收口：问候 \u002F 人工客服 \u002F 越界请求，直接返回，不进检索\n第二段  规则候选 + 模型打分：规则给可解释的高频判断，BERT 负责长尾表达\n第三段  网关仲裁：按优先级决策树融合两路结果，产出可治理、可回放的意图结论\n","text","",[37,38,33],"code",{"__ignoreMap":35},[17,40,42],{"id":41},"一先分层别急着上模型","一、先分层，别急着上模型",[10,44,45],{},"很多项目一上来就训一个意图分类模型，结果高频场景反而退化了——\n因为「你好」这种问题，规则判断的准确率是 100%，模型的准确率是 99%，\n而后者需要 GPU、需要训练数据、需要每次改分类都重训。",[10,47,48,49,52,53,56],{},"所以这里先做",[24,50,51],{},"收口","：问候、转人工、越界请求由路由层的 ",[37,54,55],{},"classify_direct_intent()","\n直接判定并返回，根本不进网关。网关只处理三种检索类意图：",[29,58,61],{"className":59,"code":60,"language":34,"meta":35},[32],"FAQ_QUERY         高频标准问题，走 FAQ 快路径\nKNOWLEDGE_QUERY   制度、流程、方案类知识问题，走文档检索\nFOLLOW_UP         依赖上下文的追问，需要放宽召回\n",[37,62,60],{"__ignoreMap":35},[10,64,65,66],{},"这个边界很重要：",[24,67,68],{},"能用确定性规则解决的部分，一行模型推理都不该花。",[17,70,72],{"id":71},"二规则和模型各自负责什么","二、规则和模型，各自负责什么",[10,74,75,76,79,80,83],{},"规则分数不是概率，它是",[24,77,78],{},"确定性规则的排序权重","，写在 ",[37,81,82],{},"config\u002Frules.toml"," 里：",[29,85,89],{"className":86,"code":87,"language":88,"meta":35,"style":35},"language-toml shiki shiki-themes github-light github-dark","[intent_rule_scores]\nstrong_faq = 0.82            # 强 FAQ 特征（问法完整、命中 FAQ 句式）\nknowledge = 0.84             # 知识查询特征\nsource_question_shape = 0.85 # 问法结构指向某个 source\ndirect_faq_shape = 0.86      # 典型 FAQ 句式\n","toml",[37,90,91,99,105,111,117],{"__ignoreMap":35},[92,93,96],"span",{"class":94,"line":95},"line",1,[92,97,98],{},"[intent_rule_scores]\n",[92,100,102],{"class":94,"line":101},2,[92,103,104],{},"strong_faq = 0.82            # 强 FAQ 特征（问法完整、命中 FAQ 句式）\n",[92,106,108],{"class":94,"line":107},3,[92,109,110],{},"knowledge = 0.84             # 知识查询特征\n",[92,112,114],{"class":94,"line":113},4,[92,115,116],{},"source_question_shape = 0.85 # 问法结构指向某个 source\n",[92,118,120],{"class":94,"line":119},5,[92,121,122],{},"direct_faq_shape = 0.86      # 典型 FAQ 句式\n",[10,124,125,126,129,130,133],{},"模型侧是一个本地 BERT 分类器（",[37,127,128],{},"models\u002Fbert_intent_classifier_v1","，\n",[37,131,132],{},"max_length=64","、CPU 推理），输出标签和置信度。",[10,135,136],{},"两者的分工是明确的：",[138,139,140,155],"table",{},[141,142,143],"thead",{},[144,145,146,149,152],"tr",{},[147,148],"th",{},[147,150,151],{},"规则",[147,153,154],{},"BERT 模型",[156,157,158,170,181],"tbody",{},[144,159,160,164,167],{},[161,162,163],"td",{},"擅长",[161,165,166],{},"高频、结构固定、可枚举的问法",[161,168,169],{},"长尾表达、口语化、新出现的说法",[144,171,172,175,178],{},[161,173,174],{},"优点",[161,176,177],{},"完全可解释，改一行配置就生效",[161,179,180],{},"泛化好，不用为每种说法写规则",[144,182,183,186,189],{},[161,184,185],{},"风险",[161,187,188],{},"覆盖不到没写过的说法",[161,190,191],{},"给不出理由，误判难定位",[17,193,195],{"id":194},"三网关仲裁冲突时听谁的","三、网关仲裁：冲突时听谁的",[10,197,198,199,202],{},"规则和模型一定会打架。网关的解法不是「加权平均」，而是一棵",[24,200,201],{},"优先级决策树","：",[29,204,207],{"className":205,"code":206,"language":34,"meta":35},[32],"1. 模型误判检查：没有历史对话却判成追问 -> 以规则为准\n2. 低置信度检查：模型置信度不足 -> 退回规则结论\n3. 一致性检查：两路结论一致 -> 直接采用，并提高最终置信度\n4. 冲突处理：两路结论不同 -> 按风险等级选择更保守的一边\n",[37,208,206],{"__ignoreMap":35},[10,210,211,212,215,216,219],{},"网关输出的不只一个标签，而是一个完整的 ",[37,213,214],{},"IntentResult","：规则分数、模型分数、\n最终置信度、候选列表、风险标签、策略版本号。",[24,217,218],{},"这就是它能被回放和审计的前提","——\n线上出现一次误判，你能从 Trace 里还原当时两路分别给了什么分。",[10,221,222,223,226],{},"冷启动时 ",[37,224,225],{},"warmup_intent_decision_gateway()"," 会把模型加载进内存，\n所以意图判断不会成为首问的瓶颈。",[17,228,230],{"id":229},"四意图只是输入检索计划才是输出","四、意图只是输入，检索计划才是输出",[10,232,233,234,237],{},"拿到意图之后，真正决定召回质量的是动态检索计划（",[37,235,236],{},"qa_core\u002Fretrieval\u002Fstrategy.py","），\n它按五层决策给出参数：",[29,239,242],{"className":240,"code":241,"language":34,"meta":35},[32],"1. 意图分支        FAQ \u002F 知识查询 \u002F 追问 -> 基础 top_k 与阈值\n2. 短问题保护      查询短于 20 字 -> 限制文档检索，提高直出门槛（FAQ top_k 提到 30）\n3. 规则分数保护    规则判断越弱 -> FAQ 直出越保守，文档召回越充分\n4. 风险类别        费用 \u002F 合规 \u002F 排障 \u002F 总结 -> 各自使用不同阈值\n5. 表格偏好        表格类查询 -> 扩大文档候选池\n",[37,243,241],{"__ignoreMap":35},[10,245,246,247,79,250,253],{},"阈值本身是",[24,248,249],{},"业务护栏",[37,251,252],{},"[retrieval_strategy]"," 里，和模型参数分开管理：",[29,255,257],{"className":86,"code":256,"language":88,"meta":35,"style":35},"faq_direct_floor = 0.62                 # FAQ 直出的最低底线\npricing_direct_threshold = 0.84         # 费用类问题必须更确定才敢直出\ncompliance_direct_threshold = 0.86      # 合规类更高\nfollow_up_faq_top_k_min = 24            # 追问场景放宽 FAQ 召回\ntable_context_top_n_min = 7             # 表格问题多给上下文\n",[37,258,259,264,269,274,279],{"__ignoreMap":35},[92,260,261],{"class":94,"line":95},[92,262,263],{},"faq_direct_floor = 0.62                 # FAQ 直出的最低底线\n",[92,265,266],{"class":94,"line":101},[92,267,268],{},"pricing_direct_threshold = 0.84         # 费用类问题必须更确定才敢直出\n",[92,270,271],{"class":94,"line":107},[92,272,273],{},"compliance_direct_threshold = 0.86      # 合规类更高\n",[92,275,276],{"class":94,"line":113},[92,277,278],{},"follow_up_faq_top_k_min = 24            # 追问场景放宽 FAQ 召回\n",[92,280,281],{"class":94,"line":119},[92,282,283],{},"table_context_top_n_min = 7             # 表格问题多给上下文\n",[10,285,286,287,290],{},"注意最后两个：",[24,288,289],{},"风险越高，直出越保守；上下文越依赖，召回越宽。"," 这不是模型参数，\n是业务判断，所以它必须放在业务能改的地方。",[17,292,294],{"id":293},"五查询改写同一句话的多种问法","五、查询改写：同一句话的多种问法",[10,296,297,298,301],{},"企业知识库里的用词和员工口语经常对不上。",[37,299,300],{},"[query_variants]"," 用配置化的替换规则生成变体：",[29,303,305],{"className":86,"code":304,"language":88,"meta":35,"style":35},"[[query_variants.replacements]]\nwhen_any = [\"发票\"]\nreplace = [[\"发票\", \"开票\"], [\"发票\", \"账单\"]]\n\n[[query_variants.replacements]]\nwhen_any = [\"怎么排查\"]\nreplace = [[\"怎么排查\", \"如何处理\"], [\"怎么排查\", \"处理步骤\"]]\n",[37,306,307,312,317,322,328,332,338],{"__ignoreMap":35},[92,308,309],{"class":94,"line":95},[92,310,311],{},"[[query_variants.replacements]]\n",[92,313,314],{"class":94,"line":101},[92,315,316],{},"when_any = [\"发票\"]\n",[92,318,319],{"class":94,"line":107},[92,320,321],{},"replace = [[\"发票\", \"开票\"], [\"发票\", \"账单\"]]\n",[92,323,324],{"class":94,"line":113},[92,325,327],{"emptyLinePlaceholder":326},true,"\n",[92,329,330],{"class":94,"line":119},[92,331,311],{},[92,333,335],{"class":94,"line":334},6,[92,336,337],{},"when_any = [\"怎么排查\"]\n",[92,339,341],{"class":94,"line":340},7,[92,342,343],{},"replace = [[\"怎么排查\", \"如何处理\"], [\"怎么排查\", \"处理步骤\"]]\n",[10,345,346],{},"短且结构化的查询（不超过 24 字）才触发变体生成，避免长问题被改写跑偏。",[17,348,349],{"id":349},"动手验证",[29,351,355],{"className":352,"code":353,"language":354,"meta":35,"style":35},"language-powershell shiki shiki-themes github-light github-dark","# 用意图策略评测集跑一遍，看每类的判定准确率和冲突分布\npython scripts\u002Fintent\u002Fevaluate_intent_policy.py\n\n# 重新训练 \u002F 校准意图模型与阈值（有标注数据时）\npython scripts\u002Fintent\u002Ftrain_intent_bert.py\npython scripts\u002Fintent\u002Fcalibrate_thresholds.py\n","powershell",[37,356,357,362,367,371,376,381],{"__ignoreMap":35},[92,358,359],{"class":94,"line":95},[92,360,361],{},"# 用意图策略评测集跑一遍，看每类的判定准确率和冲突分布\n",[92,363,364],{"class":94,"line":101},[92,365,366],{},"python scripts\u002Fintent\u002Fevaluate_intent_policy.py\n",[92,368,369],{"class":94,"line":107},[92,370,327],{"emptyLinePlaceholder":326},[92,372,373],{"class":94,"line":113},[92,374,375],{},"# 重新训练 \u002F 校准意图模型与阈值（有标注数据时）\n",[92,377,378],{"class":94,"line":119},[92,379,380],{},"python scripts\u002Fintent\u002Ftrain_intent_bert.py\n",[92,382,383],{"class":94,"line":334},[92,384,385],{},"python scripts\u002Fintent\u002Fcalibrate_thresholds.py\n",[10,387,388,389,391,392,395,396],{},"更快的体感验证：把 ",[37,390,82],{}," 里的 ",[37,393,394],{},"faq_direct_floor"," 从 0.62 调到 0.9，\n重启后问几个 FAQ 问题，你会看到原本直出的问题开始走文档检索——\n",[24,397,398],{},"这就是阈值作为护栏的直观效果。",[17,400,401],{"id":401},"取舍与边界",[403,404,405,412,421],"ul",{},[406,407,408,411],"li",{},[24,409,410],{},"规则 + 模型的混合方案维护成本更高","，换来的是可解释性和长尾覆盖；\n如果你的场景问法极窄（比如只有十种查询），纯规则就够了。",[406,413,414,202,417,420],{},[24,415,416],{},"阈值必须校准，不能凭感觉设",[37,418,419],{},"eval_sets\u002Fthreshold_calibration_cases.json"," 就是干这个的。",[406,422,423,426],{},[24,424,425],{},"意图类别不要无限扩张","：类别越多，规则冲突和模型混淆越难排查，\n新增类别前先问一句「能不能归到现有的三类里」。",[10,428,429],{},"下一篇进入检索本体：dense 和 sparse 为什么必须一起用，\n以及召回之后那一步重排到底救回了多少正确答案。",[431,432,433],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":35,"searchDepth":101,"depth":101,"links":435},[436,437,438,439,440,441,442,443],{"id":19,"depth":101,"text":19},{"id":41,"depth":101,"text":42},{"id":71,"depth":101,"text":72},{"id":194,"depth":101,"text":195},{"id":229,"depth":101,"text":230},{"id":293,"depth":101,"text":294},{"id":349,"depth":101,"text":349},{"id":401,"depth":101,"text":401},"2026-06-19","使用规则候选、分类模型与网关仲裁，把用户问题转换为可解释、可治理的检索计划。",false,"md","project-chapter",{"migration":450},{"generator":451,"sourceSha256":452},"nuxt-site\u002Fscripts\u002Fmigrate-content.mjs","d6c895140877c4f577adc983468dc39f444e8c890a5974a3fc1bde4027905613","\u002Fprojects\u002Frag-knowledge-base\u002F04-意图识别与检索策略",null,"projects",{"title":5,"description":445},"content\u002Fprojects\u002Frag-knowledge-base\u002F04-意图识别与检索策略.md","projects\u002Frag-knowledge-base\u002F04-意图识别与检索策略",[460,461,462],"RAG","意图识别","混合检索",34,"grxu8nT2mpC1OnRfmzIPdOnxf_IsZMG30mdc14KLzJ4",1791279145025]