AWS Machine Learning更新于

Amazon Bedrock 上 Anthropic Claude 模型的结构化输出

Amazon Bedrock为所有Anthropic Claude模型推出结构化输出,通过受限解码在生成时强制JSON Schema,无需自定义解析与重试。文中给出代码示例,并注明新schema首次请求需编译语法、耗时更长。

配图来源 · AWS Machine Learning

Amazon Bedrock 现已在 bedrock-runtime 和 bedrock-mantle 两个端点上为所有可用该模型的区域的 Anthropic Claude 模型支持结构化输出。

无论您是通过 Boto3 和 bedrock-runtime API 调用 Claude,还是通过 Messages API 和 bedrock-mantle 端点调用 Claude,现在都可以获得符合定义结构的、符合架构的 JSON 响应。您不再需要自定义解析、重试逻辑或后处理。

实际应用

借助 Amazon Bedrock 上 Claude 的结构化输出,您可以跨行业自动化执行可靠且符合架构的任务。例如,从财报和合规文档中提取所有必填字段,将临床笔记解析为电子健康记录(EHR),以及使用一致的、经验证的结果丰富产品目录。您还可以分析合同中的关键条款、当事方和义务,或驱动智能支持工单路由,使意图、情感和实体始终与应用程序的数据模型匹配。

Amazon Bedrock 上结构化输出带来了哪些变化

结构化输出使用约束解码,在 token 生成期间(而非事后)强制执行您的 JSON 架构。模型不会产生违反您架构的 token。这将输出格式从概率性转变为确定性。

两个互补机制现已在两个 Amazon Bedrock 端点上可用:

功能 用途 用例
JSON Schema 输出格式 控制模型的响应结构 数据提取、报告生成、API 响应
严格工具调用 根据架构验证工具参数 智能体工作流、函数调用、多步骤自动化

这对您意味着什么

每个响应都是有效的 JSON,因此您不会再遇到 JSON.parse() 错误或解析异常。响应还是类型安全的:字段类型受到强制约束,必填字段始终存在。由于输出始终符合您的架构,您无需通过重试来处理架构违规,从而使您的集成更加可靠。结构化输出还将响应约束为仅包含您的架构定义的字段,这会减少输出 token 数量,并可降低高吞吐工作负载的推理成本。这些特性使结构化输出达到生产就绪水平,因此您可以大规模部署,而无需额外的架构验证代码。

支持的模型和可用性

结构化输出可与 批量推理配合使用,因此您可以在异步处理大量请求的同时,仍然获得符合架构的输出。在 bedrock-runtime 端点上,它还支持跨区域推理,因此您无需额外设置即可跨 AWS 区域使用。如果您需要实时响应,可以将结构化响应作为类型化事件进行流式传输。

工作原理

当您使用 JSON 架构发出请求时,幕后会发生以下过程:

  1. 架构验证 – Amazon Bedrock 会根据支持的 JSON Schema Draft 2020-12 子集验证您的 JSON 架构。
  2. 语法编译 – 对于新架构,Amazon Bedrock 会编译语法工件(首次请求可能耗时稍长)。
  3. 缓存 – 编译后的语法会缓存 24 小时,从而使后续请求更快。
  4. 约束生成 – 模型生成能够产生符合您的架构的有效 JSON 的 token。

性能考量

在性能方面,使用新架构的第一次请求可能耗时较长,因为 Amazon Bedrock 会在生成开始前编译一个语法工件。在完成该初始编译后,使用相同架构的后续请求将以极小的开销运行,因为编译后的语法已被缓存。此缓存的范围限于您的账户,并自首次访问起持续 24 小时。更改 JSON 架构的结构会使缓存失效并触发新的编译,而仅更改名称或描述字段则不会影响已缓存的语法。

入门指南:通过 InvokeModel API (bedrock-runtime) 使用结构化输出

InvokeModel API 采用 Anthropic 原生请求体,因此 schema 放在其中。 output_config.format 作为JSON对象而非JSON字符串。以下示例展示了如何使用boto3配合Anthropic Claude模型从客户电子邮件中提取结构化的潜在客户数据:

Python

import boto3
import json

REGION = "us-east-1" # Choose your preferred region
bedrock_runtime = boto3.client(service_name="bedrock-runtime", region_name=REGION)

# Define the JSON schema for structured output
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "description": "Customer name"},
        "email": {"type": "string", "description": "Customer email address"},
        "plan_interest": {"type": "string", "description": "Product plan of interest"},
        "demo_requested": {"type": "boolean", "description": "Whether a demo was requested"}
    },
    "required": ["name", "email", "plan_interest", "demo_requested"],
    "additionalProperties": False
}

