作者:互联网 时间: 2026-07-18 07:29:55
采集多个AI平台的模型回答时,每个平台的API认证、请求格式、响应结构和限流策略都不同。直接拼接调用会导致代码耦合、数据混乱和难以维护。本文从工程实践出发,介绍如何通过适配器模式设计一个多平台采集系统,包括统一数据模型、适配器接口、异常处理与重试策略,以及原始回答入库的实现。适合需要构建或优化AI回答采集系统的后端开发者、数据工程师和AI应用开发者。前提是熟悉HTTP请求、JSON处理和基本的错误处理模式。

为了持续观察不同AI平台对特定问题的回答情况,需要定期向多个平台发送预设问题并收集原始回答。实际约束包括:
初期采用硬编码方式,为每个平台写独立的采集函数。问题很快暴露:
例如,豆包和文心一言的响应结构不同:
// 豆包响应示例(假设)
{
"id": "chatcmpl-xxx",
"choices": [{"message": {"content": "回答内容"}}]
}
// 文心一言响应示例(假设)
{
"result": "回答内容"
}
硬编码方式下,每个平台的解析逻辑都耦合在采集函数中,维护成本高。
根本原因是平台差异没有被隔离,导致代码重复和耦合。需要引入设计模式将变化封装起来,对外暴露统一接口。适配器模式适合解决这类问题。
| 方案 | 优点 | 缺点 |
|---|---|---|
| 硬编码 | 简单直接 | 重复代码多,维护困难 |
| 工厂模式 | 创建对象灵活 | 仍需要处理不同接口 |
| 适配器模式 | 隔离平台差异,扩展性好 | 需要定义统一接口 |
| 策略模式 | 运行时切换算法 | 不适合固定平台差异 |
选择适配器模式,因为每个平台的差异是固定的,适配器可以封装所有差异,新增平台只需添加新适配器。
定义一个基础的回答模型,所有适配器返回此模型:
from pydantic import BaseModel
from datetime import datetime
from typing import Optional
class AIResponse(BaseModel):
platform: str # 平台标识,如"doubao"
model: str # 模型名称
question: str # 原始问题
raw_text: str # 模型返回的原始文本
request_id: Optional[str] # 平台请求ID,用于追踪
timestamp: datetime # 请求时间
status: str # "success" 或 "failed"
error_message: Optional[str] # 失败时的错误信息
定义抽象基类:
from abc import ABC, abstractmethod
class PlatformAdapter(ABC):
@abstractmethod
def send_request(self, question: str) -> AIResponse:
pass
@abstractmethod
def parse_response(self, raw_response: dict) -> str:
"""从原始响应中提取回答文本"""
pass
以下为通用示例,具体参数请参考各平台官方文档。
import requests
class DoubaoAdapter(PlatformAdapter):
def __init__(self, api_key: str, endpoint: str):
self.api_key = api_key
self.endpoint = endpoint
def send_request(self, question: str) -> AIResponse:
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
payload = {
"model": "", # 替换为实际模型名
"messages": [{"role": "user", "content": question}]
}
try:
resp = requests.post(self.endpoint, headers=headers, json=payload, timeout=30)
resp.raise_for_status()
data = resp.json()
raw_text = self.parse_response(data)
return AIResponse(
platform="doubao",
model="" ,
question=question,
raw_text=raw_text,
request_id=data.get("id"),
timestamp=datetime.utcnow(),
status="success"
)
except requests.exceptions.RequestException as e:
return AIResponse(
platform="doubao",
model="" ,
question=question,
raw_text="",
timestamp=datetime.utcnow(),
status="failed",
error_message=str(e)
)
def parse_response(self, raw_response: dict) -> str:
# 假设响应结构为 {"choices": [{"message": {"content": "..."}}]}
return raw_response["choices"][0]["message"]["content"]
from typing import List
import time
class Collector:
def __init__(self, adapters: List[PlatformAdapter]):
self.adapters = adapters
def collect(self, question: str) -> List[AIResponse]:
results = []
for adapter in self.adapters:
result = adapter.send_request(question)
results.append(result)
# 简单限流:每个请求间隔1秒
time.sleep(1)
return results
将结果存入数据库,保留原始JSON:
def save_response(db_connection, response: AIResponse):
query = """
INSERT INTO raw_responses (platform, model, question, raw_text, request_id, timestamp, status, error_message)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
"""
params = (
response.platform,
response.model,
response.question,
response.raw_text,
response.request_id,
response.timestamp,
response.status,
response.error_message
)
db_connection.execute(query, params)
正常情况下,每个平台应返回成功状态,raw_text非空,request_id存在。限流时日志显示重试,最终成功或失败。网络异常时日志记录错误,状态为failed。数据完整性可通过数据库查询验证。
具体性能数据(如QPS、响应时间)取决于网络环境和平台限流策略,本文不提供虚构数据。
适配器模式有效隔离了平台差异,新增平台只需添加一个适配器类,不影响现有逻辑。统一数据模型保证了下游解析和指标计算的稳定性。异常处理和重试机制提高了系统的鲁棒性。但需注意,平台接口频繁变更时,适配器的维护成本会上升,建议定期回归测试。另外,不同平台的响应时间差异可能影响调度策略,后续可考虑异步并发采集以提升效率。