跳到主要内容

批次层推理之问:当 50% 的折扣重塑你的架构时

· 阅读需 13 分钟
Tian Pan
Software Engineer

你账单中最便宜的推理费用,是那些你付了两次的钱。几乎所有主流模型提供商现在都提供批处理层(batch tier),价格大约只有同步推理的一半,代价是接受以小时而非毫秒计的完成窗口。大多数工程团队要么完全忽视这一选项,要么只是随手扔进一个深夜定时任务(cron),然后宣称省下了钱。这两种做法都白白浪费了 30%–50% 的推理总支出——并非因为折扣不够大,而是因为批处理并不是一种代金券。它是一个全新的产品层面,拥有自己的 SLA、重试语义和失败模式。那些仅将其视为计费优化的团队,最终要么使用率低下,要么上线了需要数周才能排查出来的细微回归问题。

技术核心不在于“我们是否应该使用批处理?”,而在于:你系统中的哪些动作在用户感知层面确实是同步的,哪些是工程团队为了开发体验方便而“误当成”同步的,以及哪些可以在下游消费者不预设结果实时性的前提下重新塑造为任务(jobs)。回答这个问题需要进行工作负载审计、从“请求型(request-shaped)”到“任务型(job-shaped)”契约的架构转变,以及根据用户预期而非开发便利性,对每个智能体动作进行延迟层级的诚实映射。

价格标签是最简单的部分

各大提供商给出的头条数据是真实且一致的。OpenAI 的 Batch API 为所有模型(GPT-5 系列、mini 和 nano 变体、o 系列推理模型以及 embeddings)提供统一的 50% 折扣,换取 24 小时的完成窗口。Anthropic 的 Message Batches API 同样在输入和输出 token 上提供 50% 的优惠,每批次可处理多达一万个查询,且均在 24 小时内完成。两家提供商都指出,大多数批处理任务实际上在 1 到 6 小时内就能完成,24 小时只是作为最坏情况的上限,而非预期时长。

将批处理折扣与 Prompt 缓存(prompt caching)叠加,省钱效果会成倍增长。如果一个工作负载已经受益于系统提示词 90% 的缓存命中率,那么在缓存折扣的基础上,已缓存的输入还将按批处理层级计费。对于大规模的数据增强流水线,相对于直接调用同款模型的同步接口,实际输入成本可能会降低一个数量级。这是大多数生产团队能用到的最大成本杠杆,且不需要更换模型,不会出现质量下降,也无需开发新功能——只需要一点耐心。

难点在于,这种“等待的意愿”不是团队的属性,而是工作负载的属性,而大多数团队还没学会区分二者。

没人做的负载审计

梳理一个典型智能体(Agent)产品的推理调用图,询问每一个 LLM 调用:如果结果晚到四小时会发生什么?大多数工程师会下意识地回答“用户在等着呢”——对于智能体的主循环来说,这确实没错。但一个成熟产品的调用图中,大部分路径其实并不是用户急需的:

  • 预计算摘要(Pre-computed summaries):用户打开应用时看到的每日或每周摘要,而不是在生成的瞬间就要读的。
  • 分类回填(Classification backfills):分类体系变更后的存量数据重标记、根据新政策对历史内容打分、对夜间到达的支持工单进行标注。
  • 评估评分运行(Eval scoring runs):根据质量标准对生产追踪(traces)打分的判别模型、针对候选提示词运行的回归测试套件、生成本周置信度阈值的离线校准任务。
  • 向量刷新(Embedding refreshes):模型升级后的知识库重新向量化、新摄入文档集的向量化、针对基准向量进行的定期漂移检查。
  • 内容审核队列(Content moderation queues):标记用户生成内容供审核,其 SLA 是“在人工介入之前”,而非“在用户看到自己的帖子之前”。
  • 回顾性增强(Retrospective enrichment):从历史自由文本记录中提取结构化字段、为已发布的图像生成替代文本(alt-text)、为下游分析归一化日志行。

