1.3. OpenAI Agents SDK 提供了另一种 Skills 实现路径
OpenAI Agents SDK 提供了另一种 Skills 实现路径
2025年3月11日,OpenAI 正式发布了 Agents SDK,将其定位为“从实验走向生产”的轻量级多智能体框架。与此同时,Anthropic 的 Claude Skills 已完成两轮迭代,以声明式能力包的形式在 Claude 生态中沉淀出一套标准化的技能体系。表面上看,二者都在回答同一个关键问题:如何将 AI 能力封装为可复用、可组合的工程单元。但当你真正打开 SDK 文档、写下第一行代码时,你会发现它们走的其实是两条截然不同的路——一条用“Agent 间的手递手通信”编织能力网络,另一条用“能力包的声明式封装”构建可插拔的知识模块。
核心结论先行:
OpenAI Agents SDK 并不是对 Claude Skills 的替代,而是对同一问题的另一种极端解法。它将“技能”内化为 Agent 的推理与工具调用循环,适合需要动态分解任务、跨领域协作的复杂场景;代价是状态管理更黑箱、调试成本更高,且对 Prompt 工程的依赖并未减少。而 Claude Skills 用确定性的声明式配置,把专家知识、工具接口和安全边界一并打包,更适合需要高可控性、可追溯、可审计的生产流水线。
理解这两种路径的本质区别,是你在 2025 年做 AI 能力架构选型时,必须跨越的一道坎。
OpenAI Agents SDK 的核心抽象与薄弱点
Agents SDK 把世界建模成一组相互通信的 Agent。它的核心概念包括 Agent(智能体)、Handoff(移交)、Guardrails(护栏) 和 Tool(工具)——其中前两者构成了其区别于传统 Function Calling 的骨架。
| 概念 | 在 Agents SDK 中的表现 | 与 Claude Skills 的对比 | 作者的结论 |
|---|---|---|---|
| Agent | 一个持久的对话与推理单元,拥有自己的指令、工具集和可能的 Handoff 目标 | Skills 没有持久 Agent 概念,每个 Skill 是一个无状态的能力包,由宿主 Agent 按需调度 | Agent 的持久性带来了上下文记忆,但也让使用者不得不管理对话生命周期 |
| Handoff | 允许一个 Agent 将整个对话上下文移交给另一个 Agent,完成后再移交回来 | Skills 之间不存在直接通信,都由顶层 Orchestrator 控制数据流,避免网状依赖 | Handoff 是 Agents SDK 最激进的设计,它把控制流写进了生态,但也导致了调试时的“上下文黑洞” |
| Guardrails | 输入/输出检查器,可在 Agent 执行前后插入安全或业务规则 | Skills 通过声明的约束字段和工具白名单实现,更偏向配置级而非代码级 | Agents SDK 的 Guardrails 更灵活,但需要开发者自行实现逻辑;Skills 的安全性更“开箱即用” |
| 工具封装 | 任意 Python 函数 → 自动 Schema 生成,支持 Pydantic 验证 | 工具定义在 YAML 或 JSON 中,由平台解析,与语言无关 | Python 原生工具开发效率高,但跨语言复用性差;Skills 声明式工具更易被不同平台消费 |
这个表格里能读出两条关键信息:Agents SDK 把编排权交给了 Agent 自己,而 Skills 把编排权牢牢抓在开发者或平台手中。
在 Agents SDK 里,一个典型流程可能是:入口 Agent 理解用户意图 → 将任务 Handoff 给「数据分析 Agent」→ 这个 Sub-Agent 在沙盒中运行 Python 代码 → 结果回传入口 Agent → 再 Handoff 给「报告生成 Agent」——整个过程像一场接力赛,SDK 的内置 Agent 循环(built-in agent loop)自动处理工具调用、结果回传和任务继续,开发者只需要定义每个 Agent 的指令与工具。但这种便利性的代价是:一旦接力棒(上下文)在传递中产生错误,你很难像调试一个单体函数那样直接定位问题。
相比之下,Claude Skills 的声明式模型没有“接力”这一说。每个 Skill 是一个自包含的 YAML 文件,描述了它能做什么、需要什么输入、输出什么、以及它的使用条件和限制。宿主 Agent(无论是 Claude 还是其他兼容平台)在推理时决定调用哪个 Skill,但调用过程更像一次纯函数求值:输入进,结果出,无状态,无副作用。这种差异在生产环境中会被成倍放大——我们马上就会在代码层面看到它。
代码风格对比:Python SDK vs 声明式配置
为了让差异具象化,我们假设一个常见需求:搭建一个能响应“最新销售报告”查询的 AI 功能,它需要先调用内部 API 拉取原始数据,再做数据聚合,最后返回自然语言结论。我们分别用两种范式实现。
方式一:OpenAI Agents SDK(命令式)
from agents import Agent, Runner, function_tool, handoff
@function_tool
def fetch_sales(start_date: str, end_date: str) -> dict:
"""调用内部 API 拉取销售原始数据"""
# 真实实现略
return {"products": [...]}
@function_tool
def aggregate_sales(raw: dict) -> dict:
"""对原始数据执行聚合计算"""
return {"total": 125000, "top_product": "A23"}
# 数据获取 Agent
data_agent = Agent(
name="data_fetcher",
instructions="根据用户时间范围调用 fetch_sales,成功后 handoff 给分析 agent。",
tools=[fetch_sales],
handoffs=[analysis_agent] # 定义移交目标
)
# 分析 Agent
analysis_agent = Agent(
name="analyst",
instructions="接收来自 data_fetcher 的原始数据,调用 aggregate_sales,然后把结果 handoff 给报告 agent。",
tools=[aggregate_sales],
handoffs=[report_agent]
)
# 报告 Agent
report_agent = Agent(
name="reporter",
instructions="基于分析结果生成自然语言报告,直接返回给用户。",
tools=[],
)
# 入口 Agent
entry_agent = Agent(
name="orchestrator",
instructions="接收用户查询,判断需要销售报告时 handoff 给 data_fetcher。",
handoffs=[data_agent]
)
result = await Runner.run(entry_agent, input="上周的销售情况")
这段代码展现了一个清晰的“拆分-移交”链。它使用了 Agents SDK 的 Handoff 和 function_tool 装饰器,自动处理 Schema 生成和数据流转。开发者在本地 Python 环境中就能写好全部逻辑,调试工具也相对熟悉(例如 pdb、logging)。
方式二:Claude Skills(声明式)
在 Skills 方式下,同样功能会被拆解为多个能力包,但编排逻辑不写在代码里,而是由宿主 Agent 根据声明式描述决定调用顺序。一个 Skills 定义可能像这样:
# skill: sales_data_fetcher
name: sales-data-fetcher
description: 从内部系统拉取给定时间范围的原始销售数据。
tools:
- id: fetch_sales
description: 调用内部 API。
parameters:
start_date: string
end_date: string
output: raw_sales_json
conditions:
- when: 用户要求查询销售数据
then: 必须使用此 skill
# skill: sales_aggregator
name: sales-aggregator
description: 对原始销售数据执行聚合计算,返回汇总结果。
tools:
- id: aggregate
description: 聚合计算
parameters:
raw: raw_sales_json
output: aggregated_json
# skill: report_generator
name: report-generator
description: 将聚合后的销售数据生成自然语言报告。
tools:
- id: generate_report
description: 生成报告
parameters:
aggregated: aggregated_json
output: natural_language_text
Skill 之间不存在直接引用。宿主 Claude Agent 通过读取这些声明文件,在推理时动态规划调用顺序,并将各 Skill 的输出作为下一个 Skill 的输入。整个编排行为完全由 Prompt 和工具描述驱动,没有硬编码的控制流。
开发体验与维护成本
| 维度 | OpenAI Agents SDK (Python) | Claude Skills (声明式) | 作者的结论 |
|---|---|---|---|
| 上手速度 | Python 开发者几乎零门槛,10 分钟可跑通 demo | 需理解 YAML 结构和平台约束,初期投入更大 | 短期原型阶段,SDK 更快 |
| 控制流可见性 | 控制流显式写在代码中,方便调试 | 控制流隐式,由 LLM 推理决定,调试需检查对话日志 | 前者更适合逻辑确定性强的场景 |
| 可维护性 | 代码量随 Agent 数膨胀;Handoff 嵌套深时复盘困难 | 每个 Skill 是独立文件,修改不影响其他模块 | 长期维护中,声明式更抗熵增 |
| 跨平台复用 | 强依赖 Python 生态,其他语言需重写 | YAML/JSON 描述,只要平台兼容即可复用 | 跨国队或跨服务时,Skills 优势明显 |
| Prompt 依赖 | 每个 Agent 的指令仍需精确调试 | Skill 描述被翻译成工具注释,但同样依赖良好的 Prompt 工程 | 两者都未能摆脱 Prompt 黑洞,但 Skills 将影响面限制在单个模块内 |
我们在这里面临的不是“哪个更好”的问题,而是“你更愿意在哪个层面承担复杂度”。选择 Agents SDK,你承担的是架构层面的复杂度——你要设计 Agent 间的边界、定义 Handoff 的时机、处理上下文膨胀。选择 Skills,你承担的是声明式配置与 LLM 推理不确定性之间的张力。接下来,我们把镜头拉远,看看这两种选择在生产环境中会演化成什么模样。
生产就绪度的真实差距
任何一个 SDK 或框架,从“能跑”到“能扛住生产流量”,中间隔着三个硬指标:流式与实时性、故障自愈、可观测性。我们对照一下两者在这三条线上的现况。
流式处理
Agents SDK 在最新的 Chat Completions / Responses API 基础上原生支持流式传输,你可以对 Agent 的每一次工具调用和文本生成启用 stream=True,并实时推送到前端。Claude Skills 的宿主 API 同样支持流式,但因为 Skill 是“调用即完成”的封装,流式交互的粒度只能到 Skill 级别,无法嵌入 Skill 内部的中间步骤。这让 Agents SDK 在需要逐步展示推理过程的聊天应用(比如逐步显示“查询 API → 得到结果 → 分析 → 报告”)中更自然。
错误重试与降级
Agents SDK 内置了简单的重试机制(基于 API 返回状态码),并提供沙盒 Agent(Sandbox Agent)来隔离高风险任务。但定制重试策略(如指数退避、条件重试)仍要由开发者自己实现。Claude Skills 的错误处理依赖平台,如果平台稳定,你几乎不需要操心;但如果平台没有暴露重试钩子,你就只能干瞪眼。从当前调研资料看,两者在自动降级和熔断方面的能力都不够成熟,都需要引入外部中间层(如你的网关或编排框架)。
可观测性
这是差距最大的地方。Agents SDK 的“内置 Agent 循环”是一把双刃剑:它可以自动记录工具调用和 Handoff 过程,但这些日志的结构化程度有限,且缺乏开箱即用的 trace ID 跨 Agent 串联。你通常需要自行集成 OpenTelemetry 或使用 OpenAI 的 Dashboard 来补全监控。而 Claude Skills 由于本身是无状态的,每次 Skill 调用都会返回清晰的输入/输出对,你可以用 API 网关直接截获这些请求,做完整的审计和策略检测。这对于合规性要求高的企业场景,是一个实打实的加分项。
生产就绪度对比速览:
| 能力项 | OpenAI Agents SDK | Claude Skills | 作者的结论 |
|---|---|---|---|
| 流式响应 | Agent 级别原生支持 | Skill 级别支持,无法流式输出内部步骤 | SDK 更适合渐进式 UI |
| 错误重试 | 基础重试,需自行扩展 | 依赖平台;较难自定义 | 都需要额外设计容错层 |
| 沙盒/隔离 | 内置沙盒 Agent | Skill 运行在平台沙箱内 | 两者安全性都足够 |
| 监控与追踪 | 日志有结构,但跨 Agent 追踪需自建 | 请求/响应天然可记录 | Skills 的审计成本更低 |
| 会话管理 | 内建 Sessions 机制,需管理生命周期 | 无状态,每次调用独立 | SDK 的状态管理更容易出 bug |
看完这些,你可能会形成一个印象:Agents SDK 更灵活但更“重”,Skills 更克制但更“稳”。 这个印象基本正确。但为了不让决策停留在直觉层,我们最后把它固化为可操作的建议。
结论与选型建议
回到开头的那句话:它们是对同一问题的两种极端解法。 我们无法断言哪种方法绝对领先,但可以根据团队的技能栈、产品的可预测性需求,以及你对调试成本的承受力,做出一张清晰的决策地图。
| 对比维度 | OpenAI Agents SDK | Claude Skills |
|---|---|---|
| 核心编排模型 | Agent 间 Handoff(命令式) | 声明式能力包 + LLM 调度 |
| 适合的任务特征 | 多步推理、动态分解、多 Agent 协作 | 明确步骤、可枚举工具、需审计安全 |
| 开发调试难度 | 中高(Agent 间上下文调试困难) | 中(单 Skill 调试简单,多 Skill 协作需观察 Prompt) |
| 生产运维成本 | 需要自建监控、重试、状态管理 | 依赖平台 SLA,运维边界清晰 |
| 生态系统兼容性 | 强绑定 OpenAI 模型(虽支持其他 API 但 Handoff 特性可能受限) | 理论上模型无关,但目前主要在 Claude 上实现 |
具体场景推荐:
- 你的团队是 Python 原生,需要快速搭建一个能动态决定“接下来让哪个 Agent 干活”的智能体系统,并且可以接受在调试阶段投入较多时间排查 Handoff 问题 → 选 OpenAI Agents SDK。
- 你需要的是为已有的 Claude 工作流增加可复用的知识模块,每个模块独立测试、独立上线,且要求每次调用行为都可审计、可解释 → 选 Claude Skills。
- 你正处在一个混合生态中(既有 OpenAI 模型也有 Claude,或者未来可能切换模型提供商),并且看重能力模块的跨平台移植性 → 优先考虑声明式 Skills 方向,或者将 Agents SDK 的工具封装也用声明式描述的方式组织,以降低锁定风险。
无论选择哪条路,有一个准则不会变:不要把控制流全部扔给模型你自己又不管。 在 Agents SDK 里,这意味着你要主动限制 Handoff 深度,为每个 Agent 写清退出条件;在 Skills 里,这意味着你要在声明文件中明确使用条件和权限边界,避免模型在“自由发挥”中偏离预期。
在下一章,我们会跳出这两个具体实现,站在更高的视角俯瞰整个多智能体框架的演进路线。CrewAI、AutoGen、LangGraph 各自带着不同的设计主张和典型故障模式走上牌桌,而你将学会如何从“编排方式”和“故障模式”两个维度,为后续的深度选型打下基础。
agent skills 入门到精通
关于 LearnKu