5.1 模型抽象层架构概览
模型抽象层是OpenAI Agents SDK的核心组件,负责统一不同模型提供商的API接口,实现"提供商无关性"的设计目标。该层主要包含:
- 接口定义层: 定义统一的模型接口
- 提供商实现层: 实现具体的模型调用逻辑
- 多提供商管理层: 管理和选择不同的模型提供商
- 模型设置层: 统一的模型参数配置
5.2 模型抽象架构图
graph TD
A[Agent代理] --> B[Model接口]
B --> C{模型提供商选择}
C --> D[OpenAIProvider]
C --> E[LiteLLMProvider]
C --> F[自定义Provider]
D --> G[OpenAI Responses API]
D --> H[OpenAI Chat Completions API]
E --> I[Anthropic Claude]
E --> J[Google Gemini]
E --> K[其他100+模型]
F --> L[自定义模型实现]
B --> M[ModelSettings 模型设置]
M --> N[温度参数]
M --> O[最大token数]
M --> P[工具选择策略]
M --> Q[推理设置]
style B fill:#e3f2fd
style C fill:#f3e5f5
style M fill:#e8f5e8
5.3 Model接口定义详解
5.3.1 核心Model接口
# 位于 src/agents/models/interface.py
from abc import ABC, abstractmethod
from typing import Any, AsyncIterator, Generic, TypeVar
from openai.types.responses import ResponsePromptParam
class Model(ABC):
"""
模型的抽象基类,定义了所有模型实现必须遵循的接口
这个接口使得框架可以支持不同的模型提供商,
而代理层不需要关心具体的实现细节
"""
@abstractmethod
async def get_response(
self,
system_instructions: str | None, # 系统指令(系统提示)
input: list[TResponseInputItem], # 输入消息列表
model_settings: ModelSettings, # 模型设置参数
tools: list[Tool], # 可用工具列表
output_schema: AgentOutputSchemaBase | None, # 输出schema定义
handoffs: list[Handoff], # 可切换的代理列表
tracing: ModelTracing, # 追踪配置
previous_response_id: str | None = None, # 前一个响应ID (OpenAI专用)
conversation_id: str | None = None, # 对话ID (OpenAI专用)
prompt: ResponsePromptParam | None = None, # 提示参数 (OpenAI专用)
) -> ModelResponse:
"""
获取模型响应的主要方法
这是同步获取完整响应的方法,用于非流式场景
"""
pass
@abstractmethod
async def stream_response(
self,
system_instructions: str | None,
input: list[TResponseInputItem],
model_settings: ModelSettings,
tools: list[Tool],
output_schema: AgentOutputSchemaBase | None,
handoffs: list[Handoff],
tracing: ModelTracing,
previous_response_id: str | None = None,
conversation_id: str | None = None,
prompt: ResponsePromptParam | None = None,
) -> AsyncIterator[ResponseEvent]:
"""
流式获取模型响应的方法
返回异步迭代器,可以实时获取模型输出事件
"""
pass
@property
@abstractmethod
def name(self) -> str:
"""模型名称标识符"""
pass
5.3.2 ModelProvider接口
# 位于 src/agents/models/interface.py
class ModelProvider(ABC):
"""
模型提供商的抽象基类
负责根据模型名称创建相应的Model实例
支持模型名称的解析和路由
"""
@abstractmethod
def get_model(self, model_name: str | None) -> Model:
"""
根据模型名称获取Model实例
Args:
model_name: 模型名称,如 "gpt-4", "claude-3.5-sonnet" 等
如果为None,应该返回默认模型
Returns:
Model: 对应的模型实现实例
Raises:
ValueError: 当模型名称不支持时
"""
pass
@abstractmethod
def supports_model(self, model_name: str) -> bool:
"""
检查是否支持指定的模型名称
Args:
model_name: 要检查的模型名称
Returns:
bool: 是否支持该模型
"""
pass
5.3.3 ModelTracing追踪接口
# 位于 src/agents/models/interface.py
@dataclass
class ModelTracing:
"""
模型调用追踪配置
控制是否记录敏感数据和追踪状态
"""
disabled: bool = False # 是否禁用追踪
include_sensitive_data: bool = True # 是否包含敏感数据
def include_data(self) -> bool:
"""是否应该记录追踪数据"""
return not self.disabled and self.include_sensitive_data
5.4 OpenAI模型实现分析
5.4.1 OpenAI Responses API实现
# 位于 src/agents/models/openai_responses.py
class OpenAIResponsesModel(Model):
"""
OpenAI Responses API的模型实现
支持OpenAI最新的Responses API,提供更好的结构化输出
和对话状态管理能力
"""
def __init__(
self,
model_name: str, # 模型名称,如 "gpt-4"
client: AsyncOpenAI | None = None, # OpenAI客户端实例
):
self._model_name = model_name
self._client = client or _get_default_openai_client()
async def get_response(
self,
system_instructions: str | None,
input: list[TResponseInputItem],
model_settings: ModelSettings,
tools: list[Tool],
output_schema: AgentOutputSchemaBase | None,
handoffs: list[Handoff],
tracing: ModelTracing,
previous_response_id: str | None = None,
conversation_id: str | None = None,
prompt: ResponsePromptParam | None = None,
) -> ModelResponse:
"""
调用OpenAI Responses API获取完整响应
实现流程:
1. 准备API调用参数
2. 转换工具和handoff为API格式
3. 设置结构化输出schema
4. 调用OpenAI API
5. 解析和转换响应
6. 记录追踪信息
"""
# 1. 准备基本参数
request_params = {
"model": self._model_name,
"messages": self._prepare_messages(system_instructions, input),
**self._prepare_model_settings(model_settings),
}
# 2. 添加工具定义
if tools:
request_params["tools"] = [self._convert_tool(tool) for tool in tools]
# 3. 添加handoff选项
if handoffs:
request_params["handoffs"] = [self._convert_handoff(h) for h in handoffs]
# 4. 设置结构化输出
if output_schema:
request_params["response_format"] = output_schema.to_response_format()
# 5. 设置对话状态参数
if previous_response_id:
request_params["previous_response_id"] = previous_response_id
if conversation_id:
request_params["conversation_id"] = conversation_id
if prompt:
request_params["prompt"] = prompt
# 6. 开始追踪span
with generation_span(
model=self._model_name,
provider="openai",
input=request_params if tracing.include_data() else None,
) as span:
try:
# 7. 调用OpenAI API
response = await self._client.responses.create(**request_params)
# 8. 记录追踪信息
if tracing.include_data():
span.span_data.output = response.model_dump()
# 9. 转换响应格式
return self._convert_response(response)
except Exception as e:
# 10. 错误处理和追踪
error_data = {"error": str(e), "model": self._model_name}
_error_tracing.attach_error_to_span(
span,
SpanError(message="OpenAI API call failed", data=error_data)
)
raise
def _prepare_messages(
self,
system_instructions: str | None,
input: list[TResponseInputItem]
) -> list[dict]:
"""
准备发送给OpenAI API的消息格式
将框架内部的消息格式转换为OpenAI API要求的格式
"""
messages = []
# 添加系统消息
if system_instructions:
messages.append({
"role": "system",
"content": system_instructions
})
# 转换输入消息
for item in input:
if isinstance(item, dict):
# 简单字典格式消息
messages.append(item)
else:
# 复杂消息对象,需要转换
messages.append(self._convert_input_item(item))
return messages
def _convert_response(self, response) -> ModelResponse:
"""
将OpenAI API响应转换为框架内部格式
提取使用情况、输出内容等信息
"""
# 提取使用情况统计
usage = Usage()
if response.usage:
usage = Usage(
requests=1,
input_tokens=response.usage.input_tokens,
output_tokens=response.usage.output_tokens,
total_tokens=response.usage.total_tokens,
input_tokens_details=response.usage.input_tokens_details,
output_tokens_details=response.usage.output_tokens_details,
)
# 构建ModelResponse对象
return ModelResponse(
output=response.output, # 输出项目列表
usage=usage, # 使用统计
response_id=response.id, # 响应ID
)
5.4.2 OpenAI Chat Completions API实现
# 位于 src/agents/models/openai_chatcompletions.py
class OpenAIChatCompletionsModel(Model):
"""
OpenAI Chat Completions API的模型实现
这是更传统的API,但兼容性更好,支持更多的模型
"""
def __init__(
self,
model_name: str,
client: AsyncOpenAI | None = None,
):
self._model_name = model_name
self._client = client or _get_default_openai_client()
async def get_response(self, **kwargs) -> ModelResponse:
"""Chat Completions API调用实现"""
# 1. 准备Chat Completions API参数
chat_params = {
"model": self._model_name,
"messages": self._prepare_chat_messages(kwargs["system_instructions"], kwargs["input"]),
"temperature": kwargs["model_settings"].temperature,
"max_tokens": kwargs["model_settings"].max_tokens,
}
# 2. 处理工具调用(转换为functions格式)
if kwargs["tools"]:
chat_params["tools"] = [
{
"type": "function",
"function": self._convert_tool_to_function(tool)
}
for tool in kwargs["tools"]
]
# 设置工具选择策略
tool_choice = kwargs["model_settings"].tool_choice
if tool_choice:
chat_params["tool_choice"] = self._convert_tool_choice(tool_choice)
# 3. 处理结构化输出(使用response_format)
if kwargs["output_schema"]:
chat_params["response_format"] = {
"type": "json_schema",
"json_schema": {
"name": kwargs["output_schema"].name(),
"schema": kwargs["output_schema"].json_schema(),
"strict": kwargs["output_schema"].strict_json_schema,
}
}
# 4. 调用API
with generation_span(model=self._model_name, provider="openai_chat") as span:
try:
response = await self._client.chat.completions.create(**chat_params)
# 5. 转换响应格式
return self._convert_chat_response(response)
except Exception as e:
_error_tracing.attach_error_to_span(span, SpanError(message=str(e)))
raise
def _convert_chat_response(self, response) -> ModelResponse:
"""
将Chat Completions响应转换为框架格式
需要处理message、tool_calls等不同类型的响应内容
"""
choice = response.choices[0]
message = choice.message
# 转换为ResponseOutputItem列表
output_items = []
# 处理文本消息
if message.content:
output_items.append(
ResponseOutputMessage(
id=f"msg_{response.id}",
content=[
ResponseOutputText(text=message.content, type="output_text")
],
role="assistant",
status="completed",
type="message"
)
)
# 处理工具调用
if message.tool_calls:
for tool_call in message.tool_calls:
output_items.append(
ResponseOutputFunctionCall(
id=tool_call.id,
name=tool_call.function.name,
arguments=tool_call.function.arguments,
type="function_call"
)
)
# 构建使用统计
usage = Usage()
if response.usage:
usage = Usage(
requests=1,
input_tokens=response.usage.prompt_tokens,
output_tokens=response.usage.completion_tokens,
total_tokens=response.usage.total_tokens,
)
return ModelResponse(
output=output_items,
usage=usage,
response_id=response.id,
)
5.5 LiteLLM集成实现
5.5.1 LiteLLM模型实现
# 位于 src/agents/extensions/models/litellm_model.py
import litellm
from litellm.types.utils import ModelResponse as LiteLLMResponse
class LitellmModel(Model):
"""
LiteLLM模型实现,支持100+种不同的LLM模型
通过LiteLLM库,可以统一访问:
- Anthropic Claude系列
- Google Gemini系列
- Mistral系列
- Cohere系列
- 本地模型(Ollama等)
- 以及更多提供商
"""
def __init__(
self,
model_name: str, # LiteLLM模型名称,如 "claude-3.5-sonnet"
api_key: str | None = None, # API密钥
base_url: str | None = None, # 自定义API端点
**litellm_kwargs, # 传递给LiteLLM的其他参数
):
self._model_name = model_name
self._api_key = api_key
self._base_url = base_url
self._litellm_kwargs = litellm_kwargs
async def get_response(self, **kwargs) -> ModelResponse:
"""使用LiteLLM调用模型获取响应"""
# 1. 准备LiteLLM调用参数
litellm_params = {
"model": self._model_name,
"messages": self._prepare_litellm_messages(
kwargs["system_instructions"],
kwargs["input"]
),
**self._convert_model_settings(kwargs["model_settings"]),
**self._litellm_kwargs,
}
# 2. 设置认证信息
if self._api_key:
litellm_params["api_key"] = self._api_key
if self._base_url:
litellm_params["base_url"] = self._base_url
# 3. 处理工具调用(转换为LiteLLM格式)
if kwargs["tools"]:
litellm_params["tools"] = [
self._convert_tool_for_litellm(tool)
for tool in kwargs["tools"]
]
tool_choice = kwargs["model_settings"].tool_choice
if tool_choice:
litellm_params["tool_choice"] = tool_choice
# 4. 处理结构化输出
if kwargs["output_schema"]:
# 不同的模型对结构化输出的支持方式不同
if self._supports_native_json_schema():
litellm_params["response_format"] = {
"type": "json_schema",
"json_schema": kwargs["output_schema"].json_schema()
}
else:
# 对于不支持原生JSON schema的模型,使用提示工程
schema_prompt = self._generate_schema_prompt(kwargs["output_schema"])
litellm_params["messages"][-1]["content"] += f"\n\n{schema_prompt}"
# 5. 调用LiteLLM
with generation_span(model=self._model_name, provider="litellm") as span:
try:
response: LiteLLMResponse = await litellm.acompletion(**litellm_params)
# 6. 转换响应格式
return self._convert_litellm_response(response)
except Exception as e:
error_msg = f"LiteLLM call failed for model {self._model_name}: {str(e)}"
_error_tracing.attach_error_to_span(
span,
SpanError(message=error_msg, data={"model": self._model_name})
)
raise ModelBehaviorError(error_msg) from e
def _supports_native_json_schema(self) -> bool:
"""检查模型是否支持原生JSON schema"""
# OpenAI模型支持
if self._model_name.startswith(("gpt-", "o1-")):
return True
# 其他模型通常不支持
return False
def _convert_litellm_response(self, response: LiteLLMResponse) -> ModelResponse:
"""将LiteLLM响应转换为框架内部格式"""
choice = response.choices[0]
message = choice.message
output_items = []
# 处理消息内容
if message.content:
output_items.append(
ResponseOutputMessage(
id=f"litellm_{response.id}",
content=[ResponseOutputText(text=message.content, type="output_text")],
role="assistant",
status="completed",
type="message"
)
)
# 处理工具调用
if hasattr(message, 'tool_calls') and message.tool_calls:
for tool_call in message.tool_calls:
output_items.append(
ResponseOutputFunctionCall(
id=tool_call.id,
name=tool_call.function.name,
arguments=tool_call.function.arguments,
type="function_call"
)
)
# 处理使用统计
usage = Usage()
if response.usage:
usage = Usage(
requests=1,
input_tokens=getattr(response.usage, 'prompt_tokens', 0),
output_tokens=getattr(response.usage, 'completion_tokens', 0),
total_tokens=getattr(response.usage, 'total_tokens', 0),
)
return ModelResponse(
output=output_items,
usage=usage,
response_id=response.id,
)
5.6 多提供商管理器
5.6.1 MultiProvider实现
# 位于 src/agents/models/multi_provider.py
class MultiProvider(ModelProvider):
"""
多提供商管理器,根据模型名称自动选择合适的提供商
支持的提供商优先级:
1. OpenAI模型(gpt-*, o1-*, etc.)
2. LiteLLM支持的模型
3. 自定义注册的提供商
"""
def __init__(self):
self._custom_providers: dict[str, ModelProvider] = {}
self._openai_provider = OpenAIProvider()
self._litellm_provider: LiteLLMProvider | None = None
# 尝试初始化LiteLLM提供商(如果可用)
try:
from .litellm_provider import LiteLLMProvider
self._litellm_provider = LiteLLMProvider()
except ImportError:
logger.debug("LiteLLM not available, skipping LiteLLM provider")
def register_provider(self, pattern: str, provider: ModelProvider) -> None:
"""
注册自定义模型提供商
Args:
pattern: 模型名称匹配模式(支持glob语法)
provider: 提供商实例
"""
self._custom_providers[pattern] = provider
def get_model(self, model_name: str | None) -> Model:
"""
根据模型名称获取相应的Model实例
查找顺序:
1. 检查自定义提供商
2. 检查OpenAI提供商
3. 检查LiteLLM提供商
4. 抛出异常
"""
if model_name is None:
# 使用默认模型
return self._openai_provider.get_model(None)
# 1. 检查自定义提供商
for pattern, provider in self._custom_providers.items():
if fnmatch.fnmatch(model_name, pattern):
return provider.get_model(model_name)
# 2. 检查OpenAI提供商
if self._openai_provider.supports_model(model_name):
return self._openai_provider.get_model(model_name)
# 3. 检查LiteLLM提供商
if self._litellm_provider and self._litellm_provider.supports_model(model_name):
return self._litellm_provider.get_model(model_name)
# 4. 未找到支持的提供商
raise ValueError(
f"Unsupported model: {model_name}. "
f"Supported providers: OpenAI, LiteLLM (if installed), custom providers"
)
def supports_model(self, model_name: str) -> bool:
"""检查是否支持指定的模型"""
# 检查自定义提供商
for pattern, provider in self._custom_providers.items():
if fnmatch.fnmatch(model_name, pattern):
return provider.supports_model(model_name)
# 检查内置提供商
if self._openai_provider.supports_model(model_name):
return True
if self._litellm_provider and self._litellm_provider.supports_model(model_name):
return True
return False
5.7 模型设置统一管理
5.7.1 ModelSettings类
# 位于 src/agents/model_settings.py
@dataclass
class ModelSettings:
"""
模型调用的统一设置类
提供跨不同模型提供商的一致参数接口
"""
# 基本生成参数
temperature: float | None = None # 温度参数 (0.0-2.0)
max_tokens: int | None = None # 最大生成token数
top_p: float | None = None # 核采样参数
frequency_penalty: float | None = None # 频率惩罚
presence_penalty: float | None = None # 存在惩罚
# 工具使用控制
tool_choice: Literal["auto", "required", "none"] | str | None = None # 工具选择策略
parallel_tool_calls: bool | None = None # 是否允许并行工具调用
# 高级功能
reasoning: ReasoningSettings | None = None # 推理设置(GPT-5等)
logprobs: bool | None = None # 是否返回对数概率
top_logprobs: int | None = None # 返回top-k对数概率
# 安全和过滤
user: str | None = None # 用户标识符
def resolve(self, override_settings: ModelSettings | None) -> ModelSettings:
"""
合并设置,override_settings中的非None值会覆盖当前设置
Args:
override_settings: 要覆盖的设置
Returns:
ModelSettings: 合并后的设置
"""
if override_settings is None:
return self
# 使用dataclass的replace方法进行合并
resolved_values = {}
for field in fields(self):
override_value = getattr(override_settings, field.name)
if override_value is not None:
resolved_values[field.name] = override_value
else:
resolved_values[field.name] = getattr(self, field.name)
return ModelSettings(**resolved_values)
@dataclass
class ReasoningSettings:
"""
推理模型的特殊设置(如GPT-5系列)
"""
effort: Literal["low", "medium", "high"] | None = None # 推理努力程度
5.8 模型选择和配置策略
5.8.1 默认模型管理
# 位于 src/agents/models/default_models.py
def get_default_model_settings() -> ModelSettings:
"""
获取默认的模型设置
根据当前默认模型类型返回相应的设置
"""
if is_gpt_5_default():
# GPT-5系列的特殊设置
return ModelSettings(
temperature=1.0,
reasoning=ReasoningSettings(effort="medium"),
tool_choice="auto",
)
else:
# 标准模型的默认设置
return ModelSettings(
temperature=0.7,
max_tokens=4096,
tool_choice="auto",
parallel_tool_calls=True,
)
def is_gpt_5_default() -> bool:
"""检查是否默认使用GPT-5系列模型"""
default_model = os.getenv("OPENAI_DEFAULT_MODEL", "gpt-4.1")
return gpt_5_reasoning_settings_required(default_model)
def gpt_5_reasoning_settings_required(model_name: str) -> bool:
"""检查模型是否需要推理设置"""
gpt_5_patterns = ["gpt-5", "o1-", "o3-"]
return any(model_name.startswith(pattern) for pattern in gpt_5_patterns)
这个模型抽象层为OpenAI Agents SDK提供了强大的"提供商无关性"能力,使得开发者可以轻松切换不同的模型提供商,同时保持一致的API体验。通过这种设计,框架能够支持从OpenAI的最新模型到各种开源模型的广泛选择。