调试进阶教程
AI API 错误处理与调试完全指南:从 429 到 500 全覆盖
2026-04-17 · 约 9 分钟阅读
AI API 错误处理与调试完全指南
用 AI API 时遇到报错是常事,但很多错误都是可以解决的。本文整理了常见错误、排查方法和最佳实践,帮你快速定位和解决问题。
常见错误分类
| 错误类型 | 说明 | 占比 |
|---|---|---|
| 认证错误 | API Key 无效、过期、权限不足 | 30% |
| 速率限制 | 请求太快、超过配额 | 25% |
| 输入错误 | Prompt 太长、格式不对 | 20% |
| 服务端错误 | 平台挂了、超时 | 15% |
| 其他错误 | 网络问题、中转问题 | 10% |
1. 认证错误(最常见)
错误信息:
401 Unauthorized
Invalid API Key
Authentication failed
API key expired
原因:
- Key 写错了(多/少字符)
- Key 已过期/被撤销
- 权限不足(只读 Key 想写操作)
- 中转平台的 Key 和官方不通用
排查步骤:
# 1. 先确认 Key 是否正确
print(f"Key starts with: {api_key[:10]}...") # 只看前 10 位
print(f"Key length: {len(api_key)}") # 长度对吗?
# 2. 用最简单的请求测试
from openai import OpenAI
client = OpenAI(api_key=api_key, base_url=base_url)
try:
# 最简单的测试请求
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Hi"}],
max_tokens=5
)
print("✅ Key 有效!")
except Exception as e:
print(f"❌ 认证失败: {e}")
解决方案:
- ✅ 重新复制 Key(不要手打)
- ✅ 去平台控制台生成新 Key
- ✅ 确认用的是对应平台的 Key(中转≠官方)
- ✅ 检查 Key 是否有空格、换行等不可见字符
2. 速率限制错误
错误信息:
429 Too Many Requests
Rate limit exceeded
Please reduce your request rate
Quota exceeded
You have exceeded your current quota
原因:
- 请求太快(RPM/TPM 超限)
- 本月配额用完了
- 免费额度用光了
- 同一个 Key 被多个程序共用
速率限制规则示例:
| 平台 | RPM(每分钟请求数) | TPM(每分钟 Token 数) |
|---|---|---|
| OpenAI 免费 | 3 | 40,000 |
| OpenAI 付费 | 3,500 | 350,000 |
| 中转平台 | 通常 60-600 | 取决于套餐 |
解决方案 1:添加退避重试
import time
import random
from openai import OpenAI
client = OpenAI(api_key=api_key, base_url=base_url)
def call_with_retry(messages, max_retries=5):
for attempt in range(max_retries):
try:
return client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
except Exception as e:
if "rate limit" in str(e).lower() or "429" in str(e):
# 指数退避 + 抖动
wait_time = (2 ** attempt) + random.uniform(0, 1)
print(f"⚠️ 触发速率限制,等待 {wait_time:.1f}s... (尝试 {attempt+1}/{max_retries})")
time.sleep(wait_time)
else:
# 其他错误直接抛出
raise e
raise Exception("重试次数用完")
# 使用
response = call_with_retry(messages)
解决方案 2:控制并发
from concurrent.futures import ThreadPoolExecutor, as_completed
from threading import Semaphore
# 限制同时最多 5 个请求
semaphore = Semaphore(5)
def safe_call(message):
with semaphore: # 获取信号量
return call_api(message)
# 批量调用,但限制并发
messages_list = [...] # 100 个任务
results = []
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(safe_call, msg) for msg in messages_list]
for future in as_completed(futures):
results.append(future.result())
解决方案 3:队列化
import queue
import threading
import time
class RequestQueue:
def __init__(self, max_per_minute=60):
self.queue = queue.Queue()
self.max_per_minute = max_per_minute
self.last_request = 0
self.lock = threading.Lock()
def add(self, request):
self.queue.put(request)
def worker(self):
while True:
request = self.queue.get()
with self.lock:
# 控制速率
now = time.time()
elapsed = now - self.last_request
min_interval = 60.0 / self.max_per_minute
if elapsed < min_interval:
time.sleep(min_interval - elapsed)
self.last_request = time.time()
# 执行请求
try:
result = execute_request(request)
request.callback(result)
except Exception as e:
request.error_callback(e)
self.queue.task_done()
3. 输入错误
错误信息:
400 Bad Request
Invalid prompt
Prompt is too long
Maximum context length exceeded
Invalid model name
原因 1:上下文太长
# 先算一下大概多少 tokens
def estimate_tokens(text: str) -> int:
"""粗略估算:1 token ≈ 0.75 英文词 ≈ 0.5 中文字"""
# 简单估算(也可以用 tiktoken 精确算)
return int(len(text) * 0.6)
prompt = "很长很长的文本..."
token_count = estimate_tokens(prompt)
model_limit = 128000 # GPT-4o Mini
if token_count > model_limit * 0.9: # 留一点余量
print(f"⚠️ 提示词太长!约 {token_count} tokens,限制 {model_limit}")
# 需要截断或简化
用 tiktoken 精确计算:
import tiktoken
def count_tokens(text: str, model: str = "gpt-4o") -> int:
"""精确计算 token 数"""
encoder = tiktoken.encoding_for_model(model)
return len(encoder.encode(text))
# 使用
print(count_tokens("Hello world!", "gpt-4o")) # 3
解决方法:截断或摘要
def truncate_messages(messages, max_tokens=100000):
"""保留系统提示和最近的对话,截断旧的"""
# 先保留系统提示
system_messages = [m for m in messages if m["role"] == "system"]
other_messages = [m for m in messages if m["role"] != "system"]
# 从后往前取,直到接近限制
result = system_messages.copy()
current_tokens = sum(count_tokens(m["content"]) for m in result)
for msg in reversed(other_messages):
msg_tokens = count_tokens(msg["content"])
if current_tokens + msg_tokens > max_tokens * 0.9:
break
result.insert(len(system_messages), msg)
current_tokens += msg_tokens
return result
原因 2:模型名写错
# ❌ 错误
model="gpt4o" # 少了个 -
model="GPT-4o" # 大小写问题
model="claude3.5" # 格式不对
# ✅ 正确
model="gpt-4o"
model="gpt-4o-mini"
model="claude-3-5-sonnet-20241022"
验证模型是否支持:
# 先获取支持的模型列表
try:
models = client.models.list()
model_ids = [m.id for m in models.data]
print(f"支持的模型: {model_ids}")
except Exception as e:
print(f"无法获取模型列表: {e}")
4. 服务端错误
错误信息:
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
The server had an error
原因:
- 平台挂了
- 中转服务挂了
- 请求超时
- 临时故障
解决方法:
def call_with_fallback(messages):
"""多个平台切换,高可用"""
platforms = [
{"name": "主平台", "client": main_client, "model": "gpt-4o"},
{"name": "备用1", "client": backup_client1, "model": "gpt-4o"},
{"name": "备用2", "client": backup_client2, "model": "claude-3-5-sonnet"},
]
for platform in platforms:
try:
print(f"尝试 {platform['name']}...")
response = platform['client'].chat.completions.create(
model=platform['model'],
messages=messages,
timeout=30 # 设置超时
)
print(f"✅ {platform['name']} 成功")
return response
except Exception as e:
print(f"❌ {platform['name']} 失败: {e}")
continue
raise Exception("所有平台都挂了")
5. 网络问题
错误信息:
Connection error
Request timed out
SSLError
Proxy error
排查步骤:
# 1. 先ping一下
ping api.example.com
# 2. 用 curl 测试
curl -v https://api.example.com/v1/models \
-H "Authorization: Bearer YOUR_KEY"
# 3. 检查是否需要代理
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
代码中配置代理:
from openai import OpenAI
client = OpenAI(
api_key=api_key,
base_url=base_url,
# 配置代理
http_client=httpx.Client(
proxy="http://127.0.0.1:7890",
verify=False # 如果有 SSL 问题
)
)
调试工具
1. 开启详细日志
import logging
import httpx
# 开启 DEBUG 日志
logging.basicConfig(level=logging.DEBUG)
# 或者用 httpx 的日志
client = OpenAI(
api_key=api_key,
base_url=base_url,
http_client=httpx.Client(
timeout=30.0,
transport=httpx.HTTPTransport(
retries=3,
verify=True
)
)
)
2. 捕获完整请求和响应
from openai import OpenAI
import httpx
# 创建一个带日志的 httpx client
class LoggingTransport(httpx.BaseTransport):
def __init__(self, transport):
self.transport = transport
def handle_request(self, request):
print(f"📤 Request: {request.method} {request.url}")
print(f"📤 Headers: {dict(request.headers)}")
if request.content:
print(f"📤 Body: {request.content[:500]}...")
response = self.transport.handle_request(request)
print(f"📥 Response: {response.status_code}")
print(f"📥 Headers: {dict(response.headers)}")
return response
# 使用
client = OpenAI(
api_key=api_key,
base_url=base_url,
http_client=httpx.Client(
transport=LoggingTransport(httpx.HTTPTransport())
)
)
3. 用 Postman/APIDog 测试
如果代码调不通,先用 API 测试工具手动发请求:
- 验证 URL、Key、参数是否正确
- 看返回的具体错误信息
- 对比代码和手动请求的差异
错误处理最佳实践
1. 不要吞掉异常
# ❌ 不好
try:
call_api()
except:
pass # 什么都不做,完全不知道发生了什么
# ✅ 好
try:
call_api()
except Exception as e:
print(f"API 调用失败: {type(e).__name__}: {e}")
# 记录日志
# 发送告警
# 根据错误类型决定是否重试
raise # 或者处理,不要静默失败
2. 区分错误类型
try:
response = call_api()
except AuthenticationError as e:
print("🔐 认证错误,请检查 Key")
rotate_key() # 换个 Key
except RateLimitError as e:
print("⏱️ 速率限制,等会儿再试")
time.sleep(60)
except InvalidRequestError as e:
print("❌ 输入错误,请检查参数")
fix_input()
except APIError as e:
print("⚠️ 服务端错误,试试备用平台")
switch_to_backup()
except Exception as e:
print(f"❓ 未知错误: {e}")
3. 完善的监控
from dataclasses import dataclass
from datetime import datetime
from collections import defaultdict
@dataclass
class APICall:
model: str
success: bool
duration: float
tokens_used: int
error: str = None
class APIMonitor:
def __init__(self):
self.calls = []
self.errors_by_type = defaultdict(int)
def record(self, call: APICall):
self.calls.append(call)
if not call.success:
self.errors_by_type[call.error] += 1
def report(self):
total = len(self.calls)
success = sum(1 for c in self.calls if c.success)
print("=" * 50)
print(f"总调用: {total} | 成功: {success} | 失败: {total-success}")
print(f"成功率: {success/total*100:.1f}%")
print("错误分布:")
for err, count in self.errors_by_type.items():
print(f" {err}: {count}")
print("=" * 50)
常见问题速查
| 问题 | 可能原因 | 快速检查 |
|---|---|---|
| 401 Unauthorized | Key 错/过期 | 重新复制 Key,用简单请求测试 |
| 429 Too Many | 速率超限 | 加退避重试,控制并发 |
| 400 Bad Request | 输入格式错 | 检查模型名、prompt 长度 |
| 5xx Server Error | 服务端问题 | 等会儿再试,或切换平台 |
| Connection Error | 网络/代理问题 | 先 curl 测试,检查代理设置 |
| Timeout | 超时 | 增加 timeout,或换平台 |
总结
调试流程:
1. 看错误信息(仔细读)
2. 简化问题(用最简单的请求测试)
3. 对比正常情况(之前怎么调通的?)
4. 查文档(官方文档 + 社区)
5. 问人(社群、客服)
记住:
- ✅ 加日志,方便排查
- ✅ 加重试,处理临时故障
- ✅ 加降级,保证可用性
- ✅ 加监控,及时发现问题
可在本站按「稳定」标签筛选,查看所有稳定可靠的 API 中转平台。