尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于PHP的微信AI客服系统实战:消息加解密、RAG与人工接管

基于PHP的微信AI客服系统实战:消息加解密、RAG与人工接管 做在线客服系统这件事我一开始真没觉得有多复杂。直到把微信、AI、人工坐席、知识库这几样东西串在一起才发现水比想象中深得多。微信限制多AI又不能瞎聊人工还得随时能接过去整套逻辑要是没设计好上线第一天就会被用户骂到怀疑人生。这篇文章就把我手上这套基于PHP的微信AI客服系统源码的完整设计思路、关键实现和踩坑记录整理出来给准备自己搞一套类似系统的朋友做个参考。不管你是想直接用它当项目基础还是想独立开发一套里面的消息加解密流程、会话调度机制、RAG知识库接入这几块都建议耐心看一遍全部是实操沉淀下来的东西不是随便拼凑能解决的。1. 整体设计一套微信AI客服系统要拆成哪几块1.1 核心需求拆解我刚开始构思这套系统时其实面临三类人提的需求而且这三类需求并不完全一致。老板的诉求很简单24小时在线永远秒回最好还能省人力因为他不想在深夜让用户等太久。运营那边更关心的是常见问题的自动解答要准确知识库要能维护还得能随时查聊天记录给用户回访。最后是用户本身他们最反感的就是机器人答非所问当他们明确表示“转人工”时系统得迅速响应。这三类需求叠在一起其实已经决定了系统的核心能力边界。它不能只是一个简单的关键词自动回复工具那样用户一遇到稍微绕一点的问题就会死机。它必须是一个具备语义理解能力的AI对话前端同时支持知识库检索增强还得带完整的人工客服接管流程。只有把这三个能力组合起来才谈得上真正的全天候客服。这个认知就是整个项目的地基后面所有的功能模块都是围绕它长的。明白了要做什么接下来就是技术选型的问题。1.2 技术选型为什么选了PHP说起技术选型我估计很多人第一反应是Python毕竟AI生态最全。但我的选择是PHP而且是在仔细掂量过腾讯系API适配性之后做的决定。腾讯官方SDK就是PHP和Java的支持最成熟这一点做过微信公众号、企业微信开发的朋友应该深有体会。微信消息加解密、JSAPI签名这类逻辑PHP版demo几乎就是标准答案直接参考能省下不少调试时间。再看部署成本。PHP天然适合传统机器一台普通的4核8G服务器跑Nginx加PHP-FPM再配个MySQL和Redis撑住几千个活跃用户完全没问题。对中小型项目来说这个成本优势是实打实的。最后是团队协作和维护门槛。PHP的人才储备量很大后续要接手或者扩展功能找人的成本和学习成本都比小众语言低得多。所以这套系统的语言基座就定了PHP配Nginx、MySQL、Redis这套经典组合。选工具从来不是为了炫技是为了项目能够长期稳定跑下去。1.3 系统架构与消息流转整套系统的核心架构我规划成了四大模块微信接入层、AI会话引擎、人工坐席工作台、运营管理后台。用户从微信公众号或小程序发来一条消息它会先进入Nginx转发到PHP-FPM处理脚本。脚本做的第一件事是解密消息内容然后判断客户端的当前会话状态。如果是在AI模式这条消息就发给大模型接口结合知识库内容生成回复如果是人工接管状态就直接转给坐席工作台推送给在线的客服人员。整个链路是这样一个单入口、多出口的模型。模块之间通过MySQL持久化存储消息记录和客户档案通过Redis存取实时会话状态和排队信息。这套架构的好处非常明显它的耦合度很低任何一个模块出问题不至于把整个系统的链路全部拖死。日常维护和二次开发的时候改动单个模块的影响范围都很可控。2. 微信接入消息收发这一步最容易被卡住2.1 微信公众号/小程序的账号准备做微信客服第一步肯定是搞定微信侧的环境这一步看似简单实际上坑特别多我在这里栽过好几次跟头。你需要先去微信公众平台注册一个服务号个人订阅号基本不行因为接口权限不够最好认证过的服务号也可以是企业微信应用。注册完成后在后台“基本配置”页面你会看到三个最关键的信息AppID、AppSecret和服务器配置URL。这里有个很关键的细节需要先把服务器配置里的Token和EncodingAESKey都生成好填到自己服务器的接口地址上微信才会开始推送消息。Token相当于一个简易密码用来做首次验证EncodingAESKey则是消息体加解密的对称密钥直接关系到你能否读取出用户发来的明文内容。所以我在源码里特意放了一个接入验证的脚本第一次配置时它会自动响应微信发来的校验请求输出一个校验成功提示。只要这个通了后面消息推送的问题就少了一大半。2.2 消息签名验证与加解密流程微信的接口接入最容易被搞晕的就是验证和加解密流程很多人第一次做都被这块磨得没脾气。我第一次接入的时候光是校验失败就排查了整整两个晚上最后发现是签名数组的排序问题。完整的签名校验流程是这样的微信服务器会带着timestamp、nonce、signature三个参数请求你的接口你必须把这三者和你自己配置的Token一起按照字典序排序后拼成一个字符串再做SHA1加密然后和signature对比。如果一致说明请求确实来自微信否则就必须拒绝这一步绝不能省。验证通过之后用户发的每条消息微信POST过来的body是加密的密文XML。需要按文档规定的方式从XML中取出Encrypt节点内容用自己的EncodingAESKey做对称解密得到一个标准的明文XML结构里面包含了MsgType、FromUserName、Content这些核心字段。只有完成这一步才能把用户的话真正读到手里。我建议这段逻辑直接封装成一个独立的工具类放在Base模块里所有业务控制器统一调用。不要把加解密打散到业务代码里一旦要换密钥或者改算法你会改到怀疑人生。2.3 消息类型解析与自动回复结构微信消息的类型不少文本、图片、语音、视频、事件都得逐一处理否则体验会非常割裂。我的习惯是写一个统一的入口分发器专门负责按MsgType和Event字段做派发。用户发文本消息就走AI对话逻辑发图片就下载图片临时素材配合OCR服务把文字提取出来再进AI发语音就保存语音文件等待后续离线识别关注公众号推送的subscribe事件就直接回复欢迎语并引导他提问。回复的结构也要注意微信要求被动回复消息必须在5秒内完成否则需要先调用客服接口主动推送。所以我在源码里对所有AI接口请求都做了超时控制超时就先给用户回一句“正在思考中”然后用客服消息接口补发真正的答案。这个兜底机制能非常有效地防止微信侧报接口超时错误也能保住用户体验。3. AI对话引擎让机器人真正能回答业务问题3.1 大模型接口对接的通用接入方式搞定了微信消息的进出接下来是核心中的核心——AI对话引擎。我不打算依赖某一家特定的服务商而是做了一个统一的大模型网关层目前代码里默认对接的是国内主流大模型平台的OpenAI兼容接口这套设计方式可以很方便地切换或增加多个模型服务商。整个对话实现的关键是把用户的聊天上下文组装成messages数组然后POST到模型的chat/completions接口最后把返回内容解析出来推送给用户。这里有几个参数需要特别注意。temperature参数建议设为0.7到0.8之间太低会导致答案过于死板太高又会偏离业务事实0.7是我实测下来既自然又可控的折中值。还可以设置max_tokens控制单次回答的最大长度一般客服场景设到500到800之间最合理既不会太长引人生厌也不会太短说不清楚核心问题。接口请求我全部封装在了一个统一的HttpClient类里支持超时设置、重试机制和错误码映射。单独封装的好处是在升级模型版本或者更换模型服务商的时候只需要改配置文件业务逻辑一行都不用动简直不要太省心。3.2 让AI更懂业务RAG知识库的接入思路只拿着一个通用大模型做客服最大的问题就是它太重了而且缺乏我们关心的业务知识。用户下单后他去问客服“你们家发货要多久”没有业务上下文的大模型只能一本正经地瞎编一个时间一旦说错客户满意度就直接崩盘了。解决问题的主流做法也是现在业界非常关注的方向之一就是给AI加上RAG检索增强生成能力。通俗来说就是先建一个企业自己的专属知识库把常见问题、产品手册、物流政策、售后规则这些内容全部拆成小片段存进向量数据库。当用户提问时我们先把问题向量化在知识库里检索出最相关的几个片段再把这些业务上下文连同问题一起提交给大模型让它基于这些给定事实总结回答。这样AI的每一次输出就都有据可依了不再是一个什么都敢说的裸奔模型。我在源码中默认集成了一个本地轻量级向量检索实现即使你还没有接入外部向量数据库也能先跑起来体验完整的RAG流程。这里有个经验知识库文档不要只用一种切分方式。我做过对比简单按固定字数切分效果很一般容易把一个完整问题的答案拦腰斩断。更好的策略是先按章节再按段落最后按句子切分。每段之间保留一定重叠区保证语义完整召回效果会明显提升。3.3 Prompt设计把常识类问题挡在AI外面模型调用和知识库都搞定之后Prompt策略是决定用户体验天花板的关键环节这一点一定要专门提出来重视。我用的是三层Prompt结构。第一层是系统级指令向模型明确身份定位例如你是商城的专属客服助手小智请以简洁友好的语气服务等等。第二层是业务上下文模板把从知识库检索到的几条相关内容一并塞进去让模型严格围绕给定的业务上下文作答。第三层才是用户实时消息追加进去。还有一个非常重要的部分是设置兜底回复规则我们可以用Prompt明确限制它例如当用户询问天气、股票、新闻时直接回复“我是商城客服这类问题我无法回答”。甚至比这更彻底——针对这类与业务无关的通用闲聊直接在代码层做一个关键词意图判断命中之后就不请求模型了直接回复兜底文案。千万别小看这个设计。客服系统上线的第一天就会有用户闲着没事跟你聊娱乐新闻追问明星八卦如果没有拦截AI不仅答得离谱还会产生不必要的接口调用费用。从成本和稳定性两个角度看把短问题直接短路掉非常有必要。4. 会话调度AI兜底、人工接管的无缝切换4.1 会话状态机让每一轮对话都有据可循再智能的AI也有处理不了的问题这种时候得让真人客服上而且得保证无感衔接。这就要靠一套清晰的会话状态机来控制整个对话走向。我给每一个客户会话设定了几个状态待接入、AI接待中、人工接待中、已结束。在AI接待中状态下如果用户连续问了几次AI都无法从知识库找到答案或者用户明确打出了“找人工”这三个字系统就会自动把会话状态切换到排队或者人工接待中。这里判断逻辑的关键是给每个会话保存一个预计置信度字段。AI每次回答时除了生成内容还会自己评估一个回答的可信度分数低于0.5时候系统就自动标记为“疑似无法解决”并提示用户可联系人工客服。会话状态切换不是只要前端改个标识就行底层要做很严谨的持久化存储。我用的方案是Redis存热状态key就是用户开放IDvalue是JSON格式的会话数据。同时MySQL里的chat_session表记录全量流转历史。这个设计让查询活跃会话的时候不用频繁碰数据库性能好而且会话重建时也能完整恢复历史。4.2 多坐席排队与分配策略人工客服坐席这块我按照一线客服团队的实际工作场景做了很多细节优化比普通的“收到消息就能看到”要复杂得多。首先每个客服人员登录后会进入一个在线/离线切换页面。系统只给在线的坐席分配新会话离线坐席的会话不会自动流转过去。分配算法用的是经典的最少活跃会话优先策略避免有人忙死有人闲死。其次每个坐席有一个最大接待量配置通常是每人20到30个会话达到上限后新进的用户就进入排队队列。前端工作台窗口里实时显示“当前排队xx人”让用户心理上有个预期能有效减少因为等待引起的投诉。最后是童叟无欺的会话接管机制。人工接待开始后AI就被暂时关进评论席不再自动回复把所有对话权限交给人工客服。但坐席可以一键开启“AI辅助对话”让AI实时生成话术建议人工客服一键采纳这个功能在高峰时段特别有用效率提升不是一点半点。4.3 移动端与小程序接入的差异处理既然涉及微信免不了要聊微信生态里不同入口的接入差异。我目前重点支持了主流的微信公众号消息接口同时兼容了企业微信应用消息的接入另外对微信小程序客服会话也做了适配。微信公众号和微信小程序的客服消息虽然都走微信的官方接口但它们的消息推送格式还有客服接口的调用方式还是有一定差异的。我在路由层设置了渠道标识字段每个进站消息会自动记录它的来源渠道比如wechat_official、wechat_mini_program、wecom_app等等这样后端的AI对话层和坐席工作台完全不用关心消息是从哪进来的统一处理就行。有一个常见问题的处理经验。微信小程序的客服消息用户只能在进入小程序后的规定时间窗口内主动发送消息一旦超过时间就得重新进入这就很依赖订阅消息的引导回流。我在欢迎语中做了主动引导提示“点击这里进入客服”用户再点一下就又进入会话了。5. 部署与性能7×24小时不挂的关键5.1 PHP-FPM与Nginx的关键配置系统上线后要继续扛住全天候的访问服务器部署这关必须把牢。我用自己的4核4G云主机做基准测试压测下来Nginx加PHP-FPM的组合相当能打只要配置得当支撑几百个并发客服请求很稳。Nginx的部分我单独为客服接口路径配置了一个独立的location关掉访问日志以减少磁盘IO并用keepalive 32保持与PHP-FPM的复用连接。PHP-FPM部分则把pm设为dynamic按当前机器内存计算start_servers设为8min_spare_servers是4max_spare_servers是20max_children上限控制在32。这个配比既不会让空闲进程白占内存也不会在高峰期因进程数不够而拒接请求。还有一个极其重要的配置是默认的request_terminate_timeout。如果不调大比如保持默认30秒那当AI接口响应稍微慢一点PHP进程就会被直接掐断。我把它设成了90秒正好覆盖大模型接口的平均响应时间避免进程被误杀。5.2 消息异步化与Redis队列的正确姿势这里要单独强调千万不要在微信回调的请求周期内同步去等待AI返回结果那样做一定会出事。因为上面提过微信要求5秒内响应而大模型接口响应时间通常要3到8秒根本来不及。我在代码里做了严格的异步解耦处理。整个流程是这样的微信回调进来接住消息后马上存入待处理队列这里用的是Redis列表结构然后回调接口立刻返回状态给微信告诉它“已收到”。后端的Worker脚本我通过PHP的CLI模式常驻运行不停从队列里拉取消息提交给AI处理得到结果后再调微信客服消息接口主动推送出去。这个方案把“接收”和“回复”完全拆开了非常灵活可以解决所有超时隐患。Worker脚本可以用Supervisor守护它会自动重启挂掉的进程保证队列永远有人消费。我一共起了3个Worker进程实测单进程每秒能处理大约5到8条AI消息这个吞吐量对于客服场景绝对够用。5.3 日志、限流与防护线上系统跑了三个月这是我最想说的一段话之一客服接口是一个高频暴露的公网入口安全问题真的很重要不能只看功能跑得通。第一层是IP限流。同一IP在10分钟内最多只能发30条消息超过就提示“操作频繁”。别小看这个数字正常情况下没人会10分钟发30条能触达这个阈值的基本都是异常行为限制掉能挡住不少攻击和刷接口的机器人。第二层是用户粒度限流也就是针对每个用户OpenID限制消息频率比如每分钟最多10条。这样即使有人从多个IP换着发照样会被识别拦截。限流数据全部放Redis里用INCR加EXPIRE两条命令就能低成本实现顺便还能统计日活和对话量。最后是日志策略。每次AI请求、响应、超时、报错都必须落日志。我用了一套简单但实用的日志库按天、按渠道、按请求ID存储。用户反馈有问题时客服凭请求ID就能快速定位到当时的AI输入输出排查效率会大幅提升。6. 常见问题与排查技巧实录6.1 微信回调时报“token验证失败”这个错误应该能挤进微信开发的十大坑之首至少在我接触的开发中是这样。我遇到过的原因一共有三种。第一种是Token、timestamp、nonce三个参数的排序问题。必须严格按照URL字典序排序再拼接顺序一旦错了SHA1肯定对不上。第二种是服务器时间和微信服务器时间差太多导致时间戳校验不过这就纯属时区配置的问题把PHP默认时区设到北京时间就解决了。第三种是配置的URL本身访问不通或者返回了非200状态码。有回我测试环境开了防火墙忘记放行微信服务器IP段结果回调一直失败排查了很久才找到都是血泪教训。排查这类问题我的建议是先在代码里加一个临时调试日志把收到的所有参数、排序后的字符串、生成的signature全都打印出来再对照微信官方调试工具的签名生成结果能很快圈定是哪一步出了问题。6.2 AI回答总是“答非所问”用户定位问题说“答非所问”这个情况的成因通常不在模型能力本身而在于数据链路这是一个很多新手会忽略的思考方向。首先要看RAG检索有没有真的召回相关内容知识库片段索引不完整或者切分粒度不对都会导致检索结果为空模型只能靠自己仅有的认知硬答。我把每次检索的召回文档ID都打了日志观察AI回答时知识库是否有命中一查便知。其次要看是不是楼上说的微信5秒超时。如果每次用户收到的都是“正在思考中”这句兜底文案而不是真实回复那多半是队列Worker没有正确处理消息需要去查Worker日志了。最后还要关注的是上下文长度失控。有的用户会连续发很多条消息对话越长提交给模型的tokens越多响应越慢还容易被模型截断。我专门写了个压缩策略对话超过10轮只保留最近的8轮加上用户携带的一个全局态信息比如用户ID和当前页面这样模型既能接得上话又不会内存爆炸。6.3 高峰期“回复延时严重”怎么办上线以后经历过一次活动大促那天的消息量是平时的大概8倍。第一位用户还能秒回第50位就得等差不多10秒整体延时就爆掉了。我当时的优化措施有三板斧对后来的运营帮助很大。第一个是把知识库向量数据加了一层静态缓存热门问题的检索结果10分钟以内直接走缓存不走模型重复计算这一点很关键。第二个是把Redis队列改成了多队列隔离核心VIP用户的会话走独立的快速队列普通用户走另一个队列Worker按优先级消费这样即使系统压力很大高价值用户的体验也守住了。第三个是做了接口降级开关当错误率超过一定阈值时自动从大模型模式降级为关键词规则回复模式先保证响应再保证AI质量这是最稳妥的做法。这三招组合下来最严重的那次活动期间系统顶住了从第200条消息开始整体回复延迟压回了3秒以内用户投诉量直线下降。结尾的一些真实体验这套PHP微信AI客服系统搞到后面我自己最大的体会是做客服系统真正的难点从来不在写代码本身而是如何在AI的“无限可能”和业务的“确定需求”之间找到那条最务实的平衡线。AI要够聪明但不能乱说回复要够快但不能超时人工要能接管但不能打断体验。这中间每一个“既要又要”靠的都不是玄学而是前面讲的这些相对枯燥但不容有失的工程细节。如果你准备在上面继续扩展我的建议是优先把会话数据报表和用户画像做出来。客服系统的真正金矿是它每天沉淀下来的海量真实用户问题。把这些问题和解决结果回流到知识库里反复训练系统的AI能力会随着运行时间越来越强到那个时候你会发现这个系统带来的价值早就超过了客服本身。
返回列表