从 API 交互中提取价值通常需要对一个端点进行多次调用才能达到预期结果。直到最近,标准和规范社区在如何可行地阐明跨单个或多个 API 所暴露的端点的多次调用探险方面,提供的指导甚少。即使在使用诸如 OpenAPI 等流行 API 规范时,团队也常常需要编写以人为中心的指南,以帮助提高 API 消费者完成集成工作的能力。为了解决这一问题以及 API 领域中其他常见的实际挑战,诸如 OpenAPI 倡议 (OAI) 等项目通过成立特殊兴趣小组 (SIG),即工作组,扩展了其关注领域。其中一个工作组专注于多步骤工作流场景,他们的工作促成了 OpenAPI 倡议演变为一个多规范项目,并于 2024 年 5 月推出了 Arazzo 规范 1.0.0。
事实上,2024 年,OAI 通过发布 Arazzo 1.0.0 以及 Overlay 1.0.0,同时还有 OpenAPI 规范的两个重要补丁版本:3.1.1 和 3.0.4,为活动设定了新标准。这一势头延续到 2025 年,标志是最近发布了 Arazzo 1.0.1 的补丁版本。
Arazzo 的更广泛用例
Arazzo 是实现基于 AI 的 API 消费的关键推动者,同时它也解决了当今 API 生产者和消费者面临的几个主要挑战:
- 提供确定性 API 消费“配方”:标准化工作流,确保可重复、结构化的 API 交互。
- 作为“活”的工作流文档:保持 API 工作流最新,而无需依赖过时或外部文档。
- 自动化面向消费者的文档:通过动态生成开发者门户文档,减少对带外文档的依赖。
- 实现端到端测试自动化:定义可用于自动化测试的 API 工作流。
- 简化法规合规性验证:自动化检查,以根据合规性要求验证 API 交互。
- 赋能下一代 API SDK 生成:实现工作流感知型 SDK,以改善侧重于特定用例的开发者体验。
- 实现代理式 API 消费:为 AI 模型和代理提供一致且可互操作的机制,以与 API 交互。
Arazzo 规范不强制要求特定的开发过程,例如设计优先或代码优先。相反,它通过建立与使用 OpenAPI 规范描述的 HTTP API 的清晰工作流交互来促进这两种技术(未来计划扩展到基于事件的协议和 AsyncAPI 规范)。
既然我们已经了解了 Arazzo 的众多用例,接下来让我们深入研究该规范本身。
图 1 - Arazzo 规范标志
Arazzo 规范结构
Arazzo 规范描述了一种以可编程读取格式记录面向用例的工作流的方法。Arazzo 支持的格式是 YAML 和 JSON,因此它们既是机器可读的,也足够人类可读。当我们在 Arazzo 的上下文中谈论工作流时,我们将其定义为一系列 API 调用,这些调用组合在一起可以实现某个业务目标。
Arazzo 额外的人类可读性提高了 API 提供商以改善消费者体验的方式讲述其 API 故事的能力。Arazzo 旨在满足人类开发者的需求并提升他们的开发者体验 (DX)。同时,Arazzo 完全了解 AI 代理的需求,并通过提供它们解析和执行复杂和/或敏感 API 工作流所需的确定性语义,同时提高了代理体验 (AX)。
如果您熟悉 OpenAPI 规范 (OAS),或者其姊妹规范 AsyncAPI,那么 Arazzo 规范对您来说应该会很熟悉。一个显著的偏差与 Arazzo 中可重用组件的引用方式有关。Arazzo 不使用 OpenAPI 的 $ref
机制(该机制与 JSON Schema 关键字 $ref
冲突),而是使用运行时表达式语法来指定非 JSON Schema 对象的引用(对于 JSON Schema 对象引用,请继续使用 $ref
,因为这在 JSON Schema 中有明确定义)。此处不再赘述详细信息,您可以查看 GitHub issue 以获取更多信息。
在大多数情况下,围绕元数据对象、可重用组件和规范语言本身的各种约定和模式应该会让您感到熟悉。
甚至下面的图片(单页规范样式)对您来说也应该很熟悉!
图 2 - Arazzo 规范 - 1.0.1
编写 Arazzo 描述意味着我们将创建(手动或优选地作为低代码、无代码或自然语言处理工具的输出)一个符合 Arazzo 规范的 YAML 或 JSON 文档。这意味着,一个文档要被归类为有效的 Arazzo 文档,它至少必须包含一个有效的 Arazzo 规范字段(例如 `arazzo: 1.0.1`
)、一个 `info`
字段、一个至少定义了一个源描述对象的 `sourcesDescriptions`
字段,并且在 `workflows`
字段中必须至少定义一个工作流。
在下面的章节中,我们将涵盖所有这些内容。别担心,这并不复杂!
Arazzo 规范对象
这是 Arazzo 描述的根对象。它标识所使用的 Arazzo 规范版本、各种元数据以及表示可由处理软件解析、渲染和/或执行的工作流。
图 3 - Arazzo 规范对象 - 最小示例
上面的示例提供了一个有效 Arazzo 文档的极简示例。该文档包含一个有效的 `arazzo`
版本,它指定了一个 `sourceDescriptions`
(在此示例中引用了远程服务器上的 OpenAPI 描述),并且定义了一个至少包含一个步骤的工作流。
Arazzo 规范使用 major.minor.patch
版本控制方案。截至撰写本文时,可用的 Arazzo 版本为 1.0.1
(2025 年 1 月发布)和 1.0.0
(2024 年 5 月发布)。
字段名称
|
描述
|
必需
|
arazzo
|
Arazzo 描述所使用的 Arazzo 规范版本。
|
是
|
info
|
提供 Arazzo 描述中包含的工作流的元数据。
|
是
|
sourceDescriptions
|
工作流所适用的源描述列表(例如 OpenAPI 描述)。
|
是
|
workflows
|
应用于 sourceDescriptions 中定义的各种 API 端点的工作流列表。
|
是
|
components
|
Arazzo 描述的各种可重用元素/模式 – 有助于减少冗余。
|
否
|
Arazzo 结构 – Info 对象
Info 对象包含关于所定义 Arazzo 文档的元数据。这些信息对于可发现性、构建使用 Arazzo 描述的面向用例功能的目录或市场很有用。
图 4 - Arazzo 规范 - Info 示例
上面的示例提供了一个丰富的 Info 对象示例,其中 title, summary,
和 description
字段为消费者设置了清晰的上下文,使他们能够理解当前 Arazzo 文档可以实现什么。version
字段代表当前文档的版本,请勿与 Arazzo 规范本身的版本混淆!
字段名称
|
描述
|
必需
|
title
|
Arazzo 文档的人类可读标题。
|
是
|
summary
|
可实现内容的简短摘要。
|
否
|
description
|
所定义工作流目的的描述。
|
否
|
version
|
文档的版本标识符(这不是文档所符合的规范版本)。
|
是
|
Arazzo 结构 – 源描述对象
Arazzo 文档包含一个 sourceDescriptions
属性,它是一个 源描述对象数组。它列出了源描述,这些源描述可以是 OpenAPI 描述或另一个 Arazzo 文档,并且可以由一个或多个已定义的工作流引用。从编程语言的角度来看,最好将其视为类似于 namespaces
或 imports
。它们设置了入口 Arazzo 文档中的工作流可以应用到的范围(或边界)。
图 5 - Arazzo 规范 - SourceDescriptions 示例
在上面的示例中,指定了两个 OpenAPI sourceDescriptions
。任何定义的工作流都可以包含与所引用的一个或两个 OpenAPI 描述中的操作进行交互的步骤。这非常强大!
字段名称
|
描述
|
必需
|
name
|
源描述的唯一名称。
|
是
|
url
|
工作流将使用的源描述的 URL。它可以是相对于 Arazzo 文档的。
|
是
|
type
|
源描述的类型。可能的值为 "openapi" 或 "arazzo"。未来计划添加“asyncapi”!
|
否
|
Arazzo 结构 – 工作流对象
Arazzo 文档可以包含一个或多个工作流对象,这些对象在 workflows
属性中指定。它们描述了跨一个或多个 API 执行以实现特定目标或结果的工作流。工作流的强大之处在于,它们定义的步骤可以包含对托管在多个 API 中的 API 端点/操作的调用。工作流中的步骤也可以调用其他工作流,这意味着可以轻松地将复杂的多种工作流编排链接在一起,同时仍然确保模块化、更好的维护和可测试性。
图 6 - Arazzo 规范 - 工作流示例
在上面的部分示例中,定义了一个工作流。workflowId
唯一地定义了工作流,而 summary
和 description
则为消费者提供了工作流所涵盖用例的上下文。
在下面的章节中,我们将深入探讨其他属性的细节。
字段名称
|
描述
|
必需
|
workflowId
|
表示工作流的唯一字符串。
|
是
|
summary
|
指定工作流的目的或目标。
|
否
|
description
|
工作流的描述。
|
否
|
inputs
|
工作流正常运行所需的输入(例如 API 密钥或令牌,或您想飞往的目的地)。所需内容使用 JSON Schema 进行描述。
|
否
|
dependsOn
|
在此工作流处理之前需要完成的工作流列表。
|
否
|
steps
|
有序的步骤列表。每个步骤代表对 API 操作或另一个工作流的调用。
|
是
|
successActions
|
适用于此工作流下所有步骤的成功操作列表。可以将其视为如果某个步骤成功则要执行的操作(例如,我们可能在每个成功完成的步骤后触发一个事件)。
|
否
|
failureActions
|
适用于此工作流中所有步骤的失败操作列表。一个很好的例子是,如果一个步骤因认证令牌过期而失败,那么我们可以刷新令牌并重试该步骤。为了方便起见,我们将其放在这里,而不是在每个步骤中重复。
|
否
|
outputs
|
这些是工作流要返回的内容,可以由调用软件应用程序或代理处理。
|
否
|
parameters
|
适用于此工作流下所有步骤的参数列表。
|
否
|
Arazzo 结构 – 工作流输入
工作流通常需要提供其无法自行确定的各种输入。例如,如果我想预订一次旅行,那么我需要提供目的地、日期、费用范围(以及更多)的人工输入。此外,执行工作流的软件可能还需要传入用于 API 调用的安全凭证等。Arazzo 通过允许使用 JSON Schema 对象来描述 inputs
,从而灵活地满足了这一需求。
图 7 - Arazzo 规范 - 工作流输入示例
在上面的示例中,一个 JSON Schema 对象描述了工作流的预期输入。在此示例中,指定了四个 string
类型的输入,其中三个是必需的。
Arazzo 结构 – 步骤对象
工作流中的 steps
代表了 Arazzo 文档最重要的部分。每个步骤都代表对 API 操作的调用,或对另一个工作流的调用。后者使得工作流具有模块化特性,并允许作者在步骤级别通过利用其他预定义或可发现的工作流来构建更复杂的工作流。例如,如果存在一个用于获取 OAuth 2.0 Bearer Token 的工作流,那么利用它将比将完整的授权码流协商内联到每个创建的工作流中更为有利。
图 8 - Arazzo 规范 - 步骤示例
在上面的部分示例中,我们有一个 searchPets
步骤,其中包含清晰的 description
。该步骤将调用在 sourceDescriptions
中定义的 petsAPI 内的 getPets 操作。这里的语法遵循 Arazzo 规范的运行时表达式语法。
字段名称
|
描述
|
必需
|
stepId
|
表示步骤的唯一字符串。
|
是
|
description
|
步骤的描述。
|
否
|
operationId
|
在 sourceDescriptions 中引用的 API 内定义的 operationId 。
|
条件: operationId 或 operationPath 或 workflowId 必须定义
|
operationPath
|
指向 sourceDescriptions 中引用的 API 的 JSON Pointer 引用(由于 operationId 在 OpenAPI 中并非强制,我们必须有其他方式来引用操作 L)。
|
条件: operationId 或 operationPath 或 workflowId 必须定义
|
workflowId
|
在 sourceDescriptions 中引用的 Arazzo 工作流(或当前 Arazzo 文档中的另一个工作流)中定义的 workflowId 。
|
条件: operationId 或 operationPath 或 workflowId 必须定义
|
parameters
|
必须传递给此步骤中引用的操作或工作流的参数列表
|
否
|
requestBody
|
如果引用了操作,则要传递给操作的请求正文。
|
否
|
successCriteria
|
确定步骤成功与否的断言列表。
|
否
|
onSuccess
|
成功操作对象数组,指定步骤成功后要执行的操作(如果某些条件成立,我们可能会跳到最后一步)。
|
否
|
onFailure
|
失败操作对象数组,指定步骤失败后要执行的操作(我们是否可以恢复并重试,或者首先调用另一个工作流等)。
|
否
|
outputs
|
这些是从步骤返回的内容,可以由工作流中的后续步骤处理或映射到工作流输出。
|
否
|
Arazzo 结构 – 步骤参数
在定义将调用 API 的 Arazzo 步骤时,通常您可能需要指定操作上的某些参数。这些可以是 HTTP 头部、查询参数、路径参数等。Arazzo 通过 Parameters 对象来满足此需求。
图 9 - Arazzo 规范 - 步骤参数示例
在上面的示例中,定义了四个查询参数。前三个参数的值是动态的,并从 inputs
中定义的属性映射而来。status
属性的值是一个字面字符串(例如“available”)。
字段名称
|
描述
|
必需
|
name
|
参数名称。
|
是
|
in
|
参数的位置。可能的值为 "path"、"query"、"header" 或 "cookie"。当上下文中的步骤指定 workflowId 时,所有参数都映射到工作流输入。
|
条件:如果在步骤中指定了 operationId 或 operationPath ,则为必需。
|
value
|
要传递给参数的值。该值可以是常量或运行时表达式。
|
是
|
Arazzo 结构 – 步骤成功条件
为了决定一个步骤完成后做什么,我们需要知道该步骤是否成功。这可能是一个简单的检查,也可能更复杂,例如检查 API 调用返回的 HTTP 状态码以及检查响应负载中的特定内容。successCriteria
指定了要验证的条件列表。如果所有指定的断言都通过,则该步骤可以被视为成功。
图 10 - Arazzo 规范 - 步骤成功条件示例
在上面的示例中,指定了两个条件。这两个条件都必须评估为 true
才能认定该步骤成功。第一个条件指定 API 调用返回的 HTTP 状态码必须是 200
。第二个条件指定 API 的响应必须包含一个响应体,该响应体预期为 application/json
类型,并且在该负载中将有一个根级别的 pets 数组——其长度应大于零。
字段名称
|
描述
|
必需
|
context
|
一个用于设置条件应用上下文的运行时表达式。
|
条件:
如果指定了 type ,则必须提供 context
|
condition
|
要应用的条件。条件可以是简单的(例如 $statusCode == 200,它对从运行时表达式获得的值应用操作符),也可以是正则表达式,或 JSONPath 表达式。对于正则表达式或 JSONPath,必须指定 type 和 context。
|
是
|
type
|
要应用的条件类型。如果指定,允许的选项为 simple, regex, jsonpath 或 xpath 。
|
|
Arazzo 结构 – 失败操作对象
正如生活中一样,API 调用并非总是如我们所愿。能够处理非正常路径是 Arazzo 规范的一个独特优势。步骤中的 onFailure
属性允许我们指定当 API 返回不符合 successCriteria
属性中定义的条件时应执行的操作。如果未指定任何操作,则整个工作流将在失败点停止。
图 11 - Arazzo 规范 - 失败操作示例
上面的示例指定了一个 retry
类型的失败操作,如果步骤引用的 API 返回 HTTP 状态码 503
(例如服务器不可用),则将执行此操作。根据配置,当前步骤应在 1 秒后重试(由 retryAfter
指定),如果 API 继续返回 503
状态码,则应在 5 次尝试后停止重试(由 retryLimit
指定)。
字段名称
|
描述
|
必需
|
name
|
失败操作的名称。
|
是
|
type
|
要执行的操作类型。可能的值为 "end "、"retry " 或 "goto "。
|
是
|
workflowId
|
引用现有工作流的 workflowId ,在步骤失败时转移到该工作流。
此字段仅在 type 字段值为 "goto " 或 "retry " 时相关。一个常见示例是,如果 API 因令牌过期而返回 HTTP 401,您可以在此处引用一个刷新令牌工作流。
|
否
|
stepId
|
在步骤失败时要转移到的 stepId 。此字段仅在 type 字段值为 "goto " 或 "retry " 时相关。
|
否
|
retryAfter
|
步骤失败后延迟的秒数,在此之后进行另一次尝试。
|
|
retryLimit
|
一个整数,表示在整个步骤失败之前,步骤可能重试的次数。
|
否
|
criteria
|
确定此操作是否应执行的断言列表。
|
否
|
type
字段有三个可能的值。
end
- 工作流结束,上下文连同适用的输出返回给调用者。
retry
- 当前步骤将被重试。重试可以受 retryAfter
和 retryLimit
字段的约束。
goto
- 工作流控制的单向转移到指定标签(可以是 workflowId
或 stepId
)。
Arazzo 结构 – 成功操作对象
默认情况下,工作流中指定的步骤将按顺序执行。在某些情况下,我们可能能够确定我们拥有跳过几个步骤并加快执行所需的信息,从而更快地获取可用价值!onSuccess
属性实现了这种类型的控制。
图 12 - Arazzo 规范 - 成功操作对象
在上面的示例中,我们有一个 goto
类型的成功操作。该示例演示了,如果我们从 API 请求中获得至少一个符合条件的宠物,那么我们就可以跳转到 joinWaitingList
步骤。
字段名称
|
描述
|
必需
|
name
|
成功操作的名称。
|
是
|
type
|
要执行的操作类型。可能的值为 "end " 或 "goto "。
|
是
|
stepId
|
在步骤成功时要转移到的 stepId。此字段仅在 type 字段值为 "goto " 时相关。
|
否
|
criteria
|
确定此操作是否应执行的断言列表。
|
否
|
type
字段有两个可能的值。
end
- 工作流结束,上下文连同适用的输出返回给调用者。
goto
- 工作流控制的单向转移到指定标签(可以是 workflowId
或 stepId
)。
Arazzo 结构 – 步骤输出
当我们执行一个工作流步骤时,我们通常希望将信息提供给工作流中的后续步骤。例如,如果我们搜索了一个产品,那么我们可能希望将该产品的标识符提供给下一步,以便将其添加到我们的购物车中。步骤 outputs
数组包含一个在单个名称和动态输出值之间建立映射的映射。
图 13 - Arazzo 规范 - 步骤输出示例
在上面的简单示例中,我们返回一个名为 petId
的唯一输出,其值由运行时表达式定义,该表达式将由处理步骤的软件评估,以使宠物的实际标识符可用于工作流中的后续步骤。
Arazzo 结构 – 工作流输出
工作流 outputs
遵循与步骤中相同的原则。唯一的区别是,从处理的角度来看,工作流输出会返回到调用上下文。如果一个软件应用程序正在执行一个工作流,那么输出将返回给该应用程序进行评估、存储或渲染。
图 14 - Arazzo 规范 - 工作流输出示例
图 15 - Arazzo 中的其他可重用对象
示例
让我们通过一个简单的虚构示例,了解一家公司如何利用 Arazzo 规范来增强其 API 产品和消费者能力。为此,我们将假定一个名为 PetCo 的虚构公司的身份。
问题陈述:
我们发现了一个业务问题。我们被宠物店里被遗弃的宠物数量所困扰。
拟议解决方案:
经过广泛研究,我们决定开发能够搜索和领养我们目录中宠物的功能。我们将通过我们的网站提供此领养服务,并向在我们的研究中表示需要此类服务的更广泛的宠物收容所、宠物慈善机构和宠物孤儿院生态系统提供 API。
我们的 API:
根据我们的组织结构,我们成立了一个新团队来管理领养 API,它们与核心宠物目录设施是独立的。因此,我们提供的 API 如下:
- 宠物 API – 提供宠物编目所需的资源和方法。
- 领养 API – 提供启动和管理领养所需的资源和方法。
图 16 - 宠物 API 示例
图 17 - 领养 API 示例
工作流
为了简化更广泛的消费者生态系统的理解和消费,我们希望阐明领养符合特定条件的宠物所涉及的过程。为此,我们将利用 Arazzo 规范来描述以下所需步骤。
- 根据特定条件搜索宠物。
- 发起领养请求。
- 通过更新领养状态确认领养。
- 通过确保宠物目录条目不再将宠物标记为可用,验证领养已完成。
在下面的视频中,我们展示了如何利用我们的公共 Arazzo Specification GPT 来快速创建 Arazzo 文档,并使用“领养宠物”产品准备我们的 API Hub 开发者门户,包括分步开发者文档和客户端代码示例。
图 18 - SmartBear 提供的 Arazzo Specification GPT
结论
Arazzo 规范有望在未来 API 技术中发挥重要作用。随着对互连多个数字生态系统的复杂 API 的需求不断增长,该规范将需要处理复杂场景,适应新兴技术(如 AI)。事实上,向 AI 驱动的 API 消费的转变正在加速对确定性 API 工作流的需求!
无论您是自动化工作流、实现 AI 消费还是增强 API 治理,Arazzo 都是开启下一代 API 驱动创新的关键。作为 Linux 基金会下 OpenAPI 倡议中的一个开放标准,Arazzo 有望以开放和协作的方式发展,并继续支持行业需求。
一个充满活力的工具生态系统正在涌现,支持 Arazzo,我们正在 SmartBear 的 API Hub 产品中致力于对 Arazzo 的广泛支持。如果您等不及我们发布,您可以查看用于 Lint Arazzo 文档的 Spectral,并在 OpenAI GPT 商店中试用我们的 Arazzo GPT。