跳到正文
AWS Machine Learning Blog· Anshika Saxena·· 2 小时前精选AI 评分63

Amazon Bedrock 为 Anthropic Claude 模型推出结构化输出功能

Structured outputs for Anthropic Claude models on Amazon Bedrock

AI 导读

Amazon Bedrock 正式支持所有 Anthropic Claude 模型的结构化输出,在 bedrock-runtime 和 bedrock-mantle 两个端点可用,模型生成时通过约束解码强制 JSON schema,无需自定义解析和重试逻辑。

推荐理由

原文解释了约束解码的工作机制、24 小时语法缓存和 schema 支持范围,读者可据此评估现有解析与重试逻辑能否简化。

正文 · AI 翻译

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

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

实际应用

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

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

结构化输出使用约束解码在 token 生成过程中强制执行您的 JSON schema,而不是事后处理。模型不会生成违反您 schema 的 token。这将输出格式从概率性转变为确定性。

现在两个 Amazon Bedrock 端点上都提供了两种互补的机制:

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

这对您意味着什么

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

支持的模型与可用性

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

工作原理

当您使用 JSON schema 发起请求时,后台会发生以下操作:

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

性能考量

在性能方面,使用新 schema 的第一个请求可能耗时较长,因为 Amazon Bedrock 会在生成开始前编译一个语法工件。完成初次编译后,使用同一 schema 的后续请求几乎不会产生额外开销,因为编译后的语法已被缓存。该缓存作用于你的账户,并自首次访问起持续 24 小时。更改 JSON schema 的结构会使缓存失效并触发一次全新的编译,而仅更改 name 或 description 字段则不会影响已缓存的语法。

入门:通过 InvokeModel API 使用结构化输出

InvokeModel API 接受 Anthropic 原生请求体,因此 schema 以 JSON 对象的形式放在 output_config.format 中,而不是 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 ([email protected]) 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": "[email protected]",
    "plan_interest": "Enterprise",
    "demo_requested": true
}

响应符合你的 schema,无需额外的验证。

更多 API 使用示例(包括 Messages API),请参阅随附的 示例笔记本。

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

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

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 可将模型的工具输入约束为与你的 schema 完全匹配。location 字段始终是字符串,unit 字段始终是 celsius 或 fahrenheit。模型无法添加 schema 之外的字段,因此工具输入只包含你的 schema 所指定的内容。

这对 Amazon Bedrock Mantle 上的智能体用例尤其有价值,在这些场景中,模型会借助 web search 和 code interpreter 等服务端工具编排多步骤工作流。

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:当字段的合法取值有限时,使用 enum 来约束选项。
  4. 先从简单开始,再逐步增加复杂度:从最少必需字段开始,逐步增加复杂度。简单的 schema 编译更快、更易调试,并且由于 schema 会计入 Converse API 的负载大小,因此能让请求负载保持精简。
  5. 复用 schema 以利用缓存:在应用程序结构设计上跨请求复用 schema。24 小时的语法缓存可提升重复查询的性能。
  6. 检查每个响应中的停止原因:有两种情况可能产生不符合 schema 的响应:拒绝(模型因安全原因拒绝回答)和 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 文档并探索我们的示例笔记本。

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


关于作者

来源: AWS Machine Learning Blog · aws.amazon.com