ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

工业级Agent意图识别分层漏斗:从清洗到LLM兜底的设计实践

工业级Agent意图识别分层漏斗:从清洗到LLM兜底的设计实践 1. 为什么需要意图识别分层漏斗1.1 Agent开发中“最贵”的环节往往不是模型而是理解用户这两年Agent开发火到什么程度随便打开一个技术社区十条动态里至少有三条在聊LangChain、Dify、CrewAI的对比或者“用XX框架三天搭了一个Agent”。但真上手做过生产级Agent的人会告诉你真正劝退你的通常不是模型能力不够不是框架选错而是你搞不定用户到底想干什么。我见过不少团队把最多的精力花在工具调用、Agent记忆和编排上结果上线第一天就被真实的用户输入打回原形。用户说的话和你在评测集里精心构造的Prompt完全是两个物种他们会说“那个东西我不要了”、会说“帮我看看这是啥情况”、会发来一条只有表情包的语音转写文本甚至会在同一个句子里塞进三个意图——“顺便把上个月那个订单退了还有发票开一下对了你们怎么还不发货”。这些输入如果直接丢给Agent要么被误解要么触发错误的工具链要么就是一堆无意义的模型Token消耗。这也是“工业级Agent意图识别分层漏斗”这个方案出现的原因。它解决的核心问题不是“要不要用意图识别”而是“在真实流量、真实成本、真实延迟约束下意图识别怎么做才稳”。所谓分层漏斗本质就是一组由粗到细的过滤器串联起来让每一层只做一件事低成本的把明显的情况处理掉高成本的留给真正需要它的复杂场景。1.2 单一模型方案在真实流量下为什么站不住脚很多刚接触Agent的人第一反应是意图识别不是很简单吗把用户的话发给大模型让它返回一个JSON写上意图类型不就行了理论上确实行得通我自己早期也是这样做的。但随着流量上来问题就变得非常具体。首先是不可控。同一个Prompt模型今天的输出格式可能和昨天略有差异换一个Prompt版本某些意图的判定就飘了。你当然可以用结构化输出约束它但一旦约束复杂了模型的推理效果又会打折。更别提那些模型“自信满满给错答案”的时刻——它在返回的confidence字段里写了个0.95但意图是错的。其次是成本。工业级流量不是几十条评测样本而是每天几十万条真实请求。如果每一条都走大模型推理每月的模型账单会直接把项目的ROI打穿。然后是延迟。用户可不会等你三秒钟才回一句“我想退款”。大模型推理在大多数场景下都有几百毫秒到一两秒的时延这对交互型Agent来说是致命的。最后是排查。单模型方案的逻辑是个黑盒这条请求为什么被识别成“退款”而不是“投诉”没有中间过程没有可解释的依据出了问题只能改Prompt碰运气。这些痛点叠加在一起就迫使你从“让模型解决一切”的思路转向“把问题拆开用最便宜的工具解决每一小块”。1.3 漏斗到底在“漏”什么一句话概括这个方案让简单的输入在浅层被快速命中让复杂的输入进入深层被精细处理让无法判断的输入明确地走向“转人工”或“继续追问”而不是让系统硬猜。我用一个生活化的例子说明。假设你开了一家线下面馆门口站着一位接待员。绝大多数客人走进来说“一碗牛肉面”接待员直接记单就行不需要问任何多余的问题。少数客人说“你们有没有不辣的拌面”这时候接待员才需要动一下脑子把客人分类到“咨询”还是“点单”。只有极少数客人站在门口半天不说话最后来一句“你们这行吗”这种输入连接待员也搞不定才会喊老板出来。意图识别分层漏斗做的事情就是把接待员这个角色标准化先靠本能规则和轻量模型处理大量普通情况再动用高级技能大模型处理少数复杂情况最后明确承认自己的能力边界不让用户被一个错误答案误导。2. 漏斗的整体架构设计与分层逻辑2.1 四个层级的职责划分我在实际项目中用的方案是四层结构每一层都有自己的核心指标和代价上限。整体长这样第一层是输入清洗层。它的任务是把原始文本变成干净的、可预测的、标准化的内容。第二层是粗筛层用轻量模型在毫秒级把明显的高频意图识别出来。第三层是精排层针对粗筛层拿不准的样本用更重的模型加规则做精确判断。第四层是大模型兜底层处理真正的长尾和复杂场景最后附上置信度和解释。这里有一个关键点不是所有请求都会走完四层。每一层都有“高置信直接返回”和“低置信放行到下一层”两条路径。用得最多的流量应该在第一二层就被处理掉只有少数请求需要走到第四层——这也是分层能同时控制成本、延迟和准确率的核心原因。我在项目里实际统计过一组数据大约七成的输入在第一层和第二层就被高置信命中直接在100毫秒内返回剩余三成进入精排层后又有一半能被规则和NER模型处理掉最终真正需要调用大模型的请求占比不超过15%。这个比例直接决定了每月的模型账单和整体服务的响应速度。2.2 每一层设计的核心目标在设计每一层时我习惯用一个“三问法”来约束自己这一层要挡掉什么、要放过什么、放过的代价是什么。这三个问题想清楚层与层之间的边界自然就清晰了。第一问用于确定层的核心能力第二问用于避免过度设计第三问用于控制事故半径。举个例子清洗层要挡掉的是乱码、空语句和无意义符号但它必须放过那些口语化的长句因为后面还有模型能处理清洗层不需要在这里追求全对。粗筛层要挡掉的是高频、单一、特征明显的意图但它必须放过那些边界模糊的样本——如果粗筛层强行给出答案代价就是误判后的错误工具调用。在具体落地时我还会给每个层设计一个独立的小型评测集。这个评测集不追求覆盖所有场景只覆盖该层“应该管”的场景。这样做的好处是每次调整某一层的逻辑可以立刻看到效果是变好还是变坏而不是被整个系统的指标波动搅成一团浆糊。层与层之间传递的不仅是文本本身还有上游留下的元信息。比如清洗层可以标记出“这句话包含订单号”“这句话包含情绪强烈的词汇”粗筛层可以附上“这是高置信结果可直接使用”或“这是低置信结果建议走精排”。这些元信息让每一层都清楚地知道自己只是整个流程的组成部分而不是最终裁判。2.3 分层设计的一个容易忽略的收益故障隔离分层不仅是为了性能和成本还有一个容易被忽略的好处——故障隔离。如果整个系统只有一个大模型在撑一旦模型服务抖动或Prompt误改全线崩溃你连回滚的目标都不明确。分层之后每一层的依赖是不一样的粗筛层依赖的是本地推理服务精排层依赖的是NER模型和规则库只有兜底层依赖外部大模型API。这样即使大模型API挂了你的系统还能靠前两层支撑大部分高频场景用户体验不会断崖式下跌。我在生产环境里专门做过一次演练停掉大模型服务系统仍然能处理接近70%的请求虽然覆盖率变差但至少不会出现大面积错误。对于一套面向客户的系统来说这种“降级但不崩溃”的能力往往比某些指标上的极致提升更重要。3. 各层的技术选型与实现要点3.1 清洗层低成本消除输入的“脏东西”清洗层的地位被很多人低估。实际上输入质量直接决定了后面所有层的表现你喂给模型一堆乱码就别指望它能输出什么好东西。清洗层的处理项大致包括文本归一化全角转半角、繁体转简体、URL和邮箱提取、Emoji移除或保留标记、多余空白压缩、明显的广告和无意义内容过滤、以及一些领域专属的清洗规则。这里有一个很多人踩过的坑清洗要克制不是清洗得越狠越好。比如你不要把用户说的“不要了”里“不”字清洗掉否则后面所有否定意图全部识别失败。清洗的边界应该是“去除与意图无关的噪声”而不是“替判断层做决策”。一个实用建议把所有清洗规则做成可独立开关的模块每一条规则都配上对应的输入输出示例。这样如果某条规则误伤了正常输入你可以在线上快速单独禁用这一条而不用把整套清洗逻辑回滚。3.2 粗筛层轻量模型的高频意图速判粗筛层我推荐用fastText或TextCNN这类轻量模型起步而不是一上来就用BERT。原因很实在粗筛层处理的是七成左右的流量每个请求都要过它对推理时延和吞吐的要求极高。fastText在一台中等配置的CPU机器上能达到每毫秒处理几条文本的吞吐而BERT即使是tiny版本CPU推理也要几十毫秒起。粗筛层的分类类别不需要覆盖全部分支只覆盖Top 5到Top 10的高频意图就够了剩下的统一归为“其他”。实际项目中这个层用几千条标注样本就能训出一个不错的baseline分类准确率通常在85%以上——对粗筛来说已经足够了因为拿不准的它会放给精排层。这里需要特别聊一下阈值设计。粗筛层输出的每个类别都有一个概率分数你不能只看最大概率值来判断。我的习惯是给每个意图类别设独立阈值高频意图的阈值设在0.6左右因为它的样本量多、模型学得扎实低频意图的阈值设在0.8以上宁可漏到下一层也不要轻易给出低置信度的判定。这种设计很朴素但效果比用一个全局阈值好很多。3.3 精排层规则与NER模型配合做精细化判定到了精排层你要处理的是粗筛层认为“模棱两可”的输入。这层我通常用“NER模型抽取关键实体 规则引擎做逻辑判断”的组合。NER负责从文本中抽出结构化信息订单号、商品名、地址、金额、时间等。这些实体本身就是意图判断的关键依据。比如用户说“我不想要那个蓝色的大衣”如果你的NER能识别出“蓝色大衣”是商品“不想要”是否定情绪规则引擎就能高置信地判断这是“退货”意图。规则引擎的价值在精排层体现得最明显。它能实现很多模型做起来很费劲的逻辑否定词检测、双重否定处理、同义短语映射、时态判断等。比如“我之前说要退但现在已经收到了”——这句话的意图是“取消了退货需求”纯模型容易判断错但规则引擎看到“但”字转折再加上“已经收到”就能识别出意图反转。规则引擎的维护是一个长期工作。我的做法是每周固定一天review线上误判样本把高频误判场景抽象成规则补充进去。规则不是越写越多越好每新增一条规则都需要用回归集跑一遍确保没有把已有的正确判断改坏。3.4 大模型兜底层最后一公里的精细理解与安全控制走到这一层的输入基本是前两层搞不定的长尾场景。这一层要开放给大模型但绝不是直接把文本扔给大模型然后等结果。首先Prompt必须强制模型输出结构化JSON包含意图标签、置信度、关键依据字段和一句话解释。其次要明确告诉模型“不确定时必须输出低置信度并建议冒泡到人工处理”而不是逼着模型硬选一个答案。我见过最经典的大模型兜底翻车案例是用户输入“你们这些操作流程是违法的吧”某些模型在没有上下文的情况下会把这一句判断为“法律咨询”意图然后Agent真的去找法务工具了。为了避免这种情况我在兜底层加了两条硬规则第一条涉及安全、法律、医疗、金融的敏感词无论模型输出什么系统都强制走人工审核第二条大模型输出任何意图之前必须先给出支持该判断的文本依据系统会检查这个依据是否真的是用户原话中的内容防止模型凭空造依据。大模型层的成本控制也很关键。我会用“意图ID缓存”和“语义相似度缓存”来复用历史结果如果用户输入的语义和某个历史请求相似度超过0.95就直接返回历史意图不再调用大模型。实测下来这个简单策略能省下20%到30%的大模型调用量。4. 实操落地一个客服工单Agent的完整案例4.1 场景定义与数据集准备为了把上面的设计落成可复现的步骤我用一个实际的“客服工单自动分派Agent”来演示。这个Agent的输入是用户提交的工单文本输出是意图标签工单系统根据意图自动分派给对应处理组。意图类别设计为六个退款、换货、物流查询、发票问题、投诉建议、其他。前五个是高频意图最后一个“其他”用于兜底长尾。数据集方面我准备了两套主训练集是人工标注的5000条样本类别分布大致是退款25%、物流查询20%、换货15%、发票10%、投诉建议10%、其他20%评测集是单独留出的1000条样本用于各层的效果验证。这里有个实操经验标注数据不要全让标注团队标。我建议先用大模型批量加标注也就是让大模型对每一条样本给出意图和理由然后人工只审核置信度低的那部分。这样5000条样本的标注量人工实际需要看的大概只有1500条左右。4.2 粗筛层和精排层的实现示例粗筛层用fastText训练核心代码很简单import fasttext # 训练粗筛分类模型 model fasttext.train_supervised( inputtrain_clean.txt, lr0.5, epoch25, wordNgrams2, dim100, minCount1, losssoftmax ) # 保存模型 model.save_model(intent_l1.bin) # 预测时返回概率 labels, probabilities model.predict(我不想要这个订单了, k3) print(labels, probabilities)训练数据格式是fasttext的标准格式__label__退款 我不想要这个订单了。样本量不大十几秒就训完了。实测在评测集上这个简单模型对六个类别的加权准确率能到86%左右对退款的单独召回率更是超过90%。精排层我用了轻量NER加规则判断。NER负责抽取订单号、金额、商品关键词和否定词规则引擎根据这些抽取值做组合判断。比如一个典型的规则IF 包含否定词 AND 包含订单号 AND 含商品提及 THEN 意图退款 IF 包含“发票” OR “开票” THEN 意图发票问题优先级高于退款 IF 包含物流词发货/到哪/快递 AND NOT 包含否定词 THEN 意图物流查询每条规则都带条件的优先级。发票、投诉这类边界明确的词规则优先级要高于NER组合判断这样能减少误判。4.3 LLM兜底层的Prompt设计送入兜底层的Prompt我经过多次迭代后固定成了下面这个模板你是工单意图识别系统的一部分。请判断用户输入的意图并返回JSON。 意图选项退款、换货、物流查询、发票问题、投诉建议、其他。 要求 1. 必须返回合法JSON格式为{intent: , confidence: 0-1, evidence: 支持判断的关键句子, uncertain: true/false} 2. confidence要求严格评估不确定时不能超过0.6 3. uncertain为true时代表你判断不了系统将转人工处理 4. 只根据用户输入原文判断不要推理输入之外的信息 5. 如果输入涉及违法、安全、人身伤害等内容直接设置intent为“其他”uncertain为true 用户输入{user_input}这里有三个细节值得说明。第一uncertain字段是非常重要的安全网。模型写得越自由越容易在边界输入上犯错让它主动承认不确定比让它硬猜更可靠。第二明确要求模型只根据原文判断能减少幻觉式的推理。第三安全相关指令写在Prompt里但要记得Prompt只是软约束真正硬性的拦截要靠系统层的敏感词列表和人工审核流程。4.4 阈值调参与整体效果评估整个漏斗串起来之后需要重点调的是各层的阈值。我的调参流程有固定套路先在评测集上跑一遍统计每层的预测分数分布画出“分数阈值-准确率/召回率”曲线然后从业务角度选择阈值。选择的逻辑是优先消灭“高置信但是错的”样本。具体操作是把准确率曲线上“最后一段接近1.0但仍然有错”的位置选为阈值点宁可在那个区间漏掉一些对的结果也不要把错的放进高置信通道。我最终的参数配置是粗筛层高频类别阈值0.6、低频类别阈值0.8精排层规则命中即返回单规则匹配数不低于2个才允许高置信大模型层的置信度门槛是0.9confidence低于0.9的全部转人工。跑完整个流程后的评测数据是全量准确率96.2%单条请求P99延迟480毫秒大模型调用占比11.7%。对比原来“全量走大模型”的方案准确率基本持平延迟从平均1.8秒降到了平均180毫秒每百万条请求的模型成本下降了约78%。这个结果让我确信分层漏斗不是牺牲质量换成本而是在几乎不损失质量的前提下大幅优化了成本和体验。5. 常见问题与排查技巧实录5.1 相似意图混淆怎么办运营一个真实系统之后最高频的误判场景集中在“退款”和“换货”、“物流查询”和“投诉”这几组相似意图上。比如用户说“我要把换回来的东西退了”——这句话里同时包含换货和退款两个信号很多人会把意图误判成换货。这类问题我的排查顺序是先看清洗层有没有把关键词弄丢再看粗筛层的概率分布如果两个类别的概率非常接近说明特征本身就混淆就可以用精排层的规则硬性定优先级。在这个例子里“退”出现在“换”之后语义上更接近取消行为规则可以定为“退货关键词优先于换货关键词触发”。相似意图还有一个排查方向看看是不是上下文缺失导致的。很多工单文本只是用户对话中的一句话缺少前文。这时候单靠当前文本确实判断不了正确做法是让系统返回“需要澄清”而不是硬分派一个意图。为此我在漏斗出口设计了一个“澄清请求”通道当最终置信度仍不足时Agent会先向用户问一句“您是想退款还是换货”这比猜一个意图然后走错流程要省太多事。5.2 冷启动阶段没有标注数据如果你刚接手一个全新场景的Agent手头没有任何标注数据怎么搭漏斗我的经验是先用大模型蒸馏一批伪标注数据。把你从日志里找到的一万条真实输入用大模型打上意图标签和理由然后人工抽检500条如果抽检一致率达到90%以上就用这批伪标注数据去训粗筛模型。粗筛模型训出来后再反哺一批“模型认为低置信的样本”让人工集中标注这部分形成循环迭代。这个思路的本质是让最贵的模型去做标注让便宜的模型去承接流量人只需要做最后的质量把关而不是从头纯人工标注。我实际用下来第一周就能让粗筛层达到75%以上的准确率三周后稳定在85%以上。5.3 延迟和性能瓶颈排查分层漏斗上线后如果发现P99延迟飙高优先排查的不是模型服务而是你的调用链路有没有串行化的浪费。最常见的问题是每一层都等上一层的最终结果才开始明明粗筛层已经高置信了后面还是象征性地把请求发到了下一层做验证。我给粗筛层加了“短路开关”高置信请求直接返回低置信请求才继续向下转发。这个改动在很多情况下能让P99延迟直接砍半。另一个性能坑是规则引擎的正则太复杂。有些正则表达式在最坏情况下会回溯很久一条请求卡个几百毫秒也不奇怪。建议把所有正则加上超时保护并定期用数据集基准测试来发现哪些正则拖慢了整体速度。5.4 安全层面的边界约束做意图识别漏斗必然要考虑安全边界。因为意图识别通常位于Agent技术栈的最前端如果这里被绕过后面所有工具调用和记忆系统都会面临风险。我把安全措施也做成了漏斗形态清洗层移除可疑注入模式粗筛层识别“越权指令”意图精排层检测敏感实体兜底层强制走人工。整个过程里有一条硬性规则——涉及安全、法律、医疗等高风险领域的内容不设“自动高置信通道”一律人工审核。这条规则没有任何例外。另外就是日志脱敏。意图识别系统的日志中往往会包含用户的原话如果不做脱敏一旦日志泄露最坏情况是用户隐私批量暴露。我的做法是日志落盘前对文本中的手机号、身份证号、家庭住址、银行卡号做正则脱敏替换保留实体类型但不保留原文。这样虽然损失了部分可回溯性但安全性提升明显。6. 一些踩坑后的个人体会做完这个项目之后再回看我最想对外分享的一句话是工业级Agent不是用更好的模型堆出来的而是用更清楚的边界堆出来的。边界体现在很多层面。层与层之间的边界决定了每层能做什么、不能做什么阈值与置信度之间的边界决定了系统敢不敢返回结果自动处理与人工审核的边界决定了事故能不能被拦在最后一米。我踩过最贵的一个坑是早期把规则引擎写得太激进。有一段时间线上突然出现了大量“退款”意图排查了很久才发现是新上的一条规则“只要出现‘退’字就判定为退款”误伤了所有包含“退货运费”的物流查询。教训很深刻规则一定要写条件组合单一关键词永远不要作为意图级别的判定依据。第二个印象深刻的教训是评测集要定期更新。最初的评测集用久了模型和规则都已经过拟合到那1000条样本上了每次改动都看着涨点上线后却频频翻车。后来我把评测集改成月度滚动机制每个月淘汰一批旧的、加入一批新采集的真实误判样本效果才恢复稳定。最后分享一个小技巧无论你的漏斗设计得有多完整上线初期一定要保留一个“真实流量回放”的离线环境。把当天线上的请求原样记录下来随后跑一遍当天的漏斗版本和最新版本对比两者的输出差异。这个习惯帮我发现过好几轮Prompt冷热切换导致的行为漂移成本几乎为零但这一个动作就能避免好多次线上事故。意图识别分层漏斗不是什么花哨的技术它就是一套朴素的工程化思维把复杂问题拆开每一层都做自己有把握的事把不确定的部分明确暴露出来。如果你的Agent正在被“用户说不清话”折磨不妨先从两层漏斗跑起来——清洗加粗筛跑通之后再往上叠精排和LLM兜底。很多时候完成比完美重要跑起来比讨论架构重要。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表