# Make a request with structured outputs via the InvokeModel API
# (reusing the schema defined for the Converse example)
response = bedrock_runtime.invoke_model(
    modelId="global.anthropic.claude-sonnet-5-5",
    body=json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 512,
        "messages": [
            {"role": "user", "content": (
                "Paulo Santos (paulo@example.com) is interested in our Enterprise plan "
                "and wants to schedule a demo for next Tuesday at 2pm."
            )}
        ],
        "output_config": {"format": {"type": "json_schema", "schema": schema}}
    })
)

body = json.loads(response["body"].read())

# Check the stop reason before parsing
if body["stop_reason"] == "end_turn":
    result_text = next(b["text"] for b in body["content"] if b["type"] == "text")
    print(json.dumps(json.loads(result_text), indent=2))
elif body["stop_reason"] == "max_tokens":
    print("Response truncated: increase max_tokens and retry.")

JSON

{
    "name": "Paulo Santos",
    "email": "paulo@example.com",
    "plan_interest": "Enterprise",
    "demo_requested": true
}

响应符合您的 schema。无需进行额外的验证。

有关其他 API 使用示例,包括 Messages API,请参阅随附的 示例笔记本.

面向智能体工作流的严格工具使用

Amazon Bedrock Mantle 针对具有服务器端工具、后台推理和有状态对话的智能体应用而设计。通过 bedrock-mantle 端点上的严格工具调用,您现在可以保证工具参数与您的输入架构完全匹配。以下示例展示了如何定义一个具有严格架构约束的工具:

Import json
from anthropic import AnthropicBedrockMantle

# Reusing the client created in the Messages API example
client = AnthropicBedrockMantle(aws_region="us-east-1")

message = client.messages.create(
    model="anthropic.claude-sonnet-5",
    max_tokens=512,
    messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather for a specified location",
            "strict": True,
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g., San Francisco, CA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperature unit"
                    }
                },
                "required": ["location", "unit"],
                "additionalProperties": False
            }
        }
    ]
)

#Tool inputs conform to the schema
for block in message.content:
    if block.type == "tool_use":
        print(f"Tool: {block.name}")
        print(f"Input: {json.dumps(block.input, indent=2)}")

设置 strict: true 将模型的工具输入约束为完全匹配您的模式。location 字段始终为字符串,unit 字段始终为 celsius 或 fahrenheit。模型无法添加模式之外的字段,因此工具输入仅包含您的模式所指定的内容。

这对 Amazon Bedrock Mantle 上的代理(agentic)用例尤其有价值,因为在这类场景中,模型会借助网页搜索和代码解释器等服务器端工具来编排多步骤工作流。

Claude 结构化输出的主要用例

结构化输出在三种常见模式中最能降低错误处理的复杂性:

  • 数据提取: 从发票、合同、电子邮件和转录文稿中提取字段并转换为始终符合您的 schema 的 JSON,可直接加载到数据库或客户关系管理(CRM)系统中。
  • 可靠的代理工具调用: 在生成时根据其架构(schema)验证工具参数,从而使多步骤代理工作流能够顺利运行,不会因格式错误的输入而失败。
  • 大规模分类: 按意图、优先级和情感对工单、线索或内容进行分类,以便进行路由、审核和评估。

Claude Haiku 5.5 能够可靠地处理快速且重复的工作负载,例如摘要、压缩、数据库查询和分类请求。以下示例展示了如何使用 Invoke API 和 Haiku 5.5 对传入数据进行分类和路由:

import boto3
import json

REGION = "us-east-1" # Choose your preferred region
bedrock_runtime = boto3.client(service_name="bedrock-runtime", region_name=REGION)

# Classification schema: enums restrict output to a fixed set of labels
schema = {
    "type": "object",
    "properties": {
        "category": {
            "type": "string",
            "enum": ["billing", "technical", "account", "sales", "other"],
            "description": "Primary ticket category"
        },
        "priority": {
            "type": "string",
            "enum": ["low", "medium", "high", "urgent"],
            "description": "Urgency based on business impact"
        },
        "sentiment": {
            "type": "string",
            "enum": ["positive", "neutral", "negative"],
            "description": "Customer sentiment"
        },
        "escalate": {"type": "boolean", "description": "Whether a human should review immediately"},
        "reason": {"type": "string", "description": "One-sentence justification for the classification"}
    },
    "required": ["category", "priority", "sentiment", "escalate", "reason"],
    "additionalProperties": False
}

