ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

一分为多——意图路由与多 Agent 协作(把客服拆成一队)

一分为多——意图路由与多 Agent 协作(把客服拆成一队) 系列AgentScope 2.0 学习笔记 · 第 008 篇难度进阶适合谁客服 Agent 已经能跑、但觉得「一个 Agent 干所有活」不对劲的开发者前置建议先读 007《双剑合璧——工具 RAG做一个会查会答的客服》阅读收获用意图路由把「单兵客服」拆成一队各司其职运行环境WSL Ubuntu-24.04 Python 3.11 AgentScope 2.x你见过这种「一根筋」的客服机器人吗用户说「我用了你们家产品过敏了要退货」它张口就来「那换这款试试吧这款更温和」——人家来退货它还在推销。反过来用户说「我想买瓶面霜」它先问「您是要退货吗」。这不是模型笨是让一个人干了两个人的活。真实公司里销售和售后是两个部门、两套话术、两种考核——你见过让同一个柜员既卖货又处理投诉的吗有但一定两个都干不好。这一篇就是把「全包型单兵客服」拆成一队一个路由器负责判断来的是谁导购 Agent 和售后 Agent 各接各的活。一、007 的客服其实是个「全包型单兵」007 篇我们拼出了一个会查会答的客服。但它有个隐藏的问题它什么都得会。用户来咨询买什么 → 它答用户来投诉过敏要退货 → 它也得答。可「导购」和「售后」是两种截然不同的活儿导购要热情了解需求、推荐产品、促成下单售后要克制先安抚、再处理、复杂转人工。让一个 Agent 既热情推销、又冷静安抚就像让一个人既当销售又当客服——顾此失彼。用户说「过敏了」它可能还热情推荐「那换这款试试」用户说「想买」它可能先问「您是要退货吗」。这就是「全包型单兵」的天花板。破局的办法就是一分为多。二、一分为多让专业的 Agent 干专业的活思路很朴素与其让一个 Agent 什么都懂不如让每个 Agent 只懂一件事。导购 Agent「小帮」只管推荐、报价、搭配售后 Agent「小护」只管安抚、退换、转人工。每个 Agent 的人设system_prompt都聚焦一件事回答自然更专业、更不容易串味。这个思路本质上就是把真实公司的组织架构搬进代码销售部一个 Agent、售后部一个 Agent各有一套「岗位说明书」人设卡各守各的红线。你在真实业务里怎么分工Agent 就怎么分工——这是多 Agent 设计最容易上手的入口先从组织架构图里抄。销售和售后是两大部门所以你第一步就拆出这两个。但拆成多个 Agent 后冒出个新问题用户进线先找谁这就是「意图路由」要解决的——先判断用户意图再派给对的 Agent。三、意图路由规则快LLM 兜底意图路由的核心是一个「分流器」读用户的话判断是「导购」还是「售后」然后派单。怎么判断两层第一层规则关键词。用户的话里有「多少钱」「推荐」「买」→ 导购有「过敏」「退货」「投诉」→ 售后。关键词命中就完事快、省成本不调模型。第二层LLM兜底。规则判断不了的模糊话「我最近皮肤状态不太好」交给模型判断意图。为什么「规则优先、LLM 兜底」因为规则零成本、零延迟、可解释LLM灵活、能理解语义。两者结合既快又准——这正是系列里反复出现的「LLM 决策 规则校验」双层架构在路由场景的落地。这里要特别强调「规则优先」的顺序——别图省事每次都上 LLM。路由是用户每句话都要经过的如果每句都调一次模型就是「用大炮打蚊子」又慢又贵。真实客服一天几万次进线规则层能挡掉七八成省下的就是真金白银。成本意识要从架构的第一笔开始算。顺带说一句路由的「意图」不止导购/售后两类。真实系统里你可以再分出「查订单」「转人工」「闲聊」等更多意图每加一类就加一个专职 Agent 和一组关键词。路由的骨架不变变的只是意图清单和对应的 Agent 列表——这就是多 Agent 架构的扩展方式。四、规则层的经典坑否定句规则路由看着简单其实有个坑专门坑新手否定句。用户说「我没有过敏就是想买个洗面奶」——里面明明有「过敏」这个售后关键词但用户其实是想买导购。如果不处理规则会傻乎乎地把「想买洗面奶」的用户丢给售后。所以规则层要加否定词过滤关键词前面如果紧跟着「不、没有、没、无」这类否定词就跳过这个关键词。这个坑我在学习里真踩过写代码时专门做了修复。你在写自己的路由时一定记得加这一层——关键词匹配的朴素方案永远过不了否定句这一关。不过也要认清规则的边界否定词过滤只管「关键词前紧邻的否定词」管不了更复杂的转折和反问。比如「这款控油但不紧绷」里的「控油」是肯定语义、「但」只是转折再比如「我不太清楚自己是不是过敏」这种绕弯子的话。这些复杂情况正是交给 LLM 兜底层去处理的——规则管「快而准的常见情况」LLM 管「规则的盲区」。五、运行环境系统WSL Ubuntu-24.04Python3.11虚拟环境venv框架AgentScope 2.xAPI KeyDEEPSEEK_API_KEY对话本篇不涉及 Embedding无需百炼wsl-dUbuntu-24.04cd/2026_Study/agentscope/sourcevenv/bin/activateexportDEEPSEEK_API_KEYsk-xxxxpython 008_multi_agent.py六、完整代码单文件自包含保存为008_multi_agent.py。一个路由器 两个专职 Agent对三类问题分别派单。#!/usr/bin/env python3# -*- coding: utf-8 -*- AgentScope 2.0 · 一分为多——意图路由与多 Agent 协作 导购 Agent「小帮」 售后 Agent「小护」 双层意图路由规则关键词 LLM 兜底。 运行环境WSL Ubuntu-24.04 Python 3.11 AgentScope 2.x 运行命令python 008_multi_agent.py importosimportgcimportasyncioimportwarnings warnings.filterwarnings(ignore,categoryDeprecationWarning)fromagentscope.agentimportAgentfromagentscope.messageimportMsgfromagentscope.modelimportDeepSeekChatModelfromagentscope.credentialimportDeepSeekCredential# 1. 两个专职 Agent 的人设SALES_PROMPT 你叫【小帮】是「敏辰」的专业护肤导购。 回答流程先了解肤质需求 → 匹配产品 → 说明价格成分 → 关联推荐 → 红线检查。 ⚠️ 红线不承诺疗效、不贬低其他品牌。 .strip()AFTERSALES_PROMPT 你叫【小护】是「敏辰」的售后客服。 回答流程先安抚 → 了解情况 → 分级处理 → 确认满意 → 复杂转人工。 ⚠️ 红线不推卸责任、不过度承诺、人身伤害必须转人工。 .strip()# 2. 规则层意图关键词 否定词过滤SALES_KEYWORDS[推荐,适合,价格,多少钱,成分,搭配,买,哪款,肤质]AFTERSALES_KEYWORDS[过敏,退货,退款,物流,快递,投诉,换货,破损,质量]NEGATION_WORDS[不,没有,没,无,并非,不会]defrule_route(question:str):规则层关键词命中判断意图。返回 sales / after_sales / None。 关键技巧否定句过滤——「我没有过敏想买产品」里的「过敏」被「没有」否定 不应判为售后。关键词前紧邻否定词则跳过继续找下一个。 forkinAFTERSALES_KEYWORDS:idxquestion.find(k)whileidx!-1:prefixquestion[max(0,idx-3):idx]ifnotany(ninprefixforninNEGATION_WORDS):returnafter_salesidxquestion.find(k,idxlen(k))forkinSALES_KEYWORDS:ifkinquestion:returnsalesreturnNone# 规则判断不了交给 LLM 层# 3. LLM 层兜底意图判断asyncdefllm_route(model,question:str)-str:LLM 层规则无法判断时用模型判断意图。routerAgent(name意图路由,modelmodel,system_prompt(你是意图路由器。判断用户问题属于「导购」咨询产品/推荐/价格还是「售后」退换/过敏/物流/投诉。只回复 sales 或 after_sales。),)msgMsg(nameuser,content[{type:text,text:question}],roleuser)responseawaitrouter.reply(msg)resultextract_text(response).strip().lower()returnafter_salesifafterinresultor售后inresultelsesales# 4. 模型构建 收尾defbuild_model():对话模型DeepSeekstreamFalse 干净退出。returnDeepSeekChatModel(credentialDeepSeekCredential(api_keyos.environ[DEEPSEEK_API_KEY]),modeldeepseek-v4-flash,streamFalse,)defextract_text(response)-str:forblockinresponse.content:ifhasattr(block,type)andblock.typetext:returnblock.textreturnasyncdefcleanup(model):收尾逐个 await self.client.close()干净退出三件套。closed0clientgetattr(model,client,None)ifclientisnotNone:try:awaitclient.close()closed1exceptException:passifclosed:print(f\n 已关闭{closed}个 HTTP 连接池)# 5. 意图路由 多 Agent 协作演示asyncdefdemo(model)-None:sales_agentAgent(name小帮,modelmodel,system_promptSALES_PROMPT)after_agentAgent(name小护,modelmodel,system_promptAFTERSALES_PROMPT)test_questions[你们家的美白精华多少钱,# 导购规则命中「多少钱」我用了产品过敏了想退货,# 售后规则命中「过敏/退货」我最近皮肤状态不太好,# 模糊规则无法判断 → LLM 兜底]print(*60)print( 一分为多意图路由 多 Agent 协作)print(*60)forqintest_questions:print(f\n{─*60})print(f 用户{q})intentrule_route(q)route_source规则层ifintentisNone:intentawaitllm_route(model,q)route_sourceLLM 层targetsales_agentifintentsaleselseafter_agent target_name小帮导购ifintentsaleselse小护售后print(f 路由{route_source}→{target_name})msgMsg(nameuser,content[{type:text,text:q}],roleuser)responseawaittarget.reply(msg)print(f 回答{extract_text(response)})print(f\n{*60})print( ✅ 意图路由 多 Agent 协作演示完成)print(*60)defcheck_keys():need[DEEPSEEK_API_KEY]missing[kforkinneedifnotos.environ.get(k)]ifmissing:print(❌ 缺少环境变量, .join(missing))returnFalsereturnTrueasyncdefmain():ifnotcheck_keys():returnmodelbuild_model()try:awaitdemo(model)finally:awaitcleanup(model)delmodel gc.collect()if__name____main__:withwarnings.catch_warnings():warnings.simplefilter(ignore,DeprecationWarning)warnings.simplefilter(ignore,FutureWarning)warnings.simplefilter(ignore,PendingDeprecationWarning)asyncio.run(main())七、代码拆解三个关键点① 人设决定分工。两个 Agent 的system_prompt截然不同——小帮「先了解肤质→匹配→报价→关联」小护「先安抚→了解→分级→转人工」。同一个模型人设不同就是两个不同的「岗位」。这印证了 003 篇那句话换一张人设卡就是换一个人。② 规则优先、LLM 兜底。rule_route()先跑关键词命中就直接返回一次模型都不调只有返回None时才进llm_route()调模型。这个顺序不能反——如果每次都让 LLM 判断路由就成了「用大炮打蚊子」又慢又贵。③ 否定词过滤是规则的「安全带」。rule_route()里那段while循环专门处理「关键词前有否定词」的情况。没有它规则路由在真实对话里会频繁翻车——因为「我没有过敏」和「我过敏了」只差一个字意图却完全相反。八、运行结果真实输出下面是本文件在 WSL Ubuntu-24.04 里的真实运行结果。三类问题三种路由路径全部踩在点子上。Case 1导购—— 规则层命中「多少钱」零成本路由到小帮 用户你们家的美白精华多少钱 路由规则层 → 小帮导购 回答在给您介绍价格之前我需要先了解您的皮肤状况……请问您目前的肤质是 偏干、偏油还是混合型这样我可以为您推荐最适合的美白精华方案。Case 2售后—— 规则层命中「过敏/退货」路由到小护 用户我用了产品过敏了想退货 路由规则层 → 小护售后 回答非常理解您现在的心情请先不要着急我们一定会帮您妥善处理…… 如果是严重的过敏反应尤其是涉及面部、呼吸等请务必立即就医。Case 3模糊—— 规则层判断不了LLM 层兜底路由到小帮 用户我最近皮肤状态不太好 路由LLM 层 → 小帮导购 回答皮肤状态不好是很多原因的……方便具体说说吗您是暗沉发黄、局部泛红、 还是干起皮、偏油闭口最后一行 已关闭 1 个 HTTP 连接池程序干净退出、零收尾报错。三个回答三种味道正是「一分为多」的成果路由正确前两问走「规则层」零成本、零延迟第三问走「LLM 层」规则盲区模型兜底——两层分工清晰。人设鲜明导购「小帮」先问肤质、不盲目推贵的售后「小护」先安抚、了解情况、严重过敏提醒就医。同一个模型两张人设卡就是两个截然不同的「岗位」——这正是 003 篇「换人设卡就是换人」的实战印证。红线守住售后那句「严重过敏请务必立即就医」正是售后人设里「人身伤害必须转人工」这条红线的体现。九、总结与下一步这一篇你把「单兵客服」拆成了「一支队伍」单兵007 一个 Agent 全包顾此失彼 一分为多本篇 路由器 导购 售后各司其职核心就一句让专业的 Agent 干专业的活用意图路由做分流。路由的秘诀是「规则快、LLM 兜底」再加一层「否定词过滤」保平安。但「分工」只是多 Agent 协作的第一课。分工之后还有更进阶的玩法让多个 Agent对同一个问题各自作答、再投票汇总用「多数人的智慧」压住单个模型的随机性。下一篇《AgentScope 2.0 学习笔记集思广益——多 Agent 投票与结果汇总》我们把这套「对答案」的机制搭起来。敬请期待。十、写在最后你的业务有几条线就该有几个 Agent这一篇讲的是「一分为多」但它背后其实是一个更值钱的问题怎么判断该拆成几个 Agent我的经验是八个字跟着业务走别跟着技术走。你打开自家客服的组织架构图——有几个工种就拆几个 Agent。销售一条线、售后一条线、订单一条线就拆三个再加上意图路由当「前台」一个人力兜底当「总机转人工」一套客服系统就成型了。拆多了维护累拆少了串味「业务里怎么分工代码里就怎么分」是最不容易出错的尺度。这也正是我做 Agent 落地项目时的习惯先画组织架构再写代码。如果你正在设计自己的客服/业务系统卡在「该拆几个 Agent、路由怎么设计」这类问题上欢迎来评论区讨论。下一篇「多 Agent 投票」见。本文为「AgentScope 2.0 学习笔记」系列第 008 篇代码已通过py_compile语法校验运行环境见第五节。GitHub 仓库AgentScope 2.0 Cookbook系列 : 《AgentScope 2.0 学习笔记》Agent 编排初体验零基础跑通第一个智能体多轮对话让 Agent 记住你in-token 实证记忆机制给 Agent 一张「人设卡」五件套立规矩AI 导购实测对比给 Agent 装上「手」——工具调用入门Function Calling 从猜到查给 Agent 一库「知识」——RAG 检索入门补水也能找到保湿RAG 进阶——Top-K 调优与幻觉测试让 Agent 敢说「不知道」双剑合璧——工具 RAG做一个会查会答的客服从会说到会查会答一分为多——意图路由与多 Agent 协作把客服拆成一队集思广益——多 Agent 投票与结果汇总用多数人的智慧压住随机性给 Agent 打个分——评测体系入门零成本四维质检编价格一票否决让 AI 当裁判——LLM Judge 语义评测进阶规则查不到的「答非所问」交给 AI 二审从评测到进化——把评测结果喂回 Prompt0.75 到 1.0只差一句 Prompt从 Demo 到上线——把 Agent 部署成服务四道闸把「能跑的脚本」变成「敢上线的服务」把 Agent 放到云上——容器化部署与上线运营六步运营闭环让 Agent 越上线越好用
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进