原厂 SDK 01:OpenAI Agents SDK——Agent 声明、Tool 注册与原生 Handoff 机制

在过去,如果直接使用 OpenAI 的基础 SDK(openai 包)构建 Agent,开发者必须手动维护一套繁琐的外层逻辑:发起 Chat Completions 请求、判断模型是否返回了 tool_calls、根据名称分发执行本地函数、将工具执行结果构造为 tool 角色的消息追加到历史数组中,再发起下一轮模型调用,直到模型输出普通文本。

这套逻辑每个团队都要重复写一遍。OpenAI 推出的官方开源库 Agents SDK(openai-agents)正是官方针对这一模式给出的轻量运行时方案。它在基础 API 之上增加了一层面向智能体的抽象,同时又比 LangChain 这类通用框架轻巧得多。


安装与快速启动

Agents SDK 作为一个独立的包进行分发:

1
pip install openai-agents

运行时通过读取标准环境变量完成鉴权:

1
export OPENAI_API_KEY="sk-..."

核心架构三大原语

Agents SDK 的设计非常精炼,核心运行时围绕三个对象展开:

对象 运行时角色 职责说明
Agent 静态行为配置 声明智能体的标识、系统指令(instructions)、基底模型、挂载工具以及允许转交的目标 Agent
Tool 能力单元 被包装的本地 Python 函数,携带自动生成的 JSON Schema
Runner 动态执行驱动 负责驱动模型交互与工具调用的完整闭环,直到达成终止状态

这三者的交互关系非常直观:


最小运行示例

通过 Runner.run_sync 可以用同步方式驱动一个最基础的对话 Agent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from agents import Agent, Runner

# 1. 声明 Agent 行为
assistant = Agent(
name="技术问答助手",
instructions="你是一个资深的 Python 架构顾问,使用清晰的技术语言回答问题。",
model="gpt-4o-mini",
)

# 2. 驱动运行
result = Runner.run_sync(assistant, "解释一下什么是连接池及其核心作用。")

# 3. 获取产物
print(result.final_output)

对于基于 FastAPI 或 Tornado 搭建的异步微服务,改用 await Runner.run(...) 即可。


工具注册与 Schema 自动推导

在基础 API 中,开发者需要手写复杂的 JSON Schema 来描述函数参数。而在 Agents SDK 中,使用 @function_tool 装饰器即可完成自动提取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from agents import Agent, Runner, function_tool


@function_tool
def fetch_system_metrics(cluster_id: str, metric_name: str) -> str:
"""获取指定服务集群的运行时监控指标。

Args:
cluster_id: 集群唯一标识符,例如 'prod-east-01'
metric_name: 监控指标名称,支持 'cpu_usage' 或 'memory_rss'
"""
# 模拟从 Prometheus 或监控服务拉取数据
metrics_db = {
("prod-east-01", "cpu_usage"): "74.5%",
("prod-east-01", "memory_rss"): "14.2 GB",
}
val = metrics_db.get((cluster_id, metric_name))
if val:
return f"集群 {cluster_id} 的 {metric_name} 当前值为: {val}"
return f"未查询到集群 {cluster_id} 的 {metric_name} 数据"


# 将工具挂载进 Agent
ops_agent = Agent(
name="SRE排错助理",
instructions="你负责协助排查集群异常,优先调用监控指标工具获取事实数据。",
model="gpt-4o-mini",
tools=[fetch_system_metrics],
)

result = Runner.run_sync(ops_agent, "请检查 prod-east-01 集群的 cpu_usage 是否正常。")
print(result.final_output)

工具声明的工程规范

SDK 在底层通过 Python 的 inspect 模块分析函数的签名和类型注解:

  1. 参数必须具备类型注解:如 cluster_id: str,缺少注解会导致模型无法确定参数类型;
  2. 文档字符串(docstring)就是模型的指令输入:docstring 会被完整提取为工具描述,如果注释模糊不清,模型调用工具的参数准确率就会大幅下滑。

强类型结构化输出(Structured Outputs)

在很多自动化管线中,我们不希望 Agent 返回自由文本,而是需要符合 Schema 的结构化对象。在 Agent 中传入 output_type 并绑定 Pydantic 模型,可以保证输出类型的确定性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from pydantic import BaseModel, Field
from agents import Agent, Runner


class ClusterHealthReport(BaseModel):
cluster_id: str = Field(description="集群 ID")
is_healthy: bool = Field(description="当前状态是否健康")
risk_level: str = Field(description="风险等级: LOW / MEDIUM / HIGH")
action_items: list[str] = Field(description="建议的后续排错或扩容操作")


