Skip to main content

Structured output

情報抽出や構造化データ生成タスクを実行する際、モデルが ```json のような余分なテキストを返し、後続の解析を妨げることがあります。構造化出力を有効にすると、モデルが有効な JSON 文字列を返すことが保証されます。また、JSON スキーマモードを使用すると、出力の構造と型を正確に制御できるため、追加の検証やリトライが不要になります。

使用方法

構造化出力は、JSON オブジェクトと JSON スキーマの 2 つのモードをサポートしています。
  • JSON オブジェクトモード:出力が有効な JSON 文字列であることを保証しますが、特定の構造は保証しません。使用方法:
    1. response_format パラメーターの設定:リクエストボディで、response_format を {"type": "json_object"} に設定します。
    2. プロンプトに JSON キーワードを含める:システムメッセージまたはユーザーメッセージには、「JSON」という単語 (大文字と小文字を区別しない) を含める必要があります。そうしない場合、API は 'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'. を返します。
  • JSON スキーマモード:出力が指定された構造に準拠することを保証します。使用方法:response_format を {"type": "json_schema", "json_schema": {...}, "strict": true} に設定します。
    プロンプトに JSON キーワードは不要です。
上記のパラメーターは Chat Completions API に適用されます。Responses API を使用する場合は、代わりに text.format を設定してください。値の形式は同じです。例は後述します。JSON Object モードでは、Responses API でもプロンプトに「JSON」というキーワードを含める必要があります。含めない場合は 400 エラーが返されます。
機能比較:

機能

JSON オブジェクトモード

JSON スキーマモード

有効な JSON を出力

はい

はい

スキーマに厳密に従う

いいえ

はい

サポート対象モデル

ほとんどの Qwen モデル

一部の qwen-plus モデルのみ

response_format の設定

{"type": "json_object"}

{"type": "json_schema", "json_schema": {...}, "strict": true}

プロンプトの要件

「JSON」を含める必要があります

明示的に記述することを推奨します

ユースケース

柔軟な JSON 出力

正確なスキーマ検証

サポート対象モデル

「ノンシンキングモード」と表記されたモデルは、ノンシンキングモードでのみ構造化出力をサポートします。
  • JSON オブジェクト
  • JSON スキーマ
  • Qwen
  • GLM
  • DeepSeek
  • Kimi
  • テキスト生成モデル
    • Qwen-Max:qwen4-max-preview (Token Plan 限定)、Qwen3.8-Max シリーズ、Qwen3.7-Max シリーズ
    • Qwen-Max (ノンシンキングモード):Qwen3.6-Max シリーズ、Qwen3-Max シリーズ、Qwen-Max シリーズ
    • Qwen-Plus:Qwen3.7-Plus シリーズ
    • Qwen-Plus (ノンシンキングモード):Qwen3.6-Plus シリーズ、Qwen3.5-Plus シリーズ、Qwen-Plus シリーズ
    • Qwen-Flash:Qwen3.8-Flash シリーズ、Qwen3.7-Flash シリーズ
    • Qwen-Flash (ノンシンキングモード):Qwen3.6-Flash シリーズ、Qwen3.5-Flash シリーズ、Qwen-Flash シリーズ
    • Qwen-Turbo (ノンシンキングモード):Qwen-Turbo シリーズ
    • Qwen-Coder:Qwen3-Coder シリーズ
    • Qwen-Long:Qwen-Long シリーズ
    • Qwen3.8 オープンソースシリーズ
    • Qwen3.6 オープンソースシリーズ (ノンシンキングモード)
    • Qwen3.5 オープンソースシリーズ (ノンシンキングモード)
    • Qwen3 オープンソースシリーズ (ノンシンキングモード)
    • Qwen3-Coder オープンソースシリーズ
    • Qwen2.5 オープンソースシリーズ (数学およびコーダーモデルを除く)
  • マルチモーダルモデル
    • Qwen-VL (ノンシンキングモード):Qwen3-VL-Plus シリーズ、Qwen3-VL-Flash シリーズ、Qwen-VL-Max シリーズ (最新およびスナップショットバージョンを除く)、Qwen-VL-Plus シリーズ (最新およびスナップショットバージョンを除く)
    • Qwen-Omni:Qwen3.5-Omni-Plus シリーズ
    • Qwen3-VL オープンソースシリーズ (ノンシンキングモード)

はじめに

この例では、個人のプロファイルから構造化情報を抽出します。 API キーを取得し、API キーを環境変数としてエクスポートします。OpenAI SDK または DashScope SDK を使用して呼び出しを行う場合は、SDK をインストールします。
  • OpenAI 互換の Chat Completions API
  • OpenAI 互換の Responses API
  • DashScope
  • Python
  • Node.js
  • curl
from openai import OpenAI
import os

client = OpenAI(
    # API キーはリージョンによって異なります。環境変数を設定していない場合は、次の行を api_key="sk-xxx" に置き換えてください
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 北京リージョンのモデルを使用する場合は、base_url を https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1 に置き換えてください
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=[
        {
            "role": "system",
            "content": "ユーザーの名前と年齢を抽出し、JSON 形式で返します"
        },
        {
            "role": "user",
            "content": "皆さん、こんにちは。私の名前は田中一郎です。34 歳で、メールアドレスは alexbrown@example.com です。バスケットボールと旅行が好きです",
        },
    ],
    response_format={"type": "json_object"}
)

json_string = completion.choices[0].message.content
print(json_string)

応答

{
  "Name": "Alex Brown",
  "Age": 34
}

画像と動画のデータ処理

マルチモーダルモデルは、画像や動画の構造化出力もサポートしています。JSON モードを使用して、レシートのフィールド値、画像内のオブジェクトの位置、動画内のイベントなど、視覚コンテンツから構造化データを抽出します。
画像と動画のファイル制限については、「画像と動画の理解」をご参照ください。
  • OpenAI 互換
  • DashScope
  • Python
  • Node.js
  • curl
import os
from openai import OpenAI

client = OpenAI(
    # API キーはリージョンによって異なります。API キーの取得: https://www.alibabacloud.com/help/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 北京リージョンのモデルの場合は、base_url を https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1 に置き換えてください
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
)

completion = client.chat.completions.create(
    model="qwen3-vl-plus",
    messages=[
        {
            "role": "system",
            "content": [{"type": "text", "text": "あなたは役立つアシスタントです。"}],
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "http://duguang-labelling.oss-cn-shanghai.aliyuncs.com/demo_ocr/receipt_zh_demo.jpg"
                    },
                },
                {"type": "text", "text": "画像からチケット (配列型、travel_date、trains、seat_num、arrival_site、price を含む) と請求書情報 (配列型、invoice_code と invoice_number を含む) を抽出します。チケットと請求書の両方の配列を含む JSON を出力します"},
            ],
        },
    ],
    response_format={"type": "json_object"}
)
json_string = completion.choices[0].message.content
print(json_string)

応答

{
  "ticket": [
    {
      "travel_date": "2013-06-29",
      "trains": "stream",
      "seat_num": "371",
      "arrival_site": "Development Zone",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

プロンプトの最適化

「ユーザー情報を返す」のような曖昧なプロンプトは、予測不能な出力構造につながります。信頼性の高い結果を得るには、プロンプトで期待されるスキーマを記述してください:フィールド名、型、必須/オプションのステータス、フォーマット制約 (日付形式など) を指定し、例を含めます。
  • OpenAI 互換
  • DashScope
  • Python
  • Node.js
from openai import OpenAI
import os
import json
import textwrap  # 複数行文字列のインデントを処理して、コードの可読性を向上させます

# モデルに期待される出力形式を示すための、事前定義された応答例
# 例 1: すべてのフィールドを含む完全な応答
example1_response = json.dumps(
    {
        "info": {"name": "Alice", "age": "25 years old", "email": "alice@example.com"},
        "hobby": ["singing"]
    },
    ensure_ascii=False
)
# 例 2: 複数の趣味を含む応答
example2_response = json.dumps(
    {
        "info": {"name": "Bob", "age": "30 years old", "email": "bob@example.com"},
        "hobby": ["dancing", "swimming"]
    },
    ensure_ascii=False
)
# 例 3: hobby フィールドのない応答 (hobby はオプション)
example3_response = json.dumps(
    {
        "info": {"name": "Dave", "age": "28 years old", "email": "dave@example.com"}
    },
    ensure_ascii=False
)
# 例 4: hobby フィールドのない別の応答
example4_response = json.dumps(
    {
        "info": {"name": "Sun Qi", "age": "35 years old", "email": "sunqi@example.com"}
    },
    ensure_ascii=False
)

# OpenAI クライアントを初期化
client = OpenAI(
    # 環境変数を設定していない場合は、次の行を api_key="sk-xxx" に置き換えます
    # API キーはリージョンによって異なります。API キーの取得: https://www.alibabacloud.com/help/ja/model-studio/get-api-key
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # これは北京リージョンの base_url です。シンガポールリージョンのモデルを使用する場合は、base_url を https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1 に置き換えます
    base_url="https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
)

# dedent は各行の共通の先頭の空白を削除し、ランタイムに余分なスペースを含めずにコード内で文字列をきれいにインデントできるようにします
system_prompt = textwrap.dedent(f"""\
    ユーザー入力から個人情報を抽出し、指定された JSON スキーマ形式で出力します。

    [出力形式の要件]
    出力は、この JSON 構造に厳密に従う必要があります。
    {{
      "info": {{
        "name": "文字列型、必須フィールド、ユーザー名",
        "age": "文字列型、必須フィールド、フォーマット '数字 years old'、例: '25 years old'",
        "email": "文字列型、必須フィールド、標準のメール形式、例: 'user@example.com'"
      }},
      "hobby": ["文字列配列型、オプションのフィールド、ユーザーのすべての趣味を含む。言及がない場合は完全に省略"]
    }}

    [フィールド抽出ルール]
    1. name: テキストからユーザー名を識別し、必ず抽出する
    2. age: 年齢情報を識別し、'数字 years old' 形式に変換し、必ず抽出する
    3. email: メールアドレスを識別し、元の形式を維持し、必ず抽出する
    4. hobby: ユーザーの趣味を識別し、文字列配列として出力する。趣味について言及がない場合は hobby フィールドを完全に省略する

    [参考例]
    例 1 (趣味あり):
    Q: 私の名前は Alice、25 歳、メールアドレスは alice@example.com、趣味は歌です
    A: {example1_response}

    例 2 (複数の趣味あり):
    Q: 私の名前は Bob、30 歳、メールアドレスは bob@example.com、ダンスと水泳が好きです
    A: {example2_response}

    例 3 (趣味なし):
    Q: 私の名前は Dave、28 歳、メールアドレスは dave@example.com です
    A: {example3_response}

    例 4 (趣味なし):
    Q: 私は Sun Qi、35 歳、メールアドレスは sunqi@example.com です
    A: {example4_response}

    上記の形式とルールに厳密に従って情報を抽出し、JSON を出力してください。ユーザーが趣味について言及していない場合は、hobby フィールドを含めないでください。\
""")

# モデル API を呼び出して情報抽出を実行
completion = client.chat.completions.create(
    model="qwen3.8-max",
    messages=[
        {
            "role": "system",
            "content": system_prompt
        },
        {
            "role": "user",
            "content": "みなさん、こんにちは。私の名前は Alex Brown、34 歳、メールアドレスは alexbrown@example.com、バスケットボールと旅行が好きです",
        },
    ],
    response_format={"type": "json_object"},  # JSON 形式の戻り値を指定
)

# モデルが生成した JSON 結果を抽出して出力
json_string = completion.choices[0].message.content
print(json_string)

応答

{
  "info": {
    "name": "田中一郎",
    "age": "34 歳",
    "email": "alexbrown@example.com"
  },
  "hobby": ["バスケットボール", "旅行"]
}

構造化出力の取得

response_format の type を json_object に設定すると、有効な JSON 文字列が返されますが、その構造は期待と異なる場合があります。これは単純なシナリオに適しています。自動解析、API の相互運用性、および厳密な型制約を必要とするその他の複雑なシナリオでは、type を json_schema に設定して、モデルに指定されたフォーマットに厳密に準拠したコンテンツを出力させます。response_format のフォーマットと例:
{
  "type": "json_schema",
  "json_schema": {
    "name": "schema_name",       // スキーマの名前
    "strict": true,              // 推奨:フォーマットに厳密に従う
    "schema": {
      "type": "object",
      "properties": {...},       // フィールド構造を定義 (右の例を参照)
      "required": [...],         // 必須フィールドのリスト
      "additionalProperties": false  // 推奨:定義されたフィールドのみを出力
    }
  }
}
上記の例では、モデルに 2 つの必須フィールド (name と age) とオプションの email フィールドを持つ JSON オブジェクトを出力させます。
シンガポールリージョンのモデルはまだサポートされていません。

使用方法

OpenAI SDK の parse メソッドを使用すると、Python の Pydantic クラスまたは Node.js の Zod オブジェクトを直接渡すことができます。SDK はそれを自動的に JSON スキーマに変換するため、複雑な JSON を手動で記述する必要はありません。DashScope SDK の場合は、上記のフォーマットに従って JSON スキーマを手動で構築します。
  • OpenAI 互換の Chat Completions API
  • OpenAI 互換の Responses API
  • DashScope

Python

from pydantic import BaseModel, Field
from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 次の URL はシンガポールリージョン用です。{WorkspaceId} を実際のワークスペース ID に置き換えてください。URL はリージョンによって異なります。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
)

class UserInfo(BaseModel):
    name: str = Field(description="ユーザー名")
    age: int = Field(description="ユーザーの年齢 (年)")

completion = client.chat.completions.parse(
    model="qwen3.8-max",
    messages=[
        {"role": "system", "content": "名前と年齢の情報を抽出します。"},
        {"role": "user", "content": "私の名前は鈴木五郎、25 歳です。"},
    ],
    response_format=UserInfo,
)

result = completion.choices[0].message.parsed
print(f"名前: {result.name}, 年齢: {result.age}")

Node.js

import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";

const openai = new OpenAI(
    {
        apiKey: process.env.DASHSCOPE_API_KEY,
        // 次の URL はシンガポールリージョン用です。{WorkspaceId} を実際のワークスペース ID に置き換えてください。URL はリージョンによって異なります。
        baseURL: "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
    }
);

const UserInfo = z.object({
  name: z.string().describe("ユーザー名"),
  age: z.number().int().describe("ユーザーの年齢 (年)"),
});

const completion = await openai.chat.completions.parse({
  model: "qwen3.8-max",
  messages: [
    { role: "system", content: "名前と年齢の情報を抽出します。" },
    { role: "user", content: "私の名前は鈴木五郎、25 歳です。" },
  ],
  response_format: zodResponseFormat(UserInfo, "user_info"),
});

const userInfo = completion.choices[0].message.parsed;
console.log(`名前: ${userInfo.name}`);
console.log(`年齢: ${userInfo.age}`);
コードを実行すると、次の出力が生成されます:
Name: Liu Wu, Age: 25

設定ガイド

より信頼性の高い構造化出力を得るために、JSON スキーマを使用する際は、以下のガイドラインに従ってください:
  • 必須フィールドの宣言 required 配列に必須フィールドをリストアップすることを推奨します。オプションのフィールドは省略できます。例:
{
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "integer"},
    "email": {"type": "string"}
  },
  "required": ["name", "age"]
}
入力にメール情報が含まれていない場合、出力にはこのフィールドは含まれません。
  • オプションフィールドの実装 required から省略する以外に、null 型を許可することもできます:
{
  "properties": {
    "name": {"type": "string"},
    "email": {"type": ["string", "null"]}  // 文字列または null にすることができる
  },
  "required": ["name", "email"]  // 両方とも required に含まれる
}
出力には常に email フィールドが含まれますが、その値は null になることがあります。
  • additionalProperties の設定 スキーマで定義されていない追加のフィールドを許可するかどうかを制御します:
{
  "properties": {"name": {"type": "string"}},
  "required": ["name"],
  "additionalProperties": true  // 追加のフィールドを許可
}
入力例:"私は佐藤太郎、25 歳です";出力:{"name": "佐藤太郎", "age": 25} (未定義の age フィールドを含む)。

値

動作

ユースケース

false

定義されたフィールドのみを出力

正確な構造制御

true

追加のフィールドを許可

より多くの情報をキャプチャ

  • サポートされているデータ型:string、number、integer、boolean、object、array、enum。

本番環境への適用

  • 後続に渡す前に検証する JSON オブジェクトモードを使用する場合、後続サービスに渡す前に出力を検証してください。jsonschema (Python)、Ajv (JavaScript)、Everit (Java) などのライブラリを使用して、期待される JSON スキーマに準拠していることを確認し、フィールドの欠落、型の誤り、または不正なフォーマットによる後続の解析失敗、データ損失、またはビジネスロジックの混乱を防ぎます。失敗した場合は、リクエストをリトライするか、モデルを使用して出力を書き換えます。
  • max_tokens を設定しない 構造化出力が有効になっている場合、max_tokens を設定しないでください。このパラメーターは出力トークンの数を制限し、デフォルトではモデルの最大値に設定されています。これを設定すると、JSON 文字列が出力の途中で切り捨てられ、解析に失敗する無効な JSON が生成される可能性があります。
  • SDK を使用してスキーマを生成する SDK を使用してスキーマを自動生成します。これにより、手動でのメンテナンスによるエラーを回避し、自動的な検証と解析を提供します。
    Python
    from pydantic import BaseModel, Field
    from typing import Optional
    from openai import OpenAI
    import os
    
    client = OpenAI(
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        # 次の URL はシンガポールリージョン用です。{WorkspaceId} を実際のワークスペース ID に置き換えてください。URL はリージョンによって異なります。
        base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
    )
    class UserInfo(BaseModel):
        name: str = Field(description="ユーザー名")
        age: int = Field(description="ユーザーの年齢")
        email: Optional[str] = None  # オプションのフィールド
    
    completion = client.chat.completions.parse(
        model="qwen3.8-max",
        messages=[
            {"role": "system", "content": "名前と年齢の情報を抽出します。"},
            {"role": "user", "content": "私の名前は鈴木五郎、25 歳です。"},
        ],
        response_format=UserInfo  # Pydantic モデルを直接渡す
    )
    
    result = completion.choices[0].message.parsed  # 型安全な解析済み結果
    print(f"名前: {result.name}, 年齢: {result.age}")
    

エラーコード

モデルの呼び出しが失敗し、エラーメッセージが返された場合は、「エラーコード」で解決策をご参照ください。