3.1 核心API概览
OpenAI Agents SDK 提供了一套简洁而强大的API,主要包含以下几个核心组件:
Runner
: 代理执行器,负责运行代理工作流Agent
: 代理定义,配置代理的行为和能力function_tool
: 工具装饰器,将Python函数转换为代理工具handoff
: 代理切换机制- 各种配置类: 用于详细配置代理行为
3.2 Runner类 API详细分析
3.2.1 Runner.run() 方法
函数签名:
@classmethod
async def run(
cls,
starting_agent: Agent[TContext], # 起始代理
input: str | list[TResponseInputItem], # 输入内容
*,
context: TContext | None = None, # 运行上下文
max_turns: int = DEFAULT_MAX_TURNS, # 最大轮次
hooks: RunHooks[TContext] | None = None, # 生命周期钩子
run_config: RunConfig | None = None, # 运行配置
previous_response_id: str | None = None, # 前一个响应ID
conversation_id: str | None = None, # 对话ID
session: Session | None = None, # 会话管理
) -> RunResult:
核心实现分析:
# 位于 src/agents/run.py:233
@classmethod
async def run(cls, starting_agent, input, **kwargs) -> RunResult:
"""
执行代理工作流的主要入口方法
执行流程:
1. 准备输入和会话历史
2. 初始化追踪和上下文
3. 运行代理执行循环
4. 处理工具调用和代理切换
5. 返回最终结果
"""
runner = DEFAULT_AGENT_RUNNER # 获取默认运行器实例
return await runner.run(starting_agent, input, **kwargs)
实际执行逻辑在AgentRunner.run()中:
# 位于 src/agents/run.py:456
async def run(self, starting_agent: Agent[TContext], input, **kwargs) -> RunResult:
"""
代理运行的核心实现逻辑
"""
# 1. 参数处理和初始化
context = kwargs.get("context")
max_turns = kwargs.get("max_turns", DEFAULT_MAX_TURNS)
hooks = self._validate_run_hooks(kwargs.get("hooks"))
run_config = kwargs.get("run_config") or RunConfig()
session = kwargs.get("session")
# 2. 会话历史准备
prepared_input = await self._prepare_input_with_session(
input, session, run_config.session_input_callback
)
# 3. 初始化追踪和工具使用追踪器
tool_use_tracker = AgentToolUseTracker()
# 4. 开始追踪上下文
with TraceCtxManager(
workflow_name=run_config.workflow_name,
trace_id=run_config.trace_id,
group_id=run_config.group_id,
metadata=run_config.trace_metadata,
disabled=run_config.tracing_disabled,
):
# 5. 主执行循环
current_turn = 0
current_agent = starting_agent
generated_items: list[RunItem] = []
model_responses: list[ModelResponse] = []
while True: # 代理执行循环
current_turn += 1
# 检查最大轮次限制
if current_turn > max_turns:
raise MaxTurnsExceeded(f"Max turns ({max_turns}) exceeded")
# 获取当前代理的所有工具
all_tools = await self._get_all_tools(current_agent, context_wrapper)
# 6. 执行单轮对话
turn_result = await self._run_single_turn(
agent=current_agent,
all_tools=all_tools,
original_input=original_input,
generated_items=generated_items,
hooks=hooks,
context_wrapper=context_wrapper,
run_config=run_config,
# ... 其他参数
)
# 7. 处理执行结果
if isinstance(turn_result.next_step, NextStepFinalOutput):
# 达到最终输出,执行输出防护并返回结果
output_guardrail_results = await self._run_output_guardrails(...)
return RunResult(
input=original_input,
new_items=generated_items,
final_output=turn_result.next_step.output,
# ... 其他字段
)
elif isinstance(turn_result.next_step, NextStepHandoff):
# 代理切换,更新当前代理继续循环
current_agent = turn_result.next_step.new_agent
elif isinstance(turn_result.next_step, NextStepRunAgain):
# 继续执行当前代理(通常在工具调用后)
pass
关键函数调用链路:
Runner.run()
→DEFAULT_AGENT_RUNNER.run()
→AgentRunner._run_single_turn()
→AgentRunner._get_new_response()
→Model.get_response()
→RunImpl.execute_tools_and_side_effects()
3.2.2 AgentRunner._run_single_turn() 方法详解
这是单轮代理执行的核心方法:
# 位于 src/agents/run.py:1199
@classmethod
async def _run_single_turn(
cls,
*,
agent: Agent[TContext], # 当前代理
all_tools: list[Tool], # 可用工具列表
original_input: str | list[TResponseInputItem], # 原始输入
generated_items: list[RunItem], # 已生成的项目
hooks: RunHooks[TContext], # 生命周期钩子
context_wrapper: RunContextWrapper[TContext], # 上下文包装器
run_config: RunConfig, # 运行配置
# ... 其他参数
) -> SingleStepResult:
"""
执行代理的单轮交互
流程:
1. 触发代理开始钩子
2. 获取系统提示和提示配置
3. 调用模型获取响应
4. 处理模型响应(工具调用、代理切换、最终输出)
5. 返回单步执行结果
"""
# 1. 执行代理开始钩子
if should_run_agent_start_hooks:
await asyncio.gather(
hooks.on_agent_start(context_wrapper, agent),
(agent.hooks.on_start(context_wrapper, agent)
if agent.hooks else _coro.noop_coroutine()),
)
# 2. 获取系统提示和提示配置
system_prompt, prompt_config = await asyncio.gather(
agent.get_system_prompt(context_wrapper), # 获取系统提示
agent.get_prompt(context_wrapper), # 获取提示配置
)
# 3. 准备输入数据
output_schema = cls._get_output_schema(agent)
handoffs = await cls._get_handoffs(agent, context_wrapper)
input = ItemHelpers.input_to_new_input_list(original_input)
input.extend([item.to_input_item() for item in generated_items])
# 4. 调用模型获取新响应
new_response = await cls._get_new_response(
agent=agent,
system_prompt=system_prompt,
input=input,
output_schema=output_schema,
all_tools=all_tools,
handoffs=handoffs,
hooks=hooks,
context_wrapper=context_wrapper,
run_config=run_config,
tool_use_tracker=tool_use_tracker,
previous_response_id=previous_response_id,
conversation_id=conversation_id,
prompt_config=prompt_config,
)
# 5. 处理模型响应并返回结果
return await cls._get_single_step_result_from_response(
agent=agent,
original_input=original_input,
pre_step_items=generated_items,
new_response=new_response,
output_schema=output_schema,
all_tools=all_tools,
handoffs=handoffs,
hooks=hooks,
context_wrapper=context_wrapper,
run_config=run_config,
tool_use_tracker=tool_use_tracker,
)
3.2.3 模型调用核心方法
AgentRunner._get_new_response()
负责实际的模型调用:
# 位于 src/agents/run.py:1439
@classmethod
async def _get_new_response(
cls,
agent: Agent[TContext],
system_prompt: str | None,
input: list[TResponseInputItem],
output_schema: AgentOutputSchemaBase | None,
all_tools: list[Tool],
handoffs: list[Handoff],
hooks: RunHooks[TContext],
context_wrapper: RunContextWrapper[TContext],
run_config: RunConfig,
tool_use_tracker: AgentToolUseTracker,
previous_response_id: str | None,
conversation_id: str | None,
prompt_config: ResponsePromptParam | None,
) -> ModelResponse:
"""
调用模型获取响应的核心方法
"""
# 1. 应用输入过滤器(如果配置了)
filtered = await cls._maybe_filter_model_input(
agent=agent,
run_config=run_config,
context_wrapper=context_wrapper,
input_items=input,
system_instructions=system_prompt,
)
# 2. 获取模型实例和设置
model = cls._get_model(agent, run_config)
model_settings = agent.model_settings.resolve(run_config.model_settings)
model_settings = RunImpl.maybe_reset_tool_choice(agent, tool_use_tracker, model_settings)
# 3. 执行LLM开始钩子
await asyncio.gather(
hooks.on_llm_start(context_wrapper, agent, filtered.instructions, filtered.input),
(agent.hooks.on_llm_start(context_wrapper, agent, filtered.instructions, filtered.input)
if agent.hooks else _coro.noop_coroutine()),
)
# 4. 调用模型获取响应
new_response = await model.get_response(
system_instructions=filtered.instructions, # 系统指令
input=filtered.input, # 输入消息列表
model_settings=model_settings, # 模型设置
tools=all_tools, # 可用工具
output_schema=output_schema, # 输出模式
handoffs=handoffs, # 代理切换选项
tracing=get_model_tracing_impl(...), # 追踪设置
previous_response_id=previous_response_id, # 前一个响应ID
conversation_id=conversation_id, # 对话ID
prompt=prompt_config, # 提示配置
)
# 5. 更新使用统计
context_wrapper.usage.add(new_response.usage)
# 6. 执行LLM结束钩子
await asyncio.gather(
(agent.hooks.on_llm_end(context_wrapper, agent, new_response)
if agent.hooks else _coro.noop_coroutine()),
hooks.on_llm_end(context_wrapper, agent, new_response),
)
return new_response
3.3 Agent类 API详细分析
3.3.1 Agent类定义和字段
# 位于 src/agents/agent.py:133
@dataclass
class Agent(AgentBase, Generic[TContext]):
"""
AI代理的核心定义类
包含代理的所有配置信息:指令、工具、模型设置、
安全防护、代理切换等
"""
# 核心配置
name: str # 代理名称,必填
instructions: ( # 代理指令(系统提示)
str |
Callable[[RunContextWrapper[TContext], Agent[TContext]], MaybeAwaitable[str]] |
None
) = None
# 提示和工具配置
prompt: Prompt | DynamicPromptFunction | None = None # 动态提示配置
tools: list[Tool] = field(default_factory=list) # 工具列表
handoffs: list[Agent[Any] | Handoff[TContext, Any]] = field(default_factory=list) # 代理切换
# 模型配置
model: str | Model | None = None # 模型名称或实例
model_settings: ModelSettings = field(default_factory=get_default_model_settings) # 模型设置
# 安全防护
input_guardrails: list[InputGuardrail[TContext]] = field(default_factory=list) # 输入防护
output_guardrails: list[OutputGuardrail[TContext]] = field(default_factory=list) # 输出防护
# 输出和行为配置
output_type: type[Any] | AgentOutputSchemaBase | None = None # 输出类型定义
tool_use_behavior: ( # 工具使用行为
Literal["run_llm_again", "stop_on_first_tool"] |
StopAtTools |
ToolsToFinalOutputFunction
) = "run_llm_again"
reset_tool_choice: bool = True # 是否重置工具选择
# 生命周期钩子
hooks: AgentHooks[TContext] | None = None # 代理级别的钩子
3.3.2 Agent关键方法分析
get_system_prompt()
- 获取系统提示:
# 位于 src/agents/agent.py:443
async def get_system_prompt(self, run_context: RunContextWrapper[TContext]) -> str | None:
"""
获取代理的系统提示
支持三种类型的指令:
1. 字符串类型 - 直接返回
2. 可调用类型 - 动态生成指令
3. None - 返回None
"""
if isinstance(self.instructions, str):
# 静态字符串指令
return self.instructions
elif callable(self.instructions):
# 动态指令函数
sig = inspect.signature(self.instructions)
params = list(sig.parameters.values())
# 强制要求函数接受两个参数:(context, agent)
if len(params) != 2:
raise TypeError(
f"'instructions' callable must accept exactly 2 arguments "
f"(context, agent), but got {len(params)}: {[p.name for p in params]}"
)
# 调用指令函数
if inspect.iscoroutinefunction(self.instructions):
return await cast(Awaitable[str], self.instructions(run_context, self))
else:
return cast(str, self.instructions(run_context, self))
elif self.instructions is not None:
# 无效的指令类型
logger.error(
f"Instructions must be a string or a callable function, "
f"got {type(self.instructions).__name__}"
)
return None
get_all_tools()
- 获取所有可用工具:
# 位于 src/agents/agent.py:111
async def get_all_tools(self, run_context: RunContextWrapper[TContext]) -> list[Tool]:
"""
获取代理的所有工具,包括MCP工具和函数工具
"""
# 1. 获取MCP工具
mcp_tools = await self.get_mcp_tools(run_context)
# 2. 检查函数工具的启用状态
async def _check_tool_enabled(tool: Tool) -> bool:
if not isinstance(tool, FunctionTool):
return True
# 获取工具的启用属性
attr = tool.is_enabled
if isinstance(attr, bool):
return attr
# 调用启用检查函数
res = attr(run_context, self)
if inspect.isawaitable(res):
return bool(await res)
return bool(res)
# 3. 并行检查所有工具的启用状态
results = await asyncio.gather(*(_check_tool_enabled(t) for t in self.tools))
enabled: list[Tool] = [t for t, ok in zip(self.tools, results) if ok]
# 4. 返回MCP工具 + 启用的函数工具
return [*mcp_tools, *enabled]
clone()
- 克隆代理:
# 位于 src/agents/agent.py:367
def clone(self, **kwargs: Any) -> Agent[TContext]:
"""
创建代理的副本,可以修改指定的参数
注意:
- 使用浅拷贝,共享引用对象
- 可变属性如tools和handoffs只有在覆盖时才创建新列表
- 要独立修改这些属性,需要传入新的列表
示例:
new_agent = agent.clone(
instructions="新的指令",
tools=[new_tool_1, new_tool_2]
)
"""
return dataclasses.replace(self, **kwargs)
as_tool()
- 将代理转换为工具:
# 位于 src/agents/agent.py:382
def as_tool(
self,
tool_name: str | None, # 工具名称
tool_description: str | None, # 工具描述
custom_output_extractor: Callable[[RunResult], Awaitable[str]] | None = None, # 自定义输出提取器
is_enabled: bool | Callable[[RunContextWrapper[Any], AgentBase[Any]], MaybeAwaitable[bool]] = True, # 启用状态
run_config: RunConfig | None = None, # 运行配置
max_turns: int | None = None, # 最大轮次
hooks: RunHooks[TContext] | None = None, # 钩子
previous_response_id: str | None = None, # 前一个响应ID
conversation_id: str | None = None, # 对话ID
session: Session | None = None, # 会话
) -> Tool:
"""
将代理转换为可被其他代理调用的工具
与代理切换(handoffs)的区别:
1. 在handoffs中,新代理接收完整的对话历史
2. 在工具中,新代理只接收生成的输入,原代理继续对话
"""
@function_tool(
name_override=tool_name or _transforms.transform_string_function_style(self.name),
description_override=tool_description or "",
is_enabled=is_enabled,
)
async def run_agent(context: RunContextWrapper, input: str) -> str:
"""内部工具函数,执行代理并返回结果"""
from .run import DEFAULT_MAX_TURNS, Runner
resolved_max_turns = max_turns if max_turns is not None else DEFAULT_MAX_TURNS
# 运行代理
output = await Runner.run(
starting_agent=self,
input=input,
context=context.context,
run_config=run_config,
max_turns=resolved_max_turns,
hooks=hooks,
previous_response_id=previous_response_id,
conversation_id=conversation_id,
session=session,
)
# 提取输出
if custom_output_extractor:
return await custom_output_extractor(output)
return ItemHelpers.text_message_outputs(output.new_items)
return run_agent
3.4 function_tool装饰器 API详细分析
3.4.1 function_tool装饰器定义
# 位于 src/agents/tool.py - function_tool装饰器的多个重载定义
@overload
def function_tool(
func: ToolFunction[ToolParams], # 要装饰的函数
) -> FunctionTool: ...
@overload
def function_tool(
*,
name_override: str | None = None, # 覆盖工具名称
description_override: str | None = None, # 覆盖工具描述
strict_json_schema: bool = True, # 严格JSON模式
is_enabled: bool | Callable[[RunContextWrapper[Any], AgentBase], MaybeAwaitable[bool]] = True, # 启用状态
docstring_style: DocstringStyle = "google", # 文档字符串风格
) -> Callable[[ToolFunction[ToolParams]], FunctionTool]: ...
def function_tool(
func: ToolFunction[ToolParams] | None = None,
*,
name_override: str | None = None,
description_override: str | None = None,
strict_json_schema: bool = True,
is_enabled: bool | Callable[[RunContextWrapper[Any], AgentBase], MaybeAwaitable[bool]] = True,
docstring_style: DocstringStyle = "google",
) -> FunctionTool | Callable[[ToolFunction[ToolParams]], FunctionTool]:
"""
将Python函数转换为代理工具的装饰器
支持三种函数签名模式:
1. 无上下文函数: func(param1, param2, ...)
2. 带运行上下文函数: func(context: RunContextWrapper, param1, param2, ...)
3. 带工具上下文函数: func(tool_context: ToolContext, param1, param2, ...)
"""
3.4.2 function_tool实现逻辑
# 位于 src/agents/tool.py 的实现细节
def function_tool(func=None, **kwargs):
"""function_tool装饰器的具体实现"""
def decorator(f: ToolFunction[ToolParams]) -> FunctionTool:
# 1. 获取函数信息
func_name = name_override or f.__name__
func_signature = inspect.signature(f)
# 2. 分析函数参数,确定上下文类型
has_context, context_type = _analyze_function_parameters(func_signature)
# 3. 生成工具描述和参数JSON模式
description = description_override or _extract_function_description(f, docstring_style)
params_schema = function_schema(f, strict=strict_json_schema, docstring_style=docstring_style)
# 4. 创建工具调用处理函数
async def on_invoke_tool(tool_context: ToolContext[Any], args_json: str) -> Any:
"""处理工具调用的内部函数"""
try:
# 解析参数JSON
if args_json.strip():
args = json.loads(args_json)
else:
args = {}
# 根据函数签名调用函数
if has_context:
if context_type == "run_context":
result = f(tool_context.run_context, **args)
elif context_type == "tool_context":
result = f(tool_context, **args)
else:
result = f(**args)
# 处理异步结果
if inspect.isawaitable(result):
result = await result
return result
except Exception as e:
# 工具执行错误处理
logger.error(f"Tool {func_name} execution failed: {e}")
return f"Error executing tool {func_name}: {str(e)}"
# 5. 创建FunctionTool实例
return FunctionTool(
name=func_name,
description=description,
params_json_schema=params_schema,
on_invoke_tool=on_invoke_tool,
strict_json_schema=strict_json_schema,
is_enabled=is_enabled,
)
# 支持直接装饰和参数化装饰两种用法
if func is not None:
return decorator(func)
else:
return decorator
3.4.3 工具参数模式分析
framework支持三种不同的工具函数签名模式:
模式1:无上下文函数
@function_tool
def simple_calculator(x: int, y: int, operation: str) -> int:
"""执行简单的数学计算
Args:
x: 第一个数字
y: 第二个数字
operation: 操作类型 ('add', 'subtract', 'multiply', 'divide')
"""
if operation == 'add':
return x + y
elif operation == 'subtract':
return x - y
# ...
模式2:带运行上下文函数
@function_tool
def context_aware_tool(
context: RunContextWrapper,
message: str
) -> str:
"""需要访问运行上下文的工具
Args:
message: 要处理的消息
"""
# 可以访问context.usage, context.context等
current_usage = context.usage
print(f"当前使用情况: {current_usage}")
return f"处理消息: {message}"
模式3:带工具上下文函数
@function_tool
def advanced_tool(
tool_context: ToolContext,
data: str
) -> str:
"""需要访问完整工具上下文的高级工具
Args:
data: 要处理的数据
"""
# 可以访问工具调用的详细信息
tool_name = tool_context.tool_name
call_id = tool_context.tool_call_id
agent = tool_context.agent
return f"工具 {tool_name} (ID: {call_id}) 处理数据: {data}"
3.5 核心数据结构API
3.5.1 RunResult类
# 位于 src/agents/result.py
@dataclass
class RunResult:
"""代理运行的结果"""
input: str | list[TResponseInputItem] # 原始输入
new_items: list[RunItem] # 新生成的项目
raw_responses: list[ModelResponse] # 原始模型响应
final_output: Any # 最终输出
_last_agent: Agent[Any] # 最后执行的代理
input_guardrail_results: list[InputGuardrailResult] # 输入防护结果
output_guardrail_results: list[OutputGuardrailResult] # 输出防护结果
context_wrapper: RunContextWrapper[Any] # 上下文包装器
def to_input_list(self) -> list[TResponseInputItem]:
"""将结果转换为可用于下次输入的列表"""
input_list = ItemHelpers.input_to_new_input_list(self.input)
input_list.extend([item.to_input_item() for item in self.new_items])
return input_list
3.5.2 RunConfig类
# 位于 src/agents/run.py:129
@dataclass
class RunConfig:
"""代理运行的全局配置"""
model: str | Model | None = None # 全局模型覆盖
model_provider: ModelProvider = field(default_factory=MultiProvider) # 模型提供商
model_settings: ModelSettings | None = None # 全局模型设置
handoff_input_filter: HandoffInputFilter | None = None # 代理切换输入过滤器
input_guardrails: list[InputGuardrail[Any]] | None = None # 全局输入防护
output_guardrails: list[OutputGuardrail[Any]] | None = None # 全局输出防护
tracing_disabled: bool = False # 禁用追踪
trace_include_sensitive_data: bool = field(default_factory=_default_trace_include_sensitive_data) # 追踪敏感数据
workflow_name: str = "Agent workflow" # 工作流名称
trace_id: str | None = None # 自定义追踪ID
group_id: str | None = None # 分组ID
trace_metadata: dict[str, Any] | None = None # 追踪元数据
session_input_callback: SessionInputCallback | None = None # 会话输入回调
call_model_input_filter: CallModelInputFilter | None = None # 模型调用输入过滤器
这些API构成了OpenAI Agents SDK的核心接口,为开发者提供了灵活而强大的多代理应用开发能力。通过这些API,可以轻松构建从简单的单代理助手到复杂的多代理协作工作流。