共计 2109 个字符,预计需要花费 6 分钟才能阅读完成。
需求场景
- 典型问题分析
- Token 计算误差:实际消耗 token 常超出预估,导致账单不可控
- 流式响应中断:网络波动时半截回复影响用户体验
- 速率限制:突发流量触发 429 错误(每分钟 3,500 请求限制)
-
上下文丢失:超过 4,096 tokens 时历史对话被截断

-
业务影响
- 直接调用 API 的失败率可达 15%(基于压测数据)
- 未优化的对话系统单次调用延迟可能超过 5 秒
架构设计
-
API 选型对比
| 特性 | Completion API | Chat API |
|————|———————|———————|
| 适用场景 | 单轮文本生成 | 多轮对话 |
| 上下文管理 | 需手动拼接 | 自动维护对话状态 |
| 成本控制 | 难预测 token 消耗 | 可估算对话回合数 | -
流式传输决策树
- 启用 stream 的场景:
- 响应内容超过 512 tokens
- 需要实时显示生成过程
- 移动端网络环境较差时
- 禁用 stream 的场景:
- 需要精确计算 token 消耗
- 必须保证原子性响应
核心实现
Python 请求封装示例
import httpx
from typing import AsyncGenerator
class ChatGPTClient:
def __init__(self, api_key: str):
self.base_url = "https://api.openai.com/v1"
self.headers = {"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
async def stream_chat(
self,
messages: list[dict],
model: str = "gpt-3.5-turbo"
) -> AsyncGenerator[str, None]:
payload = {
"model": model,
"messages": messages,
"stream": True,
"temperature": 0.7
}
async with httpx.AsyncClient(timeout=30.0) as client:
try:
response = await client.post(f"{self.base_url}/chat/completions",
headers=self.headers,
json=payload
)
response.raise_for_status()
async for chunk in response.aiter_lines():
if chunk.startswith("data:"):
yield chunk[6:].strip()
except httpx.ReadTimeout:
yield "[ERROR] 响应超时,请重试"
except httpx.HTTPStatusError as e:
yield f"[ERROR] API 请求失败: {e.response.status_code}"
流式响应处理要点
- 网络中断补偿方案:
- 记录最后收到的 chunk ID
-
重连时携带 last_id 参数继续请求
-
性能优化技巧:
- 使用 HTTP/ 2 多路复用降低连接开销
- 设置合理的 TCP keepalive(建议 60 秒)
生产级优化
-
成本控制矩阵
| 参数 | 质量倾向设置 | 成本倾向设置 |
|————–|——————–|——————–|
| max_tokens | 1024 | 256 |
| temperature | 0.9 | 0.3 |
| top_p | 0.95 | 0.5 | -
Redis 幂等设计
import redis from hashlib import md5 r = redis.Redis() def request_hash(prompt: str, user_id: str) -> str: return md5(f"{prompt}_{user_id}".encode()).hexdigest() def check_duplicate(hash_key: str, ttl: int = 300) -> bool: if r.exists(hash_key): return True r.setex(hash_key, ttl, "1") return False
合规与安全
- GDPR 关键要求
- 默认关闭用户数据日志记录(设置
logprobs=False) - 欧盟用户请求必须路由到
eu-east-1区域 -
实现数据删除 API(30 天强制过期)
-
上下文管理反模式
- ❌ 将所有历史对话塞入单次请求
- ❌ 用本地缓存存储完整对话记录
- ✅ 推荐方案:
- 维护消息摘要(SHA256)
- 只保留最近 3 轮对话
延伸思考
异步日志系统设计挑战
1. 如何在不阻塞主流程的情况下记录:
– 请求 / 响应元数据
– 性能指标(响应时间、token 消耗)
– 错误分类统计
- 考虑采用的技术栈:
- 消息队列(Kafka/RabbitMQ)缓冲日志
- Fluentd 日志收集管道
-
时序数据库(InfluxDB)存储指标
-
关键指标看板应包含:
- 成功率热力图(按时间段 / 地域)
- 平均响应时间百分位
- Token 消耗成本趋势
实战建议
– 每次版本更新后对比 A / B 测试组的 API 错误率
– 为不同业务线配置独立的 API 配额池
– 使用 Hystrix 实现熔断降级

