共计 2287 个字符,预计需要花费 6 分钟才能阅读完成。
痛点分析
在批量调用 ChatGPT API 时,开发者常遇到三类典型问题:

- 速率限制 :官方对每分钟 / 每天的调用次数有严格限制,突发流量会导致 429 错误
- 网络抖动 :长距离 API 调用易受网络波动影响,出现连接超时或半开连接
- 数据清洗 :返回的 JSON 结构可能存在字段缺失或嵌套差异,需要统一处理
例如当采集 10 万条对话数据时,同步请求需要约 28 小时(按 3 秒 / 请求计算),而网络异常可能导致 5%-15% 的请求需要重试。
架构设计
推荐的分层处理流程:
- 请求队列层 :使用 Redis 存储待处理请求,实现动态限流
- 异步执行层 :aiohttp 协程池并发处理,单个 worker 支持 500+ QPS
- 缓存层 :对成功响应建立本地 SQLite 缓存,避免重复请求
- 清洗层 :通过 pandas dataframe 统一标准化输出格式
关键组件交互逻辑:
flowchart LR
A[原始数据] --> B{敏感词过滤}
B -->| 通过 | C[请求队列]
C --> D[异步 worker 集群]
D -->| 失败 | E[重试队列]
D -->| 成功 | F[结果缓存]
F --> G[标准化输出]
核心代码实现
带退避机制的异步请求
import aiohttp
import asyncio
from tenacity import retry, wait_exponential
class ChatGPTCollector:
def __init__(self, api_key):
self.semaphore = asyncio.Semaphore(100) # 并发控制
@retry(wait=wait_exponential(multiplier=1, max=60))
async def fetch_data(self, session, prompt):
async with self.semaphore: # 限流
try:
async with session.post(
'https://api.openai.com/v1/chat/completions',
json={"model": "gpt-3.5-turbo", "messages": [{"role":"user", "content": prompt}]},
timeout=aiohttp.ClientTimeout(total=30)
) as resp:
if resp.status == 429:
retry_after = int(resp.headers.get('Retry-After', 10))
await asyncio.sleep(retry_after)
raise Exception("Rate limited")
return await self._process_response(await resp.json())
except Exception as e:
print(f"Request failed: {str(e)}")
raise
def _process_response(self, raw_data):
# 标准化输出字段
return {"id": raw_data["id"],
"content": raw_data["choices"][0]["message"]["content"],
"tokens": raw_data["usage"]["total_tokens"]
}
敏感词过滤中间件
from ahocorasick import Automaton
class ContentFilter:
def __init__(self):
self.automaton = Automaton()
for word in ["暴力", "违禁品", "歧视性用语"]: # 可替换为实际词库
self.automaton.add_word(word, word)
self.automaton.make_automaton()
def check(self, text):
for end_index, original_value in self.automaton.iter(text):
return False # 存在敏感词
return True
性能优化
通过测试 10 万条请求(单台 4 核 8G 服务器):
| 模式 | 总耗时 | 平均 QPS | 错误率 |
|---|---|---|---|
| 同步请求 | 28h | 1 | 12% |
| 异步 (100 并发) | 45min | 37 | 3.7% |
| 异步 + 缓存 | 22min | 76 | 1.2% |
关键优化点:
- 使用 uvloop 替代默认事件循环,提升 15% 吞吐量
- 保持 TCP 长连接复用,减少 3 次握手开销
- 对响应数据启用 zstd 压缩,网络传输体积减少 60%
合规实践
根据 GDPR 要求必须注意:
- 数据脱敏 :对返回内容中的邮箱 / 手机号进行正则替换
import re re.sub(r'\b[\w.%-]+@[\w.-]+\.[a-zA-Z]{2,6}\b', '[EMAIL]', text) - 内容审核 :集成 OpenAI 的 moderation API
async with session.post( 'https://api.openai.com/v1/moderations', json={"input": user_input} ) as resp: if (await resp.json())["results"][0]["flagged"]: return None - 日志加密 :使用 AES 加密存储原始请求日志
避坑指南
- 429 错误雪崩 :在重试队列中添加随机延迟(0.5- 2 秒)
- 上下文丢失 :为每个对话维护独立的 session_id
- JSON 解析失败 :先用 json5 库处理非标准格式
延伸思考
当处理多语言对话数据时,如何确保中文提问与英文回答之间的语义一致性?可能的方案包括:
- 使用句子嵌入向量计算相似度
- 构建多语言知识图谱
- 引入人工校验工作流
欢迎在评论区分享你的实践经验。
正文完
