SaaS 客服系统从 0 到 1 的血泪史:我们踩过的 10 个工程与架构深坑

6 阅读7分钟

写这篇文章,并不是为了证明我们做得多对,而是想把真实踩坑的 “疤痕” 摊开给后来者看。

如果你正在做 SaaS / 企业系统、计划自研 Chat / 协作系统,或是在维护一个 “看起来很简单” 的聊天功能,那你大概率会在下面这 10 个坑里见过血。


坑 1:低估了 “客服系统” 的系统复杂度

误区:“聊天系统 = WebSocket + 消息列表 + 输入框”

真相: 整体架构不是 IM,而是高度耦合的实时业务系统。

在 TWT Chat 的实践中,聊天只是 UI 层最表面的 20%,真正的复杂性在于后端的状态机。

  • 接入层:处理多种 SDK 与 Web Widget 的兼容性。
  • 实时通信层:维护千万级长连接与 Gateway。
  • 会话与状态服务:核心挑战。会话生命周期、消息状态(已送达 / 已读 / 撤回 / 失败)、多端同步、网络抖动下的重连恢复。

**结论:**先写聊天功能、后补业务逻辑的路径几乎注定失败。客服系统是业务驱动通信,而非通信承载业务。


坑 2:没把 “多租户” 当成一等公民

误区: 认为多租户只是在数据库里加一个 tenant_id。

真相: 多租户 = 产品边界,必须从领域建模开始。

我们早期犯的错是先做功能,再补租户隔离。结果导致:

  • 权限模型推倒重来
  • 历史数据迁移成本极高

**经验教训:**必须将 租户(Tenant)、团队(Team)、坐席(Agent)、访客(Visitor) 作为一等领域对象进行建模。租户隔离、数据归属和权限边界,必须在第一行代码落下前设计好。


坑 3:把 “在线状态” 当成一个简单字段

误区: online 是个 Boolean 值。

真相: 在线 ≠ 已连接,而是可承接能力(Capacity)。

如果你只靠一个字段判断状态,分配逻辑会瞬间混乱(如:用户已断网但页面未关闭)。

我们的工程实践:

  • 连接态(Connection) :TCP/WS 连接是否活跃。
  • 活跃态(Active) :页面是否在前台、是否有操作。
  • 可分配态(Assignable) :根据排班、当前接待量、手动挂起状态综合判定。

**实现方案:**基于心跳检测 + 延迟判定窗口 + 分布式状态机。


坑 4:消息 “必达” 比你想象得难

误区: 发送成功就代表对方收到了。

真相: 客服系统里,丢一条消息 = 丢一次成交机会。

常见坑点包括:断连瞬间的消息丢失、客户端显示成功但服务端落库失败。

架构原则: 消息系统必须一致性优先,再追求实时性。

TWT 策略:写入即持久化 → ACK 驱动前端状态 → 客户端重试机制 → 每条消息具备全局唯一 ID 辅助去重与幂等处理。


坑 5:性能瓶颈不在并发,而在 “慢查询”

误区: 只要抗住千万级 WebSocket 就能高可用。

真相: 读多写多的混合场景,会拖垮你的数据库。

客服系统最重的查询往往是:“我的待接入会话”、“最近活跃访客”、“未读消息聚合”。

解决路径:

  • 会话表与消息表彻底拆分
  • 冷热数据分层(历史消息入 NoSQL / 冷库)
  • 索引完全围绕真实查询场景设计,而不是复用通用表结构

坑 6:前端状态管理复杂度被严重低估

误区: 用 React/Vue 撸个列表。

真相: 聊天前端是分布式状态同步模型。

它需要同时处理:实时数据流、本地乐观更新、失败回滚逻辑。

经验: 必须用 状态图(Statechart) 而非零散的变量驱动前端。如果状态模型不清晰,Bug 将会非常 “玄学” 且无法复现。


坑 7:安全问题来得比你想象中早

**误区:**早期项目,没啥好黑的。

**真相:**客服系统是 “半公开系统”,天然暴露在公网,是肉鸡最爱。

哪怕在早期,我们也遇到了恶意刷消息、接口撞库、非法域名嵌入。

**防御重点:**接入层限流、严格的 JWT 鉴权、域名白名单限制、不可信输入的全量清洗。


坑 8:国际化不是 “翻译”,而是 “体验适配”

误区: 把文案翻译成英文就行了。

真相: 国际化是针对全球用户行为习惯的工程抽象。

差异点:不同时区的在线时间判定、各地区对隐私提示(GDPR)的敏感度、不同文化下的自动回复策略。

工程代价: 所有策略(策略机)必须下沉为配置化,而不是写死在逻辑里。


坑 9:配置能力不足,会拖垮整个系统

误区: 先 Hardcode,等客户提需求再改。

真相: 客户的定制化需求会直接导致代码分支爆炸。

客服系统会被无限追问:能不能按团队配?能不能自定义颜色?能不能改提示语?

TWT 准则: 用配置表达差异,而不是用代码 if/else。将几乎所有策略(分配、回复、通知)下沉为:租户级、团队级、坐席级三层配置体系。


坑 10:千万别用 “免费” 掩盖系统成本

误区: 存储和长连接很便宜。

真相: 规模化后的技术债迟早会变成账单债。

客服系统的真实成本包含:长连接的心跳消耗、海量历史消息存储、实时推送的计算资源。

思考: 如果没有可持续的定价模型和存储清理策略,技术团队会陷入无止境的成本优化泥潭。


写在最后:为什么要分享这些?

如果从工程角度总结:客服系统 = 实时通信系统 + 业务协作系统 + 产品策略系统。

它绝不是很多 SaaS 产品的边缘模块,而是核心基础设施。

我们在 TWT Chat 的所有设计决策,都是从这些坑里一步步爬出来的。写下这些,是希望你在动手写第一行代码之前,对这个系统的复杂度保有足够的敬畏。

每一个 “坑” 的终点,都是 TWT Chat 的起点。

自研一个 “能发消息” 的聊天框可能只需要一周,但打磨一个 “好用、稳定且不出错” 的工业级客服系统,可能需要一个团队数年的交学费和迭代。


如果你不想再踩一遍这些坑

如果你发现你的团队正在重走我们当年的弯路,或者你不想在底层架构的挣扎中浪费数月时间,TWT Chat 或许是你更好的选择:

  • 跳过 “状态陷阱” :内置三维状态机模型(连接态 / 活跃态 / 可分配态),确保每一份工单都能精准分配。
  • 金融级消息必达:ACK 驱动与持久化优先架构,彻底解决断连、丢失、多端不同步问题。
  • 原生多租户与配置驱动:从第一天起就拥有灵活的租户隔离和策略配置能力。
  • 极致的工程性价比:我们替你承担长连接、实时推送和冷热数据管理的复杂运维成本。

不要重复造轮子,尤其是这个轮子还可能带坑。

如果你认可我们的工程理念,或者希望拥有一个从设计之初就规避了上述 10 个坑的成熟方案,欢迎体验 TWT Chat。

我们不仅提供一个工具,更提供一套经过实战验证、极其稳健的客服技术底层。

[点击这里,开启 TWT Chat 不踩坑之旅 →]—— TWT Chat 技术团队,做最懂工程实践的客服系统。