在典型的智能体产品中,这些负载加起来占到了总推理支出的一大部分,令人惊讶的是,其中绝大多数最初都是作为同步调用实现的,因为开发该功能的程序员只是顺手使用了处处都在用的 SDK 模式。审计的目的不是为了寻找显而易见的深夜任务,而是寻找那些在代码中看起来是同步的、但实际上并没有人在另一端苦等结果的调用。

从“请求型”到“任务型”契约

一旦确定了负载,将其迁移到批处理层绝不仅仅是将 messages.create 换成 batches.create 那么简单。调用者与被调用者之间的契约形式发生了变化,一些在请求模式下可选的工程原则,在任务模式下变成了强制性的。

任务级幂等,而非调用级幂等。同步请求失败可以在线重试,调用者假设只会执行一次,因为响应要么到达,要么不达。而批处理任务可能部分完成、超时,或者在调用者崩溃重启时静默成功。每个任务都需要一个能在调用者重启后存活的幂等键,每次结果写入在重复交付下必须是安全的,每个消费者都要能从任务账本中重新推导状态而不重复计算。跳过这一步的团队,会发送重复的通知、产生双倍计费的增强运行,并在分析表中留下幽灵数据。

无需值班报警的延迟结果观测。你现有的告警系统几乎肯定会将“此调用耗时超过五秒”视为事故。但在批处理中,耗时六小时的任务是健康的。值班轮值需要新的仪表盘,以区分“批处理运行时间较长但在 SLA 内”、“批处理卡住且队列堆积”以及“批处理已完成但下游消费者未取走结果”。你需要用任务耗时分布、随时间变化的队列深度以及结果过期指标,来取代你习惯的单次请求延迟直方图。

匹配延迟层级的失败语义。同步调用只有两种结果:成功或错误。批处理任务至少有四种:已入队(queued)、进行中(in-progress)、完成但部分失败(completed-with-partial-failures)以及过期且未完成(expired-without-completion)。最容易被忽视的是“完成但部分失败”——一个包含一万个查询的批次可能返回 9500 个成功响应和 500 个错误,消费者需要确定性的策略来决定如何处理、重试或丢弃那部分失败的数据。Anthropic 和 OpenAI 的批处理端点都会在结果文件中显示单个请求的错误;工程量在于消费者如何处理这些错误的策略。

与请求路径分离的任务编排。像 Temporal、Airflow 甚至持久化的 Kubernetes Jobs 等工作流引擎,将从“锦上添花”变成核心基础设施,因为批处理任务的生命周期现在是以小时计算的,并且需要跨进程重启。将批处理的“提交并轮询”循环嵌入到请求处理器中是一种反模式(anti-pattern),这会让下一个共享该 worker 的用户面临从 50% 折扣变成 200% 延迟回归的风险。

没人预料到的新鲜度回归

批处理迁移中最昂贵的错误不是成本错误,而是伪装成性能优化的正确性错误。一个团队将单个工作流——比如内容推荐评分任务——从同步迁移到批处理,以六小时为一个周期运行,并记录下节省的成本。三周后,下游消费者注意到推荐质量微妙地变差了。两周后,有人发现这种退化与迁移有关。到那时,团队已经在新的批处理输出之上发布了另外四个功能,回滚已经不再是简单的单行代码撤销。

这种失败模式是结构性的:上游管道将其新鲜度契约从“此结果反映了数秒前的世界”更改为“此结果反映了长达六小时前的世界”,但从未告知下游消费者。消费这些评分的推荐模型隐式地假设了不再成立的近时性。对比今天和昨天评分的仪表盘突然开始对比两个重叠的时间戳。向用户展示“最近评分”内容的前端体验,在无声无息中开始展示午饭前评分的内容。

