共计 2386 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
ChatGPT API 采用按 token 收费的模式,这里的 token 不是传统意义上的会话令牌,而是文本处理的基本单位。具体来说:

- 英文中 1 个 token 约等于 4 个字符
- 中文 1 个汉字通常为 2 - 3 个 token
- 标点符号、空格也都计入 token
在长对话和复杂查询场景下,token 消耗会快速累积:
- 多轮对话时,每次请求都需要携带完整上下文历史
- 复杂查询往往需要详细描述问题背景
- 系统提示词 (prompt) 会固定占用部分 token
实测数据显示,一个包含 10 轮对话的 session 可能消耗 8000+token,按照 gpt-3.5-turbo 的 $0.002/1K tokens 计算,单次对话成本就达 $0.016。对于高频调用的应用,这笔开销不容忽视。
技术方案
提示词压缩技术
优化提示词是减少 token 消耗的最直接方法:
- 删除冗余修饰词
- 将 ” 请用非常详细和专业的语言解释 ” 简化为 ” 解释 ”
-
“ 能否请你 ” -> “ 请 ”
-
使用标准缩写
- “ 例如 ” -> “e.g.”
-
“ 也就是说 ” -> “i.e.”
-
简化示例结构
- 用伪代码代替完整代码示例
- 用类型提示替代详细注释
测试表明,经过优化的提示词可以节省 15-30% 的 token 用量,而对输出质量影响微乎其微。
对话状态缓存
实现高效的上下文管理:
- 生成对话摘要
- 每 3 - 5 轮对话生成一次关键信息摘要
-
后续请求携带摘要而非完整历史
-
LRU 缓存实现
- 为每个会话维护缓存队列
-
设置合理的 TTL(如 30 分钟)
-
向量化检索
- 用 embedding 存储历史问答对
- 新问题时先检索相似历史记录
模型版本选择
gpt-3.5-turbo 与 gpt- 4 的成本对比:
| 模型 | 输入 token 成本 | 输出 token 成本 | 适合场景 |
|---|---|---|---|
| gpt-3.5-turbo | $0.0015/1K | $0.002/1K | 通用对话、代码补全 |
| gpt-4 | $0.03/1K | $0.06/1K | 复杂推理、创意生成 |
建议先用 gpt-3.5-turbo 测试效果,仅在必要时切换 gpt-4。
代码示例
上下文摘要生成
def generate_dialog_summary(messages: list, model="gpt-3.5-turbo") -> str:
"""
生成对话摘要,保留关键信息
:param messages: 原始对话记录
:param model: 使用的模型版本
:return: 摘要文本
"""prompt =""" 请将以下对话压缩为不超过 100 字的摘要,保留:
1. 核心问题
2. 关键结论
3. 待解决事项
对话记录:
"""+'\n'.join([f"{m['role']}: {m['content']}" for m in messages])
response = openai.ChatCompletion.create(
model=model,
messages=[{"role": "user", "content": prompt}],
max_tokens=150
)
return response.choices[0].message.content
带 TTL 的 LRU 缓存
from datetime import datetime, timedelta
import hashlib
class DialogCache:
def __init__(self, max_size=100, ttl=1800):
self.cache = {}
self.max_size = max_size
self.ttl = timedelta(seconds=ttl)
def _get_key(self, session_id: str) -> str:
return hashlib.md5(session_id.encode()).hexdigest()
def get(self, session_id: str) -> list:
key = self._get_key(session_id)
if key in self.cache and datetime.now() - self.cache[key]['time'] < self.ttl:
return self.cache[key]['messages']
return None
def set(self, session_id: str, messages: list):
if len(self.cache) >= self.max_size:
oldest_key = min(self.cache, key=lambda k: self.cache[k]['time'])
del self.cache[oldest_key]
key = self._get_key(session_id)
self.cache[key] = {
'messages': messages,
'time': datetime.now()}
性能考量
优化策略效果对比
| 策略 | Token 节省率 | 响应时间影响 | 实现复杂度 |
|---|---|---|---|
| 提示词压缩 | 15-30% | 无 | 低 |
| 对话摘要 | 40-60% | +100-300ms | 中 |
| 模型降级 | 成本降 95% | 质量可能下降 | 低 |
| 本地缓存 | 20-40% | 无 | 中 |
延迟与成本平衡
- 实时性要求高的场景
- 优先使用提示词压缩
-
避免频繁生成摘要
-
批处理场景
- 可启用完整优化链
- 利用非高峰时段预生成内容
避坑指南
语义保留
- 测试不同压缩级别
- 确保关键指令不被省略
-
保留必要的上下文线索
-
监控质量指标
- 记录用户反馈评分
- 跟踪任务完成率
缓存一致性
- 版本控制
- 当修改 prompt 时清空相关缓存
-
为缓存键添加模型版本标识
-
失效策略
- 关键信息变更时主动失效缓存
- 设置合理的 TTL 值
并发限流
- 分级限流
- 严格限制 gpt- 4 的并发数
-
对 gpt-3.5-turbo 适当放宽
-
异步处理
- 非实时请求入队列处理
- 实现优先级调度
结语
通过组合应用这些优化策略,我们的生产系统实现了平均 37% 的 token 节省,月 API 成本从 $1200 降至 $750。值得思考的是:
- 能否利用更精细的文本分割 (token-level) 来进一步优化?
- 如何建立自动化的 prompt 优化流程?
- 是否可以通过用户行为预测来预生成内容?
期待大家分享各自的优化经验,共同探索更高效的 API 使用模式。
正文完
发表至: 未分类
近一天内
