意图识别
Written: 2026.06第 05 章跟敲代码:上一讲:Milvus 索引机制与基本操作codealong/chapters/ch05_intent_classification。 这部分代码是本章跟敲版,用来先跑通核心闭环;完整项目源码仍以本讲后文标注的qa_core/、scripts/等路径为准。
下一讲:检索策略与动态计划
1. 本讲目标
- 理解意图识别在 RAG 链路中的关键作用
- 掌握”规则优先 + LLM 补充”的混合分类策略
- 读懂
classify_intent()的六步判断顺序及其设计理由 - 理解 Source 自动推断的机制
2. 本讲项目交付闭环
这一讲不是只讲“什么是意图分类”,而是要把在线问答链路的第一个业务判断模块落到项目代码里。完成本讲后,需要能清楚回答三个问题:用户问题进来后先被分成哪类、为什么按这个顺序判断、这个分类结果会怎样影响后面的检索和生成。
本讲实现完成后的代码结构:
闭环验证方式:
requires_rewrite=True,FAQ 问法是否优先走 FAQ_QUERY,流程/制度/文档类问题是否走 KNOWLEDGE_QUERY。
3. 本章内部流程
本章对应在线问答动画中的 Stage 1decide_route(),并提前实现 Stage 2 prepare_retrieval() 中的检索类意图识别。可以把本章理解成两层判断:
- 第一层是 route:系统下一步怎么走,是直接返回、FAQ 精确直出,还是进入检索。
- 第二层是 intent:如果进入检索,当前问题更像追问、FAQ 查询、知识查询,还是需要结构化分类器兜底。
4. 前置知识 — NLU 中的意图识别
4.1 什么是意图识别
在自然语言理解(NLU)中,意图识别(Intent Classification) 是判断用户”想干什么”的技术。4.2 传统做法 vs 本项目做法
传统 NLU 意图分类(如 Rasa、BERT 分类器):- 训练一个专门的分类模型
- 需要标注训练数据
- 意图类型固定,新增意图需要重新训练
- 高频确定场景用正则规则(快、稳定、零成本)
- 模糊场景用 LLM 结构化输出(灵活、无需标注数据)
- 不需要训练任何模型
4.3 意图识别在 RAG 中的特殊角色
在 RAG 系统中,意图识别不只是贴标签。它直接影响后续所有决策:5. 六种意图类型
6. 六步判断顺序(核心设计)
classify_intent() 的判断顺序是刻意设计的,不是随意排列。每一步都有它的理由。
6.1 意图到检索策略的映射
这张图是整个检索决策链的起点。意图识别不只是”贴标签”——标签一旦确定,后续的检索行为就完全不同了。六种意图对应四种检索策略,每一条映射都有明确的设计理由: 策略一:跳过检索(GREETING / OUT_OF_SCOPE / HUMAN_SERVICE) 这三种意图的共同特征是”答案不依赖知识库”。问候就是打招呼、越界就是拒答、人工客服就是返回电话号码——它们不需要查 Milvus,不需要调 LLM 生成,甚至不需要构建上下文。这个策略的价值在于:省掉一次无意义的检索 + LLM 调用。在实际运行中,这三类问题占所有请求的 5-10%,每次都跳过能显著降低延迟和成本。 策略二:先改写再检索(FOLLOW_UP) 追问的问题是”不完整的”。“那审批呢”这四个字如果不结合历史,任何人都看不懂。所以 FOLLOW_UP 不能直接检索——必须先调用 LLM 把省略的主语和背景补全(“入职流程中的审批步骤是什么”),再用改写后的问题去检索。threshold=0.78 是本项目当前的保护阈值,不是行业标准:它比基础 FAQ 直出阈值更谨慎,用来过滤”看起来有点相关但其实不相关”的结果。生产环境应通过 FAQ 误直出率、召回率和人工评测集继续校准。
策略三:FAQ 优先(FAQ_QUERY)
FAQ_QUERY 的问题形态通常是短问题 + 标准问法(如”xxx 怎么办""xxx 流程是什么”),这类问题大概率在 FAQ 库中有精确匹配。策略参数 threshold=0.62 是本项目为了“FAQ 标准答案优先”设置的相对宽松阈值,不是通用标准。它成立的前提是 FAQ 质量高、问题覆盖稳定、误直出率可控。同时 doc_top_k 减少到较少候选,因为 FAQ 已经覆盖了答案,不需要召回大量文档。
策略四:扩大搜索(KNOWLEDGE_QUERY)
知识咨询类问题(“入职流程有哪些步骤""如何申请预算”)答案通常分散在多个文档片段中,需要 LLM 对多个 chunk 做综合和归纳。所以 doc_top_k 会增大——召回更多候选给 Reranker 筛选,保证 LLM 有足够完整的上下文。这类问题对”漏召回”非常敏感:少召回一个关键段落,LLM 就可能生成不完整的答案。
映射规则的实际代码在 qa_core/retrieval/strategy.py 的 build_retrieval_plan() 中,它接收 IntentResult 作为输入,输出一个 RetrievalPlan 对象(包含 faq_top_k、doc_top_k、threshold、use_rerank 等字段),后续的检索环节只使用 Plan 中的参数,不再关心原始意图。
6.2 完整源码解读
OFF_TOPIC_HINTS 匹配的关键词:彩票|赌博|股票内幕|色情|违法|攻击|破解|黑客入侵
步骤 3:人工客服短句
- “客服电话”、“转人工” → 短句,确实在要联系方式
- “客服电话打不通怎么办,我在线等了一个小时了” → 长句,可能是在抱怨或问怎么联系客服的流程,不应直接截断
- 代词或追问词开头:
那|这个|那个|它|上面|刚才|还有|审批呢|费用呢 - 问题很短(≤8 字符):极短的问题在有历史上下文时更可能是追问
requires_rewrite=True 意味着后续流程会先结合历史改写问题,再进入检索。
步骤 5:强规则判断
7. 强规则设计详解
7.1 _strong_rule_domain_intent()
7.2 各规则的关键词设计
FAQ_HINTS — 触发标准问答检索:7.3 置信度阶梯
注意置信度的设计:0.82 → 0.83 → 0.84
这不是随意设置的。随着条件越来越具体(有 source 推断 + 短问题 + 特定问法),置信度逐步提高,但仍然留有余地(不设为 1.0 或 0.95)。这是因为规则毕竟是规则,总有一些边缘情况可能误判。
8. LLM 结构化分类
8.1 何时调用 LLM
只有当前面五步规则都无法确定时,才调用 LLM:- 问题较长,无法用简单关键词判断
- 没有推断出 source
- 问题表达模糊但仍在业务范围内
8.2 实现代码
8.3 白名单校验的重要性
hr 识别为 human_resources)。如果不校验就直接拼入 Milvus 过滤表达式,会导致运行时查询错误。这里丢弃无效值并使用规则推断的 source 作为兜底。
8.4 LLM 失败的处理
9. Source 自动推断
9.1 为什么需要 Source 推断
用户在页面上提问时,不一定手动选择业务分类。系统需要自动判断”入职流程有哪些步骤”属于 HR 分类,“API 限流怎么办”属于 IT 分类。 前端也有业务分类下拉框,但很多用户不会手动选择。自动推断可以作为默认值,也可以作为前端选择的补充。9.2 infer_source() 实现
source 会参与 Milvus 过滤表达式和数据隔离,必须来自当前场景的 valid_sources。新增业务分类时,只修改 scenario.toml 的 valid_sources 和 source_patterns,不要在 Python 主链路里堆业务硬编码。
9.3 场景级 Source Pattern 的优先级
10. IntentResult 与下游联动
10.1 IntentResult 的所有字段
10.2 各字段的下游影响
11. 本讲实践闭环
通过标准:问候、转人工、越界可直接处理,知识类/FAQ/追问类问题能输出稳定
IntentResult。
11.1 本章实现闭环
前面的“本章内部流程”已经说明运行路径。这里从代码实现角度看落点:先完成qa_core/pipeline/steps.py 的查询路由,再完成 qa_core/intent/classifier.py 的意图分类,最后用 tests/test_intent.py 验证直答、FAQ 精确命中和检索类意图三条分支。
实现完成后,相关代码结构应该是下面这张图:
11.1.1 :先定义意图分类的输出结构
目标:不要只返回一个字符串,而是把后续链路需要的决策一起返回。 来源:真实代码节选,见qa_core/intent/classifier.py。
direct_answer:问候、越界、转人工可以直接返回,不进入 RAG。requires_rewrite:追问类问题必须先补全上下文。suggested_source:下游会变成 Milvussource == "hr"这类过滤条件。reason:进入 Trace 和诊断面板,说明为什么这么判断。
11.1.2 :实现 6 步规则优先路径
目标:高频、确定、低风险的问题先用规则处理,只有前 5 条规则都无法判断时才调用 LLM。 来源:真实代码逻辑压缩版,对应qa_core/intent/classifier.py::classify_intent() 和 _strong_rule_domain_intent()。
强领域规则内部又分为 4 类:
来源:真实代码逻辑压缩版,对应
qa_core/intent/classifier.py::_strong_rule_domain_intent()。
confidence=0.82/0.83/0.84 不是模型计算结果,也不是 Milvus 相似度分数,而是人工设计的规则置信度标签。它表达的是“这条规则判断意图的可靠程度”,主要用于诊断面板和 LangSmith Trace。
为什么没有给到
0.9 以上?因为这些只是规则层的意图判断,只说明“用户问题大概率属于某类意图”,不代表知识库一定能检索到答案,更不代表最终答案一定可靠。最终是否可信,还要看第 8 讲的检索分数、第 10 讲的上下文构建,以及第 17 讲的评测指标。
11.1.3 :实现 source 自动推断
目标:根据场景配置推断业务分类,但不把 HR、IT、财务等业务词写死在 Python 主链路里。 来源:简化骨架,对应qa_core/intent/classifier.py::infer_source()。
scenario.toml,新增场景时改配置,不改主链路代码。
11.1.4 :接入 LLM 结构化输出兜底
目标:规则判断不了的问题交给 LLM,但 LLM 输出必须被结构校验。 来源:简化骨架,对应qa_core/intent/classifier.py::_classify_with_llm()。
source 必须经过当前场景 valid_sources 白名单校验,不能直接拼进 Milvus 表达式。
11.1.5 :写测试并接入下游
验收命令: 来源:命令行验收。跟敲代码对应codealong/chapters/ch05_intent_classification/tests/test_intent.py;完整项目对应 tests/test_intent_and_scenarios.py。
通过标准:
你好走GREETING,返回direct_answer。- 越界或风险话题走
OUT_OF_SCOPE,不进入检索和 LLM。 转人工走HUMAN_SERVICE,不检索知识库。审批呢在有历史时走FOLLOW_UP,requires_rewrite=True。- 高频 FAQ/知识类问题能通过强领域规则命中
FAQ_QUERY或KNOWLEDGE_QUERY。 - 企业知识、跨境风险、工程项目等场景的
infer_source()都能命中正确 source。 - 非法 source 不会进入下游 Milvus 过滤表达式。
12. 重点掌握
13. 本讲小结
- 意图识别不只是贴标签,它决定后续全部检索和生成策略
- 判断顺序至关重要:问候→越界→人工客服→追问→强规则→LLM,每一步都有理由
- 规则优先 + LLM 补充:高频确定用规则(快、稳、省钱),模糊用 LLM(灵活)
- LLM 失败即暴露,不静默降级到规则路径
- Source 推断只查场景 TOML source_patterns,顺序即优先级,不在主链路代码中保留业务分类硬编码
- LLM 输出的 source 必须经白名单校验,防止无效值进入 Milvus 表达式
- 所有判断都有
reason字段,确保可解释和可追踪

