共计 1956 个字符,预计需要花费 5 分钟才能阅读完成。
问题本质
在 LLM 应用中,Token 消耗的计算可以表示为:

总 Token = 输入 Token + 输出 Token
其中输入 Token 包括:
- 系统提示词(System Prompt)
- 对话历史(Chat History)
- 当前用户输入(User Input)
Agent 场景下 Token 激增的主要原因有:
- 长上下文保持:Agent 需要记忆多轮对话历史
- 工具调用:每次工具调用都会增加 prompt 长度
- 结果精炼:Agent 通常会对原始输出进行多次加工
技术方案对比
方案 1:传统动态 Prompt 拼接
特点:
- 每次请求完整拼接所有上下文
- 简单直接但 Token 消耗高
- 典型实现方式:
prompt = system_prompt + chat_history + user_input
方案 2:结构化指令模板
优化点:
- 使用固定模板替代自由文本
- 通过占位符动态填充内容
- 节省效果:15-20%
示例模板:
[系统角色]{{role}}
[历史摘要]{{summary}}
[当前输入]{{input}}
[输出格式]{{format}}
方案 3:语义缓存 + 差分更新
进阶方案:
- 缓存相似请求的语义表示
- 只发送差异部分
- 节省效果:30%+
关键技术:
- 语义相似度计算(如 cosine similarity)
- 差分编码算法
- LRU 缓存淘汰
核心代码实现
压缩 Prompt 模板
from langchain.prompts import ChatPromptTemplate
compress_template = """
[系统]你是一个专业的 {{role}},请用{{style}} 风格回答
[背景]{{context}}
[当前]{{query}}
[要求]{{requirement}}
"""
prompt = ChatPromptTemplate.from_template(compress_template)
语义缓存实现
from datetime import timedelta
import hashlib
class SemanticCache:
def __init__(self, max_size=1000, ttl=timedelta(hours=1)):
self.cache = {}
self.max_size = max_size
self.ttl = ttl
def get_key(self, text):
# 使用 SHA-256 生成语义指纹
return hashlib.sha256(text.encode()).hexdigest()
def get(self, key):
if key in self.cache:
entry = self.cache[key]
if datetime.now() - entry['time'] < self.ttl:
return entry['response']
del self.cache[key]
return None
def set(self, key, response):
if len(self.cache) >= self.max_size:
# LRU 淘汰
oldest_key = next(iter(self.cache))
del self.cache[oldest_key]
self.cache[key] = {
'response': response,
'time': datetime.now()}
生产级优化
监控指标
- Token/ 请求比 = 总 Token 数 / 有效请求数
- 缓存命中率 = 缓存命中次数 / 总请求数
- 平均响应时延
失败回滚策略
- 设置超时阈值(如 5 秒)
- 降级方案:
- 关闭缓存
- 使用简化版 prompt
- 返回预定义兜底响应
供应商适配
| 供应商 | KV Cache 支持 | 最大上下文 |
|---|---|---|
| OpenAI | 是 | 128K |
| Claude | 部分 | 200K |
| Gemini | 否 | 32K |
避坑指南
过度压缩问题
症状:
– 意图理解错误率上升
– 输出结果偏离预期
解决方案:
1. 保留关键指令原文
2. 设置压缩率上限(如不超过 50%)
缓存雪崩防护
预防措施:
1. 分级缓存(内存 +Redis)
2. 随机 TTL(±10% 波动)
3. 预热机制
敏感信息过滤
实现方案:
def sanitize_input(text):
patterns = [r'\b(密码 |token| 密钥)\b', # 关键词匹配
r'\d{4}-\d{4}-\d{4}-\d{4}' # 银行卡号模式
]
for pattern in patterns:
text = re.sub(pattern, '[REDACTED]', text)
return text
实践心得
经过三个月的生产环境验证,我们的客服 Agent 系统实现了:
- Token 消耗降低 42%
- 平均响应时间缩短 35%
- 99 分位延迟下降 28%
关键收获:
1. 结构化模板对工具调用场景最有效
2. 语义缓存在长对话中收益最大
3. 需要平衡压缩率与意图保持
建议从小规模实验开始,逐步验证各方案的实际效果。特别注意不同 LLM 提供商对压缩策略的响应差异,比如 Claude 对指令模板的适应性就明显优于 GPT-4。
正文完