audit_agent = Agent(
name="集群健康审计员",
instructions="根据集群状态分析系统健康度并产出结构化审计报告。",
model="gpt-4o-mini",
output_type=ClusterHealthReport, # 绑定强类型模型
)

result = Runner.run_sync(
audit_agent,
"集群 prod-east-01 的 CPU 占用高达 92%,内存使用达到 95%,且产生大量慢查询。",
)

# final_output 直接就是 Pydantic 实例
report: ClusterHealthReport = result.final_output

print(f"风险评估: {report.risk_level}")
print(f"建议措施: {report.action_items}")

原生多 Agent 协作:Handoff 机制

多 Agent 协同通常有两种模式:

  • 委托模式(Sub-agent Call):主 Agent 将子 Agent 当成普通工具调用,等待子 Agent 返回结果后主 Agent 继续回复;
  • 转交模式(Handoff):主 Agent 判定当前任务不属于自己范畴,直接将整个控制权与对话历史移交给目标 Agent,由目标 Agent 直接对接后续处理。

Agents SDK 的核心卖点就是原生支持 Handoff。

以客服智能分诊系统为例:

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from agents import Agent, Runner

# 1. 定义专业子 Agent
tech_agent = Agent(
name="技术支持专员",
instructions="你是资深运维工程师,专注于解决应用崩溃、接口报错与部署问题。",
model="gpt-4o-mini",
)

billing_agent = Agent(
name="财务与账单专员",
instructions="你是账单支持专员,处理付费咨询、发票开具与退款申请。",
model="gpt-4o-mini",
)

# 2. 定义分诊 Agent,并在 handoffs 中注册可转交目标
triage_agent = Agent(
name="服务台分诊助理",
instructions="""你是前台客服接待。根据用户问题判断归属:
- 遇到服务报错、异常退出、配置故障,转交给技术支持专员;
- 遇到发票、续费、充值问题,转交给财务与账单专员;
如果不能确定,先询问用户明确意图。""",
model="gpt-4o-mini",
handoffs=[tech_agent, billing_agent], # 允许转交的目标列表
)

# 3. 运行测试
query = "我们在今天凌晨收到了账单扣费通知,但想申请增值税专用发票,请问如何办理?"
result = Runner.run_sync(triage_agent, query)

print(f"最终接管并回复的 Agent: {result.last_agent.name}")
print(f"回复内容:\n{result.final_output}")

当模型判断需要转交时,SDK 会自动构建一个特殊的转移调用,将活动指针切换到目标 Agent,无需编写复杂的路由器代码。


流式输出与运行结果检查

在对响应时延敏感的终端界面,可以通过 Runner.run_streamed 消费异步事件流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import asyncio
from agents import Agent, Runner

agent = Agent(
name="实时助手",
instructions="简要分析数据库死锁的常见成因。",
model="gpt-4o-mini",
)

async def stream_output():
async with Runner.run_streamed(agent, "分析一下死锁") as stream:
async for event in stream.stream_events():
# 监听文本增量
if hasattr(event, "delta") and event.delta:
print(event.delta, end="", flush=True)
print()

asyncio.run(stream_output())

运行完成后,result 对象提供了一组检查字段用于排错审计:

1
2
3
4
5
# result 字段清单
result.final_output # 最终业务产物(文本字符串或 Pydantic 对象)
result.new_messages # 本次运行期间新产生的所有消息记录(含 Tool 调用与返回)
result.last_agent # 最终执行的 Agent 实例(便于审计是否发生了 Handoff)
result.input # 触发本轮执行的初始输入内容

适用场景与工程局限

适用场景

  • 职责清晰的客服/企业级多智能体分诊系统:Handoff 机制让工单流转逻辑非常干净;
  • 轻量级单任务 Agent:免去手写 Tool 循环的代码噪音;
  • 已有业务全量运行在 OpenAI 生态中。

工程局限

  1. 厂商强绑定:目前该 SDK 深度契合 OpenAI 消息格式与模型行为,难以原生桥接其它第三方或本地部署的模型;
  2. 缺乏显式状态机拓扑:对于需要复杂有向无环图(DAG)、并行分支聚合(Fan-out/Fan-in)或复杂自旋重试的场景,SDK 的配置式抽象不如 LangGraph 这类专门的状态机框架灵活;
  3. 中间黑盒感强:Runner 内部的重试策略和状态流转不易打断,难以插入细粒度的自定义持久化 Checkpoint。

下一篇我们将剖析 Google 全新统一的 google-genai SDK,看看它是如何用一套 API 兼顾开发者生态与企业级多模型后端的。


系列导航与参考