防止这种情况发生的准则是,在每个工作流边界建立明确的新鲜度契约(freshness contracts)。批处理作业生成的每个结果都应带有 produced_at(生成时间)和 effective_until(有效期至)时间戳。每个读取批处理结果的消费者都应声明其能忍受的最大陈旧度,理想情况下,这应通过读取时的检查来强制执行。当新鲜度契约发生变化时——从同步迁移到批处理正是这样的变化——消费者的声明容忍度必须作为迁移的一部分进行重新审视,而不是在六周后的事后复盘中才被发现。这种工作在迁移过程中感觉像是额外负担,但在回归发生后,它看起来就是理所应当要做的事情。

成本层级决策矩阵

一旦完成了审计和契约工作,出现的运作模式将是一个决策矩阵,而非二元选择。每个智能体(agent)动作根据用户感知的紧迫性被分配到三个层级之一:

  • 同步(Synchronous)。 用户正在实时等待。延迟预算在亚秒级到几秒钟之间。支付全额价格。例如:智能体对用户当前消息的回复,用户正在注视的内联工具调用。
  • 近实时(Near-real-time)。 用户期望在几分钟而非几秒钟内获得结果,系统可以展示阶段性进度。延迟预算在一到十五分钟之间。支付全额价格,但针对吞吐量而非尾部延迟(tail latency)进行优化。例如:返回多步骤报告的研究智能体,或者用户启动后会稍后回来查看的分析管道。
  • 批处理(Batch)。 用户根本不在等待,或者结果会进入一个按自身节奏运行的过程。延迟预算以小时计。支付批处理层级的价格。例如:夜间数据富集、嵌入(embedding)刷新、评估打分、回顾性标签,以及任何数据回填工作。

决策规则是“用户感知的紧迫性”而非“开发便利性”,因为便利性维度默认会将所有内容都设为同步。编写功能的工程师会选择最简单的 SDK 模式,结果在他们的开发循环中感觉很快,而代码审查中没有任何信息能体现出用户实际上在两个小时内都不会去看那个输出。在设计文档中强制明确层级选择——即使只是功能规范中的一个字段——也能尽早提出问题,从而围绕答案进行架构设计。

该矩阵还澄清了一类无法明确归类功能:用户发起但没有硬性延迟要求的负载,比如“总结我上个季度的笔记”。对于这些功能,正确的答案通常是混合模式——提交到批处理层级,并在结果就绪时通过回调或通知告知用户。产品界面必须设计为支持这种模式。“我们会在准备好时发邮件通知你”对于一类目前被实现为同步调用的功能来说,是一个非常好的用户体验,只是团队之前没有问过这个问题。

批处理是产品形态,而非折扣

整合上述所有内容的认识是:批处理层级不是一个计费项。它是模型提供商构建的一种不同的产品形态(product surface),因为底层计算具有不同的特征——可以机会性地利用闲置 GPU 容量填充,而不干扰对延迟敏感的同步队列。50% 的价格反映了这一经济现实,而非市场促销。随折扣而来的 SLA、重试语义和失败模式不是产品中的 bug,而是底层基础设施所能承诺的真实信号。

将批处理视为一种产品形态意味着要对其进行有意的设计——包括作业编排、新鲜度契约、长期运行任务的可观测性以及层级感知的决策矩阵——而不是将其强行塞入一个完全围绕同步调用设计的系统中。工程投入是实实在在的,每个主要工作负载大约需要几个人周的时间来进行审计、构建编排并干净地迁移消费者。其回报是,在那些从一开始就应该是批处理的工作负载上,推理支出减少了 30-50%,此外还有一个附带好处:同步层级变得更快、更可靠,因为队列不再与那些本不需要在那里的任务竞争。

在未来一年内领悟到这一点的团队,将在他们交付的每一个长期运行、高产量的 LLM 工作负载上拥有结构性的成本优势。而那些没有领悟到的团队,将继续在用户从未等待的任务上支付同步溢价,并在下一次预算审查时发现,他们认为的模型选择问题,其实一直都是层级选择问题。

References:Let's stay in touch and Follow me for more thoughts and updates