3217 字
约 10 分钟
15
S23-A05 · 模型服务架构:自托管与托管的取舍

"要不要自己部署模型"通常以两种错误方式被回答:拿一张 GPU 报价单去比 API 单价,或者以"数据安全"为由直接买卡。前者漏了利用率和人力,后者漏了机会成本。

这篇给判据和代价结构:什么时候自托管划算、托管 API 有哪些隐性约束、混合与切换要付什么代价。


1. 先算清四类成本

成本项 自托管口径 托管 API 口径
算力 购卡摊销或按小时租,按峰值配置 按 token 计费,按实际用量
运维 驱动/框架升级、值班、扩容 含在单价里
利用率损失 低峰空转,典型量级三到五成 不存在
机会成本 团队时间投在推理栈而非业务 供应商锁定与迁移

第三项最容易漏。算法很直接:

单卡可用小时 = 24 × 30 × 0.95(预留故障与升级窗口)
有效吞吐     = 单卡 tokens/s(实测,不是标称)
月供给 token = 单卡可用小时 × 3600 × 有效吞吐 × 卡数 × 实际利用率
月成本/token = (购卡摊销 + 电费 + 运维人力) / 月供给 token

把 实际利用率 从 0.5 改成 0.9 再算一遍。如果结论翻转,说明决策押在利用率上——先解决利用率,别急着加卡。


2. 对比口径:按峰值还是按平均

口径 自托管看到的成本 托管看到的成本 倾向
按平均负载 偏高(卡闲着也算钱) 偏低(用多少付多少) 托管
按峰值负载 与平均接近 偏高(峰时单价与限流) 自托管
按三年总拥有 含扩容与换卡周期 含调价与模型换代 逐年建模

只在一种口径下比较,结论必然是预设的。两条负载曲线的差距,就是弹性本身的价格。


3. 自托管的适用判据

判据 成立时 反例
数据不出域 合同或监管明文禁止外发 "担心泄露"但无具体要求
量大且稳定 月 token 足够摊平固定成本 淡旺季差数倍
需要微调 通用模型不达标且有标注数据 提示词还没试透
延迟要求特殊 需要固定 P99 或极短首字延迟 供应商其实能满足,只是没测
需要离线/内网 部署环境无外网 只是开发环境没开白名单

判据要写成能被反驳的句子。"数据安全"不是判据,"客户合同第 7 条禁止把数据传出 VPC"是。


4. 托管 API 的隐性约束

约束 表现 缓解
限流 并发与 TPM/RPM 双限,峰时 429 客户端排队 + 退避,别重试风暴
区域 模型只在部分 region 提供 多区域端点,或接受跨区延迟
版本下线 旧模型有退役日期 固定快照名 + 离线回归集
能力漂移 同版本输出分布轻微变化 关键路径抽样比对
内容策略 部分输入被拒答,错误码混在业务错误里 错误分类,单独成类

版本固定要落到配置,不能靠默认值:

llm:
  provider: vendor-a
  model: model-x-2025-06-01     # 写全快照名,不写 latest 别名
  fallback-model: model-x-2024-11-01
  timeout: { connect: 2s, first-token: 8s, total: 60s }

写 model-x-latest 等于把线上效果交给供应商的发布节奏。


5. 混合架构与它的复杂度

形态 用途 新增复杂度
托管主 + 自托管兜底 供应商故障或限流时接住流量 两套提示词、两套质量基线
自托管主 + 托管兜底 常规自给,尖峰溢出 溢出判据、成本突增
按任务分流 简单任务小模型本地,复杂任务远程 路由误判、双份评测

混合的代价不在部署,在两份输出要能被同一套下游消费,所以兜底模型必须过同一套回归集:

def route(req):
    if breaker.is_open("vendor-a"):        # 供应商熔断
        return serve_local(req, "small")
    if req.est_tokens > LOCAL_MAX_CTX:      # 超出本地上下文
        return serve_remote(req)
    return serve_remote(req)

路由函数要能被单测覆盖,每条分支至少一个用例。没被测过的兜底路径,故障当天就是第一次运行。


6. 版本变更如何灰度

方式 能回答的问题 成本
影子流量 新旧输出差多少 双倍推理费用,不影响用户
小流量对比 业务指标有没有变差 需要指标口径与分流能力
A/B 长跑 细微差异是否显著 周期长,样本量要求高
直接切 + 回滚开关 出问题能不能退 最省事,风险最高

影子流量比不出"用户是否更满意",因为影子结果没有进入业务。通过标准要提前写死:

1) 影子比对:500 条历史请求,新旧一致性不低于基线
2) 小流量 5%:错误率不升,首字延迟 P95 升幅 < 10%
3) 小流量 50%:核心指标(转化/采纳率)无显著下降
4) 全量:保留 24 小时一键回退

7. 部署形态与显存约束

形态 适用 主要约束
单机单副本 内部工具、低并发 无冗余,升级即中断
多副本 + 负载均衡 在线服务 KV Cache 不共享,前缀命中率打折
批处理队列 离线标注、批量摘要 与在线争卡,需配额隔离
单卡多模型分时加载 模型多、流量低 换模型的加载时间进入延迟
显存 ≈ 权重(参数量 × 每参数字节)
     + KV Cache(并发序列 × 长度 × 层数 × 头维度 × 2 × 字节)
     + 激活与框架开销(典型量级为前两项的 10%~20%)

量化只改第一项,不改第二项。长上下文场景下,量化省下的显存常被 KV Cache 吃掉——这是"量化后仍 OOM"的常见原因。精度损失必须用自己的评测集测。


8. 缓存与批处理放在哪

手段 命中条件 收益 风险
精确缓存 输入完全一致 高,命中即零算力 键要含模型版本,否则串版本
语义缓存 向量相似度超阈值 中 误命中给出错误答案
前缀缓存 相同 system prompt 前缀 中高,省 prefill 前缀一变全失效
连续批处理 同批请求 吞吐提升明显 单请求延迟上升

缓存键必须含模型版本、温度与全部影响输出的参数。少一个,就会出现"升级后仍返回旧答案"。


9. 容量规划:并发、队列、超时的三角

并发上限 C ≈ 队列容量 Q / 平均处理时长 T     (Little's Law 稳态)
定哪两个 后果
并发 + 超时 队列随流量自由增长,直到拒绝
并发 + 队列 超时被迫拉长,等待不可控
队列 + 超时 并发被流量决定,显存可能被打爆

在线服务一般定"并发 + 超时",用拒绝消化溢出;离线批处理定"并发 + 队列",让超时退化为慢而不失败。


10. 可观测与错误分类

指标 看什么 异常信号
token 吞吐 输入/输出 tokens per second 吞吐掉而 QPS 不降 → 长输入占比上升
首字延迟 P95 请求到第一个 token 与总延迟脱节 → prefill 排队
队列深度 等待调度的请求数 持续 > 0 说明并发到顶
错误分类 限流 / 超时 / 策略拒绝 / 上游 5xx 混在一起就无法定责
class LLMErrorKind(Enum):
    RATE_LIMITED = "rate_limited"    # 可退避重试
    TIMEOUT = "timeout"              # 可重试,需降级
    CONTENT_BLOCKED = "blocked"      # 不可重试,改输入
    UPSTREAM_5XX = "upstream_5xx"    # 可重试,需熔断

把 CONTENT_BLOCKED 与 UPSTREAM_5XX 一起重试是最常见的浪费:一个永远失败,一个会把供应商打到熔断。


11. 成本治理落在哪里

落点 能回答的问题 落地难度
按功能 哪个功能最贵 低,请求头打标即可
按租户 谁在用、是否要配额 中,需要身份贯通
按团队 预算归属与超支预警 中高,需要组织口径

最小可行做法是入口打三个标签,随日志落库:

meta = {"feature": "order-assistant",
        "tenant": current_tenant_id(),
        "trace_id": current_trace_id()}

没有这三个标签,月末只有一张总额账单,没法归因,也就没法治理。


12. 切换与回退

故障类型 能否临时切换 前提
供应商 5xx / 限流 能 兜底常备、提示词兼容
区域故障 能 多区域端点已测过
模型版本下线 能(切旧版) 旧版仍在服务期内
能力漂移 难 只能靠离线回归集发现
自托管显存不足 能(溢出到托管) 溢出判据与配额已设

回退要演练,不演练的回退等于没有。每季度执行一次并记录耗时:打开熔断 → 观察兜底路径 10 分钟的 P95 与错误率 → 核对输出能被下游解析 → 复位阈值、记录差异点。


13. 排错

现象 原因 处理
量化后仍 OOM KV Cache 未随量化下降 降并发或降 max-model-len,别只降精度
吞吐高但用户抱怨慢 连续批处理拉高单请求延迟 在线与离线队列分开
升级后错误率上升 输出格式变了,解析器没跟上 灰度前跑解析层回归
429 集中在整点 定时任务与在线流量同池 定时任务单独配额或错峰
兜底切换后风格突变 两套提示词未适配 兜底模型单独维护提示词变体
缓存命中率虚高 键漏了模型版本或温度 补全键,历史缓存整体失效一次

14. 边界

场景 建议 理由
月调用量小 直接用托管 固定成本摊不平
团队无 GPU 运维能力 托管 驱动与框架问题会吃掉全部排期
需要最新模型能力 托管 自托管落后一个版本周期
一次性/短期项目 托管 采购折旧周期长于项目周期
数据合规硬性要求 自托管或专有部署 唯一不需要算账的判据

一句话:自托管的门槛不是买得起卡,是能持续把卡用满。 用不满的卡比按量计费贵得多,只是账单出现在采购单上,而不是每月账单上。


15. 自测

  1. 自托管成本四项里,哪一项最常被漏算,怎么估?
  2. 同一套负载为什么要按"平均"和"峰值"各算一遍?
  3. "担心数据泄露"为什么不构成自托管的判据?
  4. 影子流量能回答什么问题,不能回答什么问题?
  5. 量化省了权重显存,为什么长上下文还是 OOM?
  6. 并发、队列、超时只能定两个,在线服务通常定哪两个?
S23-A05 · 模型服务架构:自托管与托管的取舍
https://www.clxhxhhr.top/posts/6118/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。