从接口压测到全链路质量保障:AI智能客服系统的软件测试实践
一、AI智能客服系统 的测试挑战智能客服系统远不止普通的 CRUD 业务系统它是一个典型的长连接 高并发 AI 推理链路 分布式路由复合体。任何一个环节异常用户侧感知往往就是卡死“丢消息”“答非所问”。对测试工程师而言这套系统存在四个核心难点难点典型表现对测试的冲击多渠道接入WebSocket 主通道 第三方 IM SDK 回调同一套消息逻辑要走完全不同的接入路径多实例部署服务水平扩容连接分散在不同节点消息可能发到 A 实例但用户连在 B 实例需要跨实例路由AI 链路复杂敏感词 → 意图识别 → 知识检索 → 大模型生成每一步都有外部依赖失败模式呈指数级增长响应式全栈WebFlux Reactor R2DBC传统断言方式失效ThreadLocal 不可用调试门槛陡增一句话概括这类系统的测试本质在异步、非阻塞、分布式的条件下保证消息不丢、不重、不乱序、不超时。二、被测系统技术特征概览2.1 核心技术栈通用化层技术选型说明JDKJava 21LTS虚拟线程就绪Web 框架Spring Boot 3.x Spring WebFlux响应式编程模型服务治理Spring Cloud Nacos注册中心 / 配置中心RPCDubbo Triple基于 gRPC服务间高效通信数据库PostgreSQL / MySQLR2DBC 非阻塞访问缓存 / 消息RedisHash / Stream / 分布式锁ReactiveRedisTemplate向量检索云厂商向量数据库用于 RAG 知识检索大模型主流 LLM 云服务支持流式输出认证鉴权响应式 Sa-TokenReactor Context 传递登录态对象存储云厂商 OSS文件上传 / 下载调度XXL-Job分布式定时任务监控Micrometer Prometheus 分布式追踪指标采集与链路追踪压测工具自研 Python WebSocket 压测客户端200 并发 / 200 QPS2.2 测试关注点映射模块核心职责测试重点风险等级会话模块WebSocket 接入、消息分发、跨实例路由连接管理、消息可靠性、心跳超时、多端路由 P0AI 编排意图识别、RAG、回复生成、转人工决策三级降级链路、节点分支断言、策略切换 P0LLM 服务大模型对话流式输出完整性、取消语义、超时降级 P1RAG 模块向量检索置信度阈值、多分区并发、命中 / 未命中 P1网关统一入口、限流、鉴权路由规则、限流阈值、Token 透传 P1权限中心认证、RBAC、部门数据隔离登录态、权限拦截、上下文透传 P1运营后台前端管理页面前后端接口契约、权限渲染 P2三、IM 核心全链路流程测试视角3.1 消息从发送到接收的完整链路用户浏览器 / APP │ WebSocket 连接wss://域名/ws/chat ▼ WebSocket 接入层 │ 接收 TEXT 帧 → 解析为内部消息对象 ▼ 消息分发器Dispatcher │ 按 userType messageType 路由到对应处理器 ▼ 用户消息处理器UserMessageProcessor │ ├─ 1. 敏感词检测 │ └─ 命中 → 替换为 *** │ ├─ 2. AI 回复策略选择 │ ├─ 热门话术缓存命中 → 直接返回 │ ├─ 本地缓存命中 → 直接返回 │ └─ 未命中 → 调用大模型 │ ├─ 3. AI 编排工作流执行 │ │ │ ▼ │ StateGraph 状态图驱动 │ ├─ 意图识别节点 │ ├─ 知识库检索节点RAG │ ├─ 回复生成节点 │ ├─ 转人工节点 │ └─ 兜底回复节点 │ ├─ 4. 大模型服务调用 │ │ │ ▼ │ 流式返回 FluxString │ 逐 token 推送到前端 │ ├─ 5. 消息持久化 │ │ │ ▼ │ R2DBC → PostgreSQL / MySQL │ └─ 6. 消息推送路由 │ ├─ 本地连接 → 直接内存推送 ├─ Redis 连接缓存命中 → 写入消息通道 └─ 跨节点 → Redis Stream 广播 │ ▼ WebSocketSession.send() → 客户端接收3.2 必须覆盖的 12 条分支清单编号分支场景测试类型预期结果1匿名连接发送消息功能不走分布式路由Handler 直发返回提示登录2已登录连接发送消息功能走完整业务编排链路3本机连接消息发送功能直接内存推送不写 Redis4跨实例连接消息发送集成写入 Redis Stream目标实例消费并推送5单端在线功能正常收发6多端同时在线PC 微信功能消息推送到所有在线端不漏不重7热门话术命中功能返回热门话术列表不调 AI8本地缓存命中功能返回缓存回复不调 AI9大模型策略触发集成调 AI 服务链路流式返回10敏感词命中功能消息脱敏替换原始内容仍持久化11排队转人工功能分布式锁互斥仅一个请求能进入转人工12AI 超时降级容灾返回兜底话术不阻塞用户四、测试方案分层设计七层模型层级工具 / 手段覆盖范围示例L1 单元测试JUnit 5 Mockito Reactor StepVerifier单个类 / 方法的分支覆盖AI 策略三分支逻辑L2 切片测试WebFluxTest / DataR2dbcTestWeb 层路由、R2DBC RepositoryWebSocket 握手、消息持久化L3 集成测试TestcontainersPG / Redis / 注册中心 Dubbo 本地调用跨模块端到端编排会话 → AI 编排 → LLM 完整链路L4 接口测试Postman / Newman / Shell 脚本REST 接口契约登录、会话 CRUD、知识库管理L5 WS 协议测试自研 Python WebSocket 客户端长连接入参 / 出参 / 时序握手鉴权、消息推送、心跳L6 性能压测自研 Python 压测工具200 并发 / 200 QPSRT / P95 / P99 / 可用率L7 容灾测试手动 / 自动化故障注入跨实例消息可达性实例宕机、Redis 抖动、网络隔离五、重点一WebSocket 自动化测试设计5.1 测试设计思路WebSocket 测试的核心难点在于它是异步双向流不是请求-响应模型。需要同时验证服务端能正确接收客户端消息服务端能主动推送消息到客户端心跳机制正常工作断连后资源正确释放5.2 响应式流断言StepVerifier测试目标验证 WebSocket 文本消息被正确处理并分发。文字描述测试方案准备阶段构造一条模拟的 TEXT 帧内容为 JSON 格式的消息体如{type:***,content:你好}执行阶段将该消息传入Flux.just()模拟客户端输入流断言阶段使用StepVerifier验证输出流第一条消息应为 AI 回复类型消息内容包含预期的回复文本流在超时时间内正常完成关键代码片段思路// 1. 构造输入 FluxFluxWebSocketMessageinputFlux.just(mockTextMessage(jsonPayload));// 2. 调用被测 Handler 获取输出 FluxFluxWebSocketMessageoutputhandler.handle(input);// 3. StepVerifier 断言StepVerifier.create(output).assertNext(msg-{Stringpayloadmsg.getPayloadAsText();assertTrue(payload.contains(AI_REPLY));}).expectComplete().verify(Duration.ofSeconds(5));5.3 心跳与断连测试测试目标验证 PING/PONG 心跳机制与超时断连。测试方案模拟客户端连接后不发送任何 PING 帧验证服务端在配置的心跳超时时间后主动关闭连接验证 Redis 中的连接记录被正确清理关键断言逻辑使用expectNoEvent(Duration)验证在心跳间隔内无服务端主动消息超过超时时间后连接状态变更为 CLOSEDRedis 中key:{value}对应的 Hash 记录被删除5.4 多端消息同步测试测试目标验证同一用户多端在线时消息推送到所有终端。测试方案模拟同一用户 ID 建立两个 WebSocket 连接PC 端 移动端向该用户发送一条消息验证两个连接都收到推送验证消息内容一致、不重复六、重点二AI 编排工作流测试6.1 意图三级降级链路意图识别是 AI 客服的核心决策点采用三级降级策略Level 1: 向量匹配向量数据库语义检索 ├─ 命中score ≥ 阈值 → 直接使用向量匹配结果 └─ 未命中 ↓ Level 2: 小模型意图分类 ├─ 置信度 ≥ 阈值 → 使用小模型结果 └─ 置信度 阈值 ↓ Level 3: 大模型兜底LLM 直接判断 └─ 最终结果测试设计思路采用数据驱动 Mock 控制的方式固定expectedIntent通过 Mock 控制每一级的输入和输出。Level 1 向量命中场景测试步骤Mock 向量数据库客户端使其返回高置信度结果如 score0.92阈值0.85构造输入文本“我的余额是多少”执行意图识别节点断言返回的意图为query_balance意图来源标记为VECTOR_MATCH不再调用 Level 2 和 Level 3Level 2 小模型命中场景测试步骤Mock 向量数据库返回空未命中Mock 小模型返回中等置信度结果如 confidence0.78阈值0.7构造输入文本“我要转账”执行意图识别节点断言返回的意图为transfer_money意图来源标记为SMALL_MODEL不再调用 Level 3Level 3 大模型兜底场景测试步骤Mock 向量数据库返回空Mock 小模型返回低置信度结果如 confidence0.35阈值0.7Mock 大模型返回 JSON 格式意图判断{intent: complaint, reason: 服务态度}构造输入文本“你们什么破服务”执行意图识别节点断言返回的意图为complaint意图来源标记为LLM_FALLBACK6.2 RAG 命中 / 未命中分支测试RAG 命中场景测试步骤Mock 向量数据库返回高分知识片段score0.88阈值0.75内容“7天无理由退货”内容“退货需保留包装”构造输入文本“怎么退货”执行 RAG 节点断言上下文中包含知识库内容isKnowledgeHit标记为 true后续进入知识增强回复节点RAG 未命中场景测试步骤Mock 向量数据库返回低分结果score0.21构造输入文本“我想去火星旅游”执行 RAG 节点断言isKnowledgeHit标记为 falseshouldCallLLM标记为 true后续进入大模型直答节点6.3 转人工决策测试测试目标投诉类语句触发转人工流程。测试步骤准备启用转人工的 Bot 配置设置投诉关键词列表如投诉“差评”“垃圾”构造输入文本“我要投诉你们的服务态度”执行转人工节点断言节点状态变更为TRANSFER_TO_HUMAN事件列表中包含TransferToHumanEvent转人工服务层的initiateTransfer方法被调用一次七、重点三跨实例消息路由测试7.1 跨实例路由架构用户 A 连接 → 实例 AWebSocket 接入 │ │ 消息目标用户在实例 B ▼ 消息分发器判断路由 │ ┌─────────┴─────────┐ │ 目标在本地 │ 目标在远端 │ → 直接推送 │ → 写 Redis Stream └───────────────────┘ │ ▼ 实例 B 消费 Stream → 推送用户 B7.2 Redis Hash 连接存储测试Redis Key 结构设计Key: im:user:channels:{userId} Type: Hash Field: {channelType}:{deviceId} Value: JSON {instanceId, sessionId, channelType, deviceId} TTL: 24h自动过期防止僵尸连接测试用例设计步骤操作预期结果1注册连接userId, instanceId, sessionId, channelType, deviceId返回 true2查找连接userId返回完整的 ChannelInfo 对象3验证 TTL接近 24h允许误差4注销连接userId, field返回 true5再次查找返回空八、性能与稳定性测试8.1 压测方案设计采用自研 Python WebSocket 压测工具支持以下模式模式并发QPS持续时间目的标准压测20020010 分钟验证常规负载能力长稳压测505024 小时验证内存泄漏 / 连接稳定性降级专项1001005 分钟模拟 AI 超时验证降级话术峰值冲击5005001 分钟验证限流与熔断策略压测核心指标连接建立成功率目标 ≥ 99.9%消息往返延迟RTP95 500msP99 延迟 2s错误率 0.1%流式首字延迟TTFT 1.5s8.2 监控指标与告警阈值指标采集路径告警阈值说明接口 QPS/actuator/prometheusP95 500ms 告警IM 接口响应时间AI 接口 RTPrometheus 指标P95 3s大模型调用延迟WebSocket 在线数自定义指标抖动 20%连接稳定性Redis Stream 积压XPENDING 1000 条消费能力不足JVM GC 暂停jvm_gc_pause_seconds单次 200ms内存压力错误率自定义错误计数 0.1%整体健康度8.3 分布式追踪排查TraceId 串联排查流程从 Prometheus / Grafana 发现异常请求获取 TraceId在各服务日志中按 TraceId 过滤按时间排序还原完整调用链网关层 | 14:23:01.100 | 收到用户请求 | userId10086 会话层 | 14:23:01.105 | WebSocket 消息解析完成 AI 编排层 | 14:23:01.110 | 意图识别开始 | input查余额 向量检索 | 14:23:01.115 | 向量搜索完成 | topK5 AI 编排层 | 14:23:01.130 | 意图query_balance | sourceVECTOR LLM 服务 | 14:23:01.135 | 大模型流式开始 | modelqwen-plus 会话层 | 14:23:01.280 | 推送 AI 回复 | chunks15九、典型故障排查指南9.1 场景一消息丢失排查路径1. 确认消息是否到达 WebSocket 层 → 查看 WebSocket Handler 日志确认收到 TEXT 帧 2. 确认消息是否进入分发器 → 查看 Dispatcher 路由日志 3. 确认路由结果 → 查看路由日志中的标记LOCAL / REDIS / STREAM 4. 如果走了 STREAM → 检查消费者组是否在线 → XINFO GROUPS 消费者key 5. 如果消费者在线 → 检查 Pending 是否堆积 → XPENDING 消费者key 消费组key 6. 如果 Pending 堆积 → 消费者处理阻塞 → 检查消费者线程池 / 下游服务延迟9.2 场景二转人工死锁排查路径1. 查看 Redis 中的锁状态 → GET lock:transfer:human:{会话Id} → TTL lock:transfer:human:{会话Id} 2. 如果 TTL -1永不过期 → 看门狗续期逻辑异常锁永远不会释放 → 修复方向unlock 放入 doFinally() 确保执行 3. 如果 TTL 正常倒计时但锁未释放 → 业务异常导致 unlock 未执行 → 修复方向增加锁持有时间上限强制过期 4. 如果 Redis 主从切换 → DEL 命令可能丢失 → 修复方向使用 Redlock 或增加重试机制9.3 场景三AI 回复超时排查路径1. 确认超时发生在哪一层 → 网关超时AI 编排超时LLM 调用超时 2. 查看 LLM 服务日志 → 是否收到请求是否开始流式输出 3. 查看 AI 编排状态机 → 是否触发了降级节点 → 降级话术是否正确返回 4. 验证超时配置 → WebClient 超时 AI 编排超时 网关超时 → 确保每层都有超时保护不会无限等待10.2 测试经验响应式代码必须用 StepVerifier传统assertEquals无法断言异步流的行为StepVerifier 是标配Redis Stream 是跨实例消息的命脉Pending 监控、ACK 机制、Stream 修剪缺一不可AI 链路必须三级降级向量 → 小模型 → 大模型任何一级都要有超时和兜底分布式锁必须有看门狗没有自动续期的锁在生产环境一定会出问题压测要分档位短促高压验证极限长稳低压验证泄漏两者不可互相替代TraceId 是排查的核武器从网关到 LLM 全链路串联5 分钟定位问题根因写在最后智能客服系统的测试本质上是在异步、分布式、AI 依赖三重不确定性中用工程化的手段建立确定性。分层测试是骨架Mock 是肌肉监控是可观测的神经——三者缺一不可。希望本文的实战经验能给正在做类似系统的测试同学一些参考。

