AI客服多智能体实战第5讲|分类→动态装载:客服Agent核心链路实现
一、分类模块只管进哪个 Topic先把分类这件事的边界划死分类不调业务 Agent分类只决定这条消息进哪个 Topic。它不查订单、不查物流更不直接回答用户——它的全部产出就是一个分类结果然后按这个结果把消息扔到对应队列。这种只路由不执行的克制是后面所有解耦的前提。这条链路上有两个外部依赖Redis 提供会话上下文让分类知道这是新会话还是接在某段对话后面Nacos 提供分类服务自己的系统提示词。问题分类服务拿到这两样调一次模型得到分类 JSON再投递。时序就是图 1 那样。核心入口是classifyQuestion(String question, String sessionId)。下面这段是我从原 PPT 代码里重写干净的骨架关键方法名保留先看整体再逐段拆java public ClassificationResult classifyQuestion ( String question , String sessionId) { try { // ① 取会话历史作为分类记忆空则标记新会话 String context sessionMemory . getConversationContext (sessionId); if (context null || context . trim (). isEmpty () ) { context 新会话无历史上下文 ; } else { log . info ( 取到会话上下文 sessionId{}, len{} , sessionId, context . length ()); } // ② 用问题上下文拼分类提示词 String prompt promptBuilder . buildClassificationPrompt (question, context); if (prompt null || prompt . trim (). isEmpty () ) { return ClassificationResult . failure ( ClassificationErrorCode . CONFIG_ERROR ); } // ③ 调模型返回强制 JSON 的分类结果 String raw llmClient . chat (prompt); return ClassificationResult . parse (raw); } catch ( Exception e ) { log . error ( 分类失败 sessionId{} , sessionId, e); return ClassificationResult . failure ( ClassificationErrorCode . MODEL_ERROR ); } }原 PPT 里这段长这样截图分辨率低看个结构对照即可逐段看三个关键动作。第①步拉上下文空上下文不是报错是业务信号——直接给个新会话无历史上下文的占位字符串塞进去。为什么要这么做因为分类模型拿到这是新会话后就不会强行结合上一轮的订单号去猜新会话和老会话的分类策略本来就该不一样。第②步构造提示词失败要直接failure返回这是配置问题Nacos 没配好不能吞掉继续往下走。第③步调模型注意整个方法被 try-catch 兜住——分类是同步链路的第一道闸它挂了消息不能丢要走后面的 fallback。═════════二、分类 Prompt 的输出契约与 unknown 兜底分类模型吐回来的不是一句自然语言而是一段强制 JSON。为什么强制 JSON因为后面要靠程序解析这个 category 字段去查 Topic 映射表模型要是自由发挥说我觉得这像是个退款问题程序没法路由。契约长这样json { total_questions : 1 , context_summary : 用户在追问上周订单的退款进度 , questions : [ { id : 1 , original_text : 我的退款怎么还没到账 , category : agent.payment , context_relevance : 高 , extracted_info : { order_no : SO20260908001 , user_id : U10086 , problem_desc : 退款超期未到账 , expected_solution : 确认退款进度并催促 }, confidence : 0.92 , transfer_to : null } ] }几个字段值得展开。category用agent.业务域两级格式——第一级agent表示走 Agent 链路另有faq/kb_qa走轻量通道见第 4 讲三路消费第二级对应第 2 讲的六个垂直 Agent。context_relevance高/中/低是告诉下游这条问题和历史对话的关联程度关联低的问题下游 Agent 就少带历史省 token。extracted_info把订单号、用户 ID 这类结构化信息从自然语言里抠出来——这是白送的分类这一步顺手做了实体抽取后面 Agent 调订单服务直接拿order_no不用再解析一遍。transfer_to是 Agent 侧误判时的转派信号Agent 发现答不了时填目标 Agent 名调度层重新路由。分类原则有五条PPT 里写得很死原则含义优先选最具体分类退款进度查询归 agent.payment不要偷懒归 complaint多意图选 unknown一句话里又问物流又问退款别硬猜一个模糊问题选 unknown读不懂的、缺关键信息的直接 unknown每个问题必须有分类questions[] 里不允许出现无 category 的条目结合对话历史提高准确率靠 Redis 上下文判断指代“它”那个指的是哪个订单unknown 有两层触发一是模型主动判不出 → 输出unknown二是模型判出了但confidence 0.6→ 程序降级为 unknown。两层兜底确保低置信度问题不会硬塞进错误的 Agent。第四条原则和 unknown 看似矛盾其实不矛盾允许 unknown是刻意留的安全出口。很多人做分类第一反应是模型必须给个确定答案我恰恰相反——分类错比不分类更贵。把一个退款问题错路由到售前询价 AgentAgent 会用促单话术去答退款政策这种错误用户感知极强还没法自动发现而路由到 unknown 走 fallback最多是慢一点、转个人工。答错一个退款政策比慢三秒贵得多。═════════三、分类→Topic一张 YAML 映射表拿到 category 之后怎么变成具体的 Topic不是写一堆 if-else而是 Nacos 上一张映射表。绑定类长这样java Slf4j Data Component RefreshScope // Nacos 配置热更新改完不重启 ConfigurationProperties ( prefix question-categories ) public class QuestionCategoryConfig { // key分类类别agent.payment / faq / unknownvalue对应投递的 Topic private Map String , String categoryMappings new HashMap () ; // 兜底 Topic分类未命中或 confidence 过低时走这里 private String defaultFallback agent.default-fallback ; }原 PPT 里这个类的注解就是上面这几行对照看RefreshScope是关键——它让这张映射表跟着 Nacos 实时刷新。新增一个分类运营在控制台加一行 YAML不用发版、不用重启。实际 YAML 长这样yaml question-categories : category-mappings : # 第一级答题通道分流第4讲三路消费 faq : chat.fastqa # 简单FAQ模板回复不调Agent kb_qa : chat.rag # 知识库检索问答RAG链路 # 第二级agent 通道按业务域细分对应第2讲六个垂直Agent agent.product-inquiry : agent.product-inquiry # 询价 agent.payment : agent.payment # 支付含退款进度查询 agent.stock : agent.stock # 库存 agent.logistics : agent.logistics # 物流 agent.warranty : agent.warranty # 故障报修 agent.invoice : agent.invoice # 发票 # 扩展分类投诉/技术支持暂走兜底后续可独立成Agent agent.complaint : agent.default-fallback agent.technical-support : agent.default-fallback unknown : agent.default-fallback # 分类置信度低兜底 default-fallback : agent.default-fallback投递那一行就极薄topic categoryMappings.getOrDefault(category, defaultFallback)。分类出agent.logistics就进agent.logistics分类出faq直接进chat.fastqa不调 Agent分类出unknown或者映射表压根没配统一落default-fallback。第 4 讲讲的消息队列削峰生产者在这一步就结束了——投完即返回下游按自己的速度消费。═════════四、Agent 动态装载运行时现场装配消费者那边才是这套设计的精华。先纠正一个直觉Agent 不是启动时 new 好、挂在那等消息的。服务启动时你根本不知道这一秒会来一条物流问题还是支付问题提前把六个垂直 Agent 全实例化好既浪费内存又让每个 Agent 的提示词难以隔离。真实做法是——消费端拿到分类结果后按businessType去 Nacos 现场把系统提示词和 MCP 配置捞出来现拼一个 Agent 跑这一轮对话跑完就丢。消费端入口是MessageConsumerService.consumeMessage骨架重写后是这样java public boolean consumeMessage ( String messageJson) { Message msg parse (messageJson) ; // 解出 sessionId/content/businessType/extractedInfo // businessType 由生产端投递时从 category 填入消息头如 agent.payment String businessType msg . getBusinessType (); // ① 按业务类型从 Nacos 取系统提示词和 MCP 配置 BusinessTypeConfig cfg dynamicConfigService . getBusinessTypeConfig (businessType); String systemPrompt cfg null ? : cfg . getSystemPrompt (); McpConfig mcpConfig dynamicConfigService . getMcpConfig (businessType); // ② 读会话历史 String history sessionMemory . getConversationContext ( msg . getSessionId ()); // ③ 把提示词、工具集、分类时抽取的实体信息一起交给 Agent 跑这一轮 String reply assistantService . chat ( msg . getSessionId (), msg . getContent (), systemPrompt, mcpConfig, history, msg . getExtractedInfo ()); // 分类时抽的 order_no/user_id 直接用 // ④ 回复经 IM 推回用户 imService . pushMessage ( msg . getSessionId (), reply); return true ; }原 PPT 里这段看红色下划线标的那几个调用点注意chat()的入参里systemPrompt和mcpConfig是每次调用现传的不是 Agent 实例上固化的字段。这就是动态装载四个字在代码上的全部含义Agent 运行时本身是个空壳它是谁、会调哪些工具全看这一轮 Nacos 给它喂什么配置。那 Nacos 里这些配置长什么样按业务类型一个 Data ID 一份比如物流客服就是logistics.inquiry-agent-config.yaml里面按业务隔离了两样东西——这一块是示意骨架落地时按真实话术填yaml # logistics.inquiry-agent-config.yamlnamespacepublic, groupDEFAULT_GROUP system-prompt : | 你是某电商物流客服。只回答物流轨迹、派送、签收问题。 语气克制查不到单号就引导用户提供订单号不要猜。 涉及退款/赔偿一律转工单不要自行承诺。 mcp : servers : - name : logistics-service transport : sse endpoint : http://logistics-service:8080/sse # 第6讲讲怎么套这个壳看出来了吗售前话术和售后话术是两个 YAML物理隔离。运营想改物流客服的语气只动logistics.*.yaml碰不到退款那一份。这就是第 1 讲说的每个 Agent 的提示词能单独改、单独回滚到这一讲终于落到了 Nacos 的 Data ID 上。═════════五、为什么这样设计整条链路过完回头看它的两个设计动机。第一分类与执行分离等于路由策略和业务话术解耦。分类服务只认这是 agent.payment它不知道退款话术是什么、支付 Agent 有哪些工具消费端拿到agent.payment就去捞支付的提示词。路由规则改比如新增一个分类不动任何业务话术话术改退款政策更新不动路由。两个团队各改各的不用互相提 PR。第二提示词和 MCP 配置全部 Nacos 化等于改话术不发版。传统做法里提示词写死在代码或常量类里改一句客服要走提代码→评审→构建→灰度→发布全流程一次话术调整搞一下午。现在 Nacos 控制台改 YAMLRefreshScope秒级生效客服主管自己就能改。这在客服这种话术高频迭代的场景是生产力级别的差别。我觉得这套设计最值钱的不是代码本身是那个unknown兜底分类和default-fallbackTopic——宁可转人工、走通用链路也别让分类错误的问题进了错误的 Agent。default-fallback的消费端跑什么极简骨架yaml # default-fallback 的 system_prompt不调业务工具只收集信息转人工 system-prompt : | 你是通用客服助手。这个问题暂时无法自动处理。 请礼貌致歉收集用户的订单号和问题描述然后创建人工工单。 禁止猜测业务答案禁止承诺赔偿或退款。 mcp : servers : [] # 不挂任何业务工具只有工单创建客服场景里答错一个退款政策比慢三秒贵得多。代码照抄能跑但这层宁慢勿错的克制很多人第一版是想不起来加的。═════════写在最后这一讲把第 2、4 讲的设计落到了代码上分类模块只路由、分类 JSON 有强制契约、Topic 靠 YAML 映射、Agent 在消费现场按业务类型装配提示词和工具集。可交付物清单——分类伪代码、JSON 输出契约、question-categories.yaml映射、消费端动态装载伪代码——都在上面可直接搬进自己的项目对一遍。代码跑通了但 Agent 要调订单、物流、工单这些存量服务怎么办下一讲用 Higress 控制台实证存量服务一行代码不改套个 MCP 壳就能被 Agent 调用。你在做 Agent 路由时踩过分类错进错 Agent的坑吗评论区聊聊你是怎么兜底的我挑典型案例在第 6 讲补一段。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

相关新闻

GraphRAG 前沿速递!强化学习 + 知识图谱,3 大核心痛点同时缓解,泛化指标提升 10.1%!

GraphRAG 前沿速递!强化学习 + 知识图谱,3 大核心痛点同时缓解,泛化指标提升 10.1%!

强化学习是知识图谱大模型推理的通用优化思路,三篇论文针对不同环节构建定制强化学习框架,适配图嵌入、图谱路径探索、图谱构建任务。AGE依托强化学习节点采样实现自适应掩码,改善图自监督学习效果;Explore‑on‑Graph采用SFT加双…

2026/9/26 4:15:00 阅读更多 →
DeepSeek    LeetCode 107. 二叉树的层序遍历 II Kotlin实现

DeepSeek LeetCode 107. 二叉树的层序遍历 II Kotlin实现

LeetCode 107. 二叉树的层序遍历 II — Kotlin 实现 思路 标准 BFS 层序遍历,每遍历完一层得到一个 List。题目要求自底向上,所以:方案一:每层结果插入到 result 的头部(add(0, level))方案二&#xff…

2026/9/26 4:15:00 阅读更多 →
面试官:ReAct 和 Plan-and-Execute,你平时怎么选?你答「看复杂程度」,他听到的是「我没选过」

面试官:ReAct 和 Plan-and-Execute,你平时怎么选?你答「看复杂程度」,他听到的是「我没选过」

ReAct 和 Plan-and-Execute 的差别不在难度,在「不确定性落在哪」。这篇文章给你一套能当场判定的选型流程,以及三种形态各自的失败模式。 面试现场 大厂 AI 应用岗 **面试官:**ReAct 和 Plan-and-Execute,你平时怎么选&#x…

2026/9/26 4:15:00 阅读更多 →

最新新闻

还在简历里写“熟悉Vue”?飞算JavaAI已经让Java后端独立交付项目

还在简历里写“熟悉Vue”?飞算JavaAI已经让Java后端独立交付项目

目录前言一、Java后端的求职差距,藏在交付边界里求职溢价来自更大的责任范围二、从一段社区治理需求开始提交完整业务需求三、先让AI把业务关系拆清楚14个关键点覆盖治理全流程9张数据表建立业务关联四、前后端围绕同一套规则生成Java后端负责业务判断与验收五、完整…

2026/9/26 4:53:23 阅读更多 →
Claude Code 切换 Permission Mode 时,缓存为什么通常不会被打碎:从 plan mode 到 opusplan 的配置验证

Claude Code 切换 Permission Mode 时,缓存为什么通常不会被打碎:从 plan mode 到 opusplan 的配置验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 4:53:23 阅读更多 →
2026年VirtualBox搭建Linux开发环境:从安装到性能调优的完整指南

2026年VirtualBox搭建Linux开发环境:从安装到性能调优的完整指南

1. 为什么2026年还要聊VirtualBox先把结论摆在前面:如果你是一名开发者,需要在本地跑Linux做开发、测试、验证部署脚本,VirtualBox依然是目前门槛最低、折腾成本最小的选择之一。VMware Workstation被收购后个人版授权政策反复横跳&#xff0…

2026/9/26 4:53:23 阅读更多 →
蒙特卡洛方法量化电动汽车充电负荷不确定性:从概率建模到工程实现

蒙特卡洛方法量化电动汽车充电负荷不确定性:从概率建模到工程实现

要做电动汽车充电负荷预测,绕不开的一个词就是“随机性”。什么时候插枪、插多久、功率多大、充满没充满,这些行为在时间和空间上都是高度分散的。如果只给出一条典型日曲线做规划,往往会把峰值负荷的尾部风险严重低估,变压器扩容…

2026/9/26 4:53:23 阅读更多 →
毫米波MIMO雷达天线设计:从虚拟阵列原理到工程实测避坑指南

毫米波MIMO雷达天线设计:从虚拟阵列原理到工程实测避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 4:53:23 阅读更多 →
Java后端热部署全解析:DevTools、HotSwap与JRebel实战

Java后端热部署全解析:DevTools、HotSwap与JRebel实战

大概每个写Java后端的都经历过这种崩溃瞬间:线上反馈一个字段格式不对,你打开IDEA定位到代码,改完这个if分支,然后乖乖关掉Spring Boot进程,等上十几二十秒甚至更久重启,再打开浏览器刷新验证。要是赶上依赖…

2026/9/26 4:52:22 阅读更多 →

日新闻

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、…

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →