饮墨

子安饮墨馀三斗,留与卿儿作赋来

AI Agent 生产环境 Token 成本砍半:语义缓存 + Prompt Cache + 智能路由 3 步实战

1 views

痛点

AI Agent 上线后,Token 账单往往是最大的"惊喜"。一个中等规模的客服 Agent,日均处理 5000 次对话,每次对话平均消耗 4000 tokens,按 Claude/GPT-4 级别模型计算,月费轻松突破 $3000+。更扎心的是——70% 以上的请求存在高度相似性,重复为相同问题付费。

真实场景:某 SaaS 平台的运维 Agent,处理告警自动诊断。80% 的告警是同类问题(CPU 高、磁盘满、OOM),每次都从头推理,token 白白烧掉。

方案

三层优化策略,叠加使用可降低 50-70% 的 Token 开销:

  1. 语义缓存(Semantic Cache)— 相似问题命中缓存,直接返回历史结果
  2. Prompt Cache— 利用模型厂商的 Prompt Caching 特性,减少重复前缀计费
  3. 智能路由(Model Routing)— 简单任务走小模型,复杂任务走大模型

实操步骤

第 1 步:部署语义缓存层

用 Redis + 向量相似度实现语义缓存。核心逻辑:将用户 query 转为 embedding,在缓存中查找相似度 > 0.95 的历史结果。

import hashlib
import json
import numpy as np
import redis
from openai import OpenAI

client = OpenAI()
r = redis.Redis(host="localhost", port=6379, db=0)

SIMILARITY_THRESHOLD = 0.95
CACHE_TTL = 3600  # 1小时过期

def get_embedding(text: str) -> list[float]:
    resp = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return resp.data[0].embedding

def cosine_similarity(a: list[float], b: list[float]) -> float:
    a, b = np.array(a), np.array(b)
    return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

def semantic_cache_get(query: str) -> str | None:
    query_emb = get_embedding(query)
    # 扫描缓存中的 embedding keys
    for key in r.scan_iter("cache:emb:*"):
        cached_emb = json.loads(r.get(key))
        if cosine_similarity(query_emb, cached_emb["embedding"]) > SIMILARITY_THRESHOLD:
            return cached_emb["response"]
    return None

def semantic_cache_set(query: str, response: str):
    emb = get_embedding(query)
    cache_key = f"cache:emb:{hashlib.md5(query.encode()).hexdigest()}"
    r.setex(cache_key, CACHE_TTL, json.dumps({
        "embedding": emb,
        "response": response
    }))

生产环境建议用 GPTCacheRedis 向量搜索模块(RediSearch) 替代暴力扫描,支持百万级缓存条目的毫秒级检索。

第 2 步:启用 Prompt Cache

Anthropic Claude 和 OpenAI 均支持 Prompt Caching——对请求中重复的 system prompt / 前缀部分,后续调用只收 10-25% 的费用。

from anthropic import Anthropic

anthropic = Anthropic()

# 将大段 system prompt 标记为可缓存
SYSTEM_PROMPT = """你是运维诊断 Agent,负责分析告警并给出修复方案...
(此处省略 2000 tokens 的规则和知识库内容)"""

def call_with_cache(user_query: str) -> str:
    response = anthropic.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        system=[{
            "type": "text",
            "text": SYSTEM_PROMPT,
            "cache_control": {"type": "ephemeral"}  # 标记缓存
        }],
        messages=[{"role": "user", "content": user_query}]
    )
    return response.content[0].text

关键配置cache_control: {"type": "ephemeral"} 标记后,相同前缀在 5 分钟内的后续请求,缓存命中部分按原价 10% 计费。对于 system prompt 占比 60%+ 的 Agent,这一项就能省 40-50%。

第 3 步:配置智能模型路由

用 LiteLLM 或自建路由层,根据任务复杂度分流:

# litellm_config.yaml
model_list:
  - model_name: "agent-router"
    litellm_params:
      model: "claude-sonnet-4-20250514"
      api_key: "sk-xxx"
    model_info:
      id: "complex"

  - model_name: "agent-router"
    litellm_params:
      model: "claude-haiku-3"
      api_key: "sk-xxx"
    model_info:
      id: "simple"

router_settings:
  routing_strategy: "cost-based"  # 成本优先路由
  allowed_fails: 2
  num_retries: 3

路由判定逻辑(在 Agent 框架层实现):

def classify_and_route(query: str) -> str:
    """简单分类器,决定走大模型还是小模型"""
    simple_patterns = [
        "磁盘使用率", "CPU 高", "内存不足", "服务重启",
        "证书过期", "DNS 解析失败"
    ]
    # 匹配常见模式走小模型
    if any(p in query for p in simple_patterns):
        return "claude-haiku-3"  # 成本仅为 Sonnet 的 1/10
    return "claude-sonnet-4-20250514"

生产环境推荐用一个微调过的小分类模型(如 distilbert)做意图分类,准确率可达 95%+。

避坑

  1. 语义缓存阈值不能设太低:相似度阈值低于 0.90 会导致误命中,返回不相关的历史答案。建议从 0.95 起步,观察一周后逐步调到 0.92-0.93。同时对缓存结果加一层"答案相关性校验"兜底。

  2. Prompt Cache 有最小 token 要求:Anthropic 要求可缓存部分至少 1024 tokens(Claude Sonnet/Opus),OpenAI 要求 1024 tokens。如果你的 system prompt 太短,缓存不会生效。解决方案:将知识库、Few-shot 示例合并到 system prompt 中凑够长度。

  3. 模型路由的"灰色地带"问题:不是所有 query 都能清晰分为"简单/复杂"。对于分类不确定的请求,先走小模型,加一个置信度检查——如果小模型输出置信度低于阈值,自动 fallback 到大模型重试。这比一律走大模型省钱,比一律走小模型靠谱。

总结

策略 节省幅度 实施难度 适用场景
语义缓存 30-50% 高重复率场景(客服/告警)
Prompt Cache 20-40% System Prompt 长的 Agent
智能路由 40-60% 任务复杂度差异大的场景

三者叠加,实测可将月度 Token 账单从 $3000 压到 $800-1200。优先落地 Prompt Cache(零改造成本),再上语义缓存(ROI 最高),最后精细化模型路由。成本优化的核心原则:不为重复问题重复付费,不为简单问题过度付费