演示跑通了,然后呢
周三下午,老板在群里问了一句:这个知识助手什么时候能上线?
小周把本地演示录了一段发过去。视频里上传文档、提问、答案带出处,一气呵成。群里有人回了“可以”。
然后就没人再说话了。因为“上线”这个词在那个房间里指两件事:一件是这套东西能跑在别人的机器上,另一件是坏了以后有人能把它救回来。视频只回答了第一件。
这件事的关键不在技术,在纸上。上线之前得有一份写下来的责任清单:哪件事归谁,出问题找谁,救不回来的时候放弃什么。留在脑子里就等于没有。
先把组件拆开,再谈故障
一个知识助手上线之后,链路上至少有六样东西,每样都有自己的状态和坏法。
| 组件 |
状态存在哪 |
典型故障 |
| 应用服务 |
无,代码 |
进程崩溃、内存溢出 |
| 任务队列 |
消息、任务状态 |
堆积、消息重复投递 |
| 关系数据库 |
用户、权限、任务记录 |
连接打满、误删表 |
| 对象存储 |
原始文档文件 |
桶策略变更、访问权限错 |
| 检索索引 |
向量与倒排结构 |
重建中断、语料版本对不上 |
| 模型服务 |
无,外部 |
限流、超时、模型下线 |
这张表的价值不在分类本身,而在于每写一行,你就被迫回答两个问题:这一项坏了会怎样,它的状态在哪里。
故障域就是这么划出来的。队列和数据库坏,不影响对象存储里的文件;索引重建失败,原始文档还在,重灌一遍就行。看清楚这一层,才知道半夜出事时先查哪儿。
自托管多出来的那几件事
换成自托管模型,链路上多出来的不是“一个服务”,是一整类责任。
| 事项 |
用 API 托管 |
自托管模型 |
| 容量 |
供应商承担 |
你买机器、定并发、扛峰值 |
| 模型权重 |
供应商维护 |
你下载、校验、存盘、备份 |
| 显存与调度 |
不可见 |
你选卡型、跑起来、盯利用率 |
| 服务升级 |
供应商灰度 |
你决定何时升、怎么回归 |
| 故障处理 |
供应商负责 |
你负责排查和重启 |
| 停机窗口 |
供应商计划 |
你自己找窗口 |
有一条得说在前面:把应用打成镜像丢进容器,不等于部署了大模型。应用容器化解决的是代码在哪儿跑,自托管多出来的容量、显存、权重、升级这些问题,容器化一个都不解决。
小周他们最初的想法是用的人多了就自托管省钱。这句话的毛病是把自托管当成账单问题,它首先是责任问题。你省下的调用费,换回来的是一堆没人会处理的责任。
外部的可用性数字不是你的可用性
应用对外承诺“工作时间内 99.5% 可用”,这条承诺挂在一串依赖上:
用户 → 应用 → 队列 → 数据库 → 对象存储 → 检索 → 模型 API
端到端可用性是这一串连乘的结果。假设每一环都做到 99.9%,六环连乘大约 99.4%。供应商页面写的 99.9%,只是最后一环;如果前面再串一个 RouteFast.ai 这类模型 API 中转,链路里就又多了一个乘数。
所以外部的可用性声明不能直接当自己的 SLO,中间还差着一段预算。
超时预算要提前分。假设应用给用户承诺 15 秒出答案,这 15 秒要分给队列等待、检索、模型生成、工具调用,留一段给网络和重试,剩下的才是模型能用的时间。模型超时设成多少,看它分到多少,不是照抄供应商的默认值。
供应商不可用时降级到什么程度,也要写下来。是返回“稍后再试”,是退回到不带生成的小检索结果,还是给一个人工入口?三条路的用户感受差很远,选哪条是产品决定。
哪些数据丢了能重建,哪些不能
重建成本不一样,这个差别决定你备份什么。
| 数据 |
能不能重建 |
丢了怎么办 |
| 检索索引 |
能 |
用源文档重新灌一遍 |
| 文档解析缓存 |
能 |
重新解析 |
| 原始文档文件 |
不能 |
只能从备份恢复 |
| 用户与权限 |
不能 |
只能从备份恢复 |
| 任务记录与引用 |
不能 |
只能从备份恢复 |
索引是可重建数据,因为源文档还在。权限、用户状态和任务记录是不可重建数据,它们由系统运行产生,没有第二份来源。
所以不可重建的数据必须单独保护。索引重建要几个小时,权限恢复不了就是几个小时的拒绝服务,这两种事不该放进同一个备份策略里。
每件事都要有个名字
上线之前,给下面这些事各写一个名字:
- 发布:谁批准,谁执行,谁回退
- 值班:出事找谁,多久之内响应
- 容量:谁盯磁盘和队列堆积
- 凭据轮换:谁换,多久换一次,换的时候改哪些地方
- 恢复:谁有权宣布恢复了
- 供应商升级:谁盯公告,谁决定升不升
单人项目也能写这六条,只是名字是你自己的名字,但后面要跟具体动作。凌晨三点磁盘满了,你手机上要有一条能照着做的命令,而不是“重启一下看看”。
小周的团队最后写了这么一条值班条目:
磁盘超过 85%:先看对象存储和日志目录;队列堆积超过 500:暂停上传入口,不动模型调用;模型连续 3 次超时:切到备用模型,失败请求返回“稍后重试”。
具体的数字不重要,重要的是它写下来了,而且能在半夜被读懂。
一页部署决策记录
决策记录不用长,一页够用,把五件事定下来:
- 固定的输入:团队人数、每天任务量峰值、资料规模、能接受的停机窗口。
- 数据约束:哪些数据不可重建,允许丢多少,也就是 RPO。
- 恢复目标:多久恢复可用业务,也就是 RTO。
- 运维能力:现在真实会做哪些事,谁来做,别写“以后招个人”。
- 结论:继续用 API 托管还是自托管,以及在什么条件下回头看这个结论。
三种约束下的结论大致是这样。
一个人、一天几十个任务、要求小时级恢复,继续用 API 托管。自托管带来的容量和显存责任,没有任何调用费节省能覆盖。
三五个人、任务量稳定、有专门的人管机器、数据有合规要求不能出内网,自托管值得评估,前提是把容量规划和模型升级回归写进职责表。
中间状态就用混合方案。只有敏感或高频的那部分流量走自托管,其余走 API,代价是两套运维和两套监控。
这些数字都是假设。真实价格、硬件容量和服务承诺要另外去核,这一页不能当采购依据。
你现在该做什么
- 把链路上每个组件和它的状态列成一张表。
- 给每个有状态的组件写一句:丢了之后怎么恢复。
- 把数据分成可重建和不可重建两类,只对后者做备份设计。
- 算一遍依赖链的端到端可用性,别拿供应商的数字当自己的。
- 把 15 秒拆成超时预算,分给队列、检索、生成、工具。
- 写清供应商不可用时的降级范围。
- 写一条带数字和命令的值班条目。
- 给发布、值班、容量、凭据轮换、恢复、供应商升级各写一个名字。
- 把结论写进一页决策记录,注明回头看的条件。
- 记住容器化应用和部署大模型是两件不同的事。
一个值得问自己的问题:现在半夜三点,你的知识助手挂了,第一个被叫醒的人知道他该做什么吗?