相关新闻

《从信息学发展史到 Python 循环:我的一天学习记录》

《从信息学发展史到 Python 循环:我的一天学习记录》

今天学的东西比我想象中要连贯。上午先看的是信息学的发展历史。以前我一直觉得计算机发展史离我很远,直到我读到图灵、ENIAC 和冯诺依曼,才慢慢明白计算机不是突然出现的,而是人类为了处理越来越多信息一步一步造出来的。图灵提出可计算理论…

2026/11/1 23:49:36 阅读更多 →
农牧企业出海,如何用“数字化+AI”穿越周期?——ALCF2026(越南站)观察

农牧企业出海,如何用“数字化+AI”穿越周期?——ALCF2026(越南站)观察

当前,全球供应链格局正经历深度调整,“走出去”成为中国农牧企业谋求新增长的重要选择。在众多海外市场中,越南凭借强劲的增长潜力与独特的地缘优势脱颖而出,正逐步成长为亚洲畜牧产业协同发展的重要支点。 7月19日至21日&#xf…

2026/10/26 22:38:46 阅读更多 →
素数筛法全解析:从埃氏筛到欧拉筛,掌握高效算法核心

素数筛法全解析:从埃氏筛到欧拉筛,掌握高效算法核心

1. 项目概述:为什么我们需要素数筛法?在编程和算法竞赛中,判断一个数是否为素数,或者找出一定范围内的所有素数,是一个经典且高频的需求。最直观的想法是,对于每个待判断的数n,用从2到sqrt(n)的…

2026/10/31 10:57:06 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/1 0:24:43 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/1 10:36:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/1 10:36:51 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/1 1:06:58 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/1 10:35:11 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/1 9:35:41 阅读更多 →

日新闻

周新闻

月新闻