博客 AI / Structured Output

Claude Fable 5.1 JSON 輸出能力怎麼樣?AI Structured Output 與 API 開發實測方向

Claude Fable 5.1 在 2026-09-01 上线,API 模型名是claude-fable-5-1。文档里同时出现output_config.format和工具上的strict: true——都承诺「结构化 JSON」,但保证范围并不相同。

Claude Fable 5.1把 Structured Output 做成了 Messages API 的正式能力:你在请求里附带 JSON Schema,模型在生成最终回答时被约束,使输出 conform 到字段、类型和必填项。对 API 开发来说,问题不再是「会不会吐 JSON」,而是「这份契约在 Claude、OpenAI、Gemini 上分别保证到哪一层」。Structured Output 不再是 beta 头。

本文将说明:

先记住这一点:Fable 5.1 的 JSON 能力已經夠做生產契約,但「API 層 conform」不等於「業務層正確」。forced tool 會直接 400;minimum / minLength 這類約束也不會進解碼器。下面按規格 → 能力邊界 → 廠商對比 → 實測清單拆開。

Claude Fable 5.1 是什么

Claude Fable 5.1 是 Anthropic 面向长程 Agent、多步研究和文档/表格工作的旗舰推理模型。Claude API、Amazon Bedrock、Google Cloud、Microsoft Foundry 上的模型 ID 都是claude-fable-5-1。知识截止日期 2026-06,上下文 1M,同步输出上限 128K。

官方建议大多数工作负载先用 Claude Opus 5;只有当 Opus 5 在更高 effort 下评测仍不够,或任务本身是长时 Agent / 复杂推理时,再上 Fable 5.1。价格也说明了定位:输入/输出 $10 / $50 per MTok,是 Opus 5 的两倍。

规格 Claude Fable 5.1 Claude Opus 5 Claude Sonnet 5
上下文 / 最大输出 1M / 128K 1M / 128K 1M / 128K
价格($/MTok) $10 / $50 $5 / $25 $2 / $10
Thinking Adaptive,始终开启 Adaptive Adaptive
默认 effort high high high

官方文档:Claude Fable 5.1Structured outputs

JSON / Structured Output 能力边界

Fable 5.1 支持两条互补路径,可以单独用,也可以写在同一次请求里:

和「只在 prompt 里写请返回 JSON」相比,能力差在解码阶段:schema 会约束 token,而不是生成后再祈祷能 json.loads。

能力 Fable 5.1 表现 对 API 开发的含义
合法 JSON JSON outputs 路径下可视为保证 少写正则补洞和二次 LLM 解析
字段 / 类型 / 必填 按你提交的 schema conform 可以把输出直接喂校验器和业务代码
数值 / 长度约束 不支持,提交会 400 minimum、minLength 必须放业务层
强制调用某个工具 tool_choice any/tool 直接 400 改用 auto + strict,或改走 JSON outputs

结构化输出的通用原理见2026 AI Structured Output 完整解析。本文只补 Claude 这一侧的差异和怎么测。

output_config.format 怎么用

2026 年官方已把 beta 参数output_format迁到output_config.format。新代码不要再带 structured-outputs-2025-11-13 头。Python SDK 1.0+ 在 messages.create() 里传旧字段会 TypeError。

Claude Fable 5.1 — output_config.format
import anthropic

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-fable-5-1",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": "Extract ticket fields from: billing failed for acct-9921, user wants a refund.",
        }
    ],
    output_config={
        "format": {
            "type": "json_schema",
            "schema": {
                "type": "object",
                "properties": {
                    "category": {
                        "type": "string",
                        "enum": ["billing", "technical", "account", "other"],
                    },
                    "priority": {
                        "type": "string",
                        "enum": ["low", "medium", "high"],
                    },
                    "account_id": {"type": "string"},
                    "summary": {"type": "string"},
                },
                "required": ["category", "priority", "account_id", "summary"],
                "additionalProperties": False,
            },
        }
    },
)
print(next(block.text for block in response.content if block.type == "text"))

对象必须写additionalProperties: falserequired建议列出全部 property。少一个,请求可能被拒,或多出来的字段不会出现在输出里。

