1. 缘起
在大模型时代,模型响应时间以及响应内容确定性未知的情况下,怎么做好稳定性?
过去做过的经验能不能复用呢?比如高并发系统(TPS 25w、QPS 100w、TP999 < 80ms)。
我理解是可以复用的,因为本质上都是软件工程的问题,但有几处会变,放在第 3 节展开。
把事前、事中、事后这几步给做好,做扎实,怀着敬畏之心,肯定是 OK 的。
2. 全链路稳定性
全链路走六段:设计阶段留预案,开发阶段立规则,发布阶段卡流程,运行阶段看得见、扛得住,故障时先恢复再定位,复盘时把错误变成资产。
这些流程不是凭空定的,都是血泪教训总结出来的——不要因为省事而越过流程。
2.1 设计:让稳定性融入设计
把背景、约束理清楚。遇到高速增长的系统,我们要先考虑优化系统,再考虑增加硬件资源。平衡成本与收益。
- 依赖分级:把系统的强弱依赖搞清楚,强依赖尽量保证能降级;
- 失败处理:超时、重试、熔断、降级;写操作需要幂等( 网络默认是不可靠的 );
- 隔离策略:按业务、租户、链路进行物理或逻辑隔离,避免互相影响。( eg:DB 的读写分离 )
- 兼容策略:涉及不兼容问题、特别是 C 端需要考虑新老接口共存,逐步切流。
设计阶段需要产出一份稳定性预案,主要描述:这个系统什么情况下会挂、挂了怎么办、对应怎么处置。
2.2 开发:规则约束
- 架构一致性:把架构边界写成测试( 比如”领域层不能依赖基础设施层” ),用 ArchUnit 做成用例,越界就红,不靠人记。
- 流水线卡点:静态检查、规范检查、单测覆盖率、圈复杂度,全部设成”不通过不合并”。
- 覆盖率看增量,不看整体。整体覆盖率会被历史代码稀释,新代码的覆盖率才反映当前质量;
- 圈复杂度超阈值( 比如单函数 10-15 )就该拆。复杂的地方就是出 bug 的地方,也不好读。
- 可观测埋点:新增的功能,默认的埋点是否足够?核心节点有相关日志吗?
- CR 重点:超时、幂等、埋点、日志规范、可读性、复杂度 ( 当然,业务准确性也需要看的 )
形成良好的开发习惯、通过 CR 或者排查问题复盘等沉淀团队共识,不断完善机制。
2.3 发布:流程约束
过程中主要有:优雅启停、灰度发布、观察上下游日志、监控、告警,验证业务数据。
发布之前要有上线 checklist,发布的时候按顺序傻瓜操作。什么时候算通过、什么情况要回滚需要明确。
- 灰度发布:分批次,按机房、按比例滚动发布;
- 细心监控:发布过程心怀敬畏,如果发现不符合预期,暂停发布
- 可靠回滚:允许一键回滚(一般是回滚程序,比较特殊的回滚:动态开关切回老链路),需要考虑数据兼容、版本兼容等问题。
- 变更管控:明确发版节奏( 例如周二、周四发版 ),遇到大促等,严格管控变更。( 系统变更是万恶之源!)
2.4 运行:可观测、可容错
- 可观测:尽早发现问题、排查问题
- 业务层面:单量、转化率等等
- 应用层面:延迟、错误日志
- 硬件层面:CPU、内存、网络、load等等
- 基础设施:依赖的 Redis、MySQL、发号器等
- 监控告警:早于用户感知、有专人 oncall、有执行预案
- 容错处理:限流、熔断、降级、隔离
- 容量管理:定期压测、留有一定冗余、容量告警(默认 85%,增长快速的业务要时刻盯着)
- SLO 与错误预算:上面几条讲的是”怎么发现问题”,这条讲”什么时候该停下来修”。
- SLI 是实测量( 成功率、延迟 ),SLO 是目标( 比如 99.99% ),错误预算 = 100% - SLO;
- 预算烧完就冻结发布,先修稳定性——否则稳定性永远排在业务需求后面;
- 这一步的意义是把稳定性从”口号”变成”可量化的资源”:业务要快可以,但得花预算。
2.5 故障:优先恢复而不是定位问题
实行故障分级制度,可以按时间、业务指标(GMV)等进行定级。
尽量做到 1-5-10:1 分钟发现、5分钟响应、10分钟恢复。
先恢复服务再查根因:降级、回滚、切流等进行止损,别召集排查代码。
出现重大故障,只能单一指挥,否则会出现 N 个人一直给 oncall 的人施加压力。
大部分故障来源都是:应用变更、配置修改等。所以变更管控是稳定性里性价比最高的一环。
2.6 复盘:让错误成为资产
尽量避免追责到人,否则当事人会倾向于隐藏事故,导致故障影响扩大。
复盘主要看:根因、改进(有 owner、有期限)、下次再出现怎么快速发现?
改进部分可以贯穿整个迭代过程:设计、编码、发布、监控等环节。
3. 大模型场景:这套框架哪里要变
框架是通用的,但大模型有几处和传统后端根本不一样,得单独说。
3.1 差异:三处和传统后端根本不同
- 输出非确定:同样的输入,两次输出可能不同。
- 计费在运行时:传统系统的容量成本是阶梯的( 加机器 ),大模型是每请求计费,成本随流量线性涨。
- 依赖不可控:供应商的配额、限流、故障你修不了。
3.2 指标:四个维度都要换口径
延迟上,TTFT 只是体验的一半。
- TTFT( 首字延迟 ):决定用户”等多久”;
- TBT / TPOT( token 间隔 ):决定用户”读得顺不顺”。
- 端到端总时长;
- 流式中断率:首字出来了、后面断了。传统接口没有”部分成功”这种状态,流式有。
成本上,token 用量要拆开看。
- 输入 / 输出 token 分开统计( 输出单价通常是输入的 3-5 倍,混在一起看不出问题 );
- 缓存命中率(KV-Cache / prompt cache):直接决定成本,也直接反映 prompt 布局好不好;
- 单会话 token 成本;
- 成本突增要当故障告警。prompt 膨胀、重试风暴、Agent 死循环,表现都是 token 飙升——它是前兆,不是账单。
质量维度,传统稳定性里完全没有这一块。
- 格式合法率:结构化输出( JSON / 卡片 )能不能解析;
- 幻觉率 / 忠实度;
- 工具调用成功率;
- 拒答率:该拒的拒了吗( 这类场景,漏拒比误拒危险 );
- 轮次衰减:聊到第 15 轮,效果掉没掉。
容量上,吞吐的单位变了。
- 看 token/s,不是 QPS。同样的 QPS,输出长度不同,资源占用能差 10 倍;
- 上下文长度分布:长上下文是资源黑洞,一条超长会话能拖垮一个实例。
3.3 机制:要新增的四件事
- 评测门禁:输出非确定、没有断言可写,”系统是否正常”只能靠评测集判断。评测门禁就是大模型系统的回归测试,而且是唯一可行的那个。
- token 预算 + 超限降级:单请求、单会话、单租户都要有预算,超了降级( 缩上下文、切小模型、直接拒 ),不能放任。
- 多模型路由 + Failover + 可插拔:供应商挂了、限流了、涨价了,都要能切。模型是可替换的商品,不是基础设施。
- 格式校验:结构化输出在渲染前先校验(schema / AST),非法的往下走不了。
3.4 小结:大模型带来的三条增量
上面 2.1 到 2.6 该做的还是要做。
大模型带来的增量就三条:
- 不能靠断言判断对错,所以要有评测;
- 成本随流量线性涨,所以要有预算;
- 模型不是你能修的东西,所以要有替换方案。