资讯详情

资讯详情

DigitalOcean 推理路由器新增缓存感知能力:为什么最便宜的模型不一定最省钱

1. 为什么“最便宜模型”反而让账单更贵一个 Agent 场景的真实成本账先说结论在 Agent 工作流里模型单价只是成本公式里的一个变量另一个被大多数人忽略的变量是缓存命中率。当你的 Agent 反复发送同一份 System Prompt、Tool Definition、仓库上下文和对话历史时真正决定每次请求花多少钱的是“有多少 Token 走了缓存价”而不是“每百万 Token 标价多少”。我拿一个具体场景算给你看。假设一个 Coding Agent 的上下文稳定在 100,000 输入 Token其中 90,000 Token 已经在模型 A 上建立了热缓存。模型 A 的未缓存输入价是每百万 2.5 美元缓存命中价是每百万 0.2 美元。那么下一次请求的输入成本是10,000 未缓存 Token × 2.5/1M 90,000 缓存 Token × 0.2/1M 0.025 0.018 0.043 美元。现在你看到模型 B 的未缓存输入价只要每百万 0.7 美元心想“这不是便宜三倍多吗”于是把请求切过去。问题是切换模型意味着原有缓存全部失效模型 B 必须重新 Prefill 全部 100,000 Token。成本变成 100,000 × 0.7/1M 0.07 美元。比继续用“标价更贵”的模型 A 贵了约 1.6 倍。这就是缓存感知要解决的核心问题模型选择不是单次请求的局部最优而是整个 Agent Session 的全局最优。一次破坏缓存的切换Prefill 的 Prompt 数量可能变成原来的 10 倍Time to First Token 也会明显上升——虽然不一定线性放大 10 倍因为不同模型的 Prefill 性能不同但方向是确定的。哪些人最该关心这件事三类一是把 Agent 跑在生产环境、Token 用量指数增长的团队二是已经在用多模型池、但发现账单没降下来的开发者三是正在做模型路由选型、纠结“要不要为了省钱换模型”的技术负责人。如果你属于其中任何一类下面的配置和验证步骤可以直接跟做。需要说明的是本文所有价格和数字都是示例用于说明成本结构实际以你所用平台发布时为准。不同工作负载的缓存命中率差异很大编程类负载在部分平台上能到 90% 以上但通用对话可能低得多这个前提必须先建立。2. 推理路由器的缓存感知前置Affinity 与 Routing Budget 是什么在讲配置之前得先把两个机制讲清楚否则你复制了参数也不知道在控制什么。第一个机制是显式模型亲和性Model Affinity。已经自己维护 Session ID 或 Task ID 的应用可以在每次请求里带一个 Affinity Key。推理路由器第一次收到这个 Key 时按你配置的 Task、Model Pool 和 Routing Preference 选模型之后只要请求携带相同的 Affinity 值路由器就把它们视为同一个工作单元保留 Session 与模型的绑定继续复用已缓存的上下文。Affinity Identifier 应该对应真正有意义的工作单元——一次 Coding Session、一个 Research Task、一段 Support Conversation或者单独一次 Agent Run。当应用真正开始新任务时生成新的 Identifier让路由器重新选模型。第二个机制是Routing Budget Policy。它解决的是“什么时候放弃当前模型和缓存、承担额外成本才值得”。当系统判断有必要切换模型时会先计算放弃当前 Session 热缓存所增加的额外成本比较继续用当前模型的 Cached Input 成本与在候选模型上重建全部上下文的 Uncached Input 成本再把这部分额外费用和整个 Session 已累计的切换支出做比较。你可以通过 Maximum Switching Budget 定义这个取舍基准是“如果整个 Session 一直留在当前模型上本来会花多少钱”。比如设置 20%表示累计切换成本最多只能比这个基准高 20%。模型能力判断和切换成本判断是分开的路由器先选出更适合当前任务的模型再由 Routing Budget 判断为了切过去而承担额外输入成本是否值得。这个设计很关键它避免了两个极端——既不会因为缓存热就死守一个已经不适合任务的模型也不会为了追新模型而无脑破坏缓存。如果你没有显式提供 Identifier路由器也能自行推断 Affinity从多轮请求中保持稳定的上下文生成 Session Key包括 System Instruction、Developer Instruction、Tool Definition 和第一条 User Message。如果这部分稳定 Prefix 发生变化路由器就把缓存视为冷缓存建立新的模型绑定新 Session 重新分配模型并从头积累热缓存。理解这两点后你就能明白为什么“最便宜的模型不一定最省钱”单价低但破坏缓存等于把缓存带来的折扣全部吐回去还额外付了 Prefill 的延迟代价。3. 可复制的路由配置Affinity Header 与 Budget 参数怎么写这一节给你可以直接复制的配置片段。先看 Python 侧怎么带 Affinity Header这是最常用的接入方式。import os import uuid from openai import OpenAI client OpenAI( api_keyos.environ[MODEL_ACCESS_KEY], base_urlhttps://inference.do-ai.run/v1/, ) session_id str(uuid.uuid4()) messages [] user_turns [ Help me debug this failing test., Heres the stack trace, whats causing it?, That fixed it, now can you also add a regression test?, ] for user_turn in user_turns: messages.append({role: user, content: user_turn}) response client.chat.completions.create( modelrouter:your-router-name, messagesmessages, extra_headers{ X-Model-Affinity: session_id, }, ) assistant_reply response.choices[0].message.content messages.append({role: assistant, content: assistant_reply})关键点有三个base_url指向推理服务端点model用router:前缀加你的路由器名extra_headers里带X-Model-Affinity值在整个 Session 内保持不变。第一次请求按你的 Task 和 Model Pool 选模型后续请求因为 Affinity 相同会保留模型绑定并复用缓存。如果你不想改应用代码可以用 Routing Budget 让路由器自己判断。下面这个 curl 示例展示了如何设置切换预算curl -i https://inference.do-ai.run/v1/chat/completions \ -H Authorization: Bearer $MODEL_ACCESS_KEY \ -H Content-Type: application/json \ -H X-Routing-Max-Switch-Spend-Pct: 20 \ -d { model: router:software-engineering, messages: [ {role: user, content: Summarize this in 2 sentences.} ] }X-Routing-Max-Switch-Spend-Pct: 20表示累计模型切换成本最多比“一直留在当前模型”的基准高 20%。注意这里没有显式设置X-Model-Affinity路由器会自行推断 Affinity。如果你既想显式控制工作单元又想限制切换成本两个 Header 可以同时带。如果你用的是配置文件驱动的工具链比如把路由参数写进 settings 或 TOML核心字段就是三个Base URL、Key、Model ID。以 JSON 形式表达如下{ base_url: https://inference.do-ai.run/v1/, api_key_env: MODEL_ACCESS_KEY, model: router:software-engineering, headers: { X-Model-Affinity: ${SESSION_ID}, X-Routing-Max-Switch-Spend-Pct: 20 } }这里model必须是完整的 Model ID不能只写模型名。Base URL、Key、Model ID 三件套缺一不可很多接入失败都是因为 Model ID 写成了裸模型名而不是router:前缀的路由器名。配置写完后建议先在低风险任务上跑一轮观察 Analyze 页面里的缓存效率和切换次数再决定是否放大到生产流量。4. 验证请求与成功结果怎么确认缓存真的被复用了配置写完不等于生效必须验证。验证分两步先确认请求成功再确认缓存命中。第一步发一个最小请求确认链路通。用上面的 curl把 messages 换成一句简单的话观察返回。成功的话你会拿到标准的 chat completion 响应choices[0].message.content有内容。如果这一步就失败先看第 5 节的报错排查。第二步连续发多轮请求观察缓存效率。这里的关键是第一轮请求一定是冷缓存从第二轮开始才可能命中。所以不要拿单次请求判断缓存是否生效。你可以这样构造验证import os from openai import OpenAI client OpenAI( api_keyos.environ[MODEL_ACCESS_KEY], base_urlhttps://inference.do-ai.run/v1/, ) session_id verify-cache-session-001 messages [{role: system, content: You are a coding assistant. * 200}] for i in range(5): messages.append({role: user, content: fTurn {i}: explain step {i} briefly.}) resp client.chat.completions.create( modelrouter:software-engineering, messagesmessages, extra_headers{X-Model-Affinity: session_id}, ) usage resp.usage print(fturn{i} prompt{usage.prompt_tokens} fcached{getattr(usage, prompt_tokens_details, None)}) messages.append({role: assistant, content: resp.choices[0].message.content})跑完后看输出prompt_tokens会随轮次增长但缓存相关的明细字段应该显示大部分 Token 走了缓存。不同 SDK 版本字段名可能不同有的在prompt_tokens_details.cached_tokens有的在顶层。如果字段拿不到就去 Analyze 页面看 Cache Efficiency 趋势。Analyze 页面能回答几个关键问题整体缓存效率是多少有多少请求发生了模型切换有多少请求为了保持热缓存而继续留在原模型上延迟表现如何还能下钻到具体模型和 Task看流量组成发现某些模型上的流量热点验证你的模型选择策略是否合理。Cache Efficiency 趋势追踪可以从 Request 和 Token 两个层面观察缓存效率随时间的变化这样更容易发现 Cache Regression验证 Prompt 和 Cache 调优到底有没有效果。一个实测经验如果你发现缓存命中率始终上不去先检查稳定 Prefix 是不是被破坏了。System Instruction、Tool Definition、第一条 User Message 这三部分只要有一处在每轮请求里变化路由器就会判定为冷缓存重新建立绑定。很多人把时间戳、随机 ID 塞进 System Prompt缓存直接归零。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节按真实报错来对照都是接入推理路由器时高频踩的坑。401 Unauthorized。最常见的原因是 Key 没读到或读错了环境变量。检查MODEL_ACCESS_KEY是否真的导出到了当前 shellPython 里os.environ[MODEL_ACCESS_KEY]如果 Key 不存在会直接抛 KeyError而不是 401所以如果你看到的是 401说明 Key 读到了但值不对。确认 Key 没有多余空格、没有换行、没有把别的服务的 Key 贴进来。另外确认 Authorization Header 格式是Bearer key中间一个空格。local proxy failed。这个报错通常出现在你本地网络环境有额外转发层的时候。先确认base_url写的是推理服务端点而不是某个本地地址。如果你在容器里跑检查容器网络是否能直连外网。这个报错和模型选择无关纯粹是网络链路问题先把链路打通再谈缓存。reading choices 相关报错。典型表现是response.choices为空或索引越界。原因通常是请求被路由到了某个返回结构不同的端点或者你用了流式返回但按非流式解析。检查model字段是不是router:前缀的完整 Model ID。如果用了streamTrue要按流式 chunk 解析不能直接取choices[0].message.content。还有一种情况是请求被拒绝但返回体结构异常打印完整响应体再定位。OAuth 相关报错。如果你用的是需要 OAuth 的工具链注意推理路由器的鉴权是 API Key 模式不是 OAuth 授权码模式。把 OAuth 流程和 API Key 混用会导致鉴权失败。正确做法是在工具配置里填 Base URL、Key、Model ID 三件套不要走 OAuth 回调。如果你用的是 Claude Code 这类工具确认它的配置项里填的是 API Key 而不是登录态。缓存命中率异常低。这不是报错但比报错更隐蔽。排查顺序先确认 Affinity 值在整个 Session 内是否稳定再确认稳定 Prefix 有没有被动态内容污染最后看 Routing Budget 是不是设得太宽松导致路由器频繁切换模型破坏缓存。把X-Routing-Max-Switch-Spend-Pct调低一点观察切换次数是否下降、缓存效率是否回升。切换过于频繁导致延迟抖动。如果你发现 TTFT 忽高忽低去 Analyze 页面看模型切换次数。切换本身不是坏事但如果切换发生在 Session 中途且没有预算约束每次切换都要重建缓存延迟自然抖。给 Session 加 Affinity或者设置合理的切换预算通常能稳住。6. 从成本对比到长期策略把缓存感知接进你的 Agent 工作流验证通过后下一步是把它变成长期策略。这里给几条可执行的建议。第一先建立基线再优化。在你接入缓存感知之前记录一周的 Token 用量、缓存命中率、模型切换次数和账单。没有基线你无法判断优化是否有效。Analyze 页面的 Cache Efficiency 趋势就是干这个的。第二区分“该省的”和“不该省的”。便宜的默认模型适合简单任务但复杂任务需要质量达标的模型。只根据 Benchmark 选模型不够因为模型真实表现取决于它所在的应用环境——System Prompt、Tool Definition、Context、Output Constraint、Conversation History以及什么才算成功。换个 Agent Harness模型排名可能就变了。一个在独立 Coding Benchmark 里最好的模型放进需要处理大型仓库、几十个 Tool 和长对话历史的 Agent 里不一定还是最佳选择。第三缓存感知不是“死守热缓存”。如果当前模型已经不适合任务该切还是要切Routing Budget 就是用来量化这个取舍的。真正的目标不是最大化 Token 数量也不是盲目把单价降到最低而是在满足质量、延迟和可靠性的前提下最大化每一美元的有效智能产出。第四把 Affinity 的粒度设计对。一次 Coding Session、一个 Research Task、一段 Support Conversation、一次 Agent Run各自应该是独立的 Affinity 单元。粒度太粗会导致不相关任务共享模型绑定粒度太细会导致缓存无法积累。判断标准是这些请求是否共享同一份稳定上下文。如果你还在选型阶段建议先用模型对话页面手动对比几个模型在同一份上下文下的表现和成本再决定路由器里放哪些模型。需要长期跑编码或 Agent 任务的话Coding Plan 更适合按周期评估成本结构。接入过程中遇到鉴权或配置问题直接查接入文档和 API Keys 页面比在社区里翻旧帖快得多。最后提醒一句所有成本数字都依赖你的实际缓存命中率和模型价格本文示例只用于说明结构。上线前务必用自己的真实流量跑一轮对比把“看起来便宜”和“实际便宜”分开验证。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →