大模型应用如何控制成本与延迟:Token、缓存、流式和降级实战

本文定位:AI 应用性能 / 成本治理 / 高可用设计

示例环境:Java 21、Spring Boot 3.3、Redis、PostgreSQL、OpenTelemetry。模型价格会变化,文章只讨论测量与治理方法,不绑定某个供应商价格。

摘要

AI Demo 上线后,最容易失控的两个指标是成本和延迟。Prompt 变长、检索片段增多、工具重复调用、失败重试和长历史对话都会让一次请求消耗更多 Token;模型响应慢、Rerank 排队、数据库连接池耗尽又会把用户体验拖垮。

本文先建立成本与延迟的测量模型,再讨论上下文裁剪、缓存、批处理、流式输出、模型路由、限流、超时、熔断和降级。重点是说明优化顺序:先测出钱花在哪里,再决定哪些内容值得缓存或压缩,避免为了追求一个理论上的低延迟而牺牲正确性和安全性。

一、成本模型

一次 RAG 请求成本可以拆成:

text 复制代码
总成本 = Embedding成本
       + 关键词/向量检索成本
       + Rerank成本
       + 模型输入Token成本
       + 模型输出Token成本
       + 重试成本
       + 工具和基础设施成本

很多团队只看模型输出 Token,忽略了输入上下文。RAG 把 10 个大 Chunk 塞进 Prompt 后,输入成本和延迟可能远高于回答本身。每次请求至少记录输入 Token、输出 Token、检索条数、Rerank 次数、重试次数和最终模型。

二、延迟分解

#mermaid-svg-D8d3HZTQUtrQaK67{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-D8d3HZTQUtrQaK67 .error-icon{fill:#552222;}#mermaid-svg-D8d3HZTQUtrQaK67 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D8d3HZTQUtrQaK67 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D8d3HZTQUtrQaK67 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D8d3HZTQUtrQaK67 .marker.cross{stroke:#333333;}#mermaid-svg-D8d3HZTQUtrQaK67 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D8d3HZTQUtrQaK67 p{margin:0;}#mermaid-svg-D8d3HZTQUtrQaK67 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 .cluster-label text{fill:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 .cluster-label span{color:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 .cluster-label span p{background-color:transparent;}#mermaid-svg-D8d3HZTQUtrQaK67 .label text,#mermaid-svg-D8d3HZTQUtrQaK67 span{fill:#333;color:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 .node rect,#mermaid-svg-D8d3HZTQUtrQaK67 .node circle,#mermaid-svg-D8d3HZTQUtrQaK67 .node ellipse,#mermaid-svg-D8d3HZTQUtrQaK67 .node polygon,#mermaid-svg-D8d3HZTQUtrQaK67 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D8d3HZTQUtrQaK67 .rough-node .label text,#mermaid-svg-D8d3HZTQUtrQaK67 .node .label text,#mermaid-svg-D8d3HZTQUtrQaK67 .image-shape .label,#mermaid-svg-D8d3HZTQUtrQaK67 .icon-shape .label{text-anchor:middle;}#mermaid-svg-D8d3HZTQUtrQaK67 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-D8d3HZTQUtrQaK67 .rough-node .label,#mermaid-svg-D8d3HZTQUtrQaK67 .node .label,#mermaid-svg-D8d3HZTQUtrQaK67 .image-shape .label,#mermaid-svg-D8d3HZTQUtrQaK67 .icon-shape .label{text-align:center;}#mermaid-svg-D8d3HZTQUtrQaK67 .node.clickable{cursor:pointer;}#mermaid-svg-D8d3HZTQUtrQaK67 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-D8d3HZTQUtrQaK67 .arrowheadPath{fill:#333333;}#mermaid-svg-D8d3HZTQUtrQaK67 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D8d3HZTQUtrQaK67 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D8d3HZTQUtrQaK67 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D8d3HZTQUtrQaK67 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-D8d3HZTQUtrQaK67 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D8d3HZTQUtrQaK67 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-D8d3HZTQUtrQaK67 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D8d3HZTQUtrQaK67 .cluster text{fill:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 .cluster span{color:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-D8d3HZTQUtrQaK67 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-D8d3HZTQUtrQaK67 rect.text{fill:none;stroke-width:0;}#mermaid-svg-D8d3HZTQUtrQaK67 .icon-shape,#mermaid-svg-D8d3HZTQUtrQaK67 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D8d3HZTQUtrQaK67 .icon-shape p,#mermaid-svg-D8d3HZTQUtrQaK67 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-D8d3HZTQUtrQaK67 .icon-shape .label rect,#mermaid-svg-D8d3HZTQUtrQaK67 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D8d3HZTQUtrQaK67 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-D8d3HZTQUtrQaK67 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-D8d3HZTQUtrQaK67 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 网关排队
问题改写
Embedding
关键词/向量检索
Rerank
模型首Token
模型完成
输出校验

用户感知的流式体验主要受首 Token 延迟影响,但系统总耗时还包括完整输出和后处理。监控 P50、P95、P99,以及首 Token、每 Token 间隔和完成时间,不能只看平均响应时间。

三、上下文裁剪比换模型更先做

上下文应经过"过滤---排序---去重---压缩---限长"流程:

  1. 过滤无权限、过期和低相关文档。
  2. 按 Rerank 分数、版本和来源排序。
  3. 对重复或高度相似 Chunk 去重。
  4. 对长文本只保留与问题相关的句子,但保留引用定位。
  5. 设置输入 Token 硬上限。
java 复制代码
public List<Evidence> trimContext(List<Evidence> evidence, int maxChars) {
    Set<String> seen = new HashSet<>();
    List<Evidence> result = new ArrayList<>();
    int used = 0;
    for (Evidence item : evidence) {
        String fingerprint = normalize(item.content());
        if (!seen.add(fingerprint)) continue;
        if (used + item.content().length() > maxChars) break;
        result.add(item);
        used += item.content().length();
    }
    return List.copyOf(result);
}

裁剪不能只按字符串长度截断。切掉条款的例外条件会导致答案错误,因此最好按句子、列表项或语义单元裁剪,并保留文档标题、版本和页码。

四、缓存设计

缓存适合稳定、重复和可安全复用的数据:Embedding 结果、公开文档的检索结果、相同问题的最终答案。用户权限和知识库版本必须进入缓存键。

text 复制代码
embedding:{model}:{textHash}
retrieve:{tenant}:{permissionHash}:{kbVersion}:{queryHash}
answer:{tenant}:{permissionHash}:{promptVersion}:{model}:{queryHash}

最终答案缓存需要注意两个问题:一是用户权限可能发生变化,二是文档更新后旧答案可能失效。缓存 TTL 不能代替版本失效,发布新知识库版本时要主动失效相关键。对高风险问题,可以只缓存检索结果,不缓存最终答案。

五、流式输出和取消

流式输出能降低用户感知等待,但不能解决模型总耗时。客户端断开后,服务端需要取消模型请求和工具任务,否则会出现用户看不到结果但后台仍持续消耗成本。

java 复制代码
public Flux<String> stream(Publisher<AiEvent> events, CancellationToken token) {
    return Flux.from(events)
            .takeUntil(event -> token.isCancelled())
            .map(AiEvent::safeText)
            .doOnCancel(() -> {
                token.cancel();
                audit.record("client_cancelled");
            });
}

对于有副作用的工具,取消请求不一定等于取消业务动作。必须区分"停止生成文本"和"停止已经提交的业务执行",后者需要状态机和补偿策略。

六、模型路由与备用模型

可以按任务复杂度选择模型:简单分类和查询使用低成本模型,复杂总结或多步推理使用更强模型。路由规则必须可解释,并记录实际命中模型。

java 复制代码
public ModelRoute route(RequestProfile profile) {
    if (profile.requiresTool() && profile.risk() == RiskLevel.HIGH) {
        return ModelRoute.of("quality-model", Duration.ofSeconds(30));
    }
    if (profile.inputTokens() < 600 && profile.intent() == Intent.CLASSIFY) {
        return ModelRoute.of("fast-model", Duration.ofSeconds(8));
    }
    return ModelRoute.of("balanced-model", Duration.ofSeconds(15));
}

备用模型切换需要注意上下文和工具兼容性。若备用模型不支持某种工具调用格式,不能在超时后无条件切换。高风险场景宁可降级为"展示证据并转人工",也不要为了成功率让不兼容模型执行动作。

七、限流、超时和熔断

限流至少分为用户、租户、接口和模型供应商四层。对 Token 而不是只对请求数限流,因为一个超长请求可能消耗几十个普通请求的资源。

java 复制代码
public void checkQuota(AuthContext auth, UsageEstimate estimate) {
    Quota quota = quotaService.current(auth.tenantId());
    if (quota.remainingTokens() < estimate.inputTokens()) {
        throw new QuotaExceededException("超过租户Token额度");
    }
    rateLimiter.acquire(auth.tenantId(), estimate.weight());
}

超时要分阶段设置:Embedding、检索、Rerank、模型首 Token、模型完成和工具调用分别配置。一个总超时不能替代阶段超时,否则某个下游卡住后很难定位。

熔断发生后,降级逻辑不能让模型凭空回答。可以选择关键词检索、返回已确认的缓存结果、提交异步任务或转人工。