如果用 Pydantic,SDK 的client.messages.parse()仍接受 output_format 作为便利参数,内部会转成 output_config.format,并自动补 additionalProperties: false、去掉不支持的 constraint。

Strict tool use:不要再用 forced tool

Fable 5.1 的 Thinking 始终开启。强制工具调用会跳过思考,模型把推理写进 arguments,质量下降。所以tool_choice: {"type": "any"}{"type": "tool"}会返回 400 invalid_request_error。要 schema-valid 的工具参数,保持 auto,并打开 strict。

Strict tool use + tool_choice auto
{
  "model": "claude-fable-5-1",
  "max_tokens": 1024,
  "tool_choice": { "type": "auto" },
  "tools": [
    {
      "name": "create_ticket",
      "description": "Create a support ticket from extracted fields.",
      "strict": true,
      "input_schema": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "enum": ["billing", "technical", "account", "other"]
          },
          "priority": {
            "type": "string",
            "enum": ["low", "medium", "high"]
          },
          "summary": { "type": "string" }
        },
        "required": ["category", "priority", "summary"],
        "additionalProperties": false
      }
    }
  ],
  "messages": [
    { "role": "user", "content": "Use create_ticket for this refund request." }
  ]
}

想让模型一定调工具,把触发条件写进 prompt,例如「用 create_ticket 处理这条退款」。Agent 栈里 schema 还出现在 MCP inputSchema / outputSchema,见AI Agent 與 JSON Schema 完整解析

和 OpenAI / Gemini 对比

同一份业务 schema,三家 API 的挂载位置不同。做多模型路由时,先抽象 schema,再写三套薄适配层。

Claude Fable 5.1 OpenAI Gemini
请求字段 output_config.format response_format.json_schema responseSchema
类型声明 json_schema json_schema + strict application/json
额外字段 必须 additionalProperties: false Strict 模式同样强制 建议加上,不强制同一套报错
工具契约 tools[].strict + input_schema tools[].parameters / strict function calling + responseSchema

OpenAI 兼容面(如DeepSeek V4-Pro)通常跟 OpenAI 字段走;不要假设 Claude 的 output_config 能原样贴过去。

API 開發實測方向

评估「JSON 输出能力怎么样」,不要只看一次 happy path。用同一份 schema、同一组用例,分别打 Claude / OpenAI / Gemini,记录四项通过率。

  1. 1
    冻结一份跨厂商 schema

    只用三家都支持的子集:object、string、integer、enum、required、additionalProperties: false。先不要写 minimum 或递归 $ref,否则测的是厂商限制,不是模型能力。

  2. 2
    准备 4~8 条真实文本

    覆盖枚举边界、缺字段文本、多意图、超长描述。每条用例预先写好期望 category / priority,不要事后改标签。

  3. 3
    打四项符合率

    必填齐全、无多余 key、enum 落在集合内、类型全是声明类型。四项都过才算一次成功。单独统计 json.loads 失败率——Structured Output 路径上这项应接近 0。

  4. 4
    单独测 breaking change

    对 Fable 5.1 发一条 tool_choice: any,确认 400。再发一条带 minimum / minLength 的 schema,确认 400。这两条是回归用例,升级模型时先跑。

  5. 5
    看延迟和 token,不只看正确率

    Fable 5.1 默认 high effort,Thinking 始终开启,同样 schema 往往比 Sonnet 5 / Gemini Flash 更慢、更贵。把 P50 延迟和 output tokens 记进表格,决定哪条链路走 Fable、哪条走便宜模型。

最小打分函数
CASES = [
    "billing failed for acct-9921, user wants a refund",
    "cannot login after password reset, error 403",
    "please upgrade our workspace to Enterprise",
    "the app crashes when opening a 12MB JSON file",
]

EXPECTED_KEYS = {"category", "priority", "account_id", "summary"}

def score(payload: dict) -> dict:
    keys = set(payload)
    return {
        "has_required": EXPECTED_KEYS <= keys,
        "no_extra": keys <= EXPECTED_KEYS,
        "enum_ok": payload.get("category") in {"billing", "technical", "account", "other"},
        "types_ok": all(isinstance(payload.get(k), str) for k in EXPECTED_KEYS),
    }

