客服 Agent 系统落地复盘:从 0 到 1 构建企业级智能客服的实践经验

📅 2026/7/22 3:44:36
客服 Agent 系统落地复盘:从 0 到 1 构建企业级智能客服的实践经验
客服 Agent 系统落地复盘从 0 到 1 构建企业级智能客服的实践经验一、深度引言与场景痛点去年年底我们团队接手了一个看起来很简单的需求给公司客服系统接入大模型让机器人先回答80%的常见问题剩下的转人工。老板说就调个API的事儿结果我们搞了三个月。真正做起来才发现坑多得离谱。首先客服不是闲聊——用户问我的订单怎么还没到你不能答您的订单正在处理中这种废话得查到真实的物流状态。其次知识库是活的运营每天都在改话术、换优惠、上新SKU你不能每次改完去调prompt。最要命的是客服对话有上下文——用户前一句说iPhone壳下一句说红色的有吗你得知道他在说iPhone壳的红色款而不是在问口红。这三个问题——工具调用、动态知识、多轮对话——是传统BOT迈不过去的坎。我们的解决思路就是Agent架构。二、底层机制与原理深度剖析Agent跟传统Bot的核心区别在于自主决策。传统Bot是一个if-else的决策树Agent则是一个让LLM在每一步自己决定接下来做什么的循环。上图是整个Agent客服的核心流程。用户输入进来先做意图识别如果只是知识库能回答的简单问题直接走RAG如果需要调API查物流、查订单就交给Planner去规划调用步骤如果识别到用户情绪激动或者问题太复杂直接转人工。关键的是那个评估器Evaluator。它会在Agent给出回答后做一次自检这个回答有没有准确回应用户的问题有没有遗漏关键信息如果不满意就重新规划一次。这个自检循环是整个系统不掉链子的保障。三、生产级代码实现import asyncio from dataclasses import dataclass, field from typing import Optional from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langchain_core.messages import HumanMessage, AIMessage, ToolMessage from langgraph.prebuilt import create_react_agent dataclass class CustomerAgentConfig: model_name: str gpt-4o-mini temperature: float 0.3 max_retries: int 3 timeout: float 30.0 max_turns: int 5 eval_threshold: float 0.7 tool async def query_logistics(order_id: str) - str: 根据订单号查询物流状态 try: # 实际项目中这里调用物流API await asyncio.sleep(0.2) return f订单{order_id}已发货预计明天到达 except Exception as e: return f物流查询失败: {str(e)} tool async def query_order(user_id: str) - str: 根据用户ID查询最近订单 try: await asyncio.sleep(0.2) return f用户{user_id}的最近订单iPhone 16 Pro 保护壳红色 except Exception as e: return f订单查询失败: {str(e)} tool async def search_knowledge_base(query: str) - str: 在客服知识库中搜索答案 try: await asyncio.sleep(0.15) knowledge { 退换货: 7天内无理由退换需保持商品完好, 优惠: 当前全场满200减30新用户首单9折, } for k, v in knowledge.items(): if k in query: return v return 未在知识库中找到相关信息 except Exception as e: return f知识库搜索失败: {str(e)} class CustomerServiceAgent: def __init__(self, config: Optional[CustomerAgentConfig] None): self.config config or CustomerAgentConfig() self.llm ChatOpenAI( modelself.config.model_name, temperatureself.config.temperature, max_retriesself.config.max_retries, timeoutself.config.timeout, ) self.tools [query_logistics, query_order, search_knowledge_base] self.agent create_react_agent( modelself.llm, toolsself.tools, ) async def evaluate_response( self, user_input: str, response: str ) - bool: 评估回答是否满足用户需求 eval_prompt f请评估以下客服回答的质量0-1分 用户问题{user_input} 客服回答{response} 评估标准 1. 是否直接回答了用户的问题 2. 是否包含具体可用信息非泛泛而谈 3. 是否遗漏了用户可能需要的关联信息 只回复一个0到1之间的数字。 try: result await self.llm.ainvoke([HumanMessage(contenteval_prompt)]) score float(result.content.strip()) return score self.config.eval_threshold except (ValueError, AttributeError): return True async def chat(self, user_input: str, history: Optional[list] None) - str: 处理单轮客服对话 messages list(history) if history else [] messages.append(HumanMessage(contentuser_input)) try: final_state await self.agent.ainvoke( {messages: messages}, config{recursion_limit: self.config.max_turns}, ) response_messages final_state.get(messages, []) if not response_messages: return 抱歉系统处理异常正在为您转接人工客服。 last_message response_messages[-1] response_text ( last_message.content if hasattr(last_message, content) else str(last_message) ) is_satisfied await self.evaluate_response(user_input, response_text) if not is_satisfied: response_text ( 抱歉我的回答可能不够准确。 已为您转接人工客服请稍候。 ) return response_text except Exception as e: return f系统繁忙请稍后再试或联系人工客服。 async def multi_turn_chat(self, conversation: list[dict]) - list[str]: 处理多轮对话 history [] responses [] for turn in conversation: if not turn.get(user): continue resp await self.chat(turn[user], history) responses.append(resp) history.append(HumanMessage(contentturn[user])) history.append(AIMessage(contentresp)) return responses async def main(): agent CustomerServiceAgent() conversation [ {user: 我的订单到哪了}, {user: 有优惠吗}, {user: 那个红色的能退吗}, ] responses await agent.multi_turn_chat(conversation) for i, r in enumerate(responses, 1): print(f第{i}轮回复: {r}) if __name__ __main__: asyncio.run(main())四、边界分析与架构权衡这个系统在设计过程中有几个关键权衡值得聊一下Planner的复杂度控制。一开始我们想让Agent自己决定调用工具的顺序和组合完全自主规划但发现客服场景的工具调用模式其实是有限的——查物流、查订单、查知识库基本就三件事。过度自由的规划反而容易出错。最终我们用了create_react_agent的半自主模式让LLM在有限的工具集里做选择而不是自由组合。**评估器的满意阈值**是个玄学。设太高0.9Agent会反复重试用户等得不耐烦设太低0.5质量没有保障什么都放过去。我们通过A/B测试发现0.7是个比较均衡的值——大部分回答质量过关极少数不满意的会重试一次然后转人工。知识库更新的时机。如果每次运营改了知识库都重建向量索引频繁写入会拖慢检索。我们的做法是增量更新定时全量重建。运营修改会实时追加到知识库但向量索引每4小时全量重建一次避免碎片化。转人工的策略。不能只在Agent回答不了时转人工——用户说我要投诉时哪怕Agent能回答也应该转。我们在意图识别层单独做了情绪检测对愤怒、投诉类表述优先转人工。五、总结三个月做下来最大的感受是Agent不是银弹。它擅长处理有明确工具支持的结构化任务但在纯自由对话场景下过度依赖Agent架构反而会增加不稳定性。一个好的客服系统本质上是把确定性和智能性结合起来——规则处理确定的部分Agent处理模糊的部分人工兜底处理复杂和情绪化的部分。这个系统的代码框架我已经整理到GitHub上了想直接复用的同学可以在这个脚手架基础上替换成你们自己的知识库和API工具就差不多了。最关键的是定义好你的工具集——工具越清晰、边界越明确Agent的稳定性就越高。