すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Model Studio:structured output

最終更新日:Dec 14, 2025

情報抽出や構造化データ生成タスクを実行する際、大規模言語モデル (LLM) は ```json のような余分なテキストを返すことがあります。これにより、後続の解析が失敗する可能性があります。構造化出力を有効にすることで、LLM が標準の JSON 文字列を返すように保証できます。JSON スキーマモードを使用すると、出力の構造と型を正確に制御でき、追加の検証や再試行の必要がなくなります。

利用方法

構造化出力は、JSON オブジェクトと JSON スキーマの 2 つのモードをサポートしています。

  • JSON オブジェクトモード:出力が標準の JSON 文字列であることを保証しますが、特定の構造は保証しません。このモードを使用するには:

    1. response_format パラメーターの設定:リクエストボディで、response_format パラメーターを {"type": "json_object"} に設定します。

    2. プロンプトに JSON キーワードを含める:システムメッセージまたはユーザーメッセージには、「JSON」キーワード (大文字と小文字を区別しない) を含める必要があります。そうでない場合、モデルは次のエラーを返します:'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 キーワードを含める必要はありません。

機能比較:

機能

JSON オブジェクトモード

JSON スキーマモード

有効な JSON の出力

はい

はい

スキーマへの厳密な準拠

いいえ

はい

サポート対象モデル

ほとんどの Qwen モデル

一部の qwen-plus シリーズモデルのみ

response_format パラメーター

{"type": "json_object"}

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

プロンプトの要件

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

明示的な指示を推奨します

利用シーン

柔軟な JSON 出力

正確な構造検証

サポート対象モデル

JSON オブジェクト

  • テキスト生成モデル

    • Qwen-Max シリーズ:qwen3-max、qwen3-max-2025-09-23、qwen3-max-preview (非思考モード)、qwen-max、qwen-max-latest、qwen-max-2025-01-25、およびそれ以降のスナップショットモデル

    • Qwen-Plus シリーズ (非思考モード):qwen-plus、qwen-plus-latest、qwen-plus-2025-01-25、およびそれ以降のスナップショットモデル

    • Qwen-Flash シリーズ (非思考モード):qwen-flash、qwen-flash-2025-07-28、およびそれ以降のスナップショットモデル

    • Qwen-Turbo シリーズ (非思考モード):qwen-turbo、qwen-turbo-latest、qwen-turbo-2024-11-01、およびそれ以降のスナップショットモデル

    • Qwen-Coder シリーズ:qwen3-coder-plus、qwen3-coder-plus-2025-07-22、qwen3-coder-flash、および qwen3-coder-flash-2025-07-28

    • Qwen-Long シリーズ:qwen-long-latest、および qwen-long-2025-01-25

  • オープンソースのテキスト生成モデル

    • Qwen3 (非思考モード)

    • Qwen3-Coder

    • Qwen2.5 シリーズのテキストモデル (数学およびコーダーモデルを除く)

  • マルチモーダルモデル

    • Qwen3-VL-Plus シリーズ (非思考モード):qwen3-vl-plus、qwen3-vl-plus-2025-09-23、およびそれ以降のスナップショットモデル

    • Qwen3-VL-Flash シリーズ (非思考モード):qwen3-vl-flash、qwen3-vl-flash-2025-10-15、およびそれ以降のスナップショットモデル

    • QwenVL-Max シリーズ:qwen-vl-max (latest およびスナップショットバージョンを除く)

    • QwenVL-Plus シリーズ:qwen-vl-plus (latest およびスナップショットバージョンを除く)

  • オープンソースのマルチモーダルモデル

    • Qwen3-VL (非思考モード)

説明

思考モードのモデルは現在、構造化出力をサポートしていません。

JSON スキーマ

この機能は、中国 (北京) リージョンの qwen-plus、qwen-plus-latest、qwen-plus-2025-07-28、およびそれ以降のスナップショットモデルでサポートされています。

より多くのモデルへのサポートは順次展開されています。

コンテキストウィンドウ、料金、スナップショットバージョンの詳細については、「モデルリスト」をご参照ください。

クイックスタート

このセクションでは、個人プロファイルからの情報抽出の簡単な例を使用して、構造化出力の使用方法を説明します。

API キーを取得し、API キーを環境変数として設定する必要があります。OpenAI SDK または DashScope SDK を使用して呼び出しを行う場合は、SDK をインストールする必要もあります。

OpenAI 互換

Python

from openai import OpenAI
import os

client = OpenAI(
    # シンガポールリージョンと北京リージョンの API キーは異なります。環境変数を設定していない場合は、次の行を API キーに置き換えてください:api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # シンガポールリージョンの base_url です。北京リージョンについては、https://dashscope.aliyuncs.com/compatible-mode/v1 を使用してください
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

completion = client.chat.completions.create(
    model="qwen-flash",
    messages=[
        {
            "role": "system",
            "content": "ユーザーの名前と年齢を抽出し、情報を JSON フォーマットで返してください。"
        },
        {
            "role": "user",
            "content": "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、趣味はバスケットボールと旅行です。", 
        },
    ],
    response_format={"type": "json_object"}
)

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

実行結果

{
  "name": "Liu Wu",
  "age": 34
}

Node.js

import OpenAI from "openai";

const openai = new OpenAI({
    // 環境変数を設定していない場合は、次の行を API キーに置き換えてください:apiKey: "sk-xxx"
    apiKey: process.env.DASHSCOPE_API_KEY,
    // 以下の baseURL はシンガポールリージョン用です。北京リージョンのモデルを使用するには、baseURL を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えてください
    baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
});

const completion = await openai.chat.completions.create({
    model: "qwen-flash",
    messages: [
        {
            role: "system",
            content: "ユーザーの名前と年齢の情報を抽出し、JSON フォーマットで返してください。"
        },
        {
            role: "user",
            content: "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、趣味はバスケットボールと旅行です。"
        }
    ],
    response_format: {
        type: "json_object"
    }
});

const jsonString = completion.choices[0].message.content;
console.log(jsonString);

実行結果

{
  "Name": "Liu Wu",
  "Age": 34
}

curl

# ======= 重要 =======
# シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーの取得方法の詳細については、https://www.alibabacloud.com/help/model-studio/get-api-key をご参照ください
# 以下はシンガポールリージョンの URL です。中国 (北京) リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions に置き換えてください
# === 実行前にこのコメントを削除してください ===
curl -X POST https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
    "model": "qwen-plus",
    "messages": [
        {
            "role": "system",
            "content": "名前 (文字列)、年齢 (文字列)、メールアドレス (文字列) を抽出する必要があります。JSON 文字列を出力してください。他のコンテンツは出力しないでください。\n例:\nQ: 私の名前は佐藤太郎、25歳で、メールアドレスは sato.taro@example.com です\nA:{\"name\":\"佐藤太郎\",\"age\":\"25歳\",\"email\":\"sato.taro@example.com\"}\nQ: 私の名前は鈴木花子、30歳で、メールアドレスは suzuki.hanako@example.com です\nA:{\"name\":\"鈴木花子\",\"age\":\"30歳\",\"email\":\"suzuki.hanako@example.com\"}\nQ: 私の名前は高橋健太、メールアドレスは takahashi.kenta@example.com で、40歳です\nA:{\"name\":\"高橋健太\",\"age\":\"40歳\",\"email\":\"takahashi.kenta@example.com\"}"
        },
        {
            "role": "user", 
            "content": "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com です。"
        }
    ],
    "response_format": {
        "type": "json_object"
    }
}'

実行結果

{
    "choices": [
        {
            "message": {
                "role": "assistant",
                "content": "{\"name\":\"Liu Wu\",\"age\":\"34 years old\""}"
            },
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null
        }
    ],
    "object": "chat.completion",
    "usage": {
        "prompt_tokens": 207,
        "completion_tokens": 20,
        "total_tokens": 227,
        "prompt_tokens_details": {
            "cached_tokens": 0
        }
    },
    "created": 1756455080,
    "system_fingerprint": null,
    "model": "qwen-plus",
    "id": "chatcmpl-624b665b-fb93-99e7-9ebd-bb6d86d314d2"
}

DashScope

Python

import os
import dashscope
# 以下はシンガポールリージョンの URL です。北京リージョンのモデルを使用するには、URL を https://dashscope.aliyuncs.com/api/v1 に置き換えてください
dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'

messages=[
    {
        "role": "system",
        "content": "ユーザーの名前と年齢を抽出し、情報を JSON フォーマットで返してください。"
    },
    {
        "role": "user",
        "content": "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、趣味はバスケットボールと旅行です。", 
    },
]
response = dashscope.Generation.call(
    # 中国 (北京) リージョンのモデルを使用するには、そのリージョン固有の API キーを使用する必要があります。API キーは https://bailian.console.alibabacloud.com/?tab=model#/api-key から取得できます
    # 環境変数を設定していない場合は、次の行を Model Studio の API キーに置き換えてください:api_key="sk-xxx",
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    model="qwen-flash", 
    messages=messages,
    result_format='message',
    response_format={'type': 'json_object'}
    )
json_string = response.output.choices[0].message.content
print(json_string)

実行結果

{
  "name": "Liu Wu",
  "age": 34
}

Java

DashScope Java SDK のバージョンは 2.18.4 以降である必要があります。

// DashScope Java SDK のバージョンは 2.18.4 以降である必要があります。

import java.util.Arrays;
import java.lang.System;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.common.ResponseFormat;
import com.alibaba.dashscope.protocol.Protocol;

public class Main {
    public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException {
        // 以下はシンガポールリージョンの URL です。中国 (北京) リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/api/v1 に置き換えてください
        Generation gen = new Generation(Protocol.HTTP.getValue(), "https://dashscope-intl.aliyuncs.com/api/v1");
        Message systemMsg = Message.builder()
                .role(Role.SYSTEM.getValue())
                .content("名前と年齢を抽出し、情報を JSON フォーマットで返してください。")
                .build();
        Message userMsg = Message.builder()
                .role(Role.USER.getValue())
                .content("皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、趣味はバスケットボールと旅行です。")
                .build();
        ResponseFormat jsonMode = ResponseFormat.builder().type("json_object").build();
        GenerationParam param = GenerationParam.builder()
                // 環境変数を設定していない場合は、次の行を Model Studio の API キーに置き換えてください:.apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .model("qwen-flash")
                .messages(Arrays.asList(systemMsg, userMsg))
                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                .responseFormat(jsonMode)
                .build();
        return gen.call(param);
    }

    public static void main(String[] args) {
        try {
            GenerationResult result = callWithMessage();
            System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent());
        } catch (ApiException | NoApiKeyException | InputRequiredException e) {
            // ロギングフレームワークを使用して例外情報を記録します。
            System.err.println("生成サービスの呼び出し中にエラーが発生しました: " + e.getMessage());
        }
    }
}

実行結果

{
  "name": "Alex Brown",
  "age": 34
}

curl

# ======= 重要 =======
# シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーの取得方法の詳細については、https://www.alibabacloud.com/help/model-studio/get-api-key をご参照ください
# 以下はシンガポールリージョンの URL です。中国 (北京) リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation に置き換えてください
# === 実行前にこのコメントを削除してください ===

curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/text-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
    "model": "qwen-flash",
    "input": {
        "messages": [
            {
                "role": "system",
                "content": "名前と年齢を抽出し、情報を JSON フォーマットで返してください。"
            },
            {
                "role": "user", 
                "content": "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、趣味はバスケットボールと旅行です。"
            }
        ]
    },
    "parameters": {
        "result_format": "message",
        "response_format": {
            "type": "json_object"
        }
    }
}'

実行結果

{
    "output": {
        "choices": [
            {
                "finish_reason": "stop",
                "message": {
                    "role": "assistant",
                    "content": "{\n  \"Name\": \"Liu Wu\",\n  \"Age\": 34\n}"
                }
            }
        ]
    },
    "usage": {
        "total_tokens": 72,
        "output_tokens": 18,
        "input_tokens": 54,
        "cached_tokens": 0
    },
    "request_id": "xxx-xxx-xxx-xxx-xxx"
}

画像および動画データの処理

テキストに加えて、マルチモーダルモデルは画像および動画データの構造化出力をサポートしています。この機能により、視覚情報の抽出、位置特定、イベント検出が可能になります。

画像および動画ファイルの制限については、「視覚的理解」をご参照ください。

OpenAI 互換

Python

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 です。中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えてください
    base_url="https://dashscope-intl.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": "シリアル番号",
      "seat_num": "371",
      "arrival_site": "開発区",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

Node.js

import OpenAI from "openai";

const openai = new OpenAI({
  // シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーを取得するには、https://www.alibabacloud.com/help/model-studio/get-api-key をご参照ください
  // 環境変数を設定していない場合は、次の行を Model Studio の API キーに置き換えてください:apiKey: "sk-xxx"
  apiKey: process.env.DASHSCOPE_API_KEY,
  // 以下はシンガポールリージョンの base_url です。中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えてください
  baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
});

async function main() {
  const response = await openai.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"}
  });
  console.log(response.choices[0].message.content);
}

main()

実行結果

{
  "ticket": [
    {
      "travel_date": "2013-06-29",
      "trains": "シリアル番号",
      "seat_num": "371",
      "arrival_site": "開発区",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

curl

# ======= 重要 =======
# 以下はシンガポールリージョンの base_url です。中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions に置き換えてください
# シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーを取得するには、https://www.alibabacloud.com/help/model-studio/get-api-key をご参照ください
# === 実行前にこのコメントを削除してください ===

curl --location 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
  "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"}
}'

実行結果

{
  "choices": [{
    "message": {
      "content": "{\n  \"ticket\": [\n    {\n      \"travel_date\": \"2013-06-29\",\n      \"trains\": \"シリアル番号\",\n      \"seat_num\": \"371\",\n      \"arrival_site\": \"開発区\",\n      \"price\": \"8.00\"\n    }\n  ],\n  \"invoice\": [\n    {\n      \"invoice_code\": \"221021325353\",\n      \"invoice_number\": \"10283819\"\n    }\n  ]\n}",
      "role": "assistant"
    },
    "finish_reason": "stop",
    "index": 0,
    "logprobs": null
  }],
  "object": "chat.completion",
  "usage": {
    "prompt_tokens": 486,
    "completion_tokens": 112,
    "total_tokens": 598,
    "prompt_tokens_details": {
      "cached_tokens": 0
    }
  },
  "created": 1755767481,
  "system_fingerprint": null,
  "model": "qwen3-vl-plus",
  "id": "chatcmpl-33249829-e9f3-9cbc-93e4-0536b3d7d713"
}

DashScope

Python

import os
import dashscope

# 以下はシンガポールリージョンの base_url です。中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/api/v1 に置き換えてください
dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'

messages = [
{
    "role": "system",
    "content": [
    {"text": "あなたは役に立つアシスタントです。"}]
},
{
    "role": "user",
    "content": [
    {"image": "http://duguang-labelling.oss-cn-shanghai.aliyuncs.com/demo_ocr/receipt_zh_demo.jpg"},
    {"text": "画像からチケット情報 (travel_date、trains、seat_num、arrival_site、price を含む) と請求書情報 (配列として、invoice_code と invoice_number を含む) を抽出します。チケットと請求書の配列を含む JSON オブジェクトを出力してください。"}]
}]
response = dashscope.MultiModalConversation.call(
    #環境変数を設定していない場合は、次の行を Model Studio の API キーに置き換えてください:api_key ="sk-xxx"
    api_key = os.getenv('DASHSCOPE_API_KEY'),
    model = 'qwen3-vl-plus',
    messages = messages,
    response_format={'type': 'json_object'}
)
json_string = response.output.choices[0].message.content[0]["text"]
print(json_string)

実行結果

{
  "ticket": [
    {
      "travel_date": "2013-06-29",
      "trains": "シリアル番号",
      "seat_num": "371",
      "arrival_site": "開発区",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

Java

// DashScope Java SDK のバージョンは 2.21.4 以降である必要があります。

import java.util.Arrays;
import java.util.Collections;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.common.ResponseFormat;
import com.alibaba.dashscope.utils.Constants;

public class Main {
    
    // 以下はシンガポールリージョンの base_url です。中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/api/v1 に置き換えてください
    static {
        Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
    }
    public static void simpleMultiModalConversationCall()
            throws ApiException, NoApiKeyException, UploadFileException {
        MultiModalConversation conv = new MultiModalConversation();
        MultiModalMessage systemMessage = MultiModalMessage.builder().role(Role.SYSTEM.getValue())
                .content(Arrays.asList(
                        Collections.singletonMap("text", "あなたは役に立つアシスタントです。"))).build();
        MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                .content(Arrays.asList(
                        Collections.singletonMap("image", "http://duguang-labelling.oss-cn-shanghai.aliyuncs.com/demo_ocr/receipt_zh_demo.jpg"),
                        Collections.singletonMap("text", "画像からチケット情報 (travel_date、trains、seat_num、arrival_site、price を含む) と請求書情報 (配列として、invoice_code と invoice_number を含む) を抽出します。チケットと請求書の配列を含む JSON オブジェクトを出力してください。"))).build();
        ResponseFormat jsonMode = ResponseFormat.builder().type("json_object").build();
        MultiModalConversationParam param = MultiModalConversationParam.builder()
                // 環境変数を設定していない場合は、次の行を Model Studio の API キーに置き換えてください:.apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .model("qwen3-vl-plus")
                .messages(Arrays.asList(systemMessage, userMessage))
                .responseFormat(jsonMode)
                .build();
        MultiModalConversationResult result = conv.call(param);
        System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text"));
    }
    public static void main(String[] args) {
        try {
            simpleMultiModalConversationCall();
        } catch (ApiException | NoApiKeyException | UploadFileException e) {
            System.out.println(e.getMessage());
        }
    }
}

実行結果

{
  "ticket": [
    {
      "travel_date": "2013-06-29",
      "trains": "シリアル番号",
      "seat_num": "371",
      "arrival_site": "開発区",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

curl

# ======= 重要 =======
# 以下はシンガポールリージョンの base_url です。中国 (北京) リージョンのモデルを使用する場合は、base_url を https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation に置き換えてください
# シンガポールリージョンと中国 (北京) リージョンの API キーは異なります。API キーを取得するには、https://www.alibabacloud.com/help/model-studio/get-api-key をご参照ください
# === 実行前にこのコメントを削除してください ===

curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
    "model": "qwen3-vl-plus",
    "input":{
        "messages":[
            {"role": "system",
         "content": [
           {"text": "あなたは役に立つアシスタントです。"}]},
            {
             "role": "user",
             "content": [
               {"image": "http://duguang-labelling.oss-cn-shanghai.aliyuncs.com/demo_ocr/receipt_zh_demo.jpg"},
               {"text": "画像からチケット情報 (travel_date、trains、seat_num、arrival_site、price を含む) と請求書情報 (配列として、invoice_code と invoice_number を含む) を抽出します。チケットと請求書の配列を含む JSON オブジェクトを出力してください。"}
                ]
            }
        ]
    },
    "parameters": {
        "response_format": {"type": "json_object"}
    }
}'

実行結果

{
  "output": {
    "choices": [
      {
        "message": {
          "content": [
            {
              "text": "{\n  \"ticket\": [\n    {\n      \"travel_date\": \"2013-06-29\",\n      \"trains\": \"シリアル番号\",\n      \"seat_num\": \"371\",\n      \"arrival_site\": \"開発区\",\n      \"price\": \"8.00\"\n    }\n  ],\n  \"invoice\": [\n    {\n      \"invoice_code\": \"221021325353\",\n      \"invoice_number\": \"10283819\"\n    }\n  ]\n}"
            }
          ],
          "role": "assistant"
        },
        "finish_reason": "stop"
      }
    ]
  },
  "usage": {
    "total_tokens": 598,
    "input_tokens_details": {
      "image_tokens": 418,
      "text_tokens": 68
    },
    "output_tokens": 112,
    "input_tokens": 486,
    "output_tokens_details": {
      "text_tokens": 112
    },
    "image_tokens": 418
  },
  "request_id": "b129dce1-0d5d-4772-b8b5-bd3a1d5cde63"
}

プロンプトの最適化

「ユーザー情報を返す」のような曖昧なプロンプトは、モデルが予期しない結果を生成する原因となる可能性があります。これを避けるために、プロンプトで期待されるスキーマを記述してください。フィールドの型、フィールドが必須かどうか、日付フォーマットなどのフォーマット要件を含め、例を提供してください。

OpenAI 互換

Python

from openai import OpenAI
import os
import json
import textwrap  # 複数行文字列のインデントを処理し、コードの可読性を向上させるために使用

# モデルに期待される出力フォーマットを示すために、応答例を事前に定義
# 例 1:趣味を含む完全な応答
example1_response = json.dumps(
    {
        "info": {"name": "佐藤太郎", "age": "25歳", "email": "sato.taro@example.com"},
        "hobby": ["歌唱"]
    },
    ensure_ascii=False
)
# 例 2:複数の趣味を含む応答
example2_response = json.dumps(
    {
        "info": {"name": "鈴木花子", "age": "30歳", "email": "suzuki.hanako@example.com"},
        "hobby": ["ダンス", "水泳"]
    },
    ensure_ascii=False
)
# 例 3:hobby フィールドを含まない応答 (hobby はオプション)
example3_response = json.dumps(
    {
        "info": {"name": "高橋健太", "age": "28歳", "email": "takahashi.kenta@example.com"}
    },
    ensure_ascii=False
)
# 例 4:hobby フィールドを含まない応答
example4_response = json.dumps(
    {
        "info": {"name": "伊藤さくら", "age": "35歳", "email": "ito.sakura@example.com"}
    },
    ensure_ascii=False
)

# OpenAI クライアントを初期化し、API キーとベース URL を設定
client = OpenAI(
    # シンガポールリージョンと北京リージョンの API キーは異なります。API キーを取得するには、https://www.alibabacloud.com/help/model-studio/get-api-key をご覧ください
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 以下はシンガポールリージョンの URL です。北京リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えてください
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

# dedent 関数は、文字列の各行から共通の先頭の空白を削除します。
# これにより、実行時に余分なスペースを含めずに、コード内で文字列をきれいにインデントできます。
system_prompt = textwrap.dedent(f"""\
    ユーザー入力から個人情報を抽出し、指定された JSON スキーマフォーマットで出力してください:

    [出力フォーマット要件]
    出力は、以下の JSON 構造に厳密に従う必要があります:
    {{
      "info": {{
        "name": "文字列。必須。名前。",
        "age": "文字列。必須。フォーマットは「数字+歳」、例:「25歳」。",
        "email": "文字列。必須。標準的なメールフォーマット、例:「user@example.com」。"
      }},
      "hobby": ["文字列の配列。オプション。すべての趣味を含む。趣味が言及されていない場合は、このフィールドを出力から省略する必要があります。"]
    }}

    [フィールド抽出ルール]
    1. name:テキストから名前を特定します。このフィールドは必須です。
    2. age:年齢情報を特定し、「数字+歳」のフォーマットに変換します。このフィールドは必須です。
    3. email:メールアドレスを特定し、元のフォーマットを維持します。このフィールドは必須です。
    4. hobby:趣味を特定し、文字列の配列として出力します。趣味が言及されていない場合は、hobby フィールドを完全に省略してください。

    [参照例]
    例 1 (趣味を含む):
    Q: 私の名前は佐藤太郎、25歳、メールアドレスは sato.taro@example.com、歌うのが好きです。
    A: {example1_response}

    例 2 (複数の趣味を含む):
    Q: 私の名前は鈴木花子、30歳、メールアドレスは suzuki.hanako@example.com、ダンスと水泳を楽しんでいます。
    A: {example2_response}

    例 3 (趣味を含まない):
    Q: 私の名前は高橋健太、28歳、メールアドレスは takahashi.kenta@example.com です。
    A: {example3_response}

    例 4 (趣味を含まない):
    Q: 私は伊藤さくら、35歳です。メールアドレスは ito.sakura@example.com です。
    A: {example4_response}

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

# LLM API を呼び出して情報を抽出
completion = client.chat.completions.create(
    model="qwen-plus",  # 使用するモデルを指定、qwen-plus
    messages=[
        {
            "role": "system",
            "content": system_prompt  # 上で定義したシステムプロンプトを使用
        },
        {
            "role": "user",
            "content": "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、バスケットボールと旅行が好きです。", 
        },
    ],
    response_format={"type": "json_object"},  # 構造化出力を保証するために応答フォーマットを JSON に指定
)

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

実行結果

{
  "info": {
    "name": "Liu Wu",
    "age": "34",
    "email": "liuwu@example.com"
  },
  "hobby": ["バスケットボール", "旅行"]  
}

Node.js

import OpenAI from "openai";

// モデルに期待される出力フォーマットを示すために、応答例を事前に定義
// 例 1:すべてのフィールドを含む完全な応答
const example1Response = JSON.stringify({
    info: { name: "佐藤太郎", age: "25歳", email: "sato.taro@example.com" },
    hobby: ["歌唱"]
}, null, 2);

// 例 2:複数の趣味を含む応答
const example2Response = JSON.stringify({
    info: { name: "鈴木花子", age: "30歳", email: "suzuki.hanako@example.com" },
    hobby: ["ダンス", "水泳"]
}, null, 2);

// 例 3:hobby フィールドのない応答。hobby フィールドはオプションです。
const example3Response = JSON.stringify({
    info: { name: "高橋健太", age: "28歳", email: "takahashi.kenta@example.com" }
}, null, 2);

// 例 4:hobby フィールドのない別の応答
const example4Response = JSON.stringify({
    info: { name: "伊藤さくら", age: "35歳", email: "ito.sakura@example.com" }
}, null, 2);

// OpenAI クライアント設定を初期化
const openai = new OpenAI({
    // シンガポールリージョンと北京リージョンの API キーは異なります。
    // 環境変数が設定されていない場合は、次の行を Alibaba Cloud Model Studio の API キーに置き換えてください:apiKey: "sk-xxx",
    apiKey: process.env.DASHSCOPE_API_KEY,
    // 以下はシンガポールリージョンの URL です。北京リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/compatible-mode/v1 に置き換えてください
    baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
});

// チャット補完リクエストを作成。構造化プロンプトを使用して出力の精度を向上させます。
const completion = await openai.chat.completions.create({
    model: "qwen-plus",
    messages: [
        {
            role: "system",
            content: `ユーザー入力から個人情報を抽出し、指定された JSON スキーマフォーマットで出力してください。

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

