做了几年客服系统从早期的关键词匹配、FAQ问答一步步做到现在的LLM驱动的客服Agent中间踩过的坑比写过的代码还多。这个标题里提到的三个能力——多轮对话、工具查询、情绪控制——恰好是客服Agent从“能用”迈向“好用”的三道坎也是我认为任何想在该领域动手的开发者都应该优先拆解的主干逻辑。这篇内容不会从头讲什么是大模型更多是聊聊我在实际搭建一个客服Agent时如何把这三个模块拆开设计、各自解决什么问题、互相之间怎么配合以及过程中那些无法从文档里学到的细节和教训。适合已经有一些对话系统基础、正准备落地客服Agent的开发者或者正在为团队的智能客服选型做技术调研的同学参考。1. 整体设计拆解从FAQ引擎到真正的“对话客服”1.1 三个核心能力分别解决什么问题很多团队一开始做的智能客服其实就是高级一点的搜索用户输入问题系统在知识库里找相似度最高的答案直接返回。这种方式在单轮、标准化问询上表现尚可但一遇到需要来回确认、多步操作的真实场景就露馅。所以后来演进到真正的Agent形态核心是把三个本身独立、又需要强协作的能力组合起来多轮对话解决的是“上下文记忆与连贯性”问题。用户在客服场景里几乎不会一上来就一次性把需求说清楚更多是这样的节奏“我想查一下上个月的话费……不对应该是这两个月的账单一起看一下。”如果Agent只能理解单轮提问第二次修正就无法处理整个对话直接断裂。工具查询解决的是“实时数据获取与操作执行”问题。很多客服问题并不只是查文档比如查订单物流、修改预约时间、办理退款、查询库存这些都需要Agent实时调用后端接口把动态数据带回对话里而不是从静态知识库中找答案。情绪控制解决的是“用户体验兜底”问题。客服场景天然伴随着用户的焦虑、不满甚至愤怒。一个真实案例是用户因为物流延误已经打了三次电话上来第一句就是“你们到底怎么回事”。如果Agent只做信息处理机械地回答“您的包裹还在运输中”用户会被彻底激怒。情绪控制模块决定了Agent在压力场景下是灭火还是火上浇油。1.2 模块的核心关联方式这三个模块不是三座孤岛而是呈“感知—决策—执行”的闭环关系。多轮对话模块负责维护状态并参与决策工具查询模块负责执行具体动作并返回结果情绪控制则更像一个横切面在感知层识别情绪信号在决策层影响回复策略在执行层约束回复的表达方式。我在实际架构里把情绪控制单独设计成了一个中间层而不是嵌入到多轮对话的Prompt里。原因很简单如果让对话主流程兼顾业务逻辑加情绪判断Prompt会变得极其臃肿且情绪识别的结果和业务决策耦合在一起后患无穷。拆开以后情绪模块的输出成为决策层的一个额外输入特征多轮对话的状态也把“用户情绪等级”作为一个状态位来保存。这样做的好处是某个环节出了问题可以单独修复不会影响其他流程。之所以强调这种设计也和模型能力的边界有关。LLM确实有天然的对话能力但不代表我们只需要写一个Prompt就能解决所有问题。工程化才是客服Agent落地的核心模块边界清晰意味着可控性更强出了问题也好定位。2. 多轮对话设计的几个关键细节2.1 不是所有对话都需要“深度推理”刚开始设计时很容易陷入一个误区希望通过一个大模型把所有对话全包了。但实际跑下来就会发现客服场景里的对话形态差异比想象的大。一类是标准问答比如“你们营业时间是几点”这类属于事实性回复纯查知识库即可。另一类是任务型对话用户有明确目标需要Agent引导用户提供缺失的参数然后调用工具完成操作比如“帮我改一下明天下午的预约”。两类对话对模型的要求完全不同。标准问答需要的是精准检索和忠实表达任务型对话则需要状态追踪和槽位填充。把它们全部塞给同一个Prompt意味着模型既要处理事实提取又要做复杂的状态管理哪头都不讨好。我的做法是对话入口处先做一次意图分类区分当前用户输入是查询类、任务类还是闲聊类。查询类走RAG检索链路任务类走专项的对话管理流程由状态机来驱动LLM负责自然语言理解和生成但状态流转的控制权始终握在代码手里不交给模型自由发挥。2.2 状态追踪与信息槽位管理多轮对话中最容易翻车的就是状态管理。早期我用纯LLM加Prompt里的“当前信息表”来做槽位追踪就是让模型在每轮回复后输出一个JSON表示当前已经拿到了哪些信息。看起来可行实际一测就发现问题模型偶尔会“幻觉”把用户没有明确说过的话根据上下文推断后直接填进槽位。举个例子用户说“我想预约明早九点”模型可能会自动填入“日期明天”这个推断其实是对的但有时候模型会把模糊说法当成明确信息比如用户说“周末吧”模型直接填了“本周末”在没有跟用户确认的情况下就提交给后端工具结果造成了误操作。避坑的办法有两个层面。第一所有槽位必须有来源标记区分是“用户明确陈述”还是“模型推断字段”推断字段在提交工具之前必须设计一次人工确认环节。第二不要只靠模型记忆槽位而是把槽位信息同时维护在代码层每一轮解析完成后由代码合并新旧信息再统一注入给模型。相当于给模型一个外部备忘录减少它自己记忆的负担。2.3 指代消解和省略恢复这是中文对话里特别常见的难点。用户说“那这个呢”如果没有前文“这个”完全不知道指什么。但在客服场景里指代通常是有限度的——上文刚刚提到过订单、地址、时间那么“这个”大概率是对最近实体的引用。我这里用了一个很朴素的方案不需要模型凭空去理解指代而是让多轮对话模块维护一个“最近实体列表”每轮对话提取出的关键实体按时间排序然后挂到Prompt上下文中并明确让模型优先引用最近两个实体来消解指代。效果意外地稳。这就是典型的“把模型不擅长的事情做减法通过结构化解法弥补”。2.4 确定性与生成性的平衡对话这块还有一个容易陷入的误区就是过分追求“自然”。对客服场景来说自然不等于好准确才等于好。用户说“我要投诉你们快递员”Agent如果回复“我感受到您的困扰了特意为您梳理了一份解决方案”这种话术看似高级实则让用户觉得绕。我的经验是回复策略分级需要严谨的业务口径时采用模板加关键参数填充保证不出错只有不需要承担责任、纯闲聊的时候才放给模型自由生成。这个原则在后续情绪控制模块里同样适用。3. 工具查询模块Agent的手和脚3.1 工具注册与能力枚举工具查询是整个Agent里最有“Agent味”的部分。没有工具查询的客服只能聊有了工具查询它才能真正办成事。设计上首先需要一个工具注册中心。每个工具定义清楚它的名称、功能描述、输入参数、输出格式、超时时间、权限等级。功能描述尤其重要因为LLM决定“当前是否需要调用工具”完全靠读这些描述来匹配。描述写得含糊模型就会在错误的时机调用工具或该调用时不调用。工具不是越多越好。我见过一个团队把十几个内部系统接口全部挂给Agent结果模型经常选错工具。这里一定要做信息降噪每个工具的描述尽量控制在两三句话内并把核心触发词放在靠前的位置。3.2 参数抽取、校验与二次确认工具调用最怕的参数幻觉。模型会把用户说的“大概”“可能”“随便”里猜一个值填入必填参数等工具真去执行了才发现问题。解决思路是一个工具指令在执行之前必须经过代码层的参数校验流程。校验不通过要么反问用户补充要么带着候选项让用户确认。我当时做了一个强制规则凡是涉及金额、日期、身份的变更操作Agent必须以自然语言复述一遍用户提供的信息得到用户明确确认后才执行业务工具的调用。这个设计不会让用户反感反而会增强安全感。这一步在客服场景里相当于“最后一道刹车”宁可多一步确认不能少一步核实。3.3 工具返回结果如何融入对话工具返回的一般是结构化数据比如订单状态的JSON。直接把它原样塞给用户必然无法阅读。关键一步是让LLM把结构化数据改写成自然语言同时在改写时限制内容范围——只允许表述返回数据里明确存在的字段任何推测性补充一律不要。这里还要处理“工具调用失败”的情况。查询类接口偶尔会超时或返回异常Agent不能直接说“系统开小差”而是要有明确的失败策略重试一次、换一个等价工具、将错误码返回给用户。我踩过的一个比较大的坑是超时后页面上方显示转圈用户催了两次Agent却还在等工具响应对话进程卡死。后来加了超时熔断机制超过设定时间立即返回超时结果并主动向用户说明原因体验才算稳住。3.4 从被动查询到主动操作工具查询模块发展到一定阶段可以进一步做“主动服务预判”。比如用户查物流工具返回“该包裹已签收”但签收人不是用户本人Agent就可以主动建议“需要我帮您核实代收情况并提供签收底单吗”。这一步把Agent从“应答者”变成了“服务者”价值感知完全不同。前提依然是工具数据和规则配置到位否则这种主动服务容易变成打扰。4. 情绪控制决定客服Agent口碑的隐形能力4.1 情绪识别不能只靠“关键词匹配”早期做情绪识别直接上一个关键词列表命中“投诉”“差评”“太差了”就触发安抚逻辑。跑起来后误报率极高——用户可能只是引用客服原话“你们上次回复我说‘很抱歉’”系统就误判为需要道歉。更合理的做法是分层识别。第一层是显性情绪词第二层是语气与上下文特征比如句尾使用连续感叹号、消息重复发送第三层是场景信息例如用户已经是第三次进线、历史会话中有未解决的工单。这些特征组合后给每轮对话打一个“情绪等级分”而不是简单地分“生气”和“不生气”两档。LLM在情绪识别上其实可以发挥作用但我会控制它的角色范围。具体做法是用一份小模型或者规则先做粗筛把存在情绪倾向的会话挑出来再让LLM做细粒度的情绪分类和归因分析。这种“先粗后细”的管道式设计比直接让LLM对每一轮都做情绪判断要省很多成本也更可控。4.2 情绪应对策略的分级情绪识别出来后应对策略也要分级。轻度不满比如用户语气略带急躁需要的是“快速响应明确告知下一步”。中度愤怒比如用户反复强调问题严重性需要的是“先共情再解决”先解释造成不便的原因再给出可执行的补救方案。高危情绪例如用户表达强烈投诉意图或持续语言攻击这时候应触发人工坐席接管流程Agent负责把完整的上下文同步给人工。我见过一个反面教训某客服Agent在用户持续辱骂时依然保持“礼貌而机械”的固定话术结果被用户截图发到公开平台造成了品牌舆情事件。核心原则是Agent要有能力判断自己“不适合继续对话”主动让位给人类。这不是能力不足而是系统设计成熟的标志。4.3 回复生成阶段的情绪约束即便情绪识别和策略分级做得再完整最终用户感知到的还是回复文本本身。所以生成阶段也需要一层情绪约束或者说“表达温度控制”。我实际总结了几条比较实用的约束规则不用否定词开头把“我们不能在周末处理”换成“我们可以为您在下一个工作日优先处理”。有损用户利益的信息要先给原因再给方案不能只通知结论。道歉类话术不能固定模板至少要带上用户问题里的关键实体向用户证明Agent真的“看得懂我的问题”。每一段回复只负责一个核心信息反复堆砌会让用户失去阅读耐心。把这类约束放进Prompt里模型生成的文本会明显更有分寸。另外情绪控制模块还需要有一个“自省机制”比如每次回复生成后让模型自己判断一下“这段话患者读起来会感到被推诿吗”虽然增加了调用成本但在高敏场景下值得。4.4 情绪状态的跨轮存储情绪不是一个瞬时的状态用户可能在第一轮愠怒第三轮才真正爆发。所以情绪等级必须在多轮会话的状态中持续累积而不是每轮单独判断。我设计上会用一个单独的会话维度数据结构存储情绪轨迹包含情绪等级、触发事件、累积次数。当某个触发事件反复出现Agent对应的策略要升级而不是每次都像第一次遇到一样重复道歉。这个模块的开发难度不在模型在于数据的标注和策略的沉淀。实际做的过程中建议把每一条人工客服处理过的“愤怒对话”整理成样本分析人工在什么节点让步、什么节点转接、什么节点给权限。这些信号做进策略里比让模型自己摸索靠谱得多。5. 实操过程从零搭一个可用的客服Agent需要做哪些事5.1 一个最小可行版本的基本架构很多入门的开发者会直接拿一个大模型API开始调Prompt这其实是把系统内部的复杂度转移给了模型。总的想法是第一版就用最简单的方式跑通闭环再逐步替换模块。我给一个当时在模拟项目里使用的最小架构大致分这几个部分入口层负责接收用户消息会话层维护上下文的持久化路由层完成意图识别分发给不同的处理器业务层承载状态机和工具调用情绪层在路由同时并行判断情绪等级回复生成层把业务结果和情绪策略合并成最终话术。流程图不用画得多复杂重点是每层之间的数据接口稳定。第一版可以直接用开源模型做意图分类和实体抽取对话生成默认使用模板只在空闲时用LLM润色。这一套跑通以后再逐步升级成LLM做生成、工具调用自动决策。好处是每一层都是一个可以单独替换的插槽迭代时不需要推倒重来。5.2 关键Prompt的设计技巧Prompt设计不是一次性完成的而是反复迭代出来的。我的习惯是先写一个糟糕的完整版再逐步砍掉控制不了的部分。实际效果比较好的结构是角色与边界说明、业务规则与动作限制、对话状态输入、工具调用规则、输出格式约束、发言风格约束。每个部分都要写清楚“什么不能做”比“能做什么”更重要。比如客服Agent不能承诺赔付金额不能承认责任归属不能编造订单信息。这类硬约束比任何话术指导都管用。另外还有一个小技巧在Prompt里加入“思考过程要求”。就是明确让模型先依据对话历史整理当前状态再决定动作。这个思考步骤不一定是我们人类理解的“推理”但它会给最终输出一个缓冲空间降低幻觉率。5.3 数据准备与测评体系客服Agent的上限由数据决定。多轮对话和情绪控制都需要数据支撑我当时跑出来的经验是至少需要三类数据基础。对话历史数据从真实客服系统里采集脱敏会话保留交互过程而不是只保留结论。标注数据对会话进行业务意图、情绪等级、满意度结果三类标签标注这个工作量排期至少占整个项目的一半。还有工具日志数据记录每次工具调用是否成功、返回什么值、用户后续是否还提出同类问题。测评方面除了常规的正确率我更关注三个指标任务完成率用户目标是否闭环达成、打断率用户是否经常插话修正Agent、升级率转人工的触发频率。这三个指标组合在一起基本能反映一个客服Agent是不是真的“可用”。5.4 上线前的灰度与人工兜底客服Agent上线的灰度策略也是决定成败的环节。一次性全量开放风险非常大因为真实对话的多样性远超出测试集。我建议按用户类型分桶灰度先放低风险用户群体比如查特定类型信息但很少发起投诉的群体。灰度期间所有“情绪等级高”的会话强行转人工Agent只做辅助。这时候人工坐席端要给一个“人机协作界面”画面上展示Agent的回复建议、工具调用的结果、情绪判断的标签人工可以一键采纳或改写。这样做的好处是即使Agent只是半自动状态也已经能降低人工的重复劳动量同时积累一批高质量的改写样例用于接下来的优化。5.5 模型选型与成本控制最后聊几句模型选型。客服场景完全用最强的商业模型当然效果好但成本也很感人尤其多轮对话的上下文积累起来token消耗是单轮的几倍甚至十几倍。何况客服系统的并发量往往有峰值按最大并发去配置最强模型预算会非常难看。我的经验是分级使用模型。意图分类、实体抽取这类简单理解任务用中小规模的开源模型就够速度快也省。真正需要生成自然语言的环节才调用大模型并且严格限制上下文长度及时截断历史对话的早期轮次。对于工具调用结果的摘要也不要把原始JSON全部灌给模型先用规则抽取关键字段再压缩输入。成本优化永无止境但核心是不要把所有请求都塞进同一个最大的模型里分而治之才是正道。6. 常见问题与排查技巧实录6.1 多轮对话的上下文串扰实际调试中最常见的问题是上下文污染。模型记住了早期聊过的订单号到第五轮用户问新问题时模型还在围绕旧订单作答。排查时就去看会话历史里注入的字段是否随状态更新。很多串扰的根源是记忆管理里的“旧实体清理”没做新出现的实体没有及时替换掉旧实体的优先级。6.2 工具调用格式的幻觉模型生成的工具调用格式偶尔会不符合预期比如参数名是错的或者把一个数字参数写成了字符串。这在调用真实接口前必须做格式校验。实际经验是还要额外准备一层容错解析不匹配标准JSON时就尝试按键值对提取再不行就整体重新生成一次。第二次仍然失败就固化为一个追问模板。6.3 情绪模块误报情绪识别误报是比较珍惜的问题。误报太多会导致系统频繁触发安抚甚至转人工用户本来没有不满周围却围上来一堆道歉反而尴尬。排查时优先看特征权重配置关键词评分太高就会盖过上下文信号。一个常用的办法是把情绪触发结果和人工标注做对比测试不停调整特征权重而不是改逻辑规则。6.4 用户绕圈子不进入正题怎么办有些用户表达比较发散来回几轮都不提供关键槽位。Agent一直追问同一个问题会显得很机械。我的处理是设计一个“引导话术升级”机制第一次缺失参数时直接问第二次则给出选项供用户选择第三次提供参考样例让用户照着格式给。6.5 客服Agent奇妙的保险感问题部分用户对“自己正在和机器对话”非常敏感一旦发现是机器人会产生防御心理并拒绝认真沟通。接线经验是Agent不需要刻意伪装成人。但在首轮回复中主动亮明身份同时说明自己可以调用哪些能力反而会建立信任。越是含糊地想伪装用户越容易觉得被欺骗情绪也随之恶化。我跟一些做客服系统的同行交流后大家的一致感受是技术难点在写代码阶段其实都是可控的真正决定系统口碑的往往是那些边界情况的处理——用户词不达意时Agent愿不愿意多问一句工具反复出错时Agent能不能坦诚承认并转人工用户发怒时Agent会不会为了复读机而失去底线。客服Agent是一个与人和耐心强相关的事情多花时间在情绪控制和确认机制的细节上远比往模型里堆更多参数更见效。