七个 JSONL 文件、一个模型访问密钥以及计算得到的 7.04 美元——这就是通过 DigitalOcean 统一的 批量推理 API 对 25 万条真实消费者投诉进行分类和丰富所需的全部:每条记录按产品线打标、情感和紧急程度评分、实体抽取、草拟摘要,随后根据数据集自身的真实标签对每个答案进行评分。相同的 token 在无服务器定价下计算得到 14.07 美元。我们在 GPT-5 和 Claude 两种模型上完整跑通了整个流程,并仔细记录了所学到的一切。
简要版:批量方案成立,而且包装层真的很薄——你已经发送到无服务器的请求体只需变成 JSONL 文件的一行,使用相同的基础 URL 和密钥提交。全部 25 万请求零失败完成,速度甚至快于我们的预算。提前了解以下几点很有用:同一 API 上存在三种不同的模型命名约定、可能低于文档记载的账户层级限制、两种易被忽略的失效模式,以及导致我们生产运行未命中任何缓存的缓存细则。本文将逐一指出它们的确切位置。

将你的无服务器请求仅需增加一个包装层并更改模型 ID,即可获得批量定价。基础 URL 和模型访问密钥保持不变;请求体的其余部分保持不变。数据来源:我们在 2026 年 8 月的实际测量运行;费用根据测量得到的 token 数乘以 DigitalOcean 列表价格计算得出。
本文将从头到尾完整演示整个作业(数据集、JSONL、分块、提交、轮询、评分和成本计算),随后诚实地将 DigitalOcean 的批量服务 与 OpenAI Batch、Anthropic Message Batches 和 AWS Bedrock batch 进行对比,包括每个竞争对手在何处占优。
batch-inference/ 目录)。这里的所有可靠性、准确性、token 以及时长数据均来自我们在 2026 年 8 月 3 日至 13 日之间的实际运行。这些日期尤为重要:平台行为在该时间窗口内发生了变化(Anthropic 的模型 ID 约定和队列行为在我们两次测试日期之间都有所调整),因此下文的行为结论均标注了观测日期。
美元金额是通过计算得出的,而非实际账单:使用 API 自身使用字段中测得的 token 数量,乘以 DigitalOcean 公布的列表价格,其中批处理最高可享受比无服务器低 50% 的价格。我们的测试账户免于计费,因而没有可拍照的发票,我们仅展示计算过程,并且从未声称在账单上观察到该折扣。由于批处理列表价格被定义为无服务器列表价格的一半,“我们的运行成本降低了 50%”纯属算术结果,而非实证。我们的运行所贡献的,是围绕这一算术的全部内容:token 数量是真实的,可靠性是真实的,时延是真实的,且管道中的任何因素(失败、重试、部分结果)都未导致 token 数量高于估计值。
以下是另外三点需要提前说明的注意事项。首先,缓存 token 在整个过程中按全额输入费率保守计价,这是因为 DigitalOcean 未发布批处理缓存费率表,因此所有与缓存相关的数字均为上限。其次,我们最初的 fat‑vs‑lean 提示对比在方法上存在错误(未配对、样本不同);已发表的结论是经过修正的配对版本,即在两种提示下均使用相同的 5,000 条记录,并采用 McNemar 检验。第三,若干发现仅基于单次观测:一次取消探测、一次卡住的作业、一次 17 分钟的 Anthropic 响应时间。这些应被视为带时间戳的存在性证明,而非分布式结果。
所有脚本和汇总数据已公开,以便您自行重新运行。文中引用的价格和限制均是在 2026 年 7 月 31 日至 8 月 13 日之间获取的。如果您是在以后阅读本文,请在为自己的作业制定预算前,查看 DigitalOcean 当前的 价格 和 文档,因为两者均可能发生变化。
如果您已经通过 DigitalOcean 的 无服务器推理 调用 OpenAI 或 Anthropic 模型,那么只需改变文件格式即可使用批处理。此无服务器调用:
import requests
resp = requests.post(
"https://inference.do-ai.run/v1/chat/completions",
headers={"Authorization": f"Bearer {DO_MODEL_ACCESS_KEY}"},
json={
"model": "openai-gpt-5-nano", # serverless: DO catalog ID
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Complaint:\n{narrative}"},
],
"response_format": {"type": "json_schema", "json_schema": TICKET_SCHEMA},
"max_completion_tokens": 1000,
"reasoning_effort": "minimal",
},
)
它成为批处理输入文件的一行。请求体完全相同(逐字节),只有模型 ID 不同(详见课程部分,即第 1 课):
{"custom_id": "main-9915470", "method": "POST", "url": "/v1/chat/completions",
"body": {"model": "gpt-5-nano", "messages": ["..."], "response_format": {"...": "..."},
"max_completion_tokens": 1000, "reasoning_effort": "minimal"}}
相同的基础 URL。相同的模型访问密钥。一个作业 API 用于提交、轮询和下载,适用于 OpenAI 和 Anthropic 模型。并且批处理价格最高可享 50% 的无服务器折扣。
在销售话语落地之前,先说一个诚实的范围说明:“无 schema 更改”对每个提供者都成立。您的 OpenAI 请求体会原样进入批处理。在统一 API 内切换提供者很容易但不是免费的:Anthropic 使用自己的批处理行格式(custom_id + params),自己的结构化输出机制(使用 tool 调用而非 response_format),以及第三种模型 ID 约定。真正统一的是围绕请求的一切:一个端点、一个密钥、一个作业生命周期、一个查看所有作业的地方。
我们需要一个可以评分而不仅仅是运行的演示。CFPB 消费者投诉数据库 是一个美国政府公共领域的数据集,包含数百万条真实的金融服务投诉。经用户同意的子集包含免费文本叙述(在发布前 CFPB 已将 PII 遮蔽为 XXXX),此外还有杀手级功能:每条记录都有一个官方的 Product 标签。可以把它想象成一个已经有人完成标注的支持工单堆,这样您就可以大规模检查模型的作业。
每条记录的任务:划分产品线、命名问题、评分情感和紧急程度、提取实体,并草拟一行摘要。分类和丰富在一次调用中完成。
我们编写了两版系统提示词,并在全文中保持这些名称不变。精简提示词(约 460 个 token)仅包含任务说明、产品类别名称和输出模式;这是主体 250,000 条记录运行所使用的版本。肥提示词(约 2,400 个 token)此外还嵌入了完整的 CFPB 分类法,包括所有 110+ 个问题级别类别,基于更多上下文能提高准确性的假设。肥提示词还有一个后来重要的副作用:它是唯一足够长以超过 OpenAI 1,024-token 提示缓存阈值的版本,因此使用肥提示词的运行也成为我们的缓存测试(因而成本表中出现 “fat + cache” 这一项)。
样本:对2017年后的投诉进行比例抽样,共250,000条带有叙述的记录,每条截断至1,500个字符。上限使得token消耗可预测;其对准确性的影响未单独测量。
我们自行遵循的一个框架规则是:下文所述的准确性指的是与CFPB自身标签的一致性,而非绝对真实。这些标签由提交投诉的消费者选择,且类别边界确实存在重叠(信用报告上的一笔有争议的债务可以说是三种不同的产品)。在阅读每类表格时请牢记这一点。
从7 GB CSV到分级结果。一切均为流式处理;不会将原始文件加载到内存。来源:我们的管道,在2026-08-03至2026-08-13期间在DigitalOcean统一批量推理API上进行测量。
步骤0:提交前先估算。 对1%的样本进行分词并外推。我们的精简提示平均每条记录约468个输入/约82个输出token,因此250k条记录约为1.37亿个token。在构建任何内容之前,请根据列表价格检查这一点是否符合您的预算,并根据当前限制文档中规定的每模型每账户100亿token的入队token限制进行核对。
步骤1:构建JSONL。 每条记录一行。在OpenAI上通过response_format: json_schema实现严格的JSON输出;在Anthropic上等价的是强制工具调用:
{"custom_id": "haiku-9915470",
"params": {"model": "claude-haiku-4-5-20251001", "max_tokens": 300,
"system": [{"type": "text", "text": "..."}],
"messages": [{"role": "user", "content": [{"type": "text", "text": "Complaint:\n..."}]}],
"tools": [{"name": "record_ticket", "input_schema": {"...": "..."}}],
"tool_choice": {"type": "tool", "name": "record_ticket"}}}
结构化输出为 99.99% 的 250k OpenAI 响应(20 行错误)和 100.00% 的 25k Anthropic 响应生成了可机器解析的 JSON。
步骤 2:超越限制进行分块,包括错误消息必须告诉你的那个限制。 文档化的限制是每文件 50,000 请求和 200 MB。我们的首次提交将 250k 切分为六个文件,每个最多 45k 请求。其中五个在验证时立即失败:
batch contains 45000 requests; tier limit is 40000 for provider openai
这是低于文档上限的账户层级限制(截至 2026-08-03 测试)。文档确实警告说,根据您的安全层级会有额外限制;他们只是没有公布这些数字,所以您第一次知道自己的限制是从这个错误中得知的。好消息是:错误会告知您的实际数字,且验证失败不会产生费用。我们在 40k 处重新分块,总共七个文件,用于 250k。
步骤 3:提交,具备幂等性。提交包含三次调用:创建文件意图(返回一个 file_id 和一个有效约 15 分钟的预签名上传 URL),PUT 原始字节,然后创建引用 file_id 的批处理,此外还需提供您选择的 request_id。该 request_id 是您的崩溃保险,我们在 2026-08-03 测量了其合同的两半。使用相同的 request_id 和 file_id 重新播放 create 调用会返回现有作业且不会产生重复,因此您的提交循环可以在崩溃后安全地重新运行。但如果使用相同的 request_id 并重新上传相同内容的全新副本进行重播,则会被拒绝:返回 409 错误,“request_id 已与不同的输入文件关联”。因此,请保留首次上传得到的 file_id,在重试时复用;不要重新上传。
对于 OpenAI 作业,您还需要在每行传递与 url 匹配的 endpoint(/v1/chat/completions 或 /v1/responses);而对于 Anthropic 作业,则必须省略它。
步骤 4:轮询并下载。作业会报告状态:validating → queued → in_progress → completed(或 failed / expired / cancelled),并附带每个作业的请求计数。结果最多保留 30 天。结果调用返回一个指向单个 output.jsonl 的预签名 URL;文档还定义了一个独立的错误文件(error_file_url,仅在生成错误文件时存在)。在我们生成的每一次失败中,包括所有 20 个请求均失败的探测,错误都会内联出现在每行输出中,且不会出现错误文件 URL(截至 2026-08-04 的测试)。请同时解析这两种形式:检查每行的 error 字段以及结果负载中的 error_file_url。
来自一次真实故障的韧性提示:在下载约 47 MB 的输出文件过程中,我们遇到了 HTTP/2 流重置(远程对等方重置了 Stream 1,2026-08-04)。请重试整个 GET 请求;每次调用结果端点时,预签名 URL 都会刷新。
步骤 5:合并并评估。使用 custom_id 将输出与输入连接,解析 JSON,然后与标签进行比较。完整的流水线见下方的复现工具包。
步骤 6:重新提交失败(您实际上会在生产中运行的循环) 收集错误行,构建余量 JSONL,在新的 request_id 下重新提交。我们构建了这条代码路径,随后我们的 250k 运行零失败请求,因此我们拥有该机制,但没有值得一提的失败故事。这就是“韧性”的诚实版本:机制之所以重要,正是因为你无法预测何时会需要它。
准确率:在 250,000 条记录上与数据集自身标签一致性达 83.6%
总体产品标签一致率为 83.62%(JSON 有效 99.99%)。按类别:
| CFPB 产品(样本比例) | 召回率 |
|---|---|
| 信用报告 / 个人消费者报告(70.2%) | 92.4% |
| 抵押贷款(3.0%) | 87.7% |
| 货币转账 / 虚拟货币(3.4%) | 74.1% |
| 支票或储蓄账户(5.2%) | 67.5% |
| 学生贷款(1.3%) | 64.6% |
| 催收(11.1%) | 59.9% |
| 信用卡(3.0%) | 57.5% |
| 车辆贷款或租赁(1.4%) | 46.2% |
| 预付卡(0.3%) | 38.2% |
| payday 贷款 / 车辆所有权贷款 / 个人贷款(1.0%) | 16.1% |
| 债务或信贷管理(0.2%) | 0.3% |
尾部具有启示性:模型遗漏的类别正是那些 CFPB 定义重叠的类别(比如,催收 payday 贷款问题究竟算是 payday 贷款投诉还是催收投诉?)。在 250k 规模下,你能看到分类法的接缝,而不仅仅是模型的问题。
我们的运行没有发票(免费账户),因此此部分是可审计的算术:使用 API 自身使用字段测得的 token 数量,乘以 DigitalOcean 公布的每 token 费率;批处理最高可享受无服务器价格的 50% 折扣。
半价是定义;比例而非我们的账单才是故事。这些是计算得到的数字,而非发票(测试账户免于计费)。缓存 token 按完整输入费率定价。价格采集于 2026 年 8 月;在做出决定前请再次核对。
| 运行 | 记录数 | 输入/输出 token | 批处理 @ 列表价 | 无服务器 @ 列表价 | 实际测试 |
|---|---|---|---|---|---|
| GPT-5 Nano, 精简提示 | 250,000 | 117.0M / 20.6M | $7.04 | $14.07 | 2026-08-03 |
| Claude Haiku 4.5, 精简 | 25,000 | 30.1M / 3.9M | $24.91 | $49.83 | 2026-08-11 |
| GPT-5 Nano, 肥提示 + 缓存 | 5,000 | 9.2M / 0.4M | $0.30* | $0.61 | 2026-08-11 |
* 保守地按照完整输入费率对缓存 token 进行定价。DigitalOcean 的定价页面发布了一个 无服务器 缓存读取费率(GPT-5 Nano 为 $0.005/1M,相当于输入费率的十分之一,数据截至 2026-08-11),这将使该费用进一步降低。但未发布批处理缓存费率,且批处理缓存命中是否按折扣率计费在我们的账户上无法验证;我们只能报告 API 返回了缓存命中计数。
每千条记录的费用为 $0.028(Nano)对比 $1.00(Haiku),按批处理列表价计算。处理 25 万条记录的分类任务花费七美元是头条新闻;而在无服务器价格下,相同工作负载的费用计算为十四美元,这体现了定价模型在发挥作用,而非我们的发现。
三个模型均在完全相同的记录上进行评分,均经过显著性检验:
增加一点资金帮助不大;增加提示反而让情况变差。准确率 = 与 CFPB 自身标签的一致程度。Mini 与 Nano 在 2,500 条记录的试点中配对;Haiku 与 Nano 在 25,000 条记录中配对;胖提示 vs 精简提示在 5,000 条记录中配对,使用相同模型。
| 比较(配对,麦克尼玛) | 准确率 | Δ(百分点) | p | 计算得到的成本比率 |
|---|---|---|---|---|
| GPT-5 Mini vs Nano (n=2,500) | 81.2% vs 80.8% | +0.4 个百分点 | 0.58 (不显著) | 5倍 |
| Claude Haiku 4.5 vs Nano (n=25,000) | 84.9% vs 83.6% | +1.26 个百分点 | <0.0001 | 约 35倍 |
| Fat prompt vs lean, same model (n=5,000) | 80.8% vs 82.9% | −2.06 个百分点 | <0.0001 | 约 2倍 |
请再读两次第三行:我们把完整的产品/问题分类法塞进提示里(2,400 个 token 而非 460),期望准确率上升。结果却显著下降,且在任何缓存折扣之前每条记录的成本翻倍。此外,该分类法的实际目的——问题级标签——在与 CFPB 的 110+ 个重叠问题类别比较时,仅达到了 20.2% 的一致度。更多的提示并不带来更高的准确率;它只是更多的 token,直至有相反的证据。
为了作对比,我们还在相同的提示和记录上运行了一个 2,000 条记录的无服务器对照组(2026-08-03):单请求延迟 p50 2.31 秒 / p95 3.40 秒,答案逐条流式返回,而批量则是把 250k 条记录放入队列,90 分钟后收集结果。批量牺牲交互性以换取吞吐量;如果下游没有任何任务需要在秒级内得到答案,那么您其实根本用不到这种交互性。
在以下情况下使用批量:
在以下情况下保持使用无服务器:
两者不会争夺容量:DigitalOcean 文档说明批处理作业在隔离的低优先级容量上运行;它们不会占用您的实时配额,也不会使生产环境的 p99 延迟增加超过 5%(这是一项有文档保证的声明,我们未进行测试)。使用同一个密钥同时运行两者只是一种配置选择,而不是架构变更。
您也可以参考我们的教程 无服务器 vs 专用 vs 批处理推理 以获得更详细的对比。
1. 单一 API 上的三种模型命名约定 (测试时间为 2026-08-11)。无服务器需要使用 DigitalOcean 目录 ID(openai-gpt-5-nano、anthropic-claude-haiku-4.5)。OpenAI 批处理需要使用原生名称(gpt-5-nano);目录 ID 无法通过验证。Anthropic 批处理需要使用 Anthropic 的带日期快照 ID(claude-haiku-4-5-20251001);目录 ID 和未日期别名均会被拒绝,提示 “在 DigitalOcean 上不可用”。DigitalOcean 官方的操作示例使用了未日期别名(claude-3-5-sonnet-latest),但我们的测试将其拒绝;因此当文档与验证错误相冲突时,应相信错误。错误的 ID 会导致即时且免费的验证失败,并且会指出模型名称。虽然令人烦恼,但至少错误信息很明确。
2. 您的层级限制不等于文档中的限制。 在我们的账户中,每文件限制为 40k 请求,而文档记载为 50k(2026-08-03)。Anthropic 方面的文档限制(根据发布公告为每文件 100k 请求)我们未进行测试;我们运行过的最大 Anthropic 作业为 25k 请求。
3. 推理模型不再接受经典的 body 参数。 我们的首次探测向 GPT-5 Nano 发送了 temperature + max_tokens;所有 20 条请求逐行失败(2026-08-03)。请使用 max_completion_tokens 和 reasoning_effort,并预留输出余量:即使可见答案仅为一个 JSON 对象,推理 token 仍会计为输出并计费。
4. 两种失败模式均无提示。 重复的 custom_id 和混合模型文件均能通过前置验证,正常进入队列,随后在没有任何错误信息的情况下失败(2026-08-11)。单模型每任务的规则已有文档说明;未文档化的是,违反该规则会在排队后静默失败,而不是在验证阶段直接报错。我们在验证中尝试的其他情况(格式错误的 JSON、缺少 custom_id、错误的端点 URL、错误的提供方 schema、空文件)均会快速失败并给出清晰可引用的错误信息。建议在本地使用 lint 检查唯一性和每文件单模型;API 本身不会提示这一点。
5. 取消是尽力而为的,适用于两个方向 (2026-08-11)。尚未转交给提供方的任务无法取消(返回 409:“批量作业尚未提交给提供方”)。文档将此 409 描述为暂时性错误(等待作业离开验证状态后重试),但我们在一个已在队列中停留八天的任务上遇到了它,此时等待毫无帮助(参见后续教训)。此外,正在运行的任务可能会抢在你的取消之前完成:我们的 500 请求探测在取消指令到达时已完成 99%(处于 “cancelling” 状态及全部)。它完成了运行,交付了结果,在正常账户下会被计为已完成并计费。我们从未捕获到大型任务在半途被取消的情况,因而将“取消 40k 任务的一半”视为未经测试的操作。请不要将成本控制依赖于取消操作。
6. 队列行为随提供方和周而异。 我们在 2026-08-03 提交的一个 Anthropic 任务在 “queued” 状态中停留了八天,从未被转交给提供方,不可取消,其自身的过期时间戳早已过去却未被强制执行。当我们在 2026-08-11 重新测试时,相同的文件内容经过严格验证并在几秒内被转交,随后 25,000 个请求在 17 分钟内完成。行为在我们两次测试日期之间发生了变化;我们不知道 DigitalOcean 那边发生了什么变化,也不清楚原因。这两方面都是教训:请根据 24 小时 SLA 进行规划,而非仅依赖典型情况,并为自己的平台备注添加日期戳。
7. 缓存有三个细则。 (a) 每个模型的最小可缓存前缀不同:GPT-5 Nano 为 1,024 个 token,Claude Haiku 4.5 为 4,096 个 token,是大多数团队假设值的四倍。我们的 460-token 生产提示在 250k 次请求中未缓存任何 token,因此主运行完全未获得缓存帮助。 (b) 在符合缓存条件的 OpenAI 运行中(前缀 2,400 token,5,000 次请求),55.6% 的输入 token 被标记为缓存命中,而仅 20 次请求的小规模探测达到 81%。这种差异与在许多并行工作器上扇出批量请求、各自预热自身缓存一致(机制未确认;我们看不到调度器)。请基于规模化数字而非玩具探测来估算节省。 © 在最小阈值以下,不会有任何内容被缓存,也不会收到任何警告。我们最初的 Anthropic 探测使用了 1.3k 到 3.6k token 的前缀,记录到零缓存活动,我们曾短暂误解为 DigitalOcean 不提供缓存。在超过最小阈值的重新测试中(前缀 5,975 token,日期 2026-08-13),两种模式下均干净地进行了缓存:无服务器在第一次调用时写入缓存,并在第二次调用时读回全部 5,975 token;而一个包含 10 个请求的批处理作业从缓存中提供了其输入 token 的 70%。在得出缓存失效的结论之前,请先查看您所使用模型的文档化阈值。
8. 输出模式属于提供方,而非 DigitalOcean。 将 OpenAI 批处理行解析为 OpenAI 批处理输出(response.body.choices[...]),将 Anthropic 行解析为 Message Batches 输出(result.message.content[...],包含工具使用块)。即使您的作业代码不是按提供方区分的,合并代码也需要按提供方实现。额外提示:Anthropic 的使用块会报告 service_tier: "batch",这是一个很好的 sanity check,可确认您获得了所期望的折扣层级。
DigitalOcean 列所示的数据为我们在注明处的实际测量值;竞争对手的数据来源于各厂商截至 2026 年 8 月的公开文档和定价。如果您根据此表选择平台,请先查看各厂商的最新文档,因为价格和限制可能会变动。
| DigitalOcean 批处理 | OpenAI 批处理 | Anthropic 批处理 | Bedrock 批处理 | |
|---|---|---|---|---|
| 折扣(相对实时价格) | 最高 50% | 50% | 50%(含缓存 + 思考 token) | 按需价格折扣 50% |
| 每 API 提供商 | OpenAI + Anthropic(实际测量) | OpenAI | Anthropic | 多供应商,按地区 |
| 每个作业限制 | 文档规定 50k / 200 MB;实际层级限制为 40k(测量) | 50k / 200 MB | 100k / 256 MB | 50k / 200 MB,模型特定最低限 |
| 完成窗口 | 24 小时;我们的作业运行时间为 3 分钟至 2.2 小时 | 24 小时,大多数在 1 至 6 小时 | 24 小时,大多数小于 1 小时 | 24 小时 |
| 存储设置 | 无(使用预签名 URL) | Files API | 无 | S3 + IAM 角色 |
| 幂等提交 | request_id,两半均已验证(测量) | 无一等效功能 | 无一等效功能 | 客户端令牌 |
| 批处理中的缓存 | OpenAI + Anthropic 命中通过 DigitalOcean 上报(超过各模型最小前缀,测量);计费费率未验证 | 历史上不叠加;请核实当前文档 | 是的,会叠加;尽力命中 | 没有批处理缓存方案 |
| 预先验证 | 能捕获大多数错误(测量);重复 custom_id + 混合模型随后静默失败(测量) | 预先拒绝重复 custom_id | 按请求返回成功/错误结果 | S3 端验证 |
| 部分完成时的计费 | 仅计费已完成的请求(文档所述) | 请核实 | 请核实 | 请核实 |
| 其优势所在 | 一个 API/密钥/账单服务两家提供商;无需存储设置 | 端点覆盖广(嵌入、图像、审核);成熟 | 单批限制最高;典型周转最快;缓存确定性 | 数据永不离开您的 AWS 账户;IAM/治理 |
DigitalOcean 的区别在于运营而非财务。所有人都提供约 50% 的折扣。只有 DigitalOcean 让 OpenAI 和 Anthropic 的作业共享同一个端点、密钥、作业 API 和账单。
根据测量的数值,一切都呈线性增长,因此外推非常短(全部按列表费率计算):
| 记录 | Tokens(我们的配置文件) | 文件(40k 层级限制) | 计算的批处理成本(GPT-5 Nano) |
|---|---|---|---|
| 250k(已测量) | 137M | 7 | $7.04 |
| 1M | ~550M | 25 | ~$28 |
| 10M | ~5.5B | 250 | ~$282 |
在费用出现之前就会出现两个限制。首先,排队 token 限制(每模型每账户 100 亿 token)在我们的 token 配置下大约在 1800 万条记录时变得具有约束力;超过这一点,您将在排队中排空并重新填充。其次,文件数量:当文件数达到 25+ 时,您需要使用演练中的清单 + 幂等提交循环,因为某些操作可能需要重试。我们的七个并发作业(五个 40k 和两个 25k)全部在 2.2 小时内完成;250 个文件是否表现相同尚未测试;我们预计瓶颈将是 token 配额而非并发度,但这只是一种预期,而非实际测量。
先决条件:OpenAI 和 Anthropic 的商业模型需要 Tier 3+ DigitalOcean 账户。如果批处理路由返回 403,请在调试其他内容之前先检查您在 资源限制页面 中的层级。
最小循环,无需框架:
import json, time, requests
BASE = "https://inference.do-ai.run/v1"
H = {"Authorization": f"Bearer {KEY}"} # your DO model access key
# 1. file intent -> presigned URL (valid ~15 min)
intent = requests.post(f"{BASE}/batches/files",
headers=H, json={"file_name": "job.jsonl"}).json()
# 2. upload raw bytes
with open("job.jsonl", "rb") as file:
upload = requests.put(intent["upload_url"], data=file)
upload.raise_for_status()
# 3. create the batch (request_id = safe retries; keep file_id if you must retry)
batch = requests.post(f"{BASE}/batches", headers=H, json={
"file_id": intent["file_id"],
"provider": "openai", # or "anthropic"
"endpoint": "/v1/chat/completions", # REQUIRED for openai, OMIT for anthropic
"completion_window": "24h",
"request_id": "my-job-001",
}).json()
# 4. poll
while True:
b = requests.get(f"{BASE}/batches/{batch['batch_id']}", headers=H).json()
if b["status"] in ("completed", "failed", "expired", "cancelled"):
break
time.sleep(60)
# 5. download (retry the GET whole if the stream resets; the URL refreshes each call)
res = requests.get(f"{BASE}/batches/{batch['batch_id']}/results", headers=H).json()
out = requests.get(res["output_file_url"]).text
for line in out.splitlines():
r = json.loads(line) # per-line "error" field on failures (also check
# res.get("error_file_url"): documented, not seen in our runs)
DigitalOcean 将批处理定价为比无服务器列表价低至 50%。在我们的 250,000 条记录运行中,该定价计算得出批处理为 $7.04,无服务器为 $14.07,对应相同的测量 token。
在 2026 年 8 月的测试中:40,000 请求的作业耗时 1.4 至 2.2 小时;25,000 条 Anthropic 请求耗时 17 分钟;500 请求的作业耗时约 3 分钟。SLA 为 24 小时,因此请据此进行架构设计。
同一提供商:不需要。您的请求正文保持不变;您只需将其包装在该提供商的批处理 JSONL 行格式中,并调整模型 ID 约定。不同提供商:您也需要采用其行格式和结构化输出机制。作业/提交/轮询/结果 API 对两个提供商是相同的。
在我们的运行中,错误会按请求内联返回到输出文件;文档还定义了一个单独的错误文件(error_file_url),在生成时使用,因此需要同时处理两者。失败的请求不会导致作业失败,且 DigitalOcean 仅对已完成的请求计费。将错误行收集到一个余量文件中,并在新的 request_id 下重新提交。(我们的 250k 运行中没有失败,以此演示。)
在 2026 年 8 月的测试中:是的,对于两家提供商,只要共享前缀达到模型文档规定的最小值(GPT-5 Nano 为 1,024 个 token,Claude Haiku 4.5 为 4,096 个 token)。OpenAI 批处理报告在我们符合缓存条件的运行中,55.6% 的输入 token 作为缓存命中;Anthropic 的 cache_control 在我们超过 Haiku 4.5 的 4,096‑token 最小值后,在批处理和无服务器环境中干净地完成了缓存。低于此最小值时,它会静默地不缓存任何内容。我们无法在账户上验证缓存 token 的计费费率。
在 2026 年 8 月的测试中,仅限 OpenAI 和 Anthropic 的商业文本模型:不包括开源模型或 DigitalOcean 托管的模型,不包括多模态模型,每个任务只能使用一个模型。请注意账户前提条件:Tier 1 和 Tier 2 账户无法访问 Anthropic 或 OpenAI 的商业模型(开放权重的 gpt-oss 模型是文档中规定的例外),因此使用这些提供商进行批处理实际上需要 Tier 3+。请留意三种命名约定(课程 #1)。
批量推理是一种几乎零成本采用的罕见优化:如果您的工作负载不需要秒级响应,您已经发送的相同请求体将变成一个 JSONL 文件、三次调用提交和一个轮询循环,费用仅为列表价的一半。我们的 250,000 条记录运行未出现任何失败请求,速度快于预算,计算成本为 7.04 美元。
阅读标题以外内容的原因在于我们遇到的细则:三种模型命名约定、低于文档所述的层级限制、两种静默失败模式、尽力而为的取消、一个在队列中等待时间远超预期的任务,以及仅在超过我们生产提示未达到的阈值时才有帮助的缓存。这些都不会导致 disqualification;它们正是演示与您会反复运行的管道之间的区别。
对二十五万个答案进行评分的元经验是:廉价模型表现尚可,昂贵模型在价格高出35倍的情况下仅有可测量的提升,而所谓“更聪明”的提示反而让效果变差。以批次价格计算,在自己的工作负载上运行该实验只需个位数美元,且我们的完整工具包已开源。在相信任何人的数字之前(包括我们自己的),请先自行运行一次。
在看数字之前的概念框架方面,DigitalOcean 的 推理模式对比指南 高层次地介绍了无服务器、专用、批量以及推理路由器。批量推理使用指南 和 API 参考 完整记录了作业的全生命周期;推理限制页面 给出了当前每文件、每 token 和每层级的限制;而 定价页面 提供了当前每 token 的费率。发布公告 阐述了产品定位。如果您在批量推理与自行运行 GPU 之间权衡,我们之前的教程 无服务器 vs. 专用 vs. 自托管 LLM 推理 从头到尾测量了这种权衡。竞争对手的一手资料包括:OpenAI Batch 指南、Anthropic Message Batches 以及 Bedrock 定价。此实验的配套视频演示即将推出,敬请期待链接。
完整的复现工具包(包括 harness、聚合数据和探测笔记)已在 github.com/bnarasimha21/technical-deep-dives 的 batch-inference/ 目录中开源,以便您在自己的账户上重新运行整个流程:
export DIGITALOCEAN_INFERENCE_KEY=""
python prepare_jsonl.py --profile
python prepare_jsonl.py --sample 250000
python prepare_jsonl.py --emit --sample-file sample_250000.csv \
--provider openai --model gpt-5-nano --prompt lean --tag main
python submit.py --tag main && python poll.py --tag main
python download_results.py --tag main
python merge_results.py --tag main --sample-file sample_250000.csv --provider openai
python evaluate.py --tag main
python costmodel.py --tag main --model gpt-5-nano
本文中的价格、限制和平台行为数据是在 2026 年 7 月 31 日至 8 月 13 日期间获取的。如果您是在很久以后阅读本文,请相信该方法,并重新核对数字。
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。