优化 AWS Bedrock 结构化输出: JSON Schema 设计指南
- 作者

- 姓名
- Nino
- 职业
- Senior Tech Editor
在大语言模型(LLM)的应用开发中,获取格式正确的响应往往与获取准确的内容同样重要。 AWS Bedrock 最近推出了“受限解码”(Constrained Decoding)功能,该功能可以从推理层面保证模型输出严格符合预定义的 JSON Schema。然而,许多开发者存在一个误区:认为只要 Schema 校验通过,输出的数据质量就一定高。
事实上, JSON Schema 不仅仅是一个结构契约,它更是一个高权重的“提示词”(Prompt)。字段名称、描述信息、属性顺序以及枚举值(Enums)都会直接引导模型的注意力机制。通过 n1n.ai 调用 Claude 3.5 Sonnet 等顶级模型时,深刻理解“Schema 即提示词”的设计哲学,是实现生产级可靠性的关键。
AWS Bedrock 如何强制执行结构化输出
与传统的“先生成后校验”(即生成后再通过正则或第二次 LLM 调用来修复错误 JSON)不同, AWS Bedrock 的受限解码是在推理过程中实现的。当你提交一个 Schema 时, Bedrock 会执行以下步骤:
- 校验: 验证 Schema 是否符合 JSON Schema Draft 2020-12 标准。
- 编译: 将 Schema 编译成一种专门的语法(Grammar)。首次运行可能需要几分钟时间。
- 缓存: 编译后的语法会在每个账户下缓存 24 小时,以加速后续调用。
- Token 掩码: 在模型逐个生成 Token 的过程中, Bedrock 会修改 Token 的对数概率(Logprobs)。任何会导致违反 Schema 的 Token 都会被物理遮掩(Masked),使得模型在逻辑上无法产出不符合规范的 JSON。
以下是使用 Python SDK (boto3) 的基础实现代码:
import boto3, json
# 专业建议:使用 n1n.ai 可以在不同区域和模型间快速切换测试性能
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
schema = {
"type": "object",
"properties": {
"customer_name": {"type": "string"},
"sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
},
"required": ["customer_name", "sentiment"],
"additionalProperties": False, # AWS Bedrock 强制要求设置为 False
}
response = bedrock.converse(
modelId="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
messages=[{
"role": "user",
"content": [{"text": "分析这段文字:'我非常喜欢这个产品!' —— Sarah"}],
}],
inferenceConfig={"maxTokens": 256},
outputConfig={
"textFormat": {
"type": "json_schema",
"structure": {
"jsonSchema": {
"schema": json.dumps(schema),
"name": "sentiment_analysis",
}
},
}
},
)
data = json.loads(response["output"]["message"]["content"][0]["text"])
# 输出结果:{"customer_name": "Sarah", "sentiment": "positive"}
原则一:描述性命名即语义引导
LLM 是按顺序生成 Token 的。当模型写下 "customer_full_name": 这个键名时,这串特定的 Token 序列就成为了生成后续值的上下文。像 Claude 3.5 Sonnet(可通过 n1n.ai 访问)这样在海量代码和文档上训练过的模型,对字段名具有极强的先验理解。
应尽量避免使用 field1 或 val 这种模糊的名称。相反,使用 product_rating_out_of_five 这样具有明确含义的名称。字段名越具描述性,模型预测后续数值 Token 的准确度就越高。
原则二:Description 是嵌入式指令
在传统的 JSON Schema 中, description 字段通常被视为给人类看的元数据。但在 LLM 应用中,它们是实时的指令。 PARSE 研究系统表明,通过优化字段描述(结合其他优化手段),可以将提取准确率提高 64.7% 以上。
例如,在提取客服工单时,不要只定义一个 severity 字段,而应像这样定义:
{
"severity": {
"type": "string",
"enum": ["low", "medium", "high", "critical"],
"description": "low 表示视觉或轻微问题; medium 表示性能下降; high 表示核心功能损坏; critical 表示数据丢失或系统宕机"
}
}
通过将业务逻辑直接编码进 Schema,你可以显著减少系统提示词(System Prompt)的复杂度,提高指令遵循的一致性。
原则三:字段顺序的力量(推理优先)
这是处理复杂任务时最重要的技巧。由于 LLM 是顺序生成字段的,因此 Schema 中属性出现的顺序决定了模型的“思考顺序”。你应当始终将“推理”或“分析”字段放在最终“结论”字段之前。
如果你先要求模型输出布尔值 is_fraudulent(是否欺诈),模型必须在处理证据之前就给出答案。如果你在布尔值之前放置一个 risk_analysis 字符串字段,模型在编写分析过程的同时就在进行“思考”,从而得出更准确的最终判断。这实际上是将“思维链”(Chain of Thought)直接嵌入到了数据结构中。
原则四:利用可空类型(Nullable)防止幻觉
如果一个字段被标记为 required(必填),但源文本中确实没有相关信息,模型为了满足 Schema 约束,很可能会编造(幻觉)一个值。为了防止这种情况,请使用可空类型:
{
"company_name": {
"type": ["string", "null"],
"description": "如果文本中提到了公司名称则返回,否则返回 null"
}
}
这给了模型一个安全的“出口”,在 RAG(检索增强生成)流程中能显著降低幻觉率。
原则五:枚举(Enums)的机械与语义约束
枚举值不仅在机械层面限制了输出(模型无法产出集合之外的 Token),还在语义层面告诉了模型存在哪些类别。 AWS Bedrock 官方建议尽可能使用枚举来提高准确性。如果不使用枚举,你可能会得到 "positive"、 "Positive"、 "good" 等各种不统一的回复,给下游业务逻辑带来巨大麻烦。
企业级扩展的最佳实践
在生产环境中扩展 LLM 应用时,请注意以下技术细节:
- Token 限制: 如果
maxTokens设置过小,导致 JSON 在闭合前被截断,输出将变为非法格式。务必预留足够的 Token 空间。 - 额外属性: AWS Bedrock 要求所有对象必须设置
"additionalProperties": false。这是为了确保语法状态机的确定性。 - 扁平化设计: 尽量保持 Schema 结构扁平。深层嵌套(超过 3 层)会增加推理延迟,并可能导致模型丢失上下文注意力。
通过将这些 Schema 设计策略与 n1n.ai 提供的多模型聚合能力相结合,你可以确保结构化输出不仅格式正确,而且在语义上高度可靠,为后续的自动化流程打下坚实基础。
在 n1n.ai 获取免费 API 密钥。