共计 3990 个字符,预计需要花费 10 分钟才能阅读完成。
背景痛点分析
在实际对接 Claude 和 DeepSeek 这两个 AI 服务时,开发者经常会遇到以下几个典型问题:

- API 规范差异:Claude 使用 RESTful 风格接口,而 DeepSeek 采用 GraphQL 查询语言,请求结构和参数完全不同
- 响应格式不统一:Claude 返回嵌套 JSON 结构,DeepSeek 则采用平铺式数据格式,导致下游处理逻辑需要分别适配
- 认证机制不同:Claude 支持简单的 API Key 验证,DeepSeek 要求 OAuth2.0 token,每次调用都需要处理认证流程
- 限流策略各异 :Claude 按每分钟请求数(RPM) 限流,DeepSeek 采用并发连接数限制,需要不同的流量控制策略
技术方案设计
1. 适配器模式架构
我们采用适配器模式 (Adapter Pattern) 来统一不同 AI 服务的接口,核心模块包括:
- 鉴权适配层:处理各种认证方式
- 请求转换器:将标准请求格式转为各 API 需要的结构
- 响应归一化:统一处理不同格式的返回数据
2. 鉴权模块封装
# 认证工厂类示例
class AuthFactory:
@staticmethod
def get_auth_handler(api_type):
if api_type == 'claude':
return ClaudeAuth()
elif api_type == 'deepseek':
return DeepSeekOAuth()
else:
raise ValueError('Unsupported API type')
# Claude 的 API Key 认证实现
class ClaudeAuth:
def __init__(self):
self.api_key = os.getenv('CLAUDE_KEY')
def get_headers(self):
return {'Authorization': f'Bearer {self.api_key}'}
# DeepSeek 的 OAuth2.0 实现
class DeepSeekOAuth:
def __init__(self):
self.token_url = 'https://api.deepseek.com/oauth/token'
self._refresh_token()
def _refresh_token(self):
# 实际实现应包含重试逻辑和错误处理
response = requests.post(self.token_url, auth=(CLIENT_ID, SECRET))
self.access_token = response.json()['access_token']
def get_headers(self):
return {'Authorization': f'Bearer {self.access_token}'}
3. 请求 / 响应标准化
# 请求转换器示例
class RequestAdapter:
@staticmethod
def to_claude(prompt, max_tokens):
return {
'prompt': prompt,
'max_tokens_to_sample': max_tokens,
'stop_sequences': ['\n\nHuman:']
}
@staticmethod
def to_deepseek(prompt, max_tokens):
return {
'query': f'''{{generate(prompt: "{prompt}",
maxTokens: {max_tokens}) {{text}}
}}'''
}
# 响应归一化处理
class ResponseNormalizer:
@staticmethod
def from_claude(response):
try:
data = response.json()
return {'text': data['completion'],
'usage': data['usage']
}
except KeyError as e:
raise ValueError(f'Invalid Claude response: {str(e)}')
@staticmethod
def from_deepseek(response):
try:
data = response.json()
return {'text': data['data']['generate']['text'],
'usage': None # DeepSeek 不返回用量数据
}
except KeyError as e:
raise ValueError(f'Invalid DeepSeek response: {str(e)}')
核心代码实现
1. 异步调用示例
import aiohttp
from backoff import on_exception, expo
class AIClient:
def __init__(self, session: aiohttp.ClientSession):
self.session = session
@on_exception(expo, aiohttp.ClientError, max_tries=3)
async def call_api(self, url, payload, headers):
async with self.session.post(url, json=payload, headers=headers) as resp:
if resp.status != 200:
error = await resp.text()
raise ValueError(f'API error: {error}')
return await resp.json()
2. 请求签名生成
import hmac
import hashlib
import base64
def generate_signature(secret, message):
"""
HMAC-SHA256 签名生成算法
:param secret: API 密钥
:param message: 请求体原始数据
:return: Base64 编码的签名字符串
"""byte_key = secret.encode('utf-8')
message = message.encode('utf-8')
hashed = hmac.new(byte_key, message, hashlib.sha256)
return base64.b64encode(hashed.digest()).decode('utf-8')
生产环境考量
1. 连接池配置建议
conn = aiohttp.TCPConnector(
limit=100, # 最大连接数
limit_per_host=20, # 每个 host 最大连接
enable_cleanup_closed=True, # 自动清理关闭的连接
force_close=False # 禁用强制关闭
)
async with aiohttp.ClientSession(connector=conn) as session:
# 业务代码
2. Prometheus 监控指标示例
from prometheus_client import Counter, Histogram
# 定义指标
API_CALLS = Counter('ai_api_calls_total', 'Total API calls', ['service', 'status'])
LATENCY = Histogram('ai_api_latency_seconds', 'API response latency', ['service'])
# 在调用处记录
@LATENCY.time()
async def call_api():
try:
response = await actual_api_call()
API_CALLS.labels(service='claude', status='success').inc()
return response
except Exception:
API_CALLS.labels(service='claude', status='fail').inc()
raise
避坑指南
1. 证书链验证失败
现象:调用 DeepSeek API 时出现 SSL 证书验证错误
解决方案:
# 临时方案(不推荐生产环境使用)conn = aiohttp.TCPConnector(ssl=False)
# 正确方案:更新本地证书包
# Ubuntu/Debian: sudo update-ca-certificates
# CentOS/RHEL: sudo update-ca-trust
2. 分块传输编码问题
现象:接收到的响应数据不完整
解决方案:
# 显式禁用分块传输
headers = {'Accept-Encoding': 'identity'}
# 或者在读取响应时检查
async with session.post(...) as resp:
if resp.chunked:
data = await resp.read() # 一次性读取
else:
data = await resp.json()
3. 速率限制处理
现象:API 返回 429 状态码
解决方案:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, max=60)
)
async def call_api_with_retry():
# API 调用代码
总结与思考
通过本文的实践方案,我们已经成功搭建了一个可同时对接 Claude 和 DeepSeek 的 AI 服务集成层。但值得思考的是:当我们需要接入第三个 AI 服务时,当前的架构是否仍然适用?
可能的扩展方向包括:
- 采用插件化架构,每个 AI 服务作为独立插件加载
- 引入服务发现机制,动态获取 API 终端配置
- 实现统一的流量控制和熔断机制
这些思考留待读者在实践中进一步探索和完善。
正文完
