Skip to content

AI 应用如何控制 Token 成本?缓存、路由、预算和降级策略

LLM 成本控制不是简单压缩 Prompt,而是先按功能、用户和请求记录可归因用量,再依次治理无效请求、上下文、输出长度、缓存、模型路由与重试。价格应来自实际供应商账单或已核验价目表;本文不写固定单价,只给可替换费率的计算与预算方法。

先说结论

控制成本应遵循“先可见、再约束、后优化”:

  1. 建立请求级用量台账,区分输入、输出、缓存命中和重试;
  2. 在调用前做预算检查,限制上下文、输出和循环次数;
  3. 优先消除重复调用和无效长上下文;
  4. 按任务能力路由模型,而不是一律选择最高能力或最低单价;
  5. 超预算时明确降级,不静默牺牲权限、事实性和关键质量。

适合谁,不适合谁

本文适合已产生稳定调用量,需要做成本归因、限额和优化的 API、RAG 或 Agent 应用。

早期原型也应设置硬上限,但无需立刻建设复杂计费平台。若供应商按非 Token 维度收费,仍可沿用“请求级归因、预算、路由、降级”的方法,只需替换计量单位。

先建立可归因成本模型

单次请求的估算可以写成:

text
estimatedCost =
  inputUnits × verifiedInputRate
  + outputUnits × verifiedOutputRate
  + toolOrHostingCost

费率必须来自当前合同、账单或核验过的官方价目表,并保存币种、计费单位、生效时间和来源。不能把文章中的示例数值直接用于生产预算。

请求台账至少包含:

  • 业务功能、租户或成本中心;
  • 内部模型别名与实际 Provider;
  • 输入、输出和可用的缓存计量;
  • 重试次数与失败原因;
  • 工具调用或自托管资源归因;
  • Prompt、路由策略和应用版本。

用量缺失应记为 unknown,不要记为零。定期用供应商账单对账,才能发现统计口径差异。

调用前预算守卫

下面的 TypeScript 示例把价格配置与业务逻辑分离,费率由已核验配置注入:

ts
interface VerifiedRates {
  inputPerUnit: number
  outputPerUnit: number
  currency: string
  source: string
  effectiveAt: string
}

interface UsageEstimate {
  inputUnits: number
  maxOutputUnits: number
}

function estimateMaximumCost(
  usage: UsageEstimate,
  rates: VerifiedRates,
): number {
  return (
    usage.inputUnits * rates.inputPerUnit +
    usage.maxOutputUnits * rates.outputPerUnit
  )
}

function assertWithinBudget(
  usage: UsageEstimate,
  rates: VerifiedRates,
  remainingBudget: number,
): void {
  const maximum = estimateMaximumCost(usage, rates)
  if (maximum > remainingBudget) {
    throw new Error('request exceeds remaining budget')
  }
}

生产实现还应处理计费单位换算和小数精度。预算守卫使用“最大可能输出”做保守估算;请求结束后再以实际用量记账。

六类优化手段怎么选

手段适用条件主要收益风险与边界
输入裁剪历史或检索片段冗余减少输入用量与延迟不能裁掉权限、目标和关键证据
输出上限任务可定义长度防止失控长输出上限过低会截断 JSON 或答案
语义/结果缓存输入规范化且结果可复用避免重复生成权限、时效、模型版本必须进缓存键
模型路由任务难度可分层简单任务不用高能力模型需要评估集验证最低能力
批处理非实时且接口支持降低调度开销增加等待,失败隔离更难
降级预算或依赖异常维持核心服务必须告诉调用方结果能力下降

缓存不是只用 Prompt 字符串做键。至少考虑租户/权限范围、任务版本、模型别名、Schema 版本、数据版本和时效窗口。含个人数据或权限结果时,宁可不跨用户复用。

路由策略的可执行边界

路由应先满足能力,再比较成本和延迟:

ts
interface RouteCandidate {
  name: string
  supportsSchema: boolean
  supportsTools: boolean
  estimatedMaximumCost: number
  healthy: boolean
}

function selectRoute(
  candidates: RouteCandidate[],
  needsSchema: boolean,
  needsTools: boolean,
  budget: number,
): RouteCandidate {
  const eligible = candidates
    .filter(item => item.healthy)
    .filter(item => !needsSchema || item.supportsSchema)
    .filter(item => !needsTools || item.supportsTools)
    .filter(item => item.estimatedMaximumCost <= budget)
    .sort((a, b) => a.estimatedMaximumCost - b.estimatedMaximumCost)

  if (eligible.length === 0) {
    throw new Error('no healthy route satisfies capability and budget')
  }
  return eligible[0]
}

仅按估算成本排序仍不够。候选模型必须先通过该任务的最小评估集;质量不达标的低成本路线不能进入候选集合。

超时、重试、降级和观测边界

  • 超时:超时也是成本边界。调用方结束后要取消上游生成,避免“用户已经离开、模型仍在计量”。
  • 重试:把重试用量归到原请求;限制总尝试次数和总预算。格式错误不应无限重试。
  • 降级:按顺序考虑减少非关键上下文、改用已验证的低成本路由、返回缓存、切换确定性搜索或进入异步队列。不得移除安全检查。
  • 观测:看每个成功业务结果的总用量,而不只看单次调用;Agent 多轮和失败重试可能让单次便宜变成整体昂贵。

建议告警维度包括:每功能单位成本异常、未知用量比例、缓存命中变化、重试放大、输出接近上限、单请求预算拒绝和租户配额耗尽。

常见误区与失败边界

  1. 只比较单价:忽略质量、输出长度、重试率和工具循环。
  2. 压缩所有上下文:关键证据丢失后,错误与重试反而增加。
  3. 缓存不含权限信息:造成跨用户数据泄漏。
  4. 预算只在月末统计:没有调用前守卫,异常循环无法及时停止。
  5. 降级静默发生:调用方以为仍获得完整能力。
  6. 用估算代替账单:估算用于守卫,财务核对应基于真实计费记录。

本文没有提供任何供应商价格。实施时必须对费率来源和生效日期做配置审查;模型、地区、合同或计费方式变化后重新核验。

可执行检查清单

  • [ ] 每个请求可归因到功能、租户和路由
  • [ ] 输入、输出、重试和工具成本分开记录
  • [ ] 未返回用量时记为未知,并能与账单对账
  • [ ] 调用前检查上下文、输出、循环和金额预算
  • [ ] 缓存键包含权限、版本和时效边界
  • [ ] 低成本路由已通过相同评估集
  • [ ] 客户端取消会终止上游生成
  • [ ] 重试共享总超时和总预算
  • [ ] 降级不绕过安全与业务校验,且对调用方可见
  • [ ] 费率配置包含来源、币种和生效时间

下一步

回到 AI 工程化专题 可以查看成本与可靠性、部署的关系。预算策略确定后,使用 AI 项目上线前检查清单 统一核对安全、权限、成本、监控和回滚。

AI 应用开发训练营 · 现在开始

别只收藏 AI 文章,今天就做出第一个能上线的项目

文章解决认知,项目才证明能力。把 Agent、RAG、MCP 变成可运行、可展示、可面试表达的成果,现在就从一次岗位准备度自测开始。

立即开始 AI 岗位准备度自测 查看训练营路线
真实学员成果先看成果,再决定是否开始 →
  1. 01选方向
  2. 02做项目
  3. 03出成果
  4. 04拿面试