1810 字
9 分钟
- 次浏览
模型价格表加一份本地兜底
读前导览

Sub2API 的模型价格和上下文窗口不能每次都从远端拉。加了本地兜底,拉不到的时候服务还能跑。

正文
1810 字
阅读
9 分钟
结构
8 节
来源线索

sub2api/model-pricing-fallback

sub2api:model-pricing-readme sub2api:model-pricing-fallback sub2api:price-mirror

模型代理服务里有一类数据很不起眼:模型价格表。

它不像鉴权、转发、流式响应那样站在主路径上,也不像账号池和代理池那样每天都能看见状态变化。不过只要系统需要展示预估成本、识别上下文窗口、区分模型能力,它就会变成基础依赖。

这类依赖最怕被写成“运行时去远端拉一下”。

网络正常时,它当然能工作;网络抖动、容器 DNS 异常、GitHub 访问失败、某个地区被限制、上游文件临时不可用时,一个本来不该阻断主流程的数据文件,就会把整条服务拖进不确定状态。

所以我更喜欢给价格表设计一条明确的降级链路。

价格表更适合按配置处理#

模型价格数据看起来像外部资料,但对代理服务来说,它更像配置。

它通常包含几类信息:

  • 模型标识。
  • 输入和输出计价。
  • 上下文窗口大小。
  • 是否支持某些能力。

这些字段不一定每小时都变,但它们会影响用户对请求成本和模型能力的判断。把它们当成临时查询,就会出现一个麻烦:服务能不能正常展示信息,取决于那一刻能不能连上远端文件。

这类文件加载失败,不应该影响接口转发和管理页打开。

更合理的是:远端可以提供新鲜数据,但本地必须有一份可用副本。远端失败时,系统继续运行,只是明确告诉维护者“现在用的是本地兜底版本”。

镜像分支比直接依赖上游更稳#

直接从上游公开文件读取,链路最短,也最脆。

上游路径变化、访问受限、请求被限流,都会影响运行时。中间加一层镜像分支,反而更适合个人服务。

这层镜像可以由 GitHub Actions 定期更新,把上游价格数据复制到自己仓库的某个分支。运行时优先读镜像地址,减少每次直连上游带来的不确定性。

这样做有几个好处:

  • 上游变化先进入可观察的更新任务。
  • 自己可以控制镜像地址和文件格式。
  • 运行时读取路径更稳定。
  • 出问题时能区分“上游坏了”和“我自己的镜像没更新”。

多复制这一份数据,主要是把外部不确定性从运行时挪到更新流程里。

本地副本是最后的兜底#

镜像也可能失败。

所以项目里还应该保留一份本地副本。运行时流程可以很朴素:

先读远端镜像
失败则读本地副本
使用本地副本时写 warning

这条路不是为了保证每次都拿到最新价格,而是为了让价格表下载失败时服务还能继续跑。

我后来按两个问题看它:数据够不够新,服务还能不能用。

远端成功,得到较新的价格表;远端失败,得到较旧但格式稳定的本地表。用户请求仍然能走,管理界面仍然能打开,日志里能看见当前处于降级状态。

对小服务器来说,这种降级比一次次重试远端更实际。

降级必须可见#

本地兜底不能悄悄发生。

如果服务从本地副本读取价格表,却没有任何日志或状态提示,后面排查成本显示异常时就很麻烦。维护者会以为系统正在使用最新数据,实际它可能已经离线好几天。

所以降级时至少要记录:

  • 远端读取失败的原因。
  • 使用的是哪一份本地文件。
  • 本地文件的大致版本或更新时间。
  • 后续是否需要人工刷新。

这些信息不一定要展示给最后用户,但维护端应该能看到。

“可用但不新鲜”和“完全不可用”是两种状态。日志要把它们分开。

手动更新路径也要保留#

自动化会失败。

定时任务可能没跑,镜像分支可能权限异常,本地服务器可能临时无法访问外网。此时文档里最好保留一条手动更新路径:从公开源下载新文件,覆盖本地副本,再由发布或部署流程带上去。

这条命令不用经常跑,但它让系统不依赖某个单点自动化。

很多个人服务都有自动任务,但手动接管的步骤没人写清楚,自动任务一坏就卡住。

格式稳定比字段多更重要#

价格表里当然可以有很多字段。

但运行时最需要的是稳定解析。字段可以扩展,读取层不能因为一个新增字段或局部缺失就崩掉。更稳的做法是只依赖必要字段,并对缺失值给出明确默认或跳过策略。

比如:

  • 识别不到的模型,别假装知道价格。
  • 没有上下文窗口,就别在界面里展示一个猜测值。
  • 远端字段变了,应该记录解析失败,别让整个服务启动失败。

价格表是辅助判断,不是主业务数据库。

辅助数据的失败范围应该被限制住。

这类缓存适合写进发布检查门#

价格表本地副本还有一个好处:它能被发布检查门检查。

构建或发布前可以确认:

  • 本地文件存在。
  • JSON 格式可解析。
  • 至少包含若干常用模型条目。
  • 文件大小在合理范围内。
  • 最后更新时间不会离谱。

这些检查不需要复杂,但能防止“空文件也被打包”“格式坏了才到线上发现”这种低级问题。

远端镜像负责更新,本地副本负责兜底。发布前检查的重点是:本地这份文件至少能被正常读出来。

我的处理方式:先读远端,失败就读本地#

这件事给我的提醒很简单:外部数据不要都做成运行时硬依赖。

模型价格表、能力表、上下文窗口、公开规则列表,这类数据都可以有相似设计:

上游公开源 -> 自己的镜像 -> 本地副本 -> 可见降级

上游负责提供新数据,镜像负责把外部变化变成可观察更新,本地副本负责让服务在网络不稳时继续工作,日志负责告诉维护者现在是不是降级。

对我这种小服务器来说,多放一份本地文件,比运行时反复赌外网稳定更省心。

服务不需要因为一个价格文件下载失败就变得脆弱。它只需要诚实地说:这次没拿到最新数据,我先用本地副本继续跑。

模型价格表加一份本地兜底
https://blog.sunmmyapi.xyz/posts/model-pricing-cache-before-runtime-fetch/
作者
Sun
发布于
2026-05-29
许可协议
CC BY-NC-SA 4.0

继续读

相关内容