把三次调用的原始 JSON 贴进 JSONNote Diff,比看日志更容易发现字段漂移。符合率掉到 95% 以下,先查 schema 是否混进了不支持的关键字,再查 prompt 是否和 enum 打架。

Schema 限制:官方不支持什么

JSON outputs 和 Strict tool use 共用同一套 JSON Schema 子集。用不支持的特性会直接 400,而不是「尽量遵守」。

类别 支持 不支持
基础 / 数值 type / properties / required / enum / const minimum / maximum / multipleOf
字符串 format date-time / email / uri / uuid minLength / maxLength
数组 minItems = 0 或 1 更大的 minItems / maxItems
$ref 本地 $ref / $def 外部 $ref、递归 schema

Python / TypeScript SDK 会自动剥掉不支持的 constraint,并写进 description。不要依赖这层静默改写——评测和线上应提交同一份已裁剪的 schema。

校验工作流:API 到业务层

推荐三层:API 选 JSON outputs 或 Strict tool → 业务层 json.loads + JSON Schema validate → 监控层记录违规率。Fable 5.1 不能替代后两层:空 content、截断、枚举大小写仍可能出现。

Python 校验示例
import json
from jsonschema import validate, ValidationError

SCHEMA = {
    "type": "object",
    "properties": {
        "category": {"type": "string", "enum": ["billing", "technical", "account", "other"]},
        "priority": {"type": "string", "enum": ["low", "medium", "high"]},
        "account_id": {"type": "string"},
        "summary": {"type": "string"},
    },
    "required": ["category", "priority", "account_id", "summary"],
    "additionalProperties": False,
}

def parse_llm_json(raw: str) -> dict:
    try:
        data = json.loads(raw)
    except json.JSONDecodeError as e:
        raise ValueError(f"Invalid JSON: {e}") from e
    try:
        validate(instance=data, schema=SCHEMA)
    except ValidationError as e:
        raise ValueError(f"Schema mismatch: {e.message}") from e
    return data

这份 SCHEMA 同时用于请求和校验。开发时把模型原文和 schema 贴进 JSONNote,比在终端里 print 快得多。

用 JSONNote 调试模型 JSON

跨厂商实测最耗时的是对比三次输出。JSONNote 在浏览器本地运行,Key 和样本都不上传:

  1. 1
    校验 schema 与输出

    把 Fable / OpenAI / Gemini 返回的 JSON 和同一份 schema 贴进JSON Schema,立刻看到缺字段、类型错、多余 key。

  2. 2
    格式化原始响应

    JSON 格式化确认是不是合法 JSON,排除日志转义造成的假错误。

  3. 3
    对比三次调用

    JSON Diff看字段名和枚举是否漂移,作为回归基线。

常見問題

Claude Fable 5.1 的 JSON 輸出可靠嗎?

在 output_config.format 路径上,语法合法和字段 conform 可以当作 API 保证。不可靠的是业务语义、数值范围、字符串长度——这些官方明确不进解码器。

還能用 tool_choice: any 嗎?

不能。Fable 5.1 / Mythos 5.1 对 any 和 tool 返回 400。改 auto + strict,或把最终结构放到 output_config.format;需要调用时在 prompt 里写清工具名。

和 OpenAI、Gemini 怎麼選?

要长程 Agent 和复杂抽取,Fable 5.1 的 schema 约束够用,但贵、慢。常规 CRUD 结构化输出优先 Sonnet 5 或 Gemini;多模型路由时 schema 用公共子集。

開了 Structured Output 還要手動校驗嗎?

要。API 约束不能替代 try/except + validate。空响应、网络截断、enum 大小写都可能漏过解码器。

舊的 output_format 還能用嗎?

REST 仍接受一段时间,但 Python SDK 1.0+ 的 messages.create() 会 TypeError。新代码一律写 output_config.format;parse() 助手可以继续用 output_format 这个便利名。

總結

Claude Fable 5.1 的 JSON 输出能力可以概括成三句:

Structured Output 已 GA;forced tool 被关掉;不支持的 schema 关键字会 400。

API 开发不要只 demo 一次 happy path。冻结公共 schema、跑符合率、把 breaking change 写成回归,再用 JSONNote 本地对比三次输出——这比再写一段「请返回 JSON」的 prompt 更接近生产。

← 返回博客