[フィールド抽出ルール]
1. name:テキストから名前を特定し、抽出します。このフィールドは必須です。
2. age:年齢情報を特定し、「[数字]歳」のフォーマットに変換して抽出します。このフィールドは必須です。
3. email:メールアドレスを特定し、元のフォーマットを維持して抽出します。このフィールドは必須です。
4. hobby:趣味を特定し、文字列配列として出力します。趣味情報が言及されていない場合は、hobby フィールドを出力から完全に省略してください。

[参照例]
例 1 (趣味あり):
Q: 私の名前は佐藤太郎、25歳、メールアドレスは sato.taro@example.com、趣味は歌唱です。
A: ${example1Response}

例 2 (複数の趣味あり):
Q: 私の名前は鈴木花子、30歳、メールアドレスは suzuki.hanako@example.com、普段はダンスと水泳が好きです。
A: ${example2Response}

例 3 (趣味なし):
Q: 私の名前は高橋健太、28歳、メールアドレスは takahashi.kenta@example.com です。
A: ${example3Response}

例 4 (趣味なし):
Q: 私は伊藤さくら、35歳、メールアドレスは ito.sakura@example.com です。
A: ${example4Response}

前述のフォーマットとルールに厳密に従って情報を抽出し、JSON を出力してください。ユーザーが趣味について言及していない場合は、hobby フィールドを出力に含めないでください。`
        },
        {
            role: "user",
            content: "皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、普段はバスケットボールと旅行が好きです。"
        }
    ],
    response_format: {
        type: "json_object"
    }
});

// モデルによって生成された JSON 結果を抽出して出力
const jsonString = completion.choices[0].message.content;
console.log(jsonString);

実行結果

{
  "info": {
    "name": "Liu Wu",
    "age": "34歳",
    "email": "liuwu@example.com"
  },
  "hobby": [
    "バスケットボール",
    "旅行"
  ]
}

DashScope

Python

import os
import json
import dashscope
# 以下はシンガポールリージョンの URL です。中国 (北京) リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/api/v1 に置き換えてください。
dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'

# モデルに期待される出力フォーマットを示すために、応答例を事前定義します。
example1_response = json.dumps(
    {
        "info": {"name": "John Doe", "age": "25 years old", "email": "johndoe@example.com"},
        "hobby": ["singing"]
    },
    ensure_ascii=False
)
example2_response = json.dumps(
    {
        "info": {"name": "Jane Smith", "age": "30 years old", "email": "janesmith@example.com"},
        "hobby": ["dancing", "swimming"]
    },
    ensure_ascii=False
)
example3_response = json.dumps(
    {
        "info": {"name": "Peter Jones", "age": "40 years old", "email": "peterjones@example.com"},
        "hobby": ["Rap", "basketball"]
    },
    ensure_ascii=False
)

messages=[
        {
            "role": "system",
            "content": f"""ユーザー入力から個人情報を抽出し、指定された JSON スキーマフォーマットで出力してください:

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

[フィールド抽出ルール]
1. name: テキストからユーザー名を特定します。このフィールドは必須です。
2. age: 年齢情報を特定し、「数字 years old」フォーマットに変換します。このフィールドは必須です。
3. email: E メールアドレスを特定し、元のフォーマットを維持します。このフィールドは必須です。
4. hobby: ユーザーの趣味を特定し、文字列配列として出力します。趣味に関する情報が言及されていない場合は、hobby フィールドを完全に省略してください。

[参照例]
例 1 (趣味が 1 つ含まれる場合):
Q: My name is John Doe, I am 25 years old, my email is johndoe@example.com, and my hobby is singing.
A: {example1_response}

例 2 (趣味が複数含まれる場合):
Q: My name is Jane Smith, I am 30 years old, my email is janesmith@example.com, and I like dancing and swimming.
A: {example2_response}

例 3 (趣味が複数含まれる場合):
Q: My email is peterjones@example.com, I am 40 years old, my name is Peter Jones, and I can rap and play basketball.
A: {example3_response}

上記のフォーマットとルールに厳密に従って情報を抽出し、JSON を出力してください。ユーザーが趣味について言及しなかった場合は、出力に hobby フィールドを含めないでください。"""
        },
        {
            "role": "user",
            "content": "Hello everyone, my name is Alex Brown, I am 34 years old, my email is alexbrown@example.com, and I like to play basketball and travel.", 
        },
    ]
response = dashscope.Generation.call(
    # 中国 (北京) リージョンのモデルを使用する場合は、中国 (北京) リージョン用の API キーを使用する必要があります。入手先: https://bailian.console.alibabacloud.com/?tab=model#/api-key
    # 環境変数が設定されていない場合は、次の行を Alibaba Cloud Model Studio API キーに置き換えてください: api_key="sk-xxx",
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    model="qwen-plus", 
    messages=messages,
    result_format='message',
    response_format={'type': 'json_object'}
    )
json_string = response.output.choices[0].message.content
print(json_string)

実行結果

{
  "info": {
    "name": "Liu Wu",
    "age": "34歳",
    "email": "liuwu@example.com"
  },
  "hobby": [
    "バスケットボール",
    "旅行"
  ]
}

Java

import java.util.Arrays;
import java.lang.System;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.common.ResponseFormat;
import com.alibaba.dashscope.protocol.Protocol;

public class Main {
    public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException {
        // 以下はシンガポールリージョンの URL です。中国 (北京) リージョンのモデルを使用する場合は、URL を https://dashscope.aliyuncs.com/api/v1 に置き換えてください
        Generation gen = new Generation(Protocol.HTTP.getValue(), "https://dashscope-intl.aliyuncs.com/api/v1");
        Message systemMsg = Message.builder()
                .role(Role.SYSTEM.getValue())
                .content("""
                ユーザー入力から個人情報を抽出し、指定された JSON スキーマフォーマットで出力してください:

[出力フォーマット要件]
出力は、この JSON 構造に厳密に従う必要があります:
{
  "info": {
    "name": "文字列、必須、名前",
    "age": "文字列、必須、フォーマットは「数字+歳」、例:「25歳」",
    "email": "文字列、必須、標準的なメールフォーマット、例:「user@example.com」"
  },
  "hobby": ["文字列配列、オプション、すべてのユーザーの趣味を含む。言及されていない場合は、このフィールドを出力に含めないでください。"]
}

[フィールド抽出ルール]
1. name:テキストから名前を特定します。これは必須フィールドです。
2. age:年齢を特定し、「数字+歳」のフォーマットに変換します。これは必須フィールドです。
3. email:メールアドレスを特定し、元のフォーマットを維持します。これは必須フィールド。
4. hobby:ユーザーの趣味を特定し、文字列配列として出力します。趣味が言及されていない場合は、hobby フィールドを完全に省略してください。

[参照例]
例 1 (趣味あり):
Q: 私の名前は佐藤太郎、25歳、メールアドレスは sato.taro@example.com、趣味は歌唱です。
A:{"info":{"name":"佐藤太郎","age":"25歳","email":"sato.taro@example.com"},"hobby":["歌唱"]}

例 2 (複数の趣味あり):
Q: 私の名前は鈴木花子、30歳、メールアドレスは suzuki.hanako@example.com、ダンスと水泳が好きです。
A:{"info":{"name":"鈴木花子","age":"30歳","email":"suzuki.hanako@example.com"},"hobby":["ダンス","水泳"]}

例 3 (趣味なし):
Q: 私の名前は渡辺大輔、メールアドレスは watanabe.daisuke@example.com、40歳です。
A:{"info":{"name":"渡辺大輔","age":"40歳","email":"watanabe.daisuke@example.com"}}""")
                .build();
        Message userMsg = Message.builder()
                .role(Role.USER.getValue())
                .content("皆さん、こんにちは。私の名前は田中一郎、34歳です。メールアドレスは tanaka.ichiro@example.com で、趣味はバスケットボールと旅行です。")
                .build();
        ResponseFormat jsonMode = ResponseFormat.builder().type("json_object").build();
        GenerationParam param = GenerationParam.builder()
                // 中国 (北京) リージョンのモデルを使用する場合は、そのリージョン用の API キーを使用する必要があります。API キーは https://bailian.console.alibabacloud.com/?tab=model#/api-key で取得してください
                // 環境変数を設定していない場合は、次の行を Model Studio の API キーに置き換えてください:.apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .model("qwen-plus")
                .messages(Arrays.asList(systemMsg, userMsg))
                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                .responseFormat(jsonMode)
                .build();
        return gen.call(param);
    }
    public static void main(String[] args) {
        try {
            GenerationResult result = callWithMessage();
            System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent());
        } catch (ApiException | NoApiKeyException | InputRequiredException e) {
            // ロギングフレームワークを使用して例外情報を記録します。
            System.err.println("生成サービスの呼び出し中にエラーが発生しました: " + e.getMessage());
        }
    }
}

実行結果

{
  "info": {
    "name": "Liu Wu",
    "age": "34",
    "email": "liuwu@example.com"
  },
  "hobby": [
    "バスケットボール",
    "旅行"
  ]
}

指定されたフォーマットでの出力取得

response_formattypejson_object に設定すると、標準の JSON 文字列が返されますが、コンテンツの構造が期待どおりでない場合があります。このアプローチは単純なシナリオに適しています。自動解析や API の相互運用性など、厳密な型制約が必要な複雑なシナリオでは、typejson_schema に設定して、モデルが指定されたフォーマットに厳密に準拠したコンテンツを出力するように強制できます。response_format のフォーマットと例を以下に示します:

フォーマット

{
  "type": "json_schema",
  "json_schema": {
    "name": "schema_name",       // スキーマの名前
    "strict": true,              // 厳密なフォーマット準拠のために true に設定することを推奨
    "schema": {
      "type": "object",
      "properties": {...},       // フィールド構造を定義、右の例を参照
      "required": [...],         // 必須フィールドのリスト
      "additionalProperties": false  // 定義されたフィールドのみを出力するために false に設定することを推奨
    }
  }
}
{
  "type": "json_schema",
  "json_schema": {
    "name": "user_info",
    "strict": true,
    "schema": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "ユーザー名"
        },
        "age": {
          "type": "integer",
          "description": "ユーザーの年齢"
        },
        "email": {
          "type": "string",
          "description": "メールアドレス"
        }
      },
      "required": ["name", "age"],
      "additionalProperties": false
    }
  }
}

上記の例では、モデルは必須フィールドである nameage、およびオプションの email フィールドを含む JSON オブジェクトを出力するように強制されます。

この機能は、中国 (北京) リージョンの次のモデルでのみサポートされています:qwen-plus-latestqwen-plus-2025-12-01qwen-plus-2025-09-11、および qwen-plus-2025-07-28
シンガポールリージョンのモデルは現在サポートされていません。

利用方法

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

OpenAI 互換

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

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

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

completion = client.chat.completions.parse(
    model="qwen-plus",
    messages=[
        {"role": "system", "content": "名前と年齢の情報を抽出してください。"},
        {"role": "user", "content": "私の名前は佐藤太郎、25歳です。"},
    ],
    response_format=UserInfo,
)

result = completion.choices[0].message.parsed
print(f"名前: {result.name}, 年齢: {result.age}")
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";

const openai = new OpenAI(
    {
        apiKey: process.env.DASHSCOPE_API_KEY,
        baseURL: "https://dashscope.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: "qwen-plus",
  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

DashScope

Java SDK は現在サポートされていません。
import os
import dashscope
import json

messages = [
    {
        "role": "user",
        "content": "私の名前は田中一郎、25歳です。",
    },
]
response = dashscope.Generation.call(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    model="qwen-plus",
    messages=messages,
    result_format="message",
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "user_info",
            "schema": {
                "properties": {
                    "name": {"title": "名前", "type": "string"},
                    "age": {"title": "年齢", "type": "integer"},
                },
                "required": ["name", "age"],
                "title": "UserInfo",
                "type": "object",
            },
        },
        "strict": True,
    },
)
json_object = json.loads(response.output.choices[0].message.content)
print(f"名前: {json_object['name']}, 年齢: {json_object['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  // 追加のフィールドを許可
    }

    例えば、入力 "I am Zhang San, 25 years old" は、出力 {"name": "Zhang San", "age": 25} を生成します。この出力には、入力では明示的に定義されていない age フィールドが含まれています。

    動作

    シナリオ

    false

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

    構造を正確に制御する必要がある場合

    true

    追加のフィールドを許可

    より多くの情報をキャプチャする必要がある場合

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

本番環境でのベストプラクティス

  • 検証

    JSON オブジェクトモードを使用する場合、後続のアプリケーションに渡す前にツールで出力を検証してください。jsonschema (Python)、Ajv (JavaScript)、または Everit (Java) などのツールを使用できます。これにより、出力が指定された JSON スキーマに準拠していることが保証され、フィールドの欠落、型の誤り、または不正なフォーマットによる解析の失敗、データ損失、またはビジネスロジックの中断を防ぎます。失敗が発生した場合は、再試行や LLM に出力の修正を促すなどの戦略を使用できます。

  • max_tokens の無効化

    構造化出力を有効にする場合、max_tokens (出力トークン数を制御し、デフォルトでモデルの最大出力制限に設定されるパラメーター) を指定しないでください。そうしないと、返される JSON 文字列が不完全になり、後続のサービスの解析が失敗する可能性があります。

  • SDK を使用してスキーマの生成を支援

    SDK を使用してスキーマを自動的に生成します。これにより、手動メンテナンスによるエラーを回避し、自動検証と解析が可能になります。

    from pydantic import BaseModel, Field
    from typing import Optional
    from openai import OpenAI
    import os
    
    client = OpenAI(
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        base_url="https://dashscope.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="qwen-plus",
        messages=[
            {"role": "system", "content": "名前と年齢の情報を抽出してください。"},
            {"role": "user", "content": "私の名前は田中一郎、25歳です。"},
        ],
        response_format=UserInfo  # Pydantic モデルを直接渡す
    )
    
    result = completion.choices[0].message.parsed  # 型安全な解析済み結果
    print(f"名前: {result.name}, 年齢: {result.age}")
    import { z } from "zod";
    import { zodResponseFormat } from "openai/helpers/zod";
    import OpenAI from "openai";
    
    const client = new OpenAI(
        {
            apiKey: process.env.DASHSCOPE_API_KEY,
            baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
        }
    );
    
    const UserInfo = z.object({
      name: z.string().describe("ユーザー名"),
      age: z.number().int().describe("ユーザーの年齢"),
      email: z.string().optional().nullable()  // オプションフィールド
    });
    
    const completion = await client.chat.completions.parse({
      model: "qwen-plus",
      messages: [
        { role: "system", content: "名前と年齢の情報を抽出してください。" },
        { role: "user", content: "私の名前は田中一郎、25歳です。" },
      ],
      response_format: zodResponseFormat(UserInfo, "user_info")
    });
    
    console.log(completion.choices[0].message.parsed);

よくある質問

Q:Qwen モデルは思考モードでどのように構造化出力を生成しますか?

A:Qwen の思考モードは現在、構造化出力をサポートしていません。思考モードで標準の JSON 文字列を取得するには、JSON 解析が失敗した場合に JSON モードをサポートするモデルを使用して出力を修正できます。

  1. 思考モードで出力を取得

    思考モードでモデルを呼び出して高品質の出力を取得しますが、これは標準の JSON 文字列ではない場合があります。

    思考モードを有効にする場合、response_format パラメーターを {"type": "json_object"} に設定しないでください。そうしないと、エラーが発生します。
    completion = client.chat.completions.create(
        model="qwen-plus",
        messages=[
            {"role": "system", "content": system_prompt},
            {
                "role": "user",
                "content": "皆さん、こんにちは。私の名前は Alex Brown です。34 歳で、メールは alexbrown@example.com です。バスケットボールと旅行が趣味です。",
            },
        ],
        # 思考モードを有効にします。response_format パラメーターを {"type": "json_object"} に設定すると、エラーが発生します。
        extra_body={"enable_thinking": True},
        # 思考モードのストリーミング出力を有効にします。
        stream=True
    )
    # モデルによって生成された JSON 結果を抽出して出力します。
    json_string = ""
    for chunk in completion:
        if chunk.choices[0].delta.content is not None:
            json_string += chunk.choices[0].delta.content
  2. 出力の検証と修正

    前のステップの json_string を解析してみてください:

    • モデルが標準の JSON 文字列を生成した場合、直接解析して返すことができます。

    • モデルが非標準の JSON 文字列を生成した場合、構造化出力をサポートするモデルを呼び出してフォーマットを修正できます。非思考モードの qwen-flash のような、高速でコスト効率の良いモデルを選択することをお勧めします。

    import json
    
    try:
        json_object_from_thinking_model = json.loads(json_string)
        print("標準の JSON 文字列が生成されました。")
    except json.JSONDecodeError:
        print("非標準の JSON 文字列が生成されました。構造化出力をサポートするモデルで修正します。")
        completion = client.chat.completions.create(
            model="qwen-flash",
            messages=[
                {
                    "role": "system",
                    "content": "あなたは JSON フォーマットの修正の専門家です。ユーザーが入力した JSON 文字列を標準フォーマットに修正してください。",
                },
                {
                    "role": "user",
                    "content": json_string,
                },
            ],
            response_format={"type": "json_object"},
        )
        json_object_from_thinking_model = json.loads(completion.choices[0].message.content)

エラーコード

呼び出しが失敗した場合は、「エラーメッセージ」でトラブルシューティングをご参照ください。