ticket = (
    "Our production API calls have been failing with 500 errors since this morning. "
    "We're losing orders every minute. This is the second outage this month!"
)

# Make a request with structured outputs via the InvokeModel API
response = bedrock_runtime.invoke_model(
    modelId="global.anthropic.claude-haiku-5-5",
    body=json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 512,
        "system": "You are a support ticket classifier. Classify the ticket accurately.",
        "messages": [
            {"role": "user", "content": f"Classify this support ticket:\n\n{ticket}"}
        ],
        "output_config": {"format": {"type": "json_schema", "schema": schema}}
    })
)

body = json.loads(response["body"].read())

# Check the stop reason before parsing
if body["stop_reason"] == "end_turn":
    result_text = next(b["text"] for b in body["content"] if b["type"] == "text")
    result = json.loads(result_text)
    print(json.dumps(result, indent=2))
    # Route the ticket based on the guaranteed-valid labels
    if result["escalate"]:
        print(f"Escalating to on-call: {result['category']} / {result['priority']}")
elif body["stop_reason"] == "max_tokens":
    print("Response truncated: increase max_tokens and retry.")

要求与最佳实践

要在 Amazon Bedrock 上有效使用结构化输出,请遵循以下指南:

  1. 在所有对象上设置 additionalProperties: false:这是结构化输出生效所必需的。没有它,你的 schema 将不会被接受。
  2. 使用描述性的字段名称和描述:模型使用属性名称和描述来理解需要提取哪些数据。像 customer_email 跑赢诸如以下这样的通用名称: field1.
  3. 对受限取值使用枚举:当某个字段的合法值有限时,请使用 enum 以限制选项。
  4. 从基础开始,然后逐步增加复杂性:从最少必需字段开始,逐步增加复杂性。基础 schema 编译更快、更易于调试,并使请求负载保持精简,因为 schema 会计入 Converse API 的负载大小。
  5. 复用 schema 以利用缓存:将应用程序设计为跨请求复用 schema。24 小时语法缓存可提高重复查询的性能。
  6. 检查每个响应中的停止原因:有两种情况可能产生不符合要求的响应:拒绝(模型出于安全原因拒绝)和 token 限制(在完成之前达到 max_tokens )。请在代码中处理这两种情况。
  7. 部署前使用真实数据进行测试:使用贴近生产环境的输入验证您的 schema。真实数据中的边缘情况常常会暴露 schema 设计问题。

有关其他最佳实践和 schema 设计建议,请参阅 Amazon Bedrock 用户指南 中的相关内容。

支持的 JSON Schema 特性

  1. 所有基本类型: object, array, string, integer, number, boolean, null.
  2. enum (仅限字符串、数字、布尔值或 null)。
  3. const, anyOf, allOf (有限制)。
  4. $ref, $def以及 definitions (仅限内部引用)。
  5. 字符串格式: date-time, time, date, duration, email, hostname, uri, ipv4, ipv6, uuid.
  6. 数组 minItems (仅限值 0 和 1)。

不支持

这些关键字会被 API 接受,但在生成过程中不会被强制执行。包含它们的请求会返回成功响应,并且模型仍可能返回违反这些约束的值。请在您的应用程序中验证这些约束,而不是依赖 schema 来强制执行它们。

  1. 递归 schema。
  2. 外部 $ref 引用。
  3. 数值约束(minimum, maximum, multipleOf).
  4. 字符串约束(minLength, maxLength).
  5. additionalProperties 设置为 false 以外的任何值。

结论

Amazon Bedrock 上 Anthropic Claude 模型的结构化输出提供了生产级 AI 应用程序所需的可靠性。该功能现已在 bedrock-runtime 和 bedrock-mantle 两个端点上可用。通过结合 JSON Schema 输出格式和严格工具使用,您可以构建无需额外验证的数据管道。您还可以创建可靠的智能体工作流和生产级 AI 应用程序,而无需自定义解析或重试逻辑。

Amazon Bedrock 上 Claude 的结构化输出现已正式发布。要了解更多信息,请参阅 Amazon Bedrock 文档 并探索我们的 示例 notebook.

经过验证的、符合 schema 的 JSON 可以改进您组织中的哪些工作流程?请在评论中分享您的反馈和问题。


关于作者

原始出处

AWS Machine Learning

内容说明

原始发布及相关权利归来源方。

机器翻译 · 请以原文为准