
1. 为什么工业级Agent意图识别要设计成漏斗工业级Agent意图识别分层漏斗这个说法听起来像学术名词但它本质上就是我日常在生产环境里反复折腾的一件事用户一句话进来系统必须判断这句话属于哪个业务域、要完成什么动作、需要哪些参数然后才能决定让Agent去调什么工具、走什么流程。如果这第一步没做好后面哪怕挂了再强的Agent框架也是白搭——指令错了工具调用再顺都是在错误的方向上加速。我先说个真实场景。用户对客服机器人说“帮我把上周那个订单的地址改一下。”这句话的意图链至少包含三层业务域是“交易/订单”细粒度意图是“修改配送地址”槽位包括“订单编号”“新地址”“时间限定词”。如果意图识别只给了一个粗标签“售后咨询”那下游的Agent根本不知道该调哪个接口。更麻烦的是真实用户不会按文档说话他们可能说“上次买的东西寄错了地方”“能不能换个收货地址”“我地址填错了”。这些都是同一个意图的不同表达但对工业系统来说每一个说法都可能触发不同的误判。工业级和Demo级的差距就在这。Demo只需要在几十条干净样本上跑通工业级要面对几百万条真实对话、不断新增的业务意图、动不动就改版的话术还有权限校验、敏感操作拦截、审计回溯这些硬性要求。所以我把意图识别设计成分层漏斗不是出于架构洁癖而是被线上事故逼出来的方案。1.1 工业级与Demo级差的不仅是吞吐量很多团队一开始都会走捷径把所有意图塞进一个大模型提示词里让模型直接输出最终标签。Demo阶段确实快几分钟就能跑通。但上了生产环境就会发现三个问题。第一是意图空间爆炸。业务方今天加一个“发票邮寄地址变更”明天加一个“电子发票抬头修改”后天又加一个“发票重开”。如果所有意图都靠同一个分类模型或同一段提示词维护每次新增意图都可能影响既有分类的稳定性你几乎无法对单个意图做精细调优。第二是可解释性差。线上有一条用户消息被错误处理后你是没辙去判断是业务域分错了还是细粒度意图分错了还是槽位抽错了。整个系统就成了一个黑盒业务方来问“为什么这个订单被取消了”你只能摊手说“模型觉得用户想取消”。这种回答在一次两次的场合还行次数多了业务方对整个Agent的信任就崩了。第三是成本失控。意图识别如果每一轮对话都调用重量级大模型且不说延迟光是成本就够喝一壶。真实业务里大量请求是重复的、固定的、甚至与业务无关的“废话”把这些流量全部塞给大模型属于典型的资源浪费。漏斗架构天然解决这三个问题。它把“意图识别”这个大任务拆成了若干层每层只做一件小事每层都有独立的模型或规则每层都能单独测试、单独回滚、单独统计错误率。就算出了事故也能马上定位到具体是哪一层出了问题而不是在一团浆糊里找原因。1.2 一次分类不够漏斗是工程妥协的最优解我经常被人问“你说的漏斗到底是个什么形状”其实它就是一组从宽到窄的过滤器像筛沙子一样每一层筛掉一部分信息把用户的模糊表达逐步收敛成机器可执行的指令。第一层是系统级开关负责拦截“帮我重新开始”“你叫什么”“停一下”这类跟业务无关的指令以及触发安全策略的异常输入。第二层是业务域分类把请求分到交易、物流、售后、账号等大的领域。第三层才是细粒度意图识别在领域内确定用户到底想干什么。第四层做槽位抽取把时间、地点、对象、数量这些执行动作必需的参数捞出来。最后才是动作决策判断能不能直接执行、需不需要和用户确认、要不要转人工。每一层都有明确的输入、输出和置信度阈值哪怕其中某层判断错了错误也不会直接放大成整套流程的崩溃。更重要的是这种结构适合团队协作规则工程师可以单独维护第0层算法工程师专心优化第1层和第2层的分类器业务分析师可以定义第3层的槽位规则大家互不干扰。工业系统本质上是一种工程妥协。漏斗不是最聪明的方案却是最好维护、最好对账、最好向业务方解释的方案。它舍弃了单模型端到端的优雅换来的是可运营、可问责的确定性。1.3 什么样的场景适合分层什么样的场景别硬分层这里我必须泼一盆冷水。分层漏斗不是所有Agent场景的银弹。如果你做的是一个开放域闲聊助手用户说“今天心情不好”“给我讲个笑话”“你觉得人生的意义是什么”这些话语的“意图”本来就是软的强行分业务域反而会让对话变得机械。这类场景保持单层的对话决策模型用大模型生成的方式去驱动效果更好。分层漏斗最适合的是任务型对话Agent尤其是背后有确定业务系统要对接的场景。客服机器人、企业内部的IT工单助手、运维操作机器人、电商导购、医疗预问诊这类系统天然需要结构化信息去调用API或触发业务流程。用户的目标是完成一件事不是陪你聊天所以“把意图搞清楚”本身就是核心价值。还有一个特殊情况我要提醒当两个业务的意图高度重叠时硬分层会导致意图边界一直扯皮。比如“改地址”既可能属于交易域也可能属于售后域。遇到这种情况我的建议是把并行的业务域判断改为带置信度的多标签打分而不是强制单选。后面我会仔细说这个先记住原则漏斗的每层边界一定要清晰如果连你自己都说不清两个意图有什么本质区别那模型更分不清。2. 分层漏斗的整体架构与每一层的职责明确了为什么需要漏斗接下来就要动手设计每一层。我基于自己落地的生产系统经验把意图识别漏斗分成五个层次。这五层不是一次请求必须走完的而是随时可以短路跳出很多简单请求在第0层就结束了。2.1 第0层系统级规则闸门先掐掉高频和危险请求第0层是我的最爱因为它最便宜、最稳定、最容易排查。它的职责不是理解业务而是做一次快速的信号筛选把三类东西先处理掉。第一类是会话控制类指令例如“帮我清空记忆”“换个话题”“重新回答”“停”“别说了”。这一类指令如果让大模型去判断既浪费上下文窗口又容易和业务意图混淆。第二类是高频固定请求例如“人工客服”“转人工”“我要投诉”这些在客服系统里往往是最高频的入口直接路由到对应的处理通道就好没必要往下走。第三类是安全与合规拦截例如包含敏感个人信息、恶意代码片段、明显越权指令的输入。这一层必须无条件挡在前面否则一旦进入后面的Agent工具调用环节风险会被放大。实现这一层我会用关键词规则加正则再加一个极轻量级的文本分类模型做补充。规则负责确定性拦截模型负责覆盖模糊变体。我见过很多团队跳过这一层结果Agent的上下文窗口里充满了“转人工”“傻逼”“你能不能听懂人话”这类没有营养的输入既占token又干扰主意图判断。这层的输出只有三种直接执行固定动作、终止或转移会话或者放行进入下一层。放行比例通常控制在40%到60%之间。我自己的一个客服项目里第0层拦掉了大约45%的流量这一下就把后面大模型的调用成本直接砍掉了一半。2.2 第1到2层粗粒度业务域与细粒度意图的接力第1层做业务域分类第2层做细粒度意图分类。很多团队觉得这两层可以合并但我建议无论如何都不要合并。核心原因是细粒度意图的分类器只有在业务域确定的前提下才能保证分类空间的稳定性。以电商客服为例第1层要区分“交易咨询”“物流查询”“售后处理”“账号安全”“营销活动”五个域。用户说“我那个快递怎么三天没动了”在第1层会被分到“物流查询”域。然后进入第2层只需要在这个域内判断具体意图“查询物流轨迹”“修改收货地址”“催派送”“投诉快递员”。如果不在第1层先做收窄第2层就要在五十个意图里做单选训练样本的稀疏性和类间混淆会瞬间膨胀。第2层还要处理一个被很多人忽略的问题意图链。真实用户往往会在一句话里表达多个意图例如“帮我改一下收货地址顺便看看能不能加急”。这个时候不能输出单一意图标签而是应该输出一个意图序列并标明主意图和从意图。我的做法是让模型输出一个带有优先级排序的意图列表主意图决定主流程从意图进入待办队列。这一层的技术选型可以灵活。如果某一业务域的标注数据足够我会用一个小型的文本多分类模型速度快、成本低。如果标注数据不足或者业务频繁增加新意图我会用大模型加few-shot提示词。提示词里只需要给出这个业务域内的意图定义和几个经典例句准确率已经足够工业使用。2.3 第3层槽位参数与实体抽取真正干活的层意图识别做了业务判断真正让Agent能干活的是槽位抽取。这一层要把“上周那个订单”“朝阳区”“加急”这些口语表达转换成结构化参数。没有参数意图再准也没用因为业务系统不接受模糊指令。同样拿“帮我把上周那个订单的地址改到朝阳区”举例。意图是“修改收货地址”但接口需要的是订单编号、老地址、新地址、期望送达时间。这里的难点在于“上周那个订单”不是直接的订单号系统必须先根据用户会话里的身份信息和时间线索去关联到具体的订单ID。工业级的做法是槽位抽取模型先抽出“上周”相对时间、“朝阳区”新地址然后把这两个槽位当作查询条件在订单系统里检索匹配的订单再把候选订单列表返回给用户确认。槽位定义是这层最容易出错的地方。我见过团队把所有能想到的字段都定义为槽位结果模型要抽取的东西太多反而每个都抽不准。我的经验是槽位必须由下游接口反向定义——你打算调用哪个接口这个接口需要什么参数那就只定义这些参数作为槽位。多一个槽位就是多一份出错风险。此外槽位抽取要处理好回指和省略。用户在第一轮说“我买了一个红色保温杯”第二轮说“帮我看看这个杯子还有没有货”“这个杯子”就需要结合第一轮的“红色保温杯”来补全。工业上必须把历史关键词和实体映射存入会话状态让槽位抽取模型能看到前文摘要和已抽取槽位。2.4 第4层动作决策、澄清与安全兜底漏斗的最后一步不是结束而是检查和决策。这一层我会做三件事。第一件是参数完整性校验。把已抽取的槽位跟目标接口的必填参数比对缺哪个就问哪个。这里的问法有讲究不能笼统地问“您确认要修改地址吗”要直接问最关键的缺失槽位“请问您要修改哪一个订单”这样用户一次回答就能补齐信息减少来回次数。第二件是安全与权限校验。意图识别之后要执行的动作必须经过权限系统的检查。用户有没有权限操作这个订单这个操作是否需要二次确认是否属于高风险操作需要转入异步人工审核我把这些判断放在漏斗末端因为这个位置已经拥有了完整的上下文可以做出更准确的业务决策。第三件是Agent Harness的对接。意图、槽位、动作决策都完成后把这些传递给Agent运行外壳由Harness负责真正的工具调用、Agent记忆管理和多Agent调度。分层漏斗的输出在这里变成一种“路由信号”决定哪个工具被调用、调用的参数是什么、执行结果要回流到哪个会话状态。这也是工业级Agent与玩具Demo最本质的区别前者有清晰的边界每一层都知道自己在干什么。3. 实操落地从0到1搭建一套可用的意图漏斗架构说得再漂亮落不了地就是纸上谈兵。我按自己重复过很多次的搭建路径把整个实施过程拆成四个步骤每一步都给出可以直接抄作业的细节。3.1 第一步先定义意图体系命名规范决定后面所有工作我踩过最大的坑就是意图命名混乱。最开始图省事直接把意图命名为“改地址”“查物流”“开发票”结果做到一半发现“改地址”这个词在物流域和交易域的含义并不完全相同模型训练数据也分不清。后来我养成了一个习惯所有意图严格按照“业务域_动作_对象”三段式命名。比如“trade.modify.shipping_address”表示交易域修改配送地址“logistics.query.track”表示物流域查询物流轨迹。这样命名有三个好处。第一看到意图名就能确定它属于哪个层级不会把不同域的相近意图混在一起。第二新增意图时只需要在对应域内追加不会打乱整个分类体系。第三模型输出的意图名可以直接作为后续接口路由的键值省去一次映射转换。定义意图体系的同时同步建立意图的口语化表达集。不要只写标准话术要专门收集真实对话里的变体说法。用户在客服场景里不会说“取消订单”他们可能说“我不要了”“申请退款”“麻烦把这单退掉”。我需要给每个意图配上至少20到50条真实表达标注时直接基于这些表达打标用来作为分类器的训练样本或大模型few-shot里的示范例句。3.2 第二步分层选型规则、小模型与大模型怎么排兵布阵意图漏斗每一层所用的技术栈可以是不同的。我给出的选型原则是越靠下的层越便宜越快速越确定越靠上的层越智能越灵活越昂贵。第0层和部分第1层用规则和轻量分类器就能解决第2层和第3层才有必要动用大模型。我整理了一份参考方便大家根据自己的资源和业务特点选型漏斗层级常用技术方案适用条件成本量级第0层系统级闸门正则规则 关键词列表 轻量分类模型意图固定、变化频率低几乎为零第1层业务域分类微调小模型如几亿参数的文本分类模型或大模型few-shot有几千条标注数据即可小模型极低大模型中等第2层细粒度意图识别大模型few-shot或小模型微调依赖业务域内的数据丰富程度与大模型调用次数正相关第3层槽位抽取大模型function calling / 序列标注模型需要结构化输出必须对接下游接口参数单次成本最高第4层动作决策规则引擎 大模型置信度校准需要结合业务权限和状态机按需触发这里我要特别强调很多人容易陷入“全部用大模型”的思维定式。实际上一个业务域的细粒度意图分类如果你积累了足够多的标注数据用一个小模型的效果不会比大模型差而且推理速度更快、推理成本更低。大模型的定位应该是“弹性补充”负责小模型覆盖不了的长尾场景和新意图冷启动。我的常用套路是启动阶段全用大模型few-shot快速跑通业务闭环同时记录所有输入输出经过人工抽样修正后沉淀成标注数据当某个业务域的标注数据量超过三千条就训练一个轻量小模型来承接该域的意图分类任务大模型退居为小模型低置信度时的兜底。这套路兼顾了上线速度和长期成本。3.3 第三步层级之间的数据结构与多轮状态传递漏斗各层之间传递的绝对不是一个裸文本而是结构化对象。每一层读取上一层的输出追加自己的处理结果最后提供给Agent Harness调用。统一的格式对后续调试和回放非常重要。我常用的传递结构中核心是识别结果对象。例如一次改地址请求经过漏斗处理后最终数据可能长这样{ domain: trade, intent: trade.modify.shipping_address, confidence: 0.87, slots: { order_ref: 20240512-8899, address_new: 北京市朝阳区望京街道XX号, time_scope: 上周 }, requires_confirmation: true, fallback_reason: order_ref_ambiguous }每条请求从头到尾串联一个唯一的追踪ID每一层的耗时、置信度、命中规则、模型版本都写进日志。这样如果某天一单被错误处理了我可以直接找到这单在每一层的表现快速定位是规则太激进还是分类器需要补样本。多轮对话的状态传递比单轮复杂但核心原则只有一个每轮结束后更新会话状态下一轮的意图识别必须能感知当前状态。我会维护一个会话状态对象包含当前业务域、已完成槽位、待填补槽位、最近两轮的用户原话、Agent上轮动作。当用户说“那周五去呢”系统不是把它当全新意图处理而是根据状态判断这是对“查询航班”任务的参数变更旧槽位里的出发地保留仅将出行日期从“后天”更新为“周五”。这个过程有个容易犯的错把历史对话全部塞进上下文窗口不做摘要或截断。直接的结果是token成本飙升、模型注意力被稀释、越来越抓不住当前意图。我的做法是让Agent记忆模块负责做滚动摘要把关键的槽位和意图链单独抽取出来放进结构化的状态对象里而不是保存原始聊天记录。3.4 第四步成本与延迟压榨算笔真实账成本控制是工业级系统的必修课。我在这里算一笔账帮助大家直观理解分层漏斗在成本上的意义。假设一个客服Agent每天处理100万次用户消息。如果每一次都由大模型做全量意图识别按单次消耗约2000 token计算一天就是20亿token。即使用相对便宜的模型一个月下来也是一笔很大的开销延迟还会普遍在1秒以上。加上第0层之后差不多40%到50%的消息在第0层就被规则直接拦截处理了它们只消耗极低的正则匹配成本。剩下的50到60万次请求中又有一部分比较简单在第1层的小模型分类器就能以高置信度结束。最终真正需要发起大模型调用的可能只有10%到20%。这个优化让大模型调用量从100万次/天降到20万次/天以内延迟也从平均1.2秒降到600毫秒以内。漏斗本身的确定性分诊还能带来一个隐性收益因为优先处理简单且明确的请求留给大模型的都是复杂请求大模型可以花更多上下文和推理步骤去处理这些硬骨头。整个系统相当于把算力集中在最需要的地方而不是平均撒在大量简单请求上。4. 常见问题与排查技巧实录再好的架构上线后也会遇到一堆实际问题。这一节我把自己在实操中反复碰到的问题整理成了排查手册每一条都来自真实的线上事故或优化记录。4.1 主意图误判之后链路里所有动作跟着全错我印象很深的一次事故发生在退货流程优化过程中。用户说“我不想要了退款吧”系统却把这个请求分到了“催发货”意图结果直接触发了催发货工单的创建把用户气得不行。复盘时发现根因是第2层的训练语料里“退款”类正样本太少而“催发货”类样本里又有大量包含“我不要了”“不想等”这种情绪化表达的负样本。分类器学到的是表面情绪词而不是真正的业务动作。这个问题的解决从三方面入手。第一扩充“退款”意图的正样本尤其要覆盖“不想要了”“退货”“钱怎么退”这些隐藏表达。第二给第2层加一个低置信度阈值当最高分意图的置信度低于0.7时不直接采信而是进入澄清分支让用户确认。第三建立误判反馈闭环每次用户明确纠正或投诉都回流成训练样本。我强烈建议所有意图分类器都保留置信度输出而不是只返回一个标签。工业系统的安全感很大程度来自“知道自己不知道”一个不确定的答案直接被拒绝比一个自信但错误的答案要安全得多。4.2 多轮对话里的意图漂移被当成新请求处理多轮对话是最容易让意图漏斗出洋相的场景。用户先问“去上海的高铁有吗”再问“那周五呢”然后又补一句“算了还是坐飞机吧”。每一次单独看意图都是模糊的但如果结合上下文就能看出这是“交通方案查询”到“改乘飞机”的意图链变化。初期我的系统会把第二轮“那周五呢”识别成“查询日期”第三轮“算了还是坐飞机吧”识别成“航班查询”每轮都新开一个任务结果用户得不到连贯的出行方案。后来我调整了策略将每一轮的识别结果先与当前会话状态做对比判断是“同任务延续”“参数变更”还是“切换任务”。判断逻辑用一套规则加分类器来完成核心特征是参考是否存在待完成任务以及已填补槽位。如果是参数变更直接复用当前任务ID只更新对应槽位如果是切换任务先关闭当前任务再开启新任务。这套机制上线后多轮场景的完成率提升非常明显。4.3 槽位抽不出来澄清话术却说不到点子上槽位抽取失败的常见原因有两个。一是用户表达隐含依赖比如“帮我改到老地址”系统中需要有一个用户常用地址列表来匹配“老地址”模型只有槽位抽取能力而不具备检索能力时自然抽不出来。二是槽位定义过细模型要在非常细的类别里做区分反而互相干扰。澄清话术是另一个被低估的问题。“请问您的订单号是多少”这种问法在真实对话里不太受欢迎。用户通常不知道自己的订单号但知道买了什么东西。好的澄清应该走“以已知推未知”的路线。例如“请问您要修改的是哪一个订单如果是昨天买的那个蓝牙耳机回复1如果是上周买的那件外套回复2。”这种话术把系统已检索到的候选订单列给用户选择用户的回答成本极低而且准确率远高于让用户自己去查订单号。我建议所有澄清话术的设计都要走这个思路不要逼用户做系统该做的事。4.4 兜底通道与识别置信度阈值的设计无论漏斗设计得多好总会有完全无法识别的输入。兜底通道的作用是承接这些输入同时不污染系统。第0层我特意设计了一个“非业务意图”类别专门吸收闲聊、问候、咒骂等与业务无关的内容。这类消息不进主流程直接回复固定话术或转接人工客服。第2层和第3层的兜底则走了另一条路当置信度低于阈值时交由大模型做一次二次判断同时附上候选意图列表和当前会话状态让大模型在一个更聚焦的搜索空间里做决策。这里要注意候选意图列表不能太长三到五个是上限。如果大模型二次判断仍然不通过就转入人工处理队列并记录完整漏斗链路的数据供后续分析。兜底通道的收束机制很重要否则系统会陷入无限制追问的死循环用户体验更差。我会在单个会话里设置兜底触发次数的上限例如3次超过次数后强制转人工。5. 我个人落地后的几点体会说一句掏心窝子的话我见过太多团队把Agent的成败押在基座模型的聪明程度上。模型确实越来越强但落地真正吃功夫的地方还是在于把“理解用户”这件事做得有章法。分层漏斗回报给我们的不仅仅是准确率数字更是一种随时可以定位问题、随时可以回滚版本、随时可以向业务方解释的工程确定性。我的另一个强烈感受是意图识别漏斗与Agent Skills是一对天然搭档。每个Skill本质上是一套可复用的能力包而漏斗产生的结果恰恰是最适合做Skill路由的信号。它让“什么时候该调用什么能力”这件事变得可预测、可编排而不是每次都在模型生成时赌一把。最后提醒一句别第一次就追求完美。先把漏斗骨架搭起来线上跑通核心路径再去补齐槽位、调优阈值、积累样本。意图体系是一个活物它跟着业务一起长不会也不可能一步到位。留好迭代空间比一次性设计出一个自认为完美的框架重要得多。