openai-agents-python 的 Agent 定义完全指南:配置属性、提示模板、输出类型与生命周期钩子
【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python
本篇围绕 openai-agents-python(OpenAI Agents SDK for Python)中最核心的构件Agent展开:讲清它的全部常用配置属性、提示模板与上下文机制、结构化输出类型、多智能体设计模式,以及工具执行行为与生命周期钩子这两个容易踩坑的运行时控制点。读完你可以独立完成一个带工具、守卫、结构化输出和自定义钩子的 Agent 定义,并理解框架在运行循环中是如何管理tool_choice、工具结果回传与生命周期回调的。
什么是 Agent:LLM 加运行时行为
Agent 是应用的核心构件:一个被指令(instructions)、工具(tools)以及可选运行时行为(handoffs、guardrails、结构化输出)配置过的大语言模型(LLM)。两个重要边界需要明确:
- 本页描述的是单一的基础
Agent的定义与定制。如果要让多个 Agent 协作,参见 Agent 编排(multi_agent);如果 Agent 需要在带清单(manifest)定义文件、具备沙箱原生能力的隔离工作区中运行,参见 Sandbox Agent 概念。 - SDK 对 OpenAI 模型默认使用 Responses API,但这里的关键区别在于编排:
Agent配合Runner时,SDK 会替你管理回合(turns)、工具、守卫、交接与会话;如果你想自己掌握这个循环,可以直接使用 Responses API。
从源码结构看,这一分工体现在Agent只是"配置描述"(一个 dataclass),而回合循环、工具执行、钩子触发都由Runner及src/agents/run_internal/下的运行循环代码完成,例如 run_loop.py 中反复调用maybe_reset_tool_choice来重置tool_choice。
相邻指南导航
以本页为 Agent 定义的中心指南,按下一步要做的决策跳转:
| 你想做什么 | 继续阅读 |
|---|---|
| 选择模型或提供方设置 | 模型 |
| 为 Agent 添加能力 | 工具 |
| 让 Agent 在真实仓库、文档包或隔离工作区中运行 | Sandbox Agents 快速上手 |
| 在"管理员式编排"与"handoff"之间做选择 | Agent 编排 |
| 配置 handoff 行为 | Handoffs |
| 执行回合、流式事件、管理对话状态 | 运行 Agent |
| 检查最终输出、运行项或可恢复状态 | 结果 |
| 共享本地依赖与运行时状态 | 上下文管理 |
基本配置属性
Agent 最常用的属性如下(属性语义已在 agent.py 的Agentdataclass 字段与__post_init__校验中逐一确认):
| 属性 | 是否必填 | 说明 |
|---|---|---|
name | 是 | 人类可读的 Agent 名称 |
instructions | 否 | 系统提示词或动态指令回调。强烈建议提供。见 动态指令 |
prompt | 否 | OpenAI Responses API 的提示词配置,接受静态提示对象或函数。见 提示模板 |
handoff_description | 否 | 当该 Agent 作为 handoff 目标提供时展示的简短描述 |
handoffs | 否 | 将会话委托给专家 Agent。见 Handoffs |
model | 否 | 要使用的 LLM。见 模型 |
model_settings | 否 | 模型调参,如temperature、top_p、tool_choice |
tools | 否 | Agent 可调用的工具。见 工具 |
mcp_servers | 否 | 为 Agent 提供 MCP 工具的 MCP 服务器。见 MCP 指南 |
mcp_config | 否 | 微调 MCP 工具的准备工作方式,如把 schema 转为严格模式、指定 MCP 失败格式等。见 MCP 指南 |
input_guardrails | 否 | 在本 Agent 链的第一个用户输入上执行的守卫。见 Guardrails |
output_guardrails | 否 | 在本 Agent 的最终输出上执行的守卫。见 Guardrails |
output_type | 否 | 替代纯文本的结构化输出类型。见 输出类型 |
hooks | 否 | Agent 作用域的生命周期回调。见 生命周期事件(钩子) |
tool_use_behavior | 否 | 控制工具结果是回传给模型还是直接结束运行。见 工具使用行为 |
reset_tool_choice | 否 | 工具调用后重置tool_choice(默认True),防止工具使用死循环。见 强制工具使用 |
最简完整示例:
from agents import Agent from agents.decorators import tool @tool def get_weather(city: str) -> str: """returns weather info for the specified city.""" return f"The weather in {city} is sunny" agent = Agent( name="Haiku agent", instructions="Always respond in haiku form", model="gpt-5-nano", tools=[get_weather], )结合源码可以补充几个实操要点:
- 属性会在构造时做类型校验。
Agent.__post_init__(agent.py)会检查name必须是字符串、instructions必须是字符串或可调用对象、prompt必须是Prompt或函数、tool_use_behavior必须是"run_llm_again"/"stop_on_first_tool"/StopAtTools字典/可调用对象、reset_tool_choice必须是布尔值等,配置错误会在构造阶段而非运行阶段暴露。 model缺省值来自 SDK 默认模型。不设置model时,Agent 使用agents.models.get_default_model()返回的默认模型;从 default_models.py 看,当前默认值为gpt-5.6-luna,且可通过环境变量OPENAI_DEFAULT_MODEL覆盖。model_settings会随模型联动。__post_init__中,如果显式传入了model而model_settings仍是全局默认,SDK 会改用该模型对应的初始默认设置(agent.py),避免把上一个模型的推理参数误套到新模型上。- 上述全部内容同样适用于
SandboxAgent,后者在此基础上新增default_manifest、base_instructions、capabilities、run_as四个面向工作区运行的参数(见 Sandbox Agent 概念)。
提示模板
设置prompt可以引用在 OpenAI 平台上创建的提示词模板(prompt template)。该能力仅在使用 Responses API 访问 OpenAI 模型时生效。
使用步骤:
前往 OpenAI 平台的提示词页面(Playground → Prompts);
创建一个新的提示变量
poem_style;用如下内容创建系统提示词:
Write a poem in {{poem_style}}使用
--prompt-id标志运行示例(仓库中对应的可运行示例是 prompt_template.py,它通过--prompt-id和--dynamic参数分别演示静态与动态两种用法)。
静态引用:
from agents import Agent agent = Agent( name="Prompted assistant", prompt={ "id": "pmpt_123", "version": "1", "variables": {"poem_style": "haiku"}, }, )在运行时动态生成提示词:
from dataclasses import dataclass from agents import Agent, GenerateDynamicPromptData, Runner @dataclass class PromptContext: prompt_id: str poem_style: str async def build_prompt(data: GenerateDynamicPromptData): ctx: PromptContext = data.context.context return { "id": ctx.prompt_id, "version": "1", "variables": {"poem_style": ctx.poem_style}, } agent = Agent(name="Prompted assistant", prompt=build_prompt) result = await Runner.run( agent, "Say hello", context=PromptContext(prompt_id="pmpt_123", poem_style="limerick"), )源码印证:Prompt是一个TypedDict,字段为必填的id与可选的version、variables;动态函数接收GenerateDynamicPromptData(内含context与agent),同步或异步均可,返回值必须是Prompt字典,否则抛出UserError。这一解析逻辑集中在 prompts.py 的 PromptUtil.to_model_input。注意prompt与instructions是两个正交的机制:prompt把提示词配置外置到 OpenAI 平台,instructions是代码内联的系统提示词。
上下文(Context)
Agent 对context类型是泛型的(Agent[TContext])。上下文是一个依赖注入工具:它是由用户创建并通过Runner.run()传入的对象,会被传递给所有 Agent、工具、handoff 等,充当承载 Agent 运行所需依赖与状态的容器。任何 Python 对象都可以作为上下文。
完整的RunContextWrapper接口、共享用量统计、嵌套tool_input与序列化注意事项见 上下文指南。
from dataclasses import dataclass @dataclass class Purchase: id: str @dataclass class UserContext: name: str uid: str is_pro_user: bool async def fetch_purchases(self) -> list[Purchase]: # implement your logic here return [] agent = AgentUserContext在 agent.py 的Agent类文档 中,上下文被描述为一个(可变的)由用户创建的对象,会传递给工具函数、handoff、守卫等——这正是动态指令、动态提示模板、守卫与钩子能够共享同一份依赖的基础。
输出类型(output_type)
默认情况下 Agent 生成纯文本(即str)输出。若希望 Agent 产出特定类型的输出,使用output_type参数。通常使用 Pydantic 对象,但数据类、列表、TypedDict 等任何能用 PydanticTypeAdapter包装的类型都支持。
from pydantic import BaseModel from agents import Agent class CalendarEvent(BaseModel): name: str date: str participants: list[str] agent = Agent( name="Calendar extractor", instructions="Extract calendar events from text", output_type=CalendarEvent, )注意:传入
output_type后,模型被指定使用 structured outputs,而非一般的纯文本响应。
从 agent.py 的output_type字段文档还能看到两个进阶定制方式:
- 需要非严格(non-strict)schema 时,传入
AgentOutputSchema(MyClass, strict_json_schema=False); - 想完全自定义 JSON schema(绕过 SDK 的自动 schema 生成)时,继承
AgentOutputSchemaBase并传入其子类(见 agent_output.py)。
多 Agent 系统设计模式
多 Agent 系统有多种设计方式,但最广泛使用的可通用模式是以下两种:
- 管理员(Agents as tools):中央管理员/编排者把专家子 Agent 作为工具调用,并始终持有对话控制权;
- Handoffs(交接):对等 Agent 把对话控制权移交给接管对话的专家 Agent,是去中心化的方式。
管理员(Agents as tools)
customer_facing_agent处理所有用户交互,并调用以工具形式暴露的专家子 Agent(详见 工具文档 的 Agents as tools 一节,可运行参考 agents_as_tools.py):
from agents import Agent booking_agent = Agent(...) refund_agent = Agent(...) customer_facing_agent = Agent( name="Customer-facing agent", instructions=( "Handle all direct user communication. " "Call the relevant tools when specialized expertise is needed." ), tools=[ booking_agent.as_tool( tool_name="booking_expert", tool_description="Handles booking questions and requests.", ), refund_agent.as_tool( tool_name="refund_expert", tool_description="Handles refund questions and requests.", ) ], )as_tool()的实现见 agent.py,其文档明确了它和 handoff 的两点本质区别:handoff 中新 Agent 收到完整对话历史并接管对话;而as_tool中被调用的 Agent 收到的是生成的输入,执行完毕后对话仍由原 Agent 继续。此外as_tool()还支持custom_output_extractor(自定义输出提取)、is_enabled(动态启停)、on_stream(透传子 Agent 的流式事件)、max_turns、needs_approval等参数,用于精细控制"Agent 作为工具"的边界。
Handoffs(交接)
配置好的 handoff 目标是 Agent 可以委托任务的子 Agent。发生 handoff 后,被委托的 Agent 会接收对话记录并继续对话。这种模式允许把单一任务拆成模块化的专家 Agent(详见 Handoffs 文档):
from agents import Agent booking_agent = Agent(...) refund_agent = Agent(...) triage_agent = Agent( name="Triage agent", instructions=( "Help the user with their questions. " "If they ask about booking, hand off to the booking agent. " "If they ask about refunds, hand off to the refund agent." ), handoffs=[booking_agent, refund_agent], )动态指令
大多数情况下在创建 Agent 时直接给出指令即可,但也可以通过函数提供动态指令:该函数接收上下文与 Agent 实例,返回提示词字符串。同步与async函数都允许。
from agents import Agent, RunContextWrapper def dynamic_instructions( context: RunContextWrapper[UserContext], agent: Agent[UserContext] ) -> str: return f"The user's name is {context.context.name}. Help them with their questions." agent = AgentUserContext这与 agent.py 中instructions的类型定义一致:str | Callable[[RunContextWrapper[TContext], Agent[TContext]], MaybeAwaitable[str]] | None。
生命周期事件(钩子)
有时你需要观察 Agent 的整个生命周期:例如在某事件发生时打日志、预取数据、记录用量。钩子分两种作用域:
- [
RunHooks][src/agents/lifecycle.py] 观察整个Runner.run(...)调用,包括向其他 Agent 的 handoff; - [
AgentHooks][src/agents/lifecycle.py] 通过agent.hooks绑定到特定 Agent 实例。
回调收到的上下文也随事件类型不同而不同:
- Agent 开始/结束钩子收到 [
AgentHookContext][src/agents/run_context.py]——它包装了原始上下文,并包含共享的运行用量状态; - LLM、工具与 handoff 钩子收到 [
RunContextWrapper][src/agents/run_context.py]。
常见钩子触发时机(签名定义见 lifecycle.py 的 RunHooksBase):
on_agent_start:某个 Agent 开始运行;on_agent_end:该 Agent 完成最终输出生成;on_llm_start/on_llm_end:每次模型调用之前/之后;on_tool_start/on_tool_end:每次本地工具调用前后。函数工具的context通常是ToolContext,因此可以检查tool_call_id等工具调用元数据;on_handoff:控制权从一个 Agent 转移到另一个 Agent 时。
需要单一观察者看完整工作流时用RunHooks,需要限定在某个 Agent 内的生命周期回调时用AgentHooks。
from agents import Agent, RunHooks, Runner class LoggingHooks(RunHooks): async def on_agent_start(self, context, agent): print(f"Starting {agent.name}") async def on_llm_end(self, context, agent, response): print(f"{agent.name} produced {len(response.output)} output items") async def on_agent_end(self, context, agent, output): print(f"{agent.name} finished with usage: {context.usage}") agent = Agent(name="Assistant", instructions="Be concise.") result = await Runner.run(agent, "Explain quines", hooks=LoggingHooks()) print(result.final_output)完整的回调接口见 生命周期 API 参考。相关行为有测试覆盖,例如 test_agent_hooks.py 与 test_global_hooks.py。
Guardrails(守卫)
使用 guardrails 可以让输入检查/校验与 Agent 执行并行运行,并在 Agent 输出产生之后检查该输出——例如验证用户输入与 Agent 输出的相关性。input_guardrails只在 Agent 是链条中第一个 Agent 时运行,output_guardrails只在 Agent 产生最终输出时运行(语义见 agent.py 的字段文档)。完整用法见 Guardrails 文档。
Agent 克隆/复制
clone()方法可以复制 Agent 并按需修改部分属性:
pirate_agent = Agent( name="Pirate", instructions="Write like a pirate", model="gpt-5.6-sol", ) robot_agent = pirate_agent.clone( name="Robot", instructions="Write like a robot", )这里有一个容易踩的坑,clone() 的源码文档 明确说明它是基于dataclasses.replace的浅拷贝:
- 未传入的列表属性(
tools、handoffs、mcp_servers、input_guardrails、output_guardrails)与原 Agent 共享同一个列表:通过任一 Agent 执行cloned.tools.append(...)都会同时影响另一个; - 传入的属性按原样使用;
- 想让克隆体持有独立的列表,请显式传一个新列表,例如
agent.clone(tools=[*agent.tools, extra_tool])(条目仍是原对象); - 额外细节:如果
clone时更换了model但未指定model_settings,且原model_settings与旧模型的隐式默认值一致,SDK 会自动换成新模型的默认设置(agent.py),避免跨模型套用错误的推理参数。
强制工具使用(Forcing tool use)
提供了工具列表并不代表 LLM 一定会调用工具。通过ModelSettings.tool_choice可以强制工具使用,有效取值有四类:
auto:由 LLM 自行决定是否使用工具;required:LLM 必须使用工具,但用哪个由它智能决定;none:指定 LLM不要使用工具;- 特定字符串(如
"my_tool"):强制 LLM 调用该指定工具。
使用 OpenAI Responses 托管工具搜索(hosted tool search)时,对"指名道姓"的工具选择有额外限制:不能用tool_choice单独指定命名空间名称或延迟专用工具,且tool_choice="tool_search"并不指向ToolSearchTool;这些场景建议使用auto或required(详见 工具文档 的 Hosted tool search 一节)。
from agents import Agent, ModelSettings from agents.decorators import tool @tool def get_weather(city: str) -> str: """Returns weather info for the specified city.""" return f"The weather in {city} is sunny" agent = Agent( name="Weather Agent", instructions="Retrieve weather details.", tools=[get_weather], model_settings=ModelSettings(tool_choice="get_weather") )工具使用行为(tool_use_behavior)
Agent配置中的tool_use_behavior参数控制工具输出的处理方式,共有四种形态(类型定义见 agent.py):
"run_llm_again":默认值。工具执行后,结果回传给 LLM 处理并生成最终响应;"stop_on_first_tool":第一个工具调用的输出直接作为最终响应,不再送回 LLM 处理;
from agents import Agent from agents.decorators import tool @tool def get_weather(city: str) -> str: """Returns weather info for the specified city.""" return f"The weather in {city} is sunny" agent = Agent( name="Weather Agent", instructions="Retrieve weather details.", tools=[get_weather], tool_use_behavior="stop_on_first_tool" )StopAtTools(stop_at_tool_names=[...])(agent.py 中定义为TypedDict):指定工具中任何一个被调用即停止运行,并以其输出作为最终响应;- 自定义函数
ToolsToFinalOutputFunction:接收运行上下文与工具结果列表,返回ToolsToFinalOutputResult,自行决定是终结运行还是继续让 LLM 处理。
from agents import Agent from agents.agent import StopAtTools from agents.decorators import tool @tool def get_weather(city: str) -> str: """Returns weather info for the specified city.""" return f"The weather in {city} is sunny" @tool def sum_numbers(a: int, b: int) -> int: """Adds two numbers.""" return a + b agent = Agent( name="Stop At Stock Agent", instructions="Get weather or sum numbers.", tools=[get_weather, sum_numbers], tool_use_behavior=StopAtTools(stop_at_tool_names=["get_weather"]) )from agents import Agent, FunctionToolResult, RunContextWrapper from agents.agent import ToolsToFinalOutputResult from agents.decorators import tool from typing import List, Any @tool def get_weather(city: str) -> str: """Returns weather info for the specified city.""" return f"The weather in {city} is sunny" def custom_tool_handler( context: RunContextWrapper[Any], tool_results: List[FunctionToolResult] ) -> ToolsToFinalOutputResult: """Processes tool results to decide final output.""" for result in tool_results: if result.output and "sunny" in result.output: return ToolsToFinalOutputResult( is_final_output=True, final_output=f"Final weather: {result.output}" ) return ToolsToFinalOutputResult( is_final_output=False, final_output=None ) agent = Agent( name="Weather Agent", instructions="Retrieve weather details.", tools=[get_weather], tool_use_behavior=custom_tool_handler )需要留意两个源码层面的细节:
- 该配置只作用于 FunctionTool。
tool_use_behavior的字段文档明确注明:文件搜索、联网搜索等托管工具(hosted tools)始终由 LLM 处理,不受此参数影响; reset_tool_choice防止无限循环:框架会在工具调用后自动把tool_choice重置为"auto"。这个行为的实现是 tool_execution.py 的 maybe_reset_tool_choice——当agent.reset_tool_choice is True且该 Agent 本轮已用过工具时,把model_settings中的tool_choice替换为None;运行循环(run_loop.py)在每次进入下一轮模型调用前调用它。之所以必要,是因为若tool_choice保持强制状态,"工具结果送回 LLM → LLM 再次发起工具调用"会无限循环。此行为通过agent.reset_tool_choice(默认True,见 agent.py)配置。
小结:Agent 定义中的关键决策点
- 用
instructions(静态或动态函数)表达角色与行为约束,用prompt把提示词外置到 OpenAI 平台; - 用
tools+mcp_servers装配能力,用tool_choice控制"用不用、用哪个",用tool_use_behavior控制"工具输出之后怎么办",两者配合reset_tool_choice才能既强制又安全; - 用
output_type把自然语言输出升级为可程序化消费的结构化数据; - 用
handoffs(去中心化接管)或as_tool(中心化调用)搭建多 Agent 结构,用RunHooks/AgentHooks观测与埋点,用input_guardrails/output_guardrails做并行校验; - 复制变体时用
clone(),并注意其浅拷贝语义。
如需继续深入,可依次阅读 工具、Handoffs、运行 Agent、结果 与 上下文管理,并对照 src/agents/agent.py 与 tests/test_agent_config.py 验证各配置项的边界行为。
【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考