成本(cost)与延迟(latency):钱和时间究竟花在哪里。
生产环境中的智能体(agent)问题,最终几乎都会归结为"太贵了"或"太慢了"。两者的根本原因相同——对成本和延迟在代理循环(agent loop)中究竟发生在哪里存在误解——解决路径也相同:先建立准确的心智模型,再针对性地应用技术。本章将向你展示真实智能体一次转轮(turn)的成本拆解(答案与大多数人的猜测不同),然后讲解三种最高杠杆优化手段——提示词缓存(prompt caching)、模型级联(model cascade)和并行/流式(parallel/streaming)模式——并教你如何衡量每种手段的效果。读完之后,你将清楚地知道面对具体问题该拨动哪根杠杆,以及能期待多大的收益。
钱和时间究竟花在哪里。
优化之前,你必须知道账单从哪里来。大多数工程师的直觉是——输出令牌(token)主导成本,工具执行主导延迟——这是错的。带着这个错误认知去优化,只会把精力花在错误的地方。
真实智能体一次转轮的构成
举一个具体的例子:一个回答问题的研究智能体。四次模型调用,三次工具调用,最终给出答案。钱是这样花出去的:
Turn 1: User asks "How do I tune Postgres autovacuum for write-heavy workloads?"
──────────────────────────────────────────────────────────────────────
Step Type Input tokens Output tokens Cost (Sonnet 4.5) Latency
──────────────────────────────────────────────────────────────────────
1 model call 3,200 120 $0.011 1.8s
(decides to search)
2 tool — — $0.00 0.4s
(search_docs)
3 model call 4,800 80 $0.015 2.1s
(decides to fetch one)
4 tool — — $0.00 0.6s
(fetch_doc)
5 model call 7,200 90 $0.022 2.6s
(decides to search again)
6 tool — — $0.00 0.5s
(search_docs)
7 model call 9,400 640 $0.038 4.1s
(synthesis: final answer)
──────────────────────────────────────────────────────────────────────
TOTAL 24,600 930 $0.086 12.1s
──────────────────────────────────────────────────────────────────────
仔细看这张表,有三点很突出:
输入令牌占主导。 输入 24,600 vs 输出 930,比例高达 26:1。以 Sonnet 定价 $3 / $15(每百万令牌,输入/输出比 5:1)来算,输入令牌仍占账单的 84%($0.074 / $0.086)。大多数成本优化应该瞄准输入,而不是输出。"输出令牌贵 5 倍"的说法在单令牌层面是对的,但在智能体循环中,输出令牌的数量是输入的 1/20,所以输入才是总账单的决定因素。
输入令牌随每次转轮递增。 第一次模型调用用了 3,200 个输入令牌;到综合步骤时已涨到 9,400——将近 3 倍。为什么?因为每次转轮都会携带完整的对话历史,包括所有此前的工具结果。每条工具结果一旦加入上下文窗口(context window),就会在此后每次模型调用时产生输入费用。上下文(context)在它存在的每次转轮都要付费,而不是只付一次。
工具执行很快;模型调用很慢。 模型调用占 12.1s 总时长中的 10.6s(88%);工具占 1.5s。如果想让智能体更快,优化模型调用(或并行执行模型调用)才是杠杆;优化工具是四舍五入的误差。
成本公式,一行搞定
对任意一次智能体转轮,成本(cost)近似为:
cost ≈ Σ (input_tokens_at_step_i × input_price)
+ Σ (output_tokens_at_step_i × output_price)
The dominant term is almost always the first sum — and the steps
near the end of the loop dominate it because they carry the most
context forward.
能移动这个公式的四根杠杆,按对典型智能体的效果排序:
- 提示词缓存(prompt caching),作用于稳定的前缀(系统提示词、工具定义、持久检索的文档)。缓存命中的输入令牌享 90% 折扣。见 STEP 2。
- 模型级联(model cascade):对 Sonnet 大材小用的路由步骤改用 Haiku。见 STEP 3。
- 上下文预算管控(context budget discipline):防止跨转轮积累的上下文膨胀(总结历史、丢弃过时的工具结果)。
- 输出预算管控(output budget discipline):合理设置
max_tokens上限;结构化输出通常比自由文本更短。
对于延迟,杠杆有所不同:
- 流式输出(streaming):在模型完成之前就开始展示输出。不减少总延迟,但能大幅改善感知延迟(perceived latency)。见 STEP 4。
- 并行工具调用(parallel tool calls):当模型在一次转轮中触发多个独立工具时,并发执行它们。见 STEP 4。
- 模型级联:与成本杠杆相同——更小的模型也更快。见 STEP 3。
- 提示词缓存:缓存命中时也能降低延迟(模型无需重新处理已缓存的令牌)。见 STEP 2。
注意,提示词缓存和模型级联同时出现在两份列表中。它们是两种最高杠杆的技术——任意一种都能可靠地同时改善成本和延迟。本章其余部分将深入讲解这两种技术。
优化前应该度量什么
在应用任何技术之前,先为每次模型调用埋好以下四个数字。没有它们,你就无法判断优化是有效还是适得其反:
# For every model call, log: { "step": "synthesis", "model": "claude-sonnet-4-5", "input_tokens": 9400, "cache_creation_input_tokens": 0, # charged at 1.25x "cache_read_input_tokens": 3200, # charged at 0.1x "output_tokens": 640, "latency_ms": 4100, "latency_to_first_token_ms": 820, # if streaming "cost_usd": 0.0285, # computed from above }
四个指标,作为跨度(span)属性记录(参考第 2.1 章的可观测性(observability)基础设施)。两个与缓存相关的指标是大多数团队最容易忽略的;没有它们,你就无法计算有效输入价格或缓存命中率。一旦拿到这些数字,每项优化主张都变得可验证。
最常见的成本优化错误:花时间调整 max_tokens 来降低输出成本,而输入账单比它大 20 倍却原封未动。"输出每令牌更贵"的直觉把人引到了这里,但输出只占总花费的一小部分。始终先度量,再在真正花钱的地方优化。
不是,但你的智能体形态不同。如果输出占你成本的 90%,要么你在生成非常长的内容(写作、代码生成、长篇综合),要么你的智能体循环很短(1-2 次转轮),积累的上下文很少。两种形态都合理;只是成本拆解看起来不一样。
通用原则依然适用:度量你的成本在哪里,然后在那里优化。20:1 的输入:输出比例是多轮研究/助手智能体的典型值。单轮生成智能体会偏向另一个方向。在选择技术之前,先算出你的实际比例。
这对于非缓存、非流式、输入几千令牌的 Sonnet 调用来说是典型值。延迟大致随输入长度线性增长(令牌越多 = 处理时间越长),加上生成输出令牌的时间(Sonnet 约 30-80 令牌/秒,取决于负载)。一次 4 秒的综合调用,生成 640 个输出令牌,以约 150 令牌/秒的速度生成加上约 1 秒的输入处理,处于预期范围之内。
有两件事会显著改变这些数字:缓存命中能将输入处理时间缩短约 70%;流式输出让用户从第一个令牌出现时(通常 0.5-1s)就感知到延迟,而不是等到最后一个令牌输出。两者在本章后面都会介绍。
提示词缓存(prompt caching):最大的单一成本杠杆。
提示词缓存是大多数团队投入不足的优化手段,尽管它是现有最大的单一成本杠杆。做对了,可以将智能体工作负载的输入令牌成本降低 60–90%。做错了,什么效果也没有,而且你不会察觉——因为 API 不会报错,账单只是比本可以更高。
机制原理
机制很简单,但值得精确理解:当你将提示词的某个部分标记为可缓存时,Anthropic 会存储该前缀的中间计算结果(键值注意力缓存,即"KV cache")。下一个携带相同前缀的请求无需重新处理——模型从缓存状态继续运行。
截至 2026 年的定价:
保本计算:5 分钟缓存只需一次读取即可回本。1 小时缓存只需两次读取。对于任何会被复用的前缀,两者几乎总是值得的。
重要约束:
- 最小前缀长度。 Sonnet/Haiku:1,024 令牌。Opus:4,096 令牌。低于最小值时,你的
cache_control指令会被静默忽略。(大多数生产系统提示词超过这个长度;非常短的提示词本来也不需要缓存。) - 精确前缀匹配。 只有当缓存前缀与已存储条目逐字节一致时,缓存才会命中。多一个空格、一个不同的时间戳、一次模型快照轮换——都会导致缓存未命中。
- 每个请求最多 4 个缓存断点。 如果你的提示词有多个稳定层,可以分别独立缓存多个片段。
最小正确的 API 调用
有两种用法,都是对标准调用的小量补充:
# Automatic caching: simplest, recommended starting point response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, cache_control={"type": "ephemeral"}, # default 5-min TTL system=LARGE_SYSTEM_PROMPT, tools=TOOLS, messages=messages, ) # Anthropic decides where to put the breakpoint (typically end of system+tools). # Explicit breakpoints: fine-grained control response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, system=[ {"type": "text", "text": LARGE_SYSTEM_PROMPT, "cache_control": {"type": "ephemeral"}} ], tools=TOOLS_WITH_CACHE, # cache_control on the last tool messages=messages, )
响应中包含 usage.cache_creation_input_tokens 和 usage.cache_read_input_tokens——这两个数字告诉你缓存是否真的在生效。请务必记录它们。
让缓存真正发挥效益的架构
大多数团队犯的错误是:在代码各处散放 cache_control,然后假设缓存已经在运行。也许是的。也有可能什么都没缓存,因为"稳定"的内容在每次请求时都在变。关键在于:将提示词结构设计为一个按稳定性分层的堆叠层次:
具体做法:把系统提示词和工具定义放在最前面,紧接其后设一个缓存断点。对话历史放在其后,在倒数第二轮之后再设一个断点(这样最新一轮是新鲜的,之前所有内容都被缓存)。当前用户消息排在最后,永远不放在缓存区域内。
这种结构通常能在生产智能体工作负载上达到 60–80% 的缓存命中率,折算下来,在扣除缓存写入开销后,输入令牌总成本大约降低 50–70%。
悄然破坏缓存的五种反模式
大多数"缓存已启用"的实现无法兑现 90% 节省承诺的原因:以下五种反模式之一在每次请求时静默地使缓存失效。
反模式 1:前缀中含有时间戳。 系统提示词开头有一行 "Current time: 2026-04-17T14:32:15Z",每次请求都会变。缓存键变了 → 每次调用都缓存未命中。修复方案:要么去掉时间戳(模型真的需要秒级精度吗?),要么截断到天("Date: 2026-04-17" 只每天变一次),要么把时间戳从缓存区域移到用户消息中。
反模式 2:缓存前缀中含有用户特定内容。 系统提示词中写了 "You are helping {user.name} who works at {user.company}",导致每个用户都拥有自己的缓存条目。如果每个用户每天发送数百个请求,这没问题;如果有数千个用户、每人请求量很少,则代价高昂。修复方案:把用户特定内容移到用户消息中;让缓存前缀与用户无关。
反模式 3:不一致的空白字符。 你的提示词构建器对末尾空白字符的处理不一致——有时结尾有换行,有时没有。缓存哈希不在乎这个差异是不可见的;它只看到了不同的前缀。修复方案:强力归一化。始终去除空白,始终用统一风格的分隔符拼接。一个 30 行的提示词规范化函数,一天之内就能回本。
反模式 4:模型快照轮换。 当 Anthropic 发布新的 Sonnet 小版本快照时,旧快照上的缓存条目就失效了。缓存写入会产生额外成本;快照轮换期间缓存重新预热会带来临时的成本峰值。修复方案:在生产环境中锁定模型快照版本(用 claude-sonnet-4-5-20250929 而不是 claude-sonnet-4-5),让轮换成为明确的决策,并将缓存预热纳入任何模型升级的计划中。
反模式 5:前缀短于最小长度。 你在一个 600 令牌的系统提示词上加了 cache_control,以为会有缓存。最小长度是 1,024 令牌;什么都没缓存。API 不会报错——只是按全价处理。始终通过响应的 cache_creation_input_tokens 字段来验证,只有当缓存真正发生时它才非零。
度量缓存是否生效
在可观测性(observability)仪表板中需要追踪的指标:
cache_hit_ratio = cache_read_input_tokens
────────────────────────────────────────────
cache_read_input_tokens + standard_input_tokens
Healthy production workloads: 50–80%
Below 20%: prefix design is broken; audit for anti-patterns
Above 90%: probably leaving even more on the table; investigate
if user-message tokens could be reduced too
光有数字还不够——要追踪其随时间的变化,留意是否下跌。缓存命中率突然下跌,通常意味着某个反模式刚刚悄悄混入(有人加了时间戳、模型快照发生了轮换、一次部署改变了提示词格式)。
5 分钟 vs 1 小时 TTL 的选择
Anthropic 默认的缓存 TTL 是 5 分钟。另有 1 小时 TTL,写入成本为 2 倍。怎么选:
5 分钟 TTL 适合交互式工作负载,这类负载预期用户会快速发起后续请求。聊天智能体在几分钟内会收到大量请求;5 分钟窗口能覆盖其中大多数。如果用户离开 20 分钟后回来,你会再次付一次缓存写入费——但这种情况很少见,而且 5 分钟写入很便宜(1.25 倍)。
1 小时 TTL 适合批处理工作负载,这类负载会在间隔数分钟的多个请求中重复使用相同上下文。一个处理 10,000 份文档、耗时 45 分钟的文档处理流水线,能从 1 小时 TTL 中获益,因为系统提示词在整个运行期间都保持预热。2 倍写入成本是值得的,因为你能以 0.1 倍的价格读取 10,000 次。
不要默认选 1 小时 TTL。如果你的工作负载实际上并不持久,2 倍写入惩罚会让你很难受;如果判断失误,5 分钟本来会更便宜。
来自真实工作负载的实际数字
以具体数字校准期望:一个每天处理 1,000 次对话的客服智能体,每次对话平均 4 轮,系统提示词 2,000 令牌,跨轮次积累的上下文从 2K 增长到 8K。按 Sonnet 定价计算:
Without caching: System prompt (2K) sent on every call: 2K × 4 turns × 1000 conv = 8M tokens Other input (~5K avg per call): = 20M tokens Total input: 28M tokens × $3/M = $84/day Output (~500 tokens × 4 calls × 1000): 2M × $15/M = $30/day ──────── Total: $114/day, $42K/year With 5-minute caching (assuming 70% cache hit ratio): Cached input: 0.70 × 28M = 19.6M tokens × $0.30/M = $5.88/day Standard input: 0.30 × 28M = 8.4M × $3/M = $25.20/day Cache writes: ~2.8M tokens × $3.75/M = $10.50/day Output: same = $30/day ──────── Total: $71.58/day, $26K/year Savings: $42 - $26 = $16K/year, ~38% reduction With model cascade on top (next step): ... ~$45/day, ~$16K/year (further 37% reduction)
单靠缓存节省的成本是真实且可观的。与模型级联叠加使用(STEP 3),生产智能体的成本通常能降到未优化时的 20–30%。
如果这周你只从本章实现一件事,就实现提示词缓存,作用于你最大的稳定提示词前缀。这只是一个 API 参数,折扣真实存在(输入节省 60–80%),唯一挡在你和折扣之间的,是没有针对五种反模式审计你的前缀。拨出一小时,做审计,部署上线。大多数团队在 24 小时内就能看到账单的明显降低。
OpenAI 在 2024 年底推出了提示词缓存,机制类似——对缓存输入令牌给予折扣(截至 2026 年初为 50%,不是 90%),并自动检测重复前缀。架构决策是相同的(稳定前缀,易变后缀);折扣幅度更小。同样的反模式审计也适用。
在各家提供商中,这个原则正在标准化:将提示词结构化以最大化前缀稳定性,就能获得折扣。具体倍数各有不同;方法论是通用的。
两种场景。第一,如果你的工作负载真的没有任何重复前缀——每个请求从头到尾都是唯一的——你就要为那些从未被读取的缓存写入支付 1.25 倍的写入费。输入侧成本上升 25%。这在真实智能体工作负载中不太可能(系统提示词和工具定义几乎总会重复),但如果你的架构设计比较特殊,就有可能。
第二,如果你有数百个不同的缓存前缀,每个只写一次、读一两次。写入开销占主导,数学上勉强算得过来。修复方案:合并前缀(减少唯一系统提示词的数量),或者接受这个特定工作负载不适合缓存。
如果你想保持防御性:埋好指标,如果缓存命中率在两周内一直低于 20%,就关掉缓存,直到你修复了前缀设计。
在某种程度上可以,但是间接的。工具结果会成为消息历史的一部分,而消息历史在下一轮就变成了输入。如果你的消息历史落在缓存区域内(在其之后设有断点),那么是的——较早的工具结果会保持缓存状态,享受 90% 的折扣。如果你的消息历史是在易变用户消息之前的最后一个内容,那么工具结果就处于缓存区域中。
模式:缓存断点放在消息历史之后、新用户消息之前。这样每次新转轮只对新用户消息和本轮工具调用支付全价,而之前的一切都享有缓存折扣。
模型级联(model cascade):用更小的模型处理简单步骤。
大多数智能体对所有步骤使用同一个模型。它们对规划步骤、工具决策步骤、综合步骤和格式化步骤都调用 claude-sonnet-4-5。这是构建智能体最省事的方式,对于低流量智能体也没问题。但对于生产智能体,这会留下可观的资金浪费。
洞察很简单:智能体循环的不同步骤有不同的难度。决定是否搜索文档很容易;从检索到的文本块综合出最终答案很难。对两者都用同一个模型,意味着你在为 Haiku 能同样胜任的任务支付 Sonnet 的价格。
模型阵容:价格与速度
当前 Anthropic 和 OpenAI 的模型阵容及大致定位:
Haiku 与 Sonnet 之间 3-5 倍的价格差就是那根杠杆。如果智能体循环中有一半模型调用能转移到 Haiku 且不损失质量,你无需做其他任何改变就能节省大量资金。
哪些步骤可以转到更小的模型?
实践中有效的框架:让模型与步骤真正需要做的事相匹配。分三类:
路由 / 分发 / 分类步骤 → 能用的最小模型。"该搜索文档、搜索网页,还是直接回答?""这个问题关于账单、技术支持,还是一般问题?""这个查询需要多个来源吗?"这些步骤的输出基数很低(3-5 个选项),不需要深度推理。Haiku 在这类任务上的质量与 Sonnet 无法区分,而且便宜 3 倍。
工具决策步骤 → 中间档模型(或能用的最小模型)。"根据这条用户消息和这些工具,应该调用哪个工具,参数是什么?"比纯分类稍难,因为参数构造需要理解问题。Haiku 通常能胜任;在你的评估(eval)集上验证。如果 Haiku 的错误路由超过 5-10%,就升到 Sonnet。
综合 / 最终回答步骤 → 预算允许范围内的最佳模型。撰写用户最终看到的答案。这是质量最显眼的地方,糟糕的输出最能损害用户满意度,更好模型的边际成本最有理由。默认用 Sonnet。当综合任务确实很难(多文档推理、代码审查)时才用 Opus。
代码中的具体模式
# agent/loop.py — model cascade ROUTING_MODEL = "claude-haiku-4-5-20251001" # cheap, fast SYNTHESIS_MODEL = "claude-sonnet-4-5" # quality async def run_agent(user_message: str): # Step 1: route — which path does this question need? # Haiku is enough: this is a classification. route = await client.messages.create( model=ROUTING_MODEL, max_tokens=50, system=ROUTING_PROMPT, messages=[{"role": "user", "content": user_message}], ) path = parse_route(route) # "search" | "calculate" | "direct" # Step 2: tool-using loop. Use Haiku — it can call simple tools fine. tool_results = [] for step in range(5): response = await client.messages.create( model=ROUTING_MODEL, # still Haiku for tool decisions max_tokens=1024, tools=TOOLS, system=TOOL_PROMPT, messages=build_messages(user_message, tool_results), ) if response.stop_reason != "tool_use": break # dispatch tools, collect results tool_results.extend(await dispatch_tools(response)) # Step 3: synthesis — write the final answer. Use Sonnet. # This is where quality matters most. final = await client.messages.create( model=SYNTHESIS_MODEL, max_tokens=2048, system=SYNTHESIS_PROMPT, messages=build_synthesis_messages(user_message, tool_results), ) return final.content[0].text
三次模型调用,三种不同选择。路由和工具调用步骤运行在 Haiku 上;只有用户可见的综合步骤运行在 Sonnet 上。对于此前所有步骤都用 Sonnet 的智能体,这在设计良好的评估(eval)套件上通常能实现 50–60% 的成本降低且无质量回退。
如何在评估集上验证级联
正确的模型级联推广方式:保留 Sonnet 作为基准,每次只将一个步骤换成 Haiku,运行评估(evaluation)套件(第 3.1 章),度量增量(delta)。如果你关心的指标(通常是 trajectory_pass_rate 或等效指标)没有变化,这次换换是安全的。如果下降了,该步骤需要更大的模型。
按风险从低到高的尝试顺序:
- 路由/分类步骤(风险最低)。Haiku 处理这些步骤几乎没有质量损失。
- 带结构化输出的简单工具调用(search_docs、get_user 等)。Haiku 通常可以胜任。
- 需要推理先前工具结果的多步工具序列。 Haiku 有时会退化;需要度量。
- 输入简单的综合步骤。 也许 Haiku 能处理简短的事实性回答。
- 输入复杂的综合步骤。 可能需要 Sonnet。评估集会告诉你答案。
关键在于:每个级联决策都是评估问题,而不是直觉问题。"Haiku 能处理这个步骤吗?"的答案,是通过在该步骤上用 Haiku 运行评估套件并与 Sonnet 基准对比得到的。如果答案是"是的,分数没有变化",就上线更便宜的版本。如果是"不,分数下降了 2 分",就保留 Sonnet。
推理模型的例外
还有一个维度:启用了推理功能的模型(带扩展思考(extended thinking)的 Opus 4.7、GPT-5 推理模式)。这些模型比其非推理版本更慢、更贵,因为它们在响应之前会生成隐藏的"思考"令牌。只有在额外推理确实能改变答案的步骤上才值得使用——通常是复杂规划或多步逻辑推断。
第 0.1 章中的心智模型适用于此:扩展思考对困难的推理问题有帮助,对简单任务则会拖累。在级联中,这意味着:
- 路由/分类:永远不用推理模式。Haiku 或非推理的 Sonnet。
- 工具决策:极少用推理模式。仅当你的智能体做复杂多步规划时。
- 综合:取决于复杂度。代码审查、数学、多文档分析用推理模式;其他情况用非推理模式。
新项目的务实默认值
如果你正在启动一个新智能体,尚不清楚哪些步骤需要哪种模型,这里有一个合理的起点供你随时间调整:
Routing / classification: Haiku 4.5 Tool decisions: Haiku 4.5 (start here; upgrade if eval fails) Synthesis: Sonnet 4.5 If you have an Opus budget, use Opus only for: - Synthesis on the highest-stakes paths - Multi-document analysis or code-review style tasks Never default to Opus across the board. The cost compounds badly in agent loops, and the quality gap vs Sonnet rarely justifies it on non-frontier tasks.
与缓存的复合效应
级联与缓存的效果是相乘的。一个未优化时成本 $100/天的工作负载,仅靠缓存降到 $60/天,仅靠级联降到 $40/天,两者都用则降到约 $25/天——因为级联降低了模型档位乘数,而缓存同时降低了输入令牌乘数。每种方法各自带来约 40% 的降低;组合起来带来约 75%。
具体金额取决于你的工作负载,但相乘结构是普遍的。如果你只实施了其中一种而忽视了另一种,那些通过实施第二种可以回收的资金就是白白浪费了。
你无法可靠地知道。抽查 5 个样例不能告诉你第 5 百分位的情况是否退化了。第 3.1 章中的方法论适用于此:每次模型换换都是一个有预测("将路由换成 Haiku 应该不会使 trajectory_pass_rate 变化超过 1 分")和判决("运行了评估;通过率变化了 0.3 分,在噪声基线(noise floor)0.044 之内 → 上线")的假设。
如果你的评估套件太慢,无法在每次级联决策时都运行,那你有一个不同的问题需要先解决(第 3.1 章)。评估的快速子集(10–15 个样例,2–3 分钟内完成)对大多数级联决策的上线与否判断已经足够。
通常不应该,但有一个具体的例外。不应该的原因:不同家族在工具调用(tool use)、结构化输出和指令跟随方面有细微的行为差异。在循环内混用意味着要调试两种失败模式而不是一种,而且你的工具调用模式可能需要针对特定提供商进行调整。
例外情况:当你有充分理由认为某个家族在特定子任务上明显更好时(例如,GPT-5-mini 在极廉价分类上,Claude Haiku 在特定输出格式的指令跟随上)。对大多数团队来说,这不值得引入这种复杂性。选择一家提供商,在其模型阵容内进行级联。
一些提供商正在探索这个方向(Anthropic 的混合推理模式,让模型自行决定投入多少思考)。目前,"哪个模型处理这个步骤"的决定是你在代码中做出的,基于你的评估结果。模型无法在每个步骤级别上自我路由——你的分发代码来做这件事。
未来方向很有意思:一个单一的 API 端点,按请求决定投入多少算力。截至 2026 年中,这已部分可用(带自动预算的扩展思考),但还没有达到"在这次转轮中自动在 Haiku 和 Sonnet 之间选择"的程度。请持续关注。
延迟:流式输出、并行化,以及感知延迟与实际延迟的分离。
成本与延迟的优化杠杆有重叠,但并不完全相同。延迟方面有两种模式尤为重要:流式输出(不减少总时长,但能大幅改善感知时长)和并行工具执行(确实能减少总时长,有时幅度很大)。两者都值得单独讲解。
感知延迟与实际延迟的分离
第一个概念转变:用户关心的是感知延迟(perceived latency),而不是实际延迟(actual latency)。感知延迟是用户感觉自己在等待的时长,它主要由用户看到任何内容之前的等待时间决定。实际延迟是智能体从开始到完成所花的时间。这两个数字可以相差很大。
一个需要 12 秒才能产出完整答案、前 11 秒屏幕上什么都没有的智能体,感觉很慢。同样的智能体需要 12 秒产出完整答案,但在 0.8 秒时就开始显示令牌,感觉很快——尽管实际延迟完全相同。用户在智能体生成的同时阅读内容;他们的等待时间是直到有内容可读的时间,而不是生成完成的时间。
这是流式输出(streaming)的根本理由,也是为什么流式输出在任何面向用户的智能体中都是不可或缺的。
流式输出,从协议层讲起
Anthropic 和 OpenAI 都通过服务器发送事件(Server-Sent Events)支持流式输出。模型每次生成一个令牌,并在产出时立即发送。客户端(浏览器、移动应用、终端)消费这个流,令牌到达时立即显示。
# Streaming with the Anthropic SDK async with client.messages.stream( model="claude-sonnet-4-5", max_tokens=2048, messages=messages, ) as stream: async for text in stream.text_stream: # Yield each token to the client as it arrives. yield {"type": "token", "text": text} final = await stream.get_final_message() # final.usage has the token counts; useful for cost tracking
# Streaming with the OpenAI SDK (Responses API) stream = client.responses.stream( model="gpt-5.5", input=[{"role": "user", "content": message}], ) with stream as s: for event in s: if event.type == "response.output_text.delta": yield {"type": "token", "text": event.delta} # final response, with full output and usage final = s.get_final_response()
流式端点需要追踪的两个指标:
- 首令牌时间(time to first token,TTFT):第一段输出出现之前的等待时长。这个数字定义了感知延迟。健康值:1 秒以内。值得关注:超过 2 秒。反映输入处理速度。
- 每秒令牌数(tokens per second,TPS):令牌开始流出后的生成速度。Sonnet 通常为 30-80 TPS;Haiku 更快。这影响用户在等待其余内容时的阅读体验。重要性低于 TTFT,但值得监控。
TTFT 是需要优化的指标。如果你的 TTFT 是 3 秒,即使 TPS 很快也没用——用户盯着空白屏幕等了三秒,已经得出结论说你的产品很慢。先降低 TTFT。
哪些因素能压低 TTFT
对 TTFT 影响最大的因素是输入令牌数量。模型必须处理完每一个输入令牌,才能产出第一个输出令牌。对于 10K 输入的提示词,即使在生成开始之前,Sonnet 通常也需要 500-1500ms 来处理。将输入通过更好的上下文管控削减到 3K,TTFT 就能降到 200-500ms。
其他因素:
- 缓存命中能大幅降低 TTFT,因为缓存令牌跳过了处理步骤。命中缓存的请求,TTFT 通常比同一请求冷缓存写入时低 30–50%。
- 模型大小:在相同输入规模下,Haiku 的 TTFT 通常是 Sonnet 的 30-50%。
- 服务端负载:提供商侧的延迟随其基础设施繁忙程度而变化。这不太在你的控制之内,但响应头中的
x-request-id可以让你在某些情况看起来异常时与他们的仪表板关联查询。
并行工具调用
第二个延迟杠杆是并发执行。从第 0.3 章你已经知道,智能体可以在一次转轮中触发多个工具调用。本章的问题是:拿到这些调用后怎么处理——串行还是并行?
朴素的分发器按顺序迭代工具调用:
# Naive: sequential — wastes latency for block in tool_use_blocks: result = await HANDLERS[block.name](**block.input) results.append(result) # 3 tools × 400ms each = 1.2s
生产级分发器并发运行它们:
# Production: parallel — bounded latency = max(individual) async def run_one(block): try: result = await HANDLERS[block.name](**block.input) return tool_result_block(block.id, result) except Exception as e: return tool_result_block(block.id, f"Error: {e}", is_error=True) results = await asyncio.gather(*[run_one(b) for b in tool_use_blocks]) # 3 tools × 400ms each ≈ 450ms (longest + overhead)
对于一个在单次转轮中触发 5 次检索调用的研究智能体,这是 2 秒与 400 毫秒的差距。免费的延迟改善——无需质量权衡。
注意事项:改变状态的工具(写入、发送、删除)不应盲目并行化。两个并发的 delete_record 调用可能产生竞争。安全的模式:将工具分为只读和改变状态两类;并行化前者,串行化后者。
延迟预算
设定每次转轮的延迟预算并强制执行。对于交互式智能体,3 秒是感知延迟的合理上限(TTFT 低于 1s,短回答的总响应时间低于 3s;只要智能体一路展示进度,更长的时间也可以接受)。
预算框架:
For a multi-turn agent, the budget at each step: ─ Pre-flight (auth, validation, cache lookup): < 50ms ─ Initial model call (routing/tool decision): < 1500ms ─ Tool execution (in parallel): < 1000ms (max of any individual) ─ Synthesis call: < 2500ms (with TTFT < 800ms) ─ Network/streaming overhead: < 200ms Total budget: ~5s, with TTFT under 1s. For agents that legitimately need more time (deep research, long synthesis), use Pattern B from chapter 2.4 — submit/poll with streaming events. The latency budget then applies per-event, not per-end-to-end-response.
关键在于:对预算的每个组成部分都进行埋点。当智能体感觉很慢时,查看跨度树(第 2.1 章),找到超出预算的组件。通常是模型调用(输入太大、没有缓存命中)或串行工具执行。两者都可以修复。
推测性执行:当延迟真的至关重要时
对于高要求的延迟场景,有一种进阶技术:在上一步完成之前,就基于对下一步需要什么的猜测,提前开始下一步的工作。
例子:研究智能体的路由步骤决定是搜索文档、搜索网页,还是直接回答。三个选项,概率大致相等。与其等待路由决策出来再开始任何工作,你可以并行触发全部三次搜索——提前预热——然后只使用路由步骤实际选择的那条路径的结果。
这会花 3 倍的工具执行费用,但能将感知延迟缩短为(路由调用时间,工具调用时间)的最大值,而不是二者之和。只有当延迟确实至关重要、且推测成本较小时才值得这样做(工具调用远比模型调用便宜,所以这个权衡往往划算)。
对大多数智能体来说这是过度工程化。但对于在响应速度上竞争的聊天机器人、或每 100ms 都很关键的交易/实时智能体,这是正确的选择。不要提前采用;当感知延迟成为用户满意度的瓶颈、且你已经穷尽了更简单的杠杆之后,再考虑它。
正确形态是什么样的
把所有这些综合起来,一个优化良好的生产智能体是这样的:
这是让你能够可持续地服务真实用户的形态。这些数字没有一个是第一天就能达到的——你需要用本章的杠杆迭代地趋近它们,用第 2.1 章可观测性工作提供的度量数据,判断自己是否在移动正确的指标。
对一个新智能体应用本章技术的正确顺序:(1) 对四个成本/延迟指标进行埋点;(2) 在最大的稳定前缀上实施提示词缓存;(3) 每次换一个步骤推出模型级联,通过评估套件验证;(4) 审查工具分发器,找出本该并行却串行的地方;(5) 如果还没有,启用流式输出;(6) 为每个步骤设定延迟预算,并对超标发出告警。每个步骤都是一天的投入,在一周的生产流量之内即可回本。
4 秒的 TTFT 偏高;缓存命中时预期值低于 1s,典型输入规模的冷缓存预期值低于 2s。诊断顺序:
- 检查输入令牌数量。 如果你每次请求向 Sonnet 发送 50K 令牌,2-4s 的 TTFT 是预期的代价。通过上下文裁剪或缓存命中减少输入。
- 检查缓存命中率。 如果接近零,你每次调用都在支付完整的处理成本。参见 STEP 2 中的反模式。
- 检查模型档位。 Opus 的 TTFT 明显高于 Sonnet,Sonnet 高于 Haiku。如果你在用 Opus,在能降级的地方降级。
- 检查提供商侧状况。 推理集群有时处于高负载状态。查看提供商状态页面,以及响应头中的 request-id。
可能会——如果你有"生成文本"和"流式文本"两条代码路径,它们往往会发散。最简洁的模式:内部始终使用流式,让非流式代码路径成为一个将流消费成单一字符串的薄包装层。这样智能体循环是单一形态(异步生成器),"非流式"只是消费输出的另一种方式。
对于不需要流式输出的工具调用,流式开销可以忽略不计(几毫秒)。统一形态带来的好处远超过这点开销。
Batch API 对输入和输出令牌均提供 50% 折扣,处理窗口为 24 小时。它可以与提示词缓存叠加(所以批处理中的缓存读取为 0.5× × 0.1× = 基础输入价格的 0.05×)。缺点:它是异步的且很慢。你提交一个批次,稍后再来查看结果。
对于交互式智能体,批处理是无关的——你的延迟预算是秒级,不是小时级。对于离线工作负载(评估套件运行、批量文档处理、训练数据生成、定期报告),批处理可以是正确答案。不要试图将批处理硬塞进实时路径;那不是它的用途。
交付物
一个在成本和延迟上有纪律的智能体:每次模型调用都有埋点指标,提示词缓存在稳定前缀上激活且命中率 60-80%,模型级联将档位与任务难度匹配,独立的工具并行分发,交互路径启用流式输出。清晰理解账单从哪里来(输入令牌,跨转轮积累)以及时间从哪里去(模型调用,大多串行)。这个心智模型能将"优化成本"和"优化延迟"从模糊愿望变成你知道如何拨动的具体杠杆。这是让智能体以真实成本基础服务真实用户的经济底座。
- 令牌级埋点:每次模型调用的 input、output、cache_creation、cache_read、latency
- 提示词缓存在最大稳定前缀上启用;最小 1,024(Sonnet)/ 4,096(Opus)令牌
- 缓存命中率仪表板,并对低于阈值发出告警
- 反模式审计:缓存区域中无时间戳、无用户特定数据、空白字符已归一化
- 模型级联:Haiku 用于路由,Sonnet 用于综合,Opus 仅在可测量地需要时使用
- 每个级联决策均通过评估套件验证,有预测值和实测增量(delta)
- 通过 asyncio.gather 并行分发工具调用;改变状态的工具串行执行
- 交互式端点启用 SSE 流式输出;非流式作为薄包装层
- TTFT 已度量并追踪;目标为缓存命中时低于 1s
- 每步延迟预算已定义并强制执行;对超标发出告警
- Batch API 用于离线工作负载(评估、文档处理);标准模式用于交互式