第 3 章 性能与成本优化
学习目标
- 将一次请求的延迟分解为各个区间,选择预期改善效果最大的环节。
- 正确处理流式传输事件,区分流式输出能够减少什么,以及不能减少什么。
- 编排提示词,使缓存命中率提高,并计算使用缓存的盈亏平衡点。
- 选择适合使用批处理API及相应处理档位的任务,并安全地取回处理结果。
- 设计按模型档位进行路由的规则和升级条件,以每项任务的成本为依据,判断延迟与成本之间的权衡。
引言
某个团队收到“响应太慢”的投诉后,换用了价格最高的模型。结果响应变得更慢,账单金额也变成了原来的三倍。另一个团队为了节省费用,把提示词缩短了一半,质量却下降了,延迟也几乎没有变化。两个团队有一个共同点:都在测量之前就进行了修改。延迟和成本是多个区间、多个项目相加的结果,其中哪一项占得最多,只有实际测量之后才能知道。
本章从测量开始。我们先学习如何把延迟分解为各个区间,以及OpenAI归纳的缩短延迟原则,然后依次学习:降低用户体感延迟的流式输出,复用重复输入的提示词缓存,以较低费用处理不紧急任务的批处理API和处理档位,以及为每次请求选择适当模型的路由。最后,用每项任务成本这一统一尺度来比较这些方法。
核心概念
将延迟分段
用户的等待时间由多个区间相加而成:应用队列、输入预处理、模型处理、工具执行、后处理、网络传输依次衔接。模型处理也分为读取全部输入与逐个生成输出token两部分。因此,测量指标也分为三种。
| 指标 | 含义 | 主要影响因素 |
|---|---|---|
| 首个token耗时(TTFT) | 从请求到首个输出片段到达 | 队列、输入长度、思考时间、缓存命中 |
| 输出速度 | 每秒生成token数 | 模型档位、处理档位 |
| 完整响应时间 | 到最后一个token为止 | 输出长度×速度、工具往返次数 |
还要从用户角度看“首个可用结果”何时出现。即使首片段很快到达,若必须等结构化结果完整后才能绘制界面,体感延迟仍接近完整响应时间。投诉往往来自尾部,因此应看p95(最慢5%的分界值),而非平均值。
降低延迟的七项原则
OpenAI的延迟优化指南提出了七项原则。这些原则是对通用方法的归纳,无论采用哪一家供应商,都适用。
| 原则 | 要点 |
|---|---|
| 更快地处理token | 较小的模型通常速度更快,价格也更低 |
| 减少输出token | 输出量减少50%,延迟也会减少接近50% |
| 减少输入token | 即使提示词缩短50%,延迟改善也只有约1~5%。除非上下文非常长,否则效果较小 |
| 减少请求次数 | 将原本按顺序执行的步骤合并到一个提示词中,以减少请求往返 |
| 并行处理 | 彼此不使用对方结果的步骤,同时发起调用 |
| 让用户少等待 | 流式输出最为有效。显示当前处理进度也有帮助 |
| 不要默认使用LLM | 能够提前计算,或用预先确定的界面解决的任务,不调用模型也可以处理 |
关键在于,输出是影响延迟最大的因素。重复用户问题的开场白、冗长的结束语,以及不必要的全文重写,都会让延迟与成本一起增加。
流式输出如何工作
流式输出以服务器发送事件(SSE)逐步接收响应。就像收到快递发货通知并不改变到达时间一样,流式输出只是更早展示首批内容,并不减少需要生成的token数量或费用。
Anthropic流按固定顺序发送事件:message_start → 每个区块的content_block_start、content_block_delta(多次)、content_block_stop → message_delta → message_stop,其中可能穿插ping。处理时注意以下事项。
stop_reason在message_start中为null,在message_delta中确定。message_delta中的usage为累计值,每次事件相加会造成重复统计。- 即使已收到HTTP 200,仍可能出现
error事件(如overloaded_error)。仅按状态码处理错误会漏掉这些情况。 - 无须亲自处理事件时,可用SDK累积辅助方法(Python
get_final_message()、TypeScriptfinalMessage())获取完整消息。
OpenAI Responses API发送response.created、response.output_text.delta、response.completed、error等语义事件;Gemini通过SDK流选项或REST的alt=sse启用流式输出。
设计完整流式链路
即使在API中开启了流式输出,用户也可能仍然面对空白界面。这是因为,如果中间层收集响应后才一次性传给下游,流式传输的效果就会消失。因此,需要检查整条传输链路。
- 在SSE路径上,关闭反向代理与API网关的响应缓冲。某些压缩设置也可能先聚集片段再发送。
- 服务器应将收到的片段立即向下游传递,但界面更新可以按适当单位(句子、100ms)合并进行,以减轻浏览器的负担。
- 用户关闭窗口或取消操作时,使用HTTP客户端的取消信号(如
AbortController),同时中断上游请求。如果继续把无人查看的内容生成到最后,就只会产生费用。 - 对需要后处理的结果,判断能否逐片段处理。OpenAI文档警告,流式输出会让输出内容审核(moderation)变得更加困难。因此,应先确定相关内容是否必须在检查完整个响应之后才能公开。
- 对工具参数或JSON,可以将收到的片段依次拼接,但执行工具和保存数据,都必须等内容完整并通过校验之后再进行(第2章)。
提示词缓存原理
可以这样理解:每次开会时,不再把同一份资料从头读一遍,而是在已经读过的部分做上标记,只阅读新增加的页面。提示词缓存会保存对请求前面部分(prefix,前缀)的处理结果,在下一次请求时重新使用。因此,前缀只要有一个字符不同,从那个位置开始就无法再使用先前的处理结果。
提示词缓存并不是保存生成的输出,再把它返回的功能。响应仍然每次重新生成。OpenAI文档也明确说明,缓存不会改变输出token的生成方式。正是在这一点上,它与直接复用先前答案的响应缓存有着根本区别(见深入阅读)。提示词缓存有两方面效果:从缓存读取的输入按更低价格计费;同时,输入处理所需时间缩短,因此首个token能够更早返回。
各厂商缓存比较
| 项目 | Anthropic | OpenAI | Gemini |
|---|---|---|---|
| 启用方式 | 顶层cache_control(自动)或各区块cache_control(显式),最多4个断点 |
支持的模型默认启用 | Gemini 2.5及之后模型默认隐式缓存 |
| 最短长度 | 按模型为512~4,096token,不足时不报错但不缓存 | GPT-5.6及之后为1,024token | Gemini 4 Argon与3.x为4,096token,2.5为2,048token |
| 保留时间 | 默认5分钟,每次使用免费续期,可选1小时 | GPT-5.6及之后使用prompt_cache_options.ttl(默认30m,可选12h);更早模型使用prompt_cache_retention(in_memory、24h) |
供应商自动管理 |
| 价格 | 写入1.25倍(5分钟)或2倍(1小时),读取0.1倍(部分最新模型更低) | GPT-5.6及之后写入1.25倍,读取大多0.1倍(部分模型0.05倍) | Gemini 4 Argon缓存输入优惠95% |
| 确认字段 | cache_creation_input_tokens、cache_read_input_tokens、input_tokens(最后断点之后) |
usage.input_tokens_details.cached_tokens |
Interactions API为usage.total_cached_tokens,generateContent为usageMetadata.cachedContentTokenCount |
| 速率限制 | 大多数模型的缓存读取不计入每分钟输入token限额(ITPM) | 缓存输入也计入每分钟token限额(TPM) | — |
Anthropic使用缓存时,input_tokens只表示最后一个断点之后的token。总输入应将三项相加。
总输入token = cache_read_input_tokens + cache_creation_input_tokens + input_tokens
Gemini在Interactions API和Gemini 4 Argon及之后模型中仅支持隐式缓存。自行创建管理的显式缓存,只能在支持它的更早模型中,通过generateContent API使用。
编排提示词以提高缓存命中率
三家的共同原则只有一条:不变的放前面,变化的放后面。开头只放一行当前时间,就可能让之后数千token全都无法命中。
- 固定顺序。Anthropic按
tools→system→messages构成前缀。工具定义、固定指令、参考资料、示例放前面,时间、用户信息、问题放末尾。 - 断点放在固定部分末尾。在每次变化的区块设置断点,只会反复写入。
- 稳定序列化。工具列表顺序、JSON键顺序、空格若每次不同,即使内容相同也是不同前缀。从集合或哈希表生成工具列表,顺序可能波动。
- 掌握破坏缓存的变更。Anthropic修改工具定义会使全部缓存失效;修改
tool_choice或增删图片使消息部分缓存失效。修改顶层effort或output_config.format也会使缓存失效。 - 检查最短长度。前缀不足模型最低要求时,即使标记也会静默不缓存。
- 实测。比较部署前后缓存读取比例,并使用能指出连续请求前缀从何处分歧的工具,例如Anthropic缓存诊断功能。
OpenAI保持工具列表不变,仅用allowed_tools改变可调用范围,有利于保留缓存。prompt_cache_key在更早模型中只影响路由,GPT-5.6及之后主要用于按客户汇总缓存用量。GPT-5.6及之后模型默认在最近消息末尾设置断点,若末尾每次变化,应在固定部分末尾设置prompt_cache_breakpoint才会命中。Anthropic缓存不跨组织共享,Claude API还按工作区隔离。
缓存的盈亏平衡点
写入缓存比处理普通输入更贵,因此,必须有足够多的重复使用,才能获得收益。下面将处理前缀的成本设为1,按照Anthropic的计费倍数来计算。
| 请求次数(保留期内,相对费用:不缓存1次=1.00) | 不缓存 | 5分钟缓存 | 1小时缓存 |
|---|---|---|---|
| 1 | 1.00 | 1.25 | 2.00 |
| 2 | 2.00 | 1.35 | 2.10 |
| 3 | 3.00 | 1.45 | 2.20 |
| 10 | 10.00 | 2.15 | 2.90 |
以读取价格为0.1倍计算,5分钟缓存在保留时间内的第二次请求开始产生收益,1小时缓存则从第三次开始产生收益(读取价格倍数更低的模型,收益还会更大)。反过来,如果两次请求的间隔长于保留时间,每次都只发生缓存写入,那么5分钟缓存会比不使用缓存贵25%,1小时缓存会贵100%。这时,选择更长的保留时间或关闭缓存更合适。保留时间是从请求开始时计算的,因此,响应生成耗时越长,所剩的缓存可用时间也越短,计算时同样需要考虑这一点。此外,缓存还能提升吞吐量。Anthropic的大多数模型不会将缓存读取计入ITPM,因此,命中率高时,就能在相同限额下处理更多输入。
批处理API
不需要当天送达的包裹,可以用便宜的普通邮寄。批处理API将不需要即时响应的大量请求集中异步处理,并提供折扣。
| 项目 | OpenAI Batch API | Anthropic Message Batches API | Gemini Batch API |
|---|---|---|---|
| 折扣 | 50% | 50% | 标准价格的50% |
| 处理时间 | 24小时窗口 | 大多1小时内,24小时未完成则过期 | 目标24小时,超过48小时过期 |
| 规模 | 每批50,000条,输入文件200MB | 100,000条或256MB | 内联低于20MB,文件最大2GB |
| 结果保留 | 完成30天后删除输出文件 | 创建后29天 | 默认6周 |
| 结果配对 | custom_id |
custom_id |
自定义键 |
OpenAI与Anthropic明确说明,结果顺序可能与输入不同,必须按标识符配对。Gemini API参考文档说明按输入顺序返回,但为确保换供应商后同一代码仍有效,按键配对更安全。Anthropic异步校验请求,批次结束才知道格式错误,建议先用Messages API测试一条同格式请求。失败请求计费也不同:Anthropic不对错误、取消、过期请求收费;OpenAI批次过期时取消未完成请求,仅对已完成的收费。可与缓存结合,但Anthropic说明批次内缓存命中是尽力而为,建议公共上下文使用1小时缓存。Gemini批处理文档说明命中部分适用上下文缓存费率,实际单价应查各模型价格表。批处理限额独立于同步API管理。
选择处理档位
同一模型也可以选择不同请求处理档位。
| 档位 | 示例 | 特点 |
|---|---|---|
| 慢但便宜 | OpenAI Flex(service_tier: "flex") |
Batch API费率,响应较慢。容量不足时返回内容为Resource Unavailable的429(不收费)。文档示例将SDK超时从10分钟延至15分钟 |
| 快但昂贵 | OpenAI Fast mode(原名priority processing,service_tier: "fast") |
每token加价。流量骤增时,部分请求降为标准档位,响应显示service_tier: "default" |
| 优先容量 | Anthropic Priority Tier(service_tier),部分Opus模型的fast mode(speed: "fast") |
是否使用优先容量,通过响应usage.service_tier确认。fast mode有独立速率限制 |
档位选择取决于时间价值。评估运行或数据补全等晚几分钟也无妨的任务,走便宜档位;客户等待路径中,只有超出延迟目标的部分才走快速档位。使用快速档位时,记录响应中的实际处理档位,关注降级比例。
模型档位路由与升级
所有请求都交给最大模型,就像派大卡车跑附近的小差事。路由按请求特点分配模型,升级(escalation)则在小模型结果不达标时交由更高档模型重新处理。
| 方式 | 判断依据 | 注意事项 |
|---|---|---|
| 规则路由 | 业务类型、输入长度、客户等级 | 简单快速,但可能漏掉规则之外的请求 |
| 分类器路由 | 小模型分类难度、意图 | 分类本身的延迟及误分类成本 |
| 基于校验的升级 | 小模型结果未通过schema或业务校验,则交高档模型 | 按失败比例增加成本与延迟 |
不要把升级决定交给模型自报的置信分数,因为置信度并不总与正确性一致。应依据可验证信号(通过schema、包含必需事实、无禁止表述),各路径分别用评估集测量质量、延迟与成本。推理模型也可按同样方式路由推理强度。
判断延迟与成本的权衡
各方法的收益与代价不同。
| 方法 | 延迟 | 成本 | 代价 |
|---|---|---|---|
| 流式输出 | 减少体感延迟 | 不变 | 实现复杂度、审核时机 |
| 提示词缓存 | 缩短首个token耗时 | 重复输入优惠 | 提示词结构约束、写入加价 |
| 缩减输出 | 大幅降低 | 降低 | 重新设计响应格式 |
| 批处理、便宜档位 | 大幅增加 | 降低 | 失去即时性 |
| 快速档位 | 降低 | 增加 | 加价、降级管理 |
| 小模型路由 | 通常降低 | 降低 | 升级设计、逐路径评估 |
比较时所用的尺度,应是每项任务的成本,而不是单次调用的成本。
每项任务成本 = (全部调用成本 + 重试、升级成本 + 人工审核成本)÷ 通过质量标准的任务数
即使单次调用费用减半,重试和人工修改增加三倍,仍然亏。先确定响应期限与失败成本,再在约束内选择每项任务成本最低的组合。
深入阅读
响应缓存何时有风险
响应缓存会将之前生成的答案原样返回。如果相同的问题很多,这样几乎可以消除延迟和成本。即使问题的措辞略有不同,只要含义接近就返回相同答案的方式,称为语义缓存;它通过嵌入相似度查找以前的问题。这种方法很强大,风险也同样明确。
- 个性化与权限。 如果答案中混有特定用户的信息,就可能把这个答案发送给其他人。应在缓存键中加入组织、权限、语言及资料版本,或者不对个性化答案使用响应缓存。
- 时效性。 如果作为依据的文档发生变化,缓存中的答案就会成为错误答案。应把文档版本放入缓存键,并在文档修订时使相应条目失效。
- 相似度阈值。 阈值过低时,“可以退款的期限”和“可以换货的期限”这样相似但不同的问题,也会收到相同的答案。阈值应通过收集了错误命中案例的评估集来确定。
- 修改操作。 对于需要执行工具的请求,不使用响应缓存。
提示词缓存没有上述风险,因为它每次都会重新生成输出。这两种缓存并非相互竞争,而是位于不同层次。对于已确定信息的说明等答案固定的部分问题,可以使用响应缓存;对于其余对话,则普遍使用提示词缓存。
如何公平比较优化实验
有几种常见情况,会让人错误地理解优化效果。第一,把不同缓存状态混在一起测量。第一次请求时缓存为空,因此既慢又贵。缓存为空和缓存已填充的状态,应分别测量。第二,没有同时测量质量。减少输出或换用较小模型,虽然可以降低延迟和成本,却也可能降低质量。因此,必须固定使用同一评估集和通过标准。第三,忽略负载。并发请求数不同,延迟的分布也会不同,因此应以接近实际峰值的并发量测量p95。第四,一次进行多项变更。如果同时修改模型、提示词和缓存编排,就无法知道哪项修改产生了效果。应遵守每次只改一项、再测量一次的原则,并以每项任务成本和p95记录结果。
工作场景
水澜语言学院:14秒空白界面的真相
在线语言学校“水澜语言学院”为学员批改英文作文。从提交作文到结果出现,平均需要14秒,这段时间里界面始终空白。运营团队提出换用更高档的模型,但开发者卓主管先测量了各个区间的耗时。
| 区间 | 平均值 |
|---|---|
| 服务器队列与预处理 | 0.3秒 |
| 首个token耗时 | 1.7秒 |
| 输出生成(平均950token) | 11.2秒 |
| 传输至界面 | 0.8秒 |
API一侧其实早已开启流式输出。但是,企业内部API网关在开启响应缓冲的状态下转发SSE,导致浏览器在响应结束之前收不到任何内容。另外,延迟的大部分来自输出生成。模型会把整篇作文修改后重新写一遍,再在后面附上冗长的修改理由。
卓主管做了两项修改:在网关的SSE路径上关闭缓冲,并把响应格式改成“需要修改的句子、修改后的句子、一行理由”的列表。只有学员希望重写全文时,才另外发起请求。平均输出从950token减少到340token。第一条批改结果显示出来的时间缩短为2.1秒,全部完成需要5.6秒,费用减少了60%。按照评估集测得的批改准确率则保持不变。
也有被否决的方案。更高档的模型输出速度反而更慢。对于减少提示词中示例的方案,团队考虑到输入只有2,000token左右,预计几乎不会有效果,因此没有尝试。
原野流通:将评价回复分成三条路径
农产品网店“原野流通”每天为约9,000条商品评价生成回复草稿。由于全部评价都通过同步API和高档模型处理,成本不断增加。公司的政策是:普通评价在48小时内回复,1~2星的投诉评价则必须在30分钟内回复。
平台工程师魏经理根据回复时限,将处理路径分开。
- 投诉评价(约占11%)进入同步处理路径。先由小模型生成草稿,再由校验器检查必需元素(道歉、处理措施说明)和禁止元素(承诺补偿金额、断言未经确认的原因)。未通过检查时,升级至中档模型重新处理。第一周的升级比例为14%。
- 普通评价每天分两次提交给批处理API。将评价ID写入
custom_id来配对结果,只有过期或发生错误的条目才重新放入下一批。 - 将回复指南和语气示例(约3,000token)固定在提示词前面,把评价正文和商品信息放到末尾。
团队以每项任务的成本比较了各方案。把需要人工修改的草稿审核时间也计入之后,发现全部评价都用小模型处理的方案,虽然调用费用最低,但投诉评价的修改时间增加,导致每项任务成本反而更高。最终方案的每项任务成本是原来的31%。团队也考虑过响应缓存,即对相似评价直接复用以前的回复;但由于回复会根据订单详情和商品状态变化,最终没有采用。
易错点
- 流式输出能够降低成本。 它减少的只是用户感受到的延迟,需要生成的token数量与费用都保持不变。
- 提示词缩短一半,延迟也会减少一半。 延迟主要由输出长度决定。减少输入所带来的延迟改善通常较小。
- 延长缓存保留时间,就能提高命中率。 如果请求前缀每次都不同,无论保留多久,都不会命中。应先修正内容顺序与序列化方式。
- 只要加上
cache_control,就会使用缓存。 如果长度没有达到相应模型的最低要求,就不会缓存,而且不会报错。应通过使用量字段来确认。 - 批处理结果会按输入顺序,在几小时内返回。 OpenAI和Anthropic不保证结果顺序;无论哪家供应商,处理时间都只在承诺的范围内确定(如最长24小时)。应按标识符配对结果,并做好请求过期的准备。
- 缓存读取在所有供应商处都不计入速率限制。 Anthropic的大多数模型不把缓存读取计入ITPM,但OpenAI仍将已缓存的输入计入TPM。
- 先使用小模型,总是比较便宜。 必须把升级、重试及人工修改的成本也加在一起,按每项任务的成本作出判断。
要点速览
- 延迟分为TTFT、输出速度、完整时间,用p95测量。输出长度是最大变量。
- 流式输出用于减少体感延迟,需检查网关缓冲、取消传播、审核时机的完整链路。
- Anthropic流:
stop_reason在message_delta中确定,用量为累计值,200之后仍可能出现error事件。 - 缓存复用前缀。固定内容在前,变化内容在后,固定序列化,检查最短长度。
- Anthropic 5分钟缓存从第二次、1小时缓存从第三次使用开始划算(读取0.1倍)。间隔长于保留期则亏。
- 三家批处理均优惠50%。OpenAI、Anthropic不保证顺序,应按标识符配对并准备应对过期。
- 处理档位:便宜档位牺牲速度,快速档位付出加价与降级管理成本。
- 路由升级依据可验证信号,比较采用每项任务成本。
查阅官方文档
- OpenAI — Latency optimization:阅读七项延迟优化原则与案例。
- Anthropic — Streaming messages:阅读事件流程、累计用量、错误事件与恢复方法。
- Anthropic — Prompt caching:确认前缀顺序、保留期、价格倍数、最短长度、失效表。
- OpenAI — Prompt caching:阅读默认启用、保留政策、
prompt_cache_key、用量字段。 - Google — Gemini API context caching:确认隐式缓存条件与最少token数。
- OpenAI — Batch API、Anthropic — Batch processing、Google — Batch API:比较限额、过期、结果配对。
自测
3-1. 定义单次请求延迟测量应区分的三项指标,说明为什么看p95而非平均值。
3-2. 列出API启用流式输出后用户仍看到空白界面的两个原因,并写出应检查的流式链路项目。
3-3. 计算Anthropic 1小时缓存(写入2倍、读取0.1倍)在保留期内复用相同前缀多少次才划算,并与5分钟缓存(写入1.25倍)比较。
3-4. 说明提示词缓存与响应缓存分别复用什么,并解释对混有用户专属信息的答案使用响应缓存的风险与对策。
3-5. 列举模型档位路由中可替代模型自报置信分数的三种升级信号,解释升级比例对每项任务成本的影响。
3-6. 为响应期限分别为即时、4小时、三天的三项业务,制定选择处理路径(同步、处理档位、批处理)与模型档位的决策表,并说明依据。
实操练习
练习
延迟分段测量(45分钟)
- 为生产或练习中的一个功能加入分段计时器,分别测队列与预处理、首个token、输出完成、后处理、传输至界面。
- 同样20个输入分别关闭、开启流式输出运行,同时记录输出token数。
- 再制作一个通过改变响应格式缩减输出的版本,运行相同20个输入,同时记录是否达到质量标准。
完成标准: 用一张表展示三版本的TTFT、完整时间p95、平均输出token、质量通过率,并用数字说明效果最大的变更。
练习
缓存编排与盈亏平衡实验(45分钟)
- 用超过最短缓存长度的固定指南与简短问题构建提示词。
- A版将当前时间放开头,B版放末尾。两版都在固定部分末尾设置缓存断点(Anthropic
cache_control,OpenAI GPT-5.6及之后用prompt_cache_breakpoint)。 - 每版以1分钟间隔发送相同问题五次,记录缓存相关用量字段。
- 按所用供应商价格倍数计算两版输入成本,也计算请求间隔长于保留期时的费用。
完成标准: 用表格展示两版缓存读写token与费用,各用一句话解释差异原因及盈亏平衡请求次数。