首页技术专题博客目录我的收藏关于与联系

一次 LLM 上线事故的复盘:模型没问题,流程一团糟

我们给客服系统接了一个大模型,用来自动生成回复建议。上线前,大家都在担心「模型会不会乱说话」,结果事故来的方向完全不一样:模型表现还行,整个系统差点被我们自己搞 down。

背景:一个看起来很简单的需求

需求很直白:在客服后台右侧加一个「智能建议」区域,根据当前会话上下文,生成几条候选回复,让客服可以一键发送或稍微改一改。

技术方案也不复杂:前端把最近 N 条对话发给后端,后端调 LLM,拿到结果再返回给前端展示。我们选了一个托管的大模型服务,简单包了一层 SDK。

上线前做了两轮内测,大家对文案质量还挺满意,产品甚至说了一句:

「文案比我写得都好,放心上吧。」

事故:CPU 撑不住的是我们自己的服务

上线当天一切正常,直到晚上 9 点多,值班同学在群里发了一张截图:推荐服务节点 CPU 95%+,RT 从 200ms 飙到了几秒。

我们一开始以为是上游 LLM 服务抖了,结果一看监控,LLM 响应时间其实还好,真正被打爆的是我们自己的「中间层」:

  • 没有做任何并发控制,同一个会话窗口能同时发起多次请求。
  • 没做缓存,用户每敲几个字就会重新请求一次。
  • 日志打得特别凶,一次调用写了几十行 debug 日志。

根因:我们完全没当「在线服务」来设计

复盘时大家想明白了一件事: 虽然我们嘴上在说「这是线上链路」,实际上我们对它的心智还是「一个实验性功能」。

几个典型的「掉以轻心」:

  • 没有限流:以为用户点的不会太频繁。
  • 没有降级:上游超时/报错时,只是简单 toast 一句「稍后再试」。
  • 没有预估 QPS:完全凭感觉拍脑袋,连压测都没做过一轮完整的。

我们后来具体改了什么

1. 前端侧的「手刹」

第一件事是给前端加了一个非常粗暴但有效的防抖+禁用逻辑:

  • 同一个会话,在上一次请求返回前,按钮直接禁用。
  • 输入内容没有实质变化(比如只多打了一个空格),不再重新发起请求。

这一条上线之后,平均 QPS 直接砍掉了三分之一。

2. 中间层的并发和缓存

后端做了两件事:

  • 针对同一个会话+同一段上下文,5 分钟内命中缓存直接返回。
  • 对单个租户做并发限制,超过阈值直接快速失败,并在前端给出「建议稍后再试」的明确提示。

3. 监控和告警拉到「可见范围」

之前我们只是给这个服务随便挂了几个指标,没人订阅告警。 这次之后,我们单独做了一块「智能建议」的监控面板,指标非常朴素:

  • 调用总量 / 成功率 / 超时数
  • 单租户 QPS 分布
  • 上游 LLM 的 RT 和错误率

值班同学也被要求把这块面板加到自己的「默认视图」里,不再是出问题才临时找。

模型本身反而是最省心的

整个事故过程中,最不需要操心的其实就是模型本身。 文案偶尔会有点「用词过于官方」,但完全在预期内,也没有生成什么离谱的内容。

真正把系统拖垮的,是我们对这条链路的轻视—— 把一个有明显「外部依赖」「高时延」「高成本」特征的调用,当成了普通 HTTP 接口来用。

给要在生产上接 LLM 的同学的 3 条建议

最后,给同样在做 LLM 上线的同学留三条很主观的建议:

  1. 把它当「外部支付渠道」一样对待,而不是「一个普通接口」。
  2. 先做好失败和超时的体验,再去卷文案质量。
  3. 上线前至少跑一轮「最坏情况」压测,假设所有人都在点那个按钮。

模型越来越强,是好事。但对我们这些搞工程的来说,麻烦反而是越来越多的。 这也算是这次事故,给我们整个团队上的一课。

评论区