为什么要设计意图树
开篇引言
上一篇讲完了查询改写,Ragent 用一次 LLM 调用同时完成了改写和拆分,输出一个 RewriteResult——改写后的完整问题加上子问题列表。每个子问题都是独立的、完整的、对检索友好的查询。
子问题列表有了,下一步做什么?意图识别——判断每个子问题应该去哪里找答案。
来看一个场景。假设你在一家电商平台做 AI 客服,平台规模不小,知识库有好几块:商品信息、售后维修、退换货政策是商品服务方向的;国内物流的配送方式和运费规则、跨境物流的海外仓和清关流程是物流方向的。除了知识库,还接了一个订单 查询的 MCP 工具,用户问“我的快递到哪了”得去调物流接口。另外还有欢迎问候、介绍助手身份这类系统交互。
用户发来一句:
跨境包裹清关一般要多久?
你作为开发者,一眼就知道该去跨境物流的清关流程知识库搜。但系统怎么知道?
基础系列里学过四种意图类型:知识检索、工具调用、闲聊对话、引导澄清。套用四分类,这个问题会被分到知识检索。没问题,但接下来呢?你有五六(可能几十)个知识库,查哪个?四分类不告诉你。
这就是本篇要解决的核心问题:当知识库数量多了,扁平的四分类不够用,需要一棵意图树来做精准路由。
本篇是意图识别子系列的第 1 篇,共 5 篇(第 5~9 篇)。本篇聚焦意图树的设计动机和数据结构——为什么需要树、树长什么样、节点上挂了什么信息、怎么存怎么读。后续第 6 篇讲怎么让大模型给节点打分,第 7 篇讲多子问题多意图的封顶算法,第 8 篇讲歧义引导,第 9 篇讲意图到检索的映射。
扁平分类的天花板
1. 四分类能做什么
基础系列的意图识别篇讲过,用户发来的消息大致可以分成四种意图:
| 意图类型 | 含义 | 典型问题 |
|---|---|---|
| 知识检索 | 去知识库里搜答案 | iPhone 16 Pro 的退货政策是什么 ? |
| 工具调用 | 调外部接口拿实时数据 | 帮我查一下订单 2024112801 的物流进度 |
| 闲聊对话 | 打招呼、闲扯、感谢 | 你好、谢谢你 |
| 引导澄清 | 问题太模糊,需要反问 | 我想退货(退哪个产品?) |
知识库只有一两个的时候,这四种分类完全够用。判断出是知识检索,直接去那个知识库搜就行;判断出是工具调用,去调那个工具。分类的粒度和知识库的数量刚好匹配。
2. 知识库多了就不够用了
问题出在知识库从 2 个变成 20 个的时候。
继续用电商客服的场景。平台有商品信息、售后维修、退换货政策、国内物流配送方式、国内物流运费规则、跨境物流海外仓、跨境物流清关流程、跨境物流运费计算……光这些就有八九个知识库了。如果再加上不同品类(3C 数码、家电、服装)各自的专属知识库,轻轻松松到 20 个。
四分类告诉你这个问题属于知识检索,然后呢?
- 不知道该查哪个知识库。 四分类的知识检索只有一个大类,所有知识库都归这一类。跨境包裹清关一般要多久?和iPhone 16 Pro 的保修期多长?都是知识检索,但该去完全不同的知识库搜。
- KB 和 MCP 混在一起也区分不了。 你有订单查询的 MCP 工具,也有物流知识库。用户问我的快递到哪了该调 MCP 工具,用户问你们支持哪些快递公司该查知识库。四分类把 MCP 工具只归为一类工具调用,但你有多个 MCP 工具的话,调哪个?
- 同一个框架里处理不了多种类型。 知识检索走一套逻辑,工具调用走另一套,闲聊走第三套。四分类做完之后还需要一层路由来决定具体走哪条路径,分类和路由是割裂的。
3. 暴力全库搜索为什么不行
最直觉的方案:不管这么多,所有知识库都搜一遍,最后合在一起排序。
算一笔账。20 个知识库各取 Top-5,合计 100 条候选 chunk。Reranker 要对这 100 条做 Cross-Encoder 精排,计算量大约是单知识库的 20 倍。延迟从几十毫秒飙升到几百毫秒甚至秒级,Token 消耗也跟着翻倍。
更麻烦的是结果质量。不同知识库的内容领域差异很大,跨境物流的 chunk 和 3C 数码的 chunk 放在一起做全局排序,Reranker 容易被迷惑——一段关于国际运费的文档和一段关于手机保修的文档,在语义上可能和用户问题都沾点边,但只有一个是真正相关的。全局排序容易把不相关的 chunk 排到前面,最终答案质量反而下降。
用一句话概括:扁平分类解决了做什么的问题,但解决不了去哪找的问题。