背景:一个看起来很简单的需求
需求很直白:在客服后台右侧加一个「智能建议」区域,根据当前会话上下文,生成几条候选回复,让客服可以一键发送或稍微改一改。
技术方案也不复杂:前端把最近 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 上线的同学留三条很主观的建议:
- 把它当「外部支付渠道」一样对待,而不是「一个普通接口」。
- 先做好失败和超时的体验,再去卷文案质量。
- 上线前至少跑一轮「最坏情况」压测,假设所有人都在点那个按钮。
模型越来越强,是好事。但对我们这些搞工程的来说,麻烦反而是越来越多的。 这也算是这次事故,给我们整个团队上的一课。
评论区