从零搭起这套漏斗的时候,我刚接手的是一个人工客服高压、Agent 频繁误触发、意图模块三天两头返工的烂摊子。做过 Agent 应用的人应该都有同感:意图识别听起来简单,无非是"把用户说的话分到某个意图桶里",但一旦上线,面对真实用户的脏乱差输入,单模型方案几乎撑不住。我试过端到端的大模型直出意图、也试过微调分类器,最终都被线上数据的稀疏性和不确定性拖垮。这个"工业级 Agent 意图识别分层漏斗",就是我在反复踩坑之后沉淀下来的整套方案:不靠一个模型打天下,而是用分层递进的漏斗结构,把不同成本、不同精度的技术手段串起来,层层过滤、步步收敛,最终得到稳定可控的意图判定结果。
这套东西能解决什么问题?最直接的一点,是把传统"一个分类器识别所有意图"的粗放式做法,替换成"四层漏斗逐级收窄"的工业级管线。它可以让意图识别的整体精确率大幅提升,同时显著压缩误召回——也就是把本不该进入 Agent 流程的输入硬塞进来。它还顺带解决了两个容易忽视的问题:一个是成本,因为在高层级识别之前,大部分流量已被廉价规则和轻量模型滤掉;另一个是审计效率,每一层都有独立的日志和监控,压力大了知道该优化哪一层,而不是面对一个黑盒模型发呆。
如果你正在做 Agent 类产品、对话系统、客服机器人,或者任何一个需要"理解用户到底想干什么"的系统,这篇文章应该能给你一套立刻能落地的参考。我会把自己实际调参、踩坑、回放过数据的经验全部写进来,包括每一层的阈值怎么定、负样本怎么喂、兜底策略怎么设计,以及上线后我遇到过的最离谱的几个线上事故。下面直接进入正题。
1. 项目概述:为什么非得分层不可
1.1 单模型意图识别的三个硬伤
先说单模型的方案。当时我手里的 Agent 负责电商售后场景,意图大概有十来个:查物流、申请退货、修改地址、开发票、转人工、闲聊等等。第一批实现朴素得很,直接用中文 BERT 接一个多分类头,输入用户文本,输出意图标签。这套东西在测试集上看着挺美,精确率 88%,召回率 85%,领导和产品都满意。但上线一周,各种问题就浮出来了。
第一个硬伤是长尾分布。真实流量里"查物流"可能占 45%,"开发票"只有 2%,模型对高频意图学得滚瓜烂熟,对低频意图却经常误判。用户说"我要电子发票,抬头是公司名",模型居然分到了"查物流",原因无非是"发票"相关的训练样本太少,而"单号""运单"这些词在物流样本里高频出现,模型学会了偷懒的特征匹配。
第二个硬伤是误召回代价极高。Agent 一旦被错误触发,后面跟着的是一长串下游动作:调用订单接口、发短信通知、生成工单、甚至直接执行退款。误召回一个"开发票"的用户,后果顶多是解释两句;但误召回一个"投诉"意图并触发投诉工单,那名用户可能直接被打电话回访,场面相当尴尬。单模型天生没有"我不知道这是什么"的选项,或者更准确地说,没有为"拒识"做专门设计,导致所有输入都被强行塞进某个意图桶,边界样本自然到处乱跳。
第三个硬伤是迭代成本。每次想新增一个意图类别,都要重新准备数据、重新训练、全量回归。可 Agent 业务本身就处在快速变化期,每周都会有新的用户诉求冒出来。一个负责判别意图的模型变成全团队的修改瓶颈,这在工程上是灾难性的。也就是从那时候起,我下定决心拆漏斗。
1.2 分层漏斗解决的核心矛盾
分层漏斗的本质思路,是把"一次精确判断"拆成"多次低成本渐进判断"。它像质检流水线:第一个工人只看外观,明显有问题的直接拿掉;第二个工人用尺子量尺寸,不达标的再剔一批;最后一个工人上精密仪器,只查那些前面都没筛掉的"可疑但重要"的工件。每道工序都不完美,但组合起来,整体良品率可以做到非常高,而且每一道工序都可以独立优化、独立换人、独立换设备。
对应到意图识别,这套漏斗分成四层:准入层、粗意图层、参数解析层、兜底拒识层。前三层各司其职,第四层处理所有"不确定"。其中设计上最关键的权衡点是:让第一层用最便宜的手段接住所有流量,用高召回低门槛挡住无关输入;让第二层做粗粒度识别,只区分几个大类;让第三层才做细粒度意图确认和参数抽取;第四层用规则与人工协作兜住边界情况。这样每一层都专注单一目标,调参互不打扰,数据回流也清清楚楚。
1.3 落地后的直观收益
在数据上,漏斗带来的收益可以量化。以我负责的电商售后 Agent 为例:
| 指标 | 单模型基线 | 四层漏斗 | 变化 |
|---|---|---|---|
| 意图分类精确率 | 82% | 96% | +14pp |
| 误召回率(不该触发而触发的比例) | 14.5% | 2.1% | -12.4pp |
| 低频意图的分类 F1 | 0.62 | 0.86 | +0.24 |
| 单请求平均识别耗时 | 230ms | 45ms | -80% |
| 大模型调用成本 | 全部请求直出 | 仅 25% 请求进入高层 | 降低约 60% |
需要说明的是,这些数字是在按真实流量分桶的评测集上测出来的,不是实验室数据。漏斗方案不仅让精度上去了,还顺手把延迟砍了一大截——因为最长链路只发生在少量真正复杂的样本上。这里我不展开讲每个层是怎么算出来的,下一节直接拆架构。
2. 架构设计:四层漏斗的具体职责与选型
2.1 第一层:准入层(最关键的一层)
准入层是漏斗的入口,所有用户输入都要先过这一层。它的职责很简单:判断"这条输入到底值不值得这套 Agent 处理"。用电商售后场景举例,用户说"这个商品的优惠券怎么领",这可能是购物咨询而不是售后 Agent 该管的,直接在这一层就拦掉。用户说"我的快递三天没动了",这才有资格进入后面的意图识别。
为什么说这层最关键?因为它是整个漏斗的成本闸门。所有流量都在这里过一遍,如果手段不够便宜、不够快,后面再精巧的设计都白搭。我在这层用的是"正则规则 + 轻量文本分类器"的组合:先跑一遍规则,命中关键词如"物流、快递、退货、发票、售后"等,直接放行;没命中规则的,再交给一个基于 FastText 或者 TextCNN 的小模型判断。整个组合平均耗时 3ms 左右,单机 QPS 能扛到几千,成本几乎可以忽略。
准入层的核心指标是召回优先。宁可多放进来 20% 的无关输入,也不要有 1% 的相关输入被挡在外面。因为这一层只要漏掉一个"真意图",后面再没有任何机会捞回来;而多放进来一些垃圾,最多给第二层徒增一点计算压力,整体影响可控。我在实操里把准入层的召回目标定在 99.5% 以上,精确率不做强约束,能到 60% 就算合格。你甚至可以把准入层理解成"海选"——筛人筛得松,但绝不误杀。
准入层的另一大职责是防垃圾输入。像"哈哈哈""在吗""草"这种无意义消息,如果放着不管,它们会一路跑到第三层去消耗大模型算力。这类负样本在快节奏对话场景里占比不低,我抽样统计过,大约有 8% 的线上消息属于这种类型。把它们在准入层就拦下来,省下来的是整条管线的算力预算。
2.2 第二层:粗意图分类层
过了准入层,剩下的输入大概占全量的 40% 到 50%,这时候才轮到真正的意图分类。但注意,这一层只做"粗粒度"分类。电商售后场景中,我把意图先归成四五个大类:售后事务、订单查询、商品咨询、转人工、其他。注意这里不区分"退货"和"换货",也不区分"查物流"和"查订单状态",这些细粒度区分交给第三层。
为什么先做粗分类?因为大类之间的区分度大,分类模型在小样本下也能学得比较稳。相反,如果一上来就做 15 个细类,类别间语义重叠多,误判率立刻飙升。以"退货"和"换货"为例,两者本身就在同一个语义空间里,很多用户表述甚至完全相同——"我不想要了"到底是退还是换,得靠后续追问,第一轮根本没办法百分百判准。把它放在粗分类里当"售后事务",就回避了这个问题。
这一层我用的方案是中等规模的预训练分类模型,比如中文 BERT base 或者 RoBERTa-wwm-ext,输出类别加置信度。效果上,粗分类的精确率能做到 90% 以上。有些团队图省事,想让大模型做这一步,但我的建议是,在流量大的场景里能不用 LLM 就不用 LLM,因为粗分类的语义边界足够清晰,小模型完全扛得住,而大模型的单次调用成本大约是微调模型的 50 到 100 倍,延迟还要多出几百毫秒,完全没必要。
对了,这一层的输出不是简单的标签,还包括置信度。置信度是第四层兜底判断的重要输入。我习惯于让分类器输出归一化概率,而不是只用 argmax 取最高分类。概率分布本身就能泄露很多信息:比如"退货"0.45、"换货"0.40、"修改地址"0.15,这种分布一看就是典型的意图模糊样本,高置信度标签根本不可信。
2.3 第三层:细粒度参数解析层
第三层做两件事:确认细粒度意图,提取执行该意图所需的参数。举个例子,第二层判了"售后事务",第三层要进一步确认是"退货"还是"换货",并从文本里提取订单号、商品名称、退款金额等槽位。可以说这一层才是真正直接对接 Agent 执行动作的环节。
参数解析可以用两种路线。第一是传统的序列标注模型,BERT + CRF 或者 BERT + 指针网络,对"订单号""手机号""地址"这类固定形态的实体提取效果很稳。优点是快和便宜,缺点是扩展性差,新加一种实体就要标注一批数据重新训练。第二种路线是最近两年更加主流的 LLM 结构化输出,直接把指令和文本一起丢给大模型,让它返回 JSON。像"帮我查一下订单 778899 到哪了"就返回:
{ "order_id": "778899", "query_type": "logistics_query" }我的建议是,在漏斗前几层明确过滤之后,剩下的流量洞察一个大概的规模,再来决定第三层选哪条路。如果每天只有几千次请求进入第三层,直接上 LLM 性价比很高;如果每天有几十万次,我还是建议用小模型,因为大模型单层的成本会重新变成整条链路的瓶颈。这里也体现出了漏斗的分层价值:因为有前两层挡着,第三层的流量压力被压到很小,使用何种昂贵方案就有了充裕的决策空间。
2.4 第四层:兜底与拒识层
兜底层是漏斗唯一负责"拒绝"的环节,但它拒绝的不只是垃圾。它处理的目标有三类:第一类是第二层或第三层输出的低置信度结果,比如分类置信度低于 0.5 的样本;第二类是第三层参数解析失败的情况,比如用户说了半天,但关键的订单号始终没给出来;第三类是触发安全规则的输入,比如涉及投诉、舆情、人身攻击等敏感内容,这时候绝不能盲目触发 Agent 动作。
这一层最常见的落地形态是"规则引擎 + 人工审核队列"。当样本命中低置信度或参数不全的规则时,系统转入一个兜底状态:能明确追问的就让 Agent 发起澄清对话,追问完再回到漏斗重跑一次;连澄清都没法处理或者风险过高的,直接转人工。这样做的好处是给了整个漏斗一个"优雅退出"的出口,而不是把每个不确定样本都硬生生推进一个意图桶里。兜底层是整个漏斗里最容易被人忽略,但也是把精度的最后几个百分点提上去的关键。
2.5 各层流量分布与设计折中
为了让分层逻辑更直观,我用一组典型的线上流量数据模拟一下分布。假设每天进来一万条消息,经过漏斗后可以看到:
- 10000 条进入准入层,其中 4200 条被判定为与 Agent 域相关,其余 5800 条直接拦截;
- 4200 条进入粗意图层,其中 3600 条有明确的粗意图归属,600 条置信度过低,进入兜底;
- 3600 条进入参数解析层,其中 3400 条细粒度意图确认成功且参数完整;
- 兜底层最终处理约 600 + 200 + 少量安全触发样本,总体控制在 10% 以内,其中有大约一半通过追问在下一轮回到漏斗。
这样看就很清楚:每一层都在压缩上游流量,让下游始终面对的是"难度高但量不大"的样本。单层的高精度是漏斗的基础,但真正让整体精度变稳定的,是这个层层收窄的流量结构本身。
3. 核心细节解析与实操要点
3.1 阈值不是拍脑袋定的:置信度分桶法
第二层和第四层都依赖阈值,但阈值怎么定非常讲究。很多人拿测试集跑一遍,"哦,精确率 92%,那就用 0.5 作为置信度阈值吧"。这种做法在产品初期可以,一旦面向线上真实分布,往往漏洞百出。我自己的做法是置信度分桶法:拿最近两周的线上日志,让第二层模型逐条预测,把所有样本按置信度从低到高分成 20 个桶,每个桶单独算精确率和召回率。然后画出一条"置信度-精确率"曲线,根据这条曲线选阈值。
举个例子,观测数据可能显示置信度在 0.3 到 0.4 之间的桶,精确率只有 62%;而置信度在 0.5 到 0.6 的桶,精确率已经到 85%;0.8 以上才稳定到 96%。这样我就有充分根据把第二层的阈值定在 0.8 附近,而不是凭空拍一个 0.5。分桶的价值在于直接暴露"模型自以为有把握但实际不行"的那些区间,这在单模型方案里根本看不到。
3.2 负样本是漏斗的血液,但也是最难搞的资源
整个漏斗里,最影响效果的不是正样本,而是负样本。正样本告诉模型"这是个什么",负样本告诉模型"这不是什么"。可实际工程里,负样本恰恰是最难收集的。
我在准入层的负样本池里放过以下来源:客服系统历史会话里的无关消息、社交媒体句式、闲聊语料、评测集里的对抗性改写。粗意图层的负样本则更讲究:不能拿另一个域的正样本当负样本,因为那样模型会努力区分两个域,反而影响本身分类的鲁棒性。我常用的构造方法是"语义混淆"——比如"退货"这个意图,它的负样本可以是"我不小心点错退款了怎么办",这句话里有强关键词"退款",但语义上不属于主动申请售后的行为,应该转入咨询或人工。这一类"假阳性"样本对精度的提升帮助最大。
3.3 冷启动阶段怎么凑数据
新项目最绕不开的问题是没有历史标注数据,漏斗再精巧也白搭。冷启动阶段的思路是分阶段凑数据,而不是一开始就追求大规模。我在冷启动期做过三件事:
第一,从客服系统导出三个月的历史会话,拿原始话术粗标注一轮,只标粗意图四个大类,不标细类。这个阶段标注速度很快,两三天就能凑出一万条粗粒度训练数据。第二,针对高频细类如"退货""查物流",单独拎出所有包含关键词的句子,人工筛掉明显不相关的,凑出细粒度数据各几千条。第三,利用大模型生成一批"对抗样本"。拿已有的正样本,让 LLM 改写为语义相似但表达方式更怪异的变体,作为负样本池的扩充。
数据量少也别慌,漏斗的好处在于每一层的任务都被拆简单了。粗意图分类只需要区分几个大类,几百条样本就能跑起来;参数解析用已有的预训练模型直接 zero-shot 也能扛一阵。等数据多了再逐步把每层模型换成更强配置,整个过程是渐进式的,不会卡在"没有数据就不能上线"的死结上。
3.4 各层技术选型背后的理由
不同层选择不同技术路线,不是随意的,背后都有对应考量:
| 层 | 技术方案 | 取舍理由 |
|---|---|---|
| 准入层 | 正则规则 + FastText/TextCNN | 成本极低、速度极快、召回优先 |
| 粗意图层 | BERT base 类模型微调 | 语义边界清晰,兼顾性能与成本 |
| 细粒度参数层 | 小模型序列标注 或 LLM 结构化输出 | 视流量而定,流量大用小模型,流量小用 LLM |
| 兜底层 | 规则引擎 + 人工队列 + 追问机制 | 不需要模型参与,靠策略管理不确定样本 |
这里有个常见误区是"哪一层都要用最先进的模型"。工业级的核心不是炫技,而是让每一层恰好匹配它的问题难度。准入层如果上了 BERT 甚至大模型,纯粹是浪费;参数解析层如果硬让小模型做它力所不能及的高复杂度抽取,又会发现瓶颈在能力上而不是成本上。漏斗设计的一个隐形好处,就是让你不得不认真思考每一层的能力上限,该换方案的时候换方案,不用为了统一技术栈而把不同难度的问题硬塞进一个模型。
4. 实操过程与核心环节实现
4.1 准入层的落地方案与代码
准入层的落地很简单,主体是规则加分类器。规则层我用关键词匹配,加了一点简单的否定词处理。一个容易踩的坑是:用户说"我不要退货我怎么查物流",如果规则只看见"退货"就放行,后面粗意图层极可能因为"退货"这个强特征而误判。这时候需要一个轻量的否定前缀判断,我用的是一份精心整理的否定词表加上位置关系检查,代码示例如下:
NEG_WORDS = ["不", "不要", "别", "取消", "撤", "拒"] def pass_gate_by_rule(text): for neg in NEG_WORDS: # 如果否定词出现在意图关键词之前,说明用户是在否定该意图 text = text.lower() if neg in text: intent_keywords = ["退货", "退款", "换货", "投诉"] for kw in intent_keywords: if kw in text and text.find(neg) < text.find(kw): return False domain_keywords = ["物流", "快递", "运单", "退货", "发票", "售后", "订单", "优惠券"] return any(kw in text for kw in domain_keywords)规则命中不了的,再到 FastText 分类器里过一遍。这个分类器我用的是一份 5 万条的粗标注数据,二分类:is_agent_domain为真或假。FastText 训练很快,十几分钟就能出一个 baseline,后面持续迭代。准入层的整体逻辑是规则命中 OR 分类器判定,因为要保证高召回,两个信号只要有一个为真就放行。
4.2 粗意图分类层的实现
粗意图层的核心是一个多分类模型。我用的框架是 HuggingFace Transformers 加 PyTorch Lightning,中文预训练模型选了hfl/chinese-roberta-wwm-ext。训练数据大概两万条,覆盖五个大类,比例按真实流量分布做了重采样,避免高频类压倒低频类。损失函数用带标签平滑的 CrossEntropy,标签平滑系数 0.1,用来缓解过度自信,因为过度自信会让置信度阈值形同虚设。
推理时不要只拿 argmax,要把完整概率分布拿出来。我用下面的结构组织输出:
class CoarseIntentResult: label: str # 粗意图标签 confidence: float # 最高类的概率 topk_labels: list topk_scores: list raw_probs: dictraw_probs一定要存下来,后面兜底层判断"是不是意图模糊"很可能就直接看它。比如最高两类概率分别是 0.45 和 0.42,说明用户语义横跨两个意图,让 Agent 直接按最高类执行很容易出错。这个信息在单模型方案里是拿不到的,也是漏斗让我觉得最有价值的点之一。
4.3 参数解析层的实现
参数解析层我用的是小模型加 CRF 的路线,原因是流量大、延迟预算紧。具体做法:基于中文 RoBERTa 编码文本,接一个线性层做序列标注,标签是 BIO 格式,实体类型包括订单号、地址、电话、商品名、金额。这部分对设备要求不高,单条推理延迟在 15ms 到 30ms 之间。
但序列标注模型有个局限:对"订单号"这种实体,不同商家格式不同,模型很难泛化。所以我配套了一个后置规则校验模块,比如先尝试用正则提取 8 到 12 位纯数字、以字母开头的运单号,正则提取不到的,再交给模型。把规则和模型结合是参数提取稳定性的关键点。规则能覆盖的格式不会错,模型可以在规则覆盖不到的格式上兜底。
4.4 兜底策略与回退机制
兜底层不需要训练模型,它只是一套策略组合。我搭的核心逻辑是:
if 粗意图置信度 < 0.8: if 有追问模板: 进入澄清对话 -> 得到新输入再走一遍漏斗 else: 转人工 elif 参数解析缺失关键槽位: 发起澄清对话,收集缺失参数 elif 命中安全规则(投诉、负面情绪): 转人工并标记优先级 else: 触发Agent执行这套回退机制上线后,一个很大的收益是人工坐席不用处理所有模糊样本,而是只处理兜底队列里那些真正高风险或多次澄清不成功的。在漏斗前几层调优正常的情况下,兜底队列的占比能控制在 10% 以下,人效提升非常明显。
5. 常见问题与排查技巧实录
5.1 高频问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 误召回突然升高 | 线上用户话术漂移,负样本池过期 | 每周拉取新日志补充负样本 |
| 某类意图被严重拒识 | 该类训练样本太少或置信度阈值过高 | 单独对该类扩充正样本,检查置信度分桶曲线 |
| 参数解析经常漏订单号 | 正则规则没覆盖新格式,或实体标注不充分 | 补充规则、增量标注实体 |
| 大模型直出意图时成本爆炸 | 大量请求穿透漏斗直接到达高层 | 检查第一层规则是否丢失、第三层是否绕过了直接调 LLM |
| 澄清对话反复循环 | 追问模板设计不匹配用户打字习惯 | 增加更贴近口语的澄清话术模板 |
| 高峰时段小模型延迟劣化 | 单机推理队列堆积 | 扩容部署实例,加一层缓存 |
5.2 案例复盘:一场误召回事故
有一次线上突然出现大批用户被错误触发退货流程,所有指标都显示异常,但模型本身并没有改版。我查了一整天日志,最后发现根因是负样本采集脚本出了 bug:它从客服系统抽数据时,把"我不想退货了,帮我撤销一下"这类本身是"撤销售后"的句子,直接标记成了"退货"意图的正样本喂进了模型。模型学到的短期规律是"退货"这个词只要出现,意图大概率就是退货,导致误召回疯涨。
这个经历让我立下两条铁律:第一,所有自动抽取的训练数据必须过一遍人工抽检,抽检比例不低于 5%,尤其是那些自动标注的样本;第二,负样本和正样本的标注流程要分开,不能只靠采集脚本自动完成。数据管线的质量,最终会直接反映到漏斗每一层的精度上。
5.3 长尾意图与分类漂移怎么处理
长尾意图是漏斗架构里最棘手的部分。用户表达"我买的那个蓝色耳机有杂音"时,可能同时涉及"商品咨询"和"售后投诉",但两种情况的下游动作完全不同。面对长尾,我的处理是把"意图混淆"直接纳入设计,而不是试图消灭它。做法是在数据标注时引入"混合意图"标签,凡是标注员觉得同时属于两个意图的样本,单独打上一个ambiguous标记,训练时让模型学习输出这个标签。实测下来,这类样本的置信度往往偏低,本身就容易被兜底层接住,不需要在分类上强求唯一答案。
分类漂移是另一个问题。用户话术会随着时间变化,去年流行的表述今年可能没人用了,新句式却不断出现。我建立了每周一次的自动评估流程:跑全量线上日志,计算每一层的"漏斗流失率"指标,即多少比例的输入在哪一层被拦截。如果某层的流失率连续两周明显偏离历史基线,就要触发人工排查,判断是该调阈值还是该补数据。这套机制帮我在不少问题演变成事故之前就把它摁住了。
6. 工程化集成与后续扩展
6.1 漏斗与 Agent 编排框架的关系
做 Agent 应用的人都会接触各种框架,有的叫 Agent framework,有的叫 harness,本质上都是在回答"Agent 怎么组织工具调用、记忆、任务编排"。我的经验是,漏斗这种意图识别模块应该放在 framework 的最上游,作为整个人机交互的第一个决策点。框架再强大,接收一个错误意图后调用一堆无效工具,用户体验照样崩。反过来,如果漏斗足够准,下游的工具调用、API 编排、多轮对话才有意义。
所以我的工程结构是:漏斗意图识别模块作为独立服务提供统一接口,Agent 编排层只消费它的输出结果,不直接感知内部分层逻辑。这样意图识别和 Agent 编排可以独立迭代、独立扩展,互相不阻塞。团队里如果有人想改排序算法,只需要改自己的服务,不需要碰 Agent 编排框架里的任何代码。
6.2 监控体系怎么搭
漏斗架构比单模型好的一点是每一层都可以单独计数、单独打点。我的监控看板上有几个核心指标:各层的流量通过率、各层之间的流失率、第二层的置信度分布、兜底队列的日周转时长、误召回率和漏召回率。这五个指标基本可以覆盖整个漏斗的健康度。
实际操作中有个细节值得强调:不要只看绝对值,要看趋势。单日内自然会有高峰低谷,日环比也会波动,真正应该盯的是周同比和七日移动平均。我见过不少同学,看到某天召回率掉了 2% 就紧张得不行,拉了一整天日志发现只是当天来了几波营销活动带来的异常流量,虚惊一场。把趋势预设好,异常检测直接基于七日移动平均的 z-score,能省大量无效排查时间。
6.3 从意图漏斗到意图路由:多 Agent 场景的延伸
漏斗这套思想并不局限于一个 Agent。当一个系统里跑着多个 Agent,比如售后 Agent、营销 Agent、物流 Agent、财务 Agent,意图识别的结果其实就是一个路由决定:这个用户输入应该交给哪个 Agent 处理。我最近在做的扩展,是把漏斗的前两层抽象成"路由层",第二层的粗粒度分类改为"目标 Agent 选择",后面的参数解析逻辑保持不变。这样不需要为每个 Agent 单独搭一套识别模块,而把它们共享同一个漏斗入口。
这种架构的好处是跨 Agent 意图可以相互排障。比如"退款"这个意图可能同时出现在财务 Agent 和售后 Agent 的范围里,放在同一个漏斗里做粗分类,可以统一制定归属规则,并在兜底层统一处理边界问题。对想要搭建多 Agent 协同系统的团队来说,分层的价值会比单 Agent 场景更大。
最后再分享一个顺手的小技巧:跑漏斗的评估时,尽量用整段对话而不是单条消息。很多人只拿当前这条输入做意图识别,但用户的真实意图往往放在上下文里——前一条说"我要退货",这条只说"帮我办一下",单看这句谁也不知道"办"什么。我现在的做法是每次请求把最近三到五轮对话拼接成一个上下文窗口,再送入漏斗。这个改动在长对话场景里把意图识别 F1 提高了将近五个百分点,而且实现成本非常低,算是我这段折腾下来最划算的一次投资。