八、重试会放大成本

只对明确的临时错误重试,并设置最大次数和指数退避。重试请求要带相同幂等键,特别是涉及工具调用时。每次重试增加的 Token 和供应商费用都要进入成本统计。

错误 是否通常重试 说明
认证失败 修复配置或权限
参数校验失败 修改输入
429 限流 有条件 按 Retry-After 退避
网络超时 有条件 限次、幂等
供应商 5xx 有条件 备用模型或降级
引用校验失败 最多一次 第二次失败转人工

无限重试既可能制造账单,也可能造成工具重复执行。

九、成本报表

按天、租户、应用、模型、工作流和用户群统计:请求数、输入输出 Token、平均成本、P95 延迟、失败率、重试率和人工转接率。成本报表要能回答"钱花在什么场景、哪个版本、哪个租户、哪类问题"。

高成本请求要保存原因标签,例如上下文过长、工具轮次过多、重复提问、超时重试或模型路由错误。没有原因标签,成本优化只能靠猜。

十、上线检查

  • 是否记录输入输出 Token 和每阶段耗时。
  • 缓存键是否包含租户、权限和知识库版本。
  • 客户端断开后是否取消可取消的后台请求。
  • 工具调用是否使用幂等键。
  • 是否按阶段设置超时和限流。
  • 备用模型是否支持相同的输出和工具协议。
  • 熔断后是否有安全降级,而非无依据回答。
  • 是否有租户级成本预算和告警。

十一、一次可复现的性能实验

建议建立三个固定场景:短问题、长上下文问题和需要工具调用的问题。每个场景分别用 1、5、20、50 并发运行,预热后重复多轮,记录首 Token、完整耗时、输入输出 Token、错误率、重试次数和峰值显存或连接数。不要只跑一次,因为网络抖动和供应商排队会影响结果。

实验报告中至少包含:代码提交号、模型与 Prompt 版本、知识库版本、缓存状态、测试机器、并发、样本数量和统计方式。P95 应说明是对所有请求统计,还是只统计成功请求;失败请求不能被简单剔除,否则结果会过于乐观。

还可以做一个"上下文裁剪前后"的对照:保持模型和问题集不变,只改变证据条数与去重策略,再比较引用准确率、输入 Token 和延迟。如果质量没有下降而成本明显降低,才说明裁剪真正有效。

十二、预算与配额

成本治理最好有租户级预算、应用级预算和单请求硬上限。预算接近阈值时,可以降低非关键场景的模型级别或暂停批量任务;高风险业务则应转人工,而不是悄悄降低质量。所有预算拒绝和降级都要对用户给出明确提示,并在审计中记录。

十三、总结

性能和成本优化的第一步是测量,不是换模型。先把 Token、检索候选、Rerank、模型首 Token、完成时间、重试和工具轮次记录下来,再针对最昂贵、最慢或最容易失败的阶段优化。

一个成熟的 AI 系统应该在"质量、成本、延迟、可靠性"之间做明确取舍:普通问题追求快和便宜,高风险问题追求可验证和可追责,所有降级都必须保留安全边界。

读者讨论

如果你的 AI 应用费用突然上升,建议先按"输入 Token、重试次数、上下文条数、工具轮次"四项拆账,通常很快能定位主因。

相关推荐
风流 少年2 小时前
Spring AI 2.0:Flux
java·人工智能·spring
小马过河R2 小时前
Graph Engineering 深度解析:模型越强,越需要给它画好“地图”
人工智能·langchain·graph·ai工程化·harness·驾驭工程
leisoo80972 小时前
涨停板次日表现因子怎么挖掘本地化Python全流程实战
大数据·人工智能·python
lucas_AI2 小时前
喂张白纸也能吐出证件号?文档 MLLM 的"关系级泄露"被测出来了
人工智能·算法·掘金技术征文
Old Uncle Tom2 小时前
手机银行用户画像设计
人工智能·智能手机
kyriewen2 小时前
前端切图仔被 AI 新闻淹死的第 N 天,我用 TRAE Work 定时任务救了自己
前端·人工智能·trae
手写码匠2 小时前
华为云Flexus+DeepSeek征文|Dify 多 Agent 灰度发布实战:让每一次变更都“小步快跑、随时可回滚“
人工智能·深度学习·算法·aigc
火云牌神2 小时前
分层整洁架构:标准化工程目录结构,防范 AI 越界调用
人工智能·架构·ai编程·分层架构·vibecoding
新知图书2 小时前
8.1 智能体的心跳执行模式:以定时器为核心(智能体工程)
人工智能·agent·ai agent·智能体
墨心@2 小时前
阶段 4:事件总线
人工智能·语言模型·大语言模型·agent·codex·harness