同一周内:一个上限被取消,一个底线被加上
2026 年 9 月的第一周,Cloudflare 的开发者平台动了两次,而这两次改动方向相反。9 月 4 日,Cloudflare 删除了 Worker 的压缩体积上限——免费版的 3 MB 与付费版的 10 MB——改为对所有套餐统一适用的 64 MiB 未压缩上限。9 月 1 日,D1 不再把免费版的每日读写行数上限当作提醒,而是当账户超额时直接返回查询错误。
对任何在 Workers 上跑 AI API 负载的人来说——不管是 OpenAI 兼容端点前面的代理、RAG 服务、Agent 网关还是流式中继——这一对改动比单独看任何一条头条都更重要。第一项改动移除了一个过去两年里一直在悄悄塑造「AI SDK 如何为边缘打包」的约束;第二项改动加入了一个以生产报错、而非控制台警告形式出现的运行时约束。合起来看,这是一次交换:Cloudflare 让你更容易部署一个大 Worker,同时让你更难运行一个不小心的免费数据库。
本文依据厂商自己的文档梳理这两项改动,然后梳理 AI API 项目中那些现在已经没有必要的打包绕行方案——以及取代它们、真正值得你去做的 D1 审计。
Worker 体积到底改了什么
机制值得说清楚,因为 64 MiB 这个数字很容易被误读。Wrangler 一直都会先把你的代码打包再压缩后上传。变的是 Cloudflare 检查这两个测量值中的哪一个。
此前,Cloudflare 检查的是压缩后的体积,超过免费版 3 MB 或付费版 10 MB 就拒绝部署。现在这个检查没有了。Cloudflare 只检查未压缩的打包体积,且所有套餐的限额统一为 64 MiB。
这个区别会大幅改变实际余量,因为 JavaScript 打包的压缩率远非一致。以应用逻辑为主的打包,gzip 后通常只有原始体积的五分之一左右——也就是说,旧的 3 MB 压缩上限大致对应 15 MB 的真实源码。而以密集的生成式数据表、protobuf 描述符或内嵌 JSON schema 为主的打包压缩率高得多,此前可以接近 25–30 MB 原始体积才会触到 3 MB 的压缩门槛。
| 套餐 | 旧上限(压缩后) | 新上限(未压缩) | 现在检查什么 |
|---|---|---|---|
| Workers 免费版 | 3 MB | 64 MiB | 仅未压缩打包体积 |
| Workers 付费版 | 10 MB | 64 MiB | 仅未压缩打包体积 |
Wrangler 仍会打印 gzip 数值,但它现在只是参考信息,不再限制部署。如果你曾经仅仅因为构建输出里的 gzip 数字逼近阈值就去裁剪某个依赖,那份压力已经没有了。
部署前如何检查打包体积
dry-run 参数是查看 Cloudflare 实际会执行的那个数字最省事的方式。它会打包并报告,但不会上传:
wrangler deploy --outdir bundled/ --dry-run
输出长这样:
Total Upload: 259.61 KiB / gzip: 47.23 KiB
Total Upload 就是你的未压缩打包体积,也是拿来和 64 MiB 比较的数字。gzip 数值仅供参照。审计现有项目时有两个细节要注意:这个数值是二进制的(1 MiB 是 2^20 字节,不是 10^6),而且它统计的是整个打包,包含 Wrangler 内联进去的每一个依赖,而不只是你自己的源码文件。
解读这个数字时还有一个前提:64 MiB 是你能上传的上限,它与 Worker 的启动时间是两个独立的限制,后者在两种套餐下都限制为 1 秒。一个舒适地低于 64 MiB 的打包,如果顶层初始化耗时超出这一秒预算,仍然可能部署失败。体积和启动成本是两种不同的约束,放宽其一并不会放宽另一个。
那些 AI 特有的、现在可以删掉的打包绕行方案
这一段对 AI API 项目最要紧,因为部署在边缘的 AI 服务,其依赖结构异常沉重。尤其有三种绕行方案,正是因为旧的压缩上限才变得普遍。
1. 把模型元数据与 schema 挪到 R2
最常见的做法是把大块静态负载从打包里挪出去放到 R2(或 KV),运行时再取。典型候选包括你要代理的上游 API 的 OpenAPI 规范、厂商模型目录(数百个模型的名称、上下文长度、价格、能力标记),以及分词器词表。这些东西都很大,变更节奏比你的代码慢,压缩率又不均匀——正好是最容易被压缩门槛卡住的形态。
如果你的 Worker 此前仅仅为了不超上传上限,而在每次冷启动时都从 R2 拉一份 2 MB 的模型目录,那么这次拉取现在就是一笔可以省掉的冷启动开销。把目录内联回去重新成为一个合法选项——但动手前先测量,因为省下的运行时取数延迟,未必抵得过你新增的启动耗时。64 MiB 的额度是「可以内联」的许可,不是「应该内联」的论证。
2. 把本该是一个服务的东西拆成多个 Worker
第二种做法是架构层面的:一个逻辑上本该是单个 Worker 的服务,被拆成好几个,再用 service binding 把它们接回来,唯一目的就是让任何单个打包不超过压缩阈值。一个典型的 AI 网关会因此变成路由 Worker、provider 适配 Worker,再加一个独立负责请求/响应转换层的 Worker——不是因为这些边界有意义,而是因为体积门槛迫使你在某处切一刀。
现在把它们合并回一个 Worker 是可行的,而且有实打实的好处:自己的组件之间网络跳数更少、部署更简单、请求上下文只有一个地方需要推理。但拆分过程中可能顺带获得了真实价值——独立的 CPU 额度、各自的部署节奏、隔离的故障半径。把合并当成一次需要评估的重构,而不是一次反射式的清理。
3. 自维护精简版 SDK
第三种做法维护成本最高:自己留一份打过补丁、做过 tree-shaking 的 AI SDK 分支,只把你实际调用的端点打进去。团队这么做的原因是官方客户端往往表面面积很大——每个模型的请求构造器、每种流式变体、每个工具调用辅助函数——而压缩门槛让完整包显得很贵。
自维护分支是最值得重新审视的一种绕行方案,因为它带来持续成本:上游每次发版都变成一次手工合并,安全修复也得手动跟进。如果你的分支只是为了控制体积而存在,那么官方包值得重新测一遍。如果它存在的理由是功能性的——缺一个端点、某个代理的怪癖、自定义重试策略——那体积从来就不是真正的动因,分支应该保留。
没有改变的部分
体积放宽并没有放松那些真正在运行时卡住 AI 负载的约束。这些在两个套餐下都没有变,而且正是它们决定了一个大 Worker 部署之后到底能不能用:
| 约束 | Workers 免费版 | Workers 付费版 | 对 AI API 的意义 |
|---|---|---|---|
| 内存 | 128 MB | 128 MB | 流式缓冲区与内存内分词器仍有硬上限 |
| 单请求 CPU 时间 | 10 ms | 5 分钟 | 免费版无法做有意义的本地推理或重转换 |
| 单请求子请求数 | 50 | 10,000 | 多 provider 扇出与 Agent 工具循环在免费版被卡住 |
| 同时打开的连接数 | 6 | 6 | 并行上游调用在两个套餐下限制相同 |
| 启动时间 | 1 秒 | 1 秒 | 大打包仍要付出顶层初始化的代价 |
| 请求数 | 10 万/天 | 无限制 | 免费版会在你的 AI 账单之前先限流 |
注意这张表的形状。每一条决定 Worker 内部能跑什么的约束,要么两种套餐完全相同,要么免费版差得多。64 MiB 是免费版与付费版现在已经相等的那一个维度——也就是说,免费版上的一个大打包可以上传成功,却仍然在 CPU 时间或内存上倒在生产环境。上传容量不等于运行容量。
另一半:D1 免费额度长牙齿了
第二项改动才是更可能把你叫起来的那个。自 2026 年 9 月 1 日起,Workers 免费版上的 D1 查询在账户超出每日读行或写行上限时会失败并返回错误。此前这是软上限——你会收到警告,但查询照常工作。现在 Worker Binding API 与 REST API 都会返回错误,直到上限在 UTC 午夜重置。已存储的数据不受影响,受影响的只是查询它的能力。
现在会硬失败的那些阈值:
| 指标 | Workers 免费版 | Workers 付费版 |
|---|---|---|
| 读取行数 | 500 万/天 | 每月前 250 亿行包含在内,之后 $0.001/百万行 |
| 写入行数 | 10 万/天 | 每月前 5000 万行包含在内,之后 $1.00/百万行 |
| 存储 | 共 5 GB | 前 5 GB 包含在内,之后 $0.75/GB-月 |
有两个错误标识了这种状态,而且都足够具体,可以据此做路由:
Your account has exceeded D1's free tier daily row read limit.
Upgrade to a paid plan or wait until tomorrow (midnight UTC) to continue.
Your account has exceeded D1's free tier daily row write limit.
Upgrade to a paid plan or wait until tomorrow (midnight UTC) to continue.
达到每日上限时 Cloudflare 会发邮件提醒,所以第一个信号是一封通知而不是一张工单——前提是有人在看那个邮箱。
会被抓到的非对称性
把读和写的上限放在一起看,失败模式就一目了然了。你每天有 500 万行读取,但只有 10 万行写入——比例是 50:1。因此读密集型的 Agent 负载远比写密集型的更安全,而写入频繁的负载才是第一个该审计的对象。
陷阱在于单条索引不当的查询代价有多高。对一张百万行的表做全表扫描会读取一百万行,从五百万的预算里算是 五次请求就能把当天免费额度耗光。行读取是按被检查的行计数的,不是按返回的行——也就是说,一条扫描一百万行后返回三行的查询,仍然花掉了一百万行的预算。成本在扫描里,不在结果里。
这解释了为什么这种失败在开发环境里往往无声无息,而在生产环境里立刻爆发。测试阶段一张只有几千行的表,产生的扫描对五百万预算来说可以忽略。同一条查询打在长到几十万行的表上,单次调用成本就是上百倍,而第一个症状不是慢查询——而是上面那行错误。
取代那些绕行方案的审计
如果上面那些打包绕行方案此前是你的主要体积管理策略,那么 D1 的强制执行就是现在应该占据那份注意力的工作。Cloudflare 自己的建议是检查查询活动、加索引以减少读行量。落到实处的版本,按顺序:
- 先找全表扫描。任何在过滤或连接列上缺少支撑索引的查询都是全表扫描的候选,而全表扫描正是随表增长超线性消耗读行预算的东西。
- 盯 meta 对象与控制台。D1 通过 Worker API 的 meta 对象、GraphQL Analytics API,以及控制台的 Metrics → Row Metrics 视图暴露行指标。改动索引前后都要测量,不要假定它起作用了。
- 把写入和读取分开计数。每天 10 万行的写入预算才是更紧的约束。一张每个请求写一行的日志表,在免费版 10 万请求的规模下,光记账就会吃掉整份每日写入额度。
- 尽可能把写操作移出请求路径。批量化写入,或写入一个队列再落盘,能把按请求计的写入成本转为按批次计——这通常是一个免费版负载能拿到的最大一笔削减。
- 把升级价格和负载价值放在一起算。Workers 付费版每账户每月最低 $5,直接取消 D1 的每日限制,代之以每月包含额度。对一个已经在生产里失败的服务来说,这往往比围绕上限做优化花掉的工程时间更便宜。
还有一个二阶效应值得点名。因为限制在 UTC 午夜重置,耗尽预算的负载面对的是一个固定的宕机窗口,而不是一个降级的窗口。如果你的服务跨时区面向消费者,UTC 午夜正好落在欧洲工作时段的正中间——所以故障暴露给用户的时刻,恰好是你本地流量最低、响应能力最慢的时刻。告警要据此设计,并且优先对消耗速率告警而不是对错误告警,因为错误到来时预算已经用完了。
这周该做什么
诚实的总结是:两项改动的紧迫性并不对称。64 MiB 上限是移除约束,对你没有任何要求——没有迁移、没有开关、没有截止日期。它是一个简化的机会,正确的应对是找出哪些体积驱动的绕行方案仅仅为了体积而存在,然后有选择地重看它们。多数团队不必着急;一个能正常工作的 SDK 自维护分支,不会因为一次非必要的重构而变好。
D1 的改动正相反。它在 9 月 1 日生效,把警告变成了错误,而它的失败模式随表增长非线性放大——这正是那种出现一次之后就再也不停的生产事故的形态。如果你在 AI API 负载后面跑着一个免费版 D1 数据库,有用的动作是今天就把读行与写行的消耗对照 500 万和 10 万这两个每日预算核一遍,并找出任何执行全表扫描的查询。
两者之间的联系才是真正有用的结论。Cloudflare 放宽了你能往 Worker 里装什么,同时收紧了你能在运行时便宜地做什么。搭建一个更大的边缘原生 AI 服务比上个月更容易了;免费地运行一个则更难了。请针对第二个事实做规划,并把第一个当作你可以选择去使用的余量。
来源
- Cloudflare changelog,"Deploy larger Workers — up to 64 MiB for both free and paid plans",2026 年 9 月 4 日
- Cloudflare changelog,"D1 enforces free tier daily query limits",2026 年 9 月 1 日
- Cloudflare Workers 平台限额文档(Worker size、startup time、账户套餐限额)
- Cloudflare D1 价格文档(计费指标、免费版读写预算)