Skip to main content

マルチターン対話

Qwen API はステートレスです。マルチターン対話を実装するには、各リクエストに会話履歴を渡します。コンテキストを管理し、トークン消費を削減するために、トリミング、要約、または取得を使用してください。

このトピックでは、OpenAI 互換のチャット補完および DashScope インターフェイスについて説明します。よりシンプルな代替方法については、「OpenAI 互換 - 応答」をご参照ください。

仕組み

マルチターン対話を実装するには、messages 配列を維持します。各ラウンドの後に、ユーザーの質問とモデルの応答を追加し、更新された配列を次のリクエストに使用します。 以下の例は、マルチターン対話中に messages 配列の状態がどのように変化するかを示しています。
  1. 第 1 ラウンド messages 配列にユーザーの質問を追加します。
// テキストモデルを使用
[
    {"role": "user", "content": "宇宙探査をテーマにした SF 映画をおすすめしてください。"}
]

// マルチモーダルモデル(例:Qwen-VL)を使用
// {"role": "user",
//       "content": [{"type": "image_url","image_url": {"url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251031/ownrof/f26d201b1e3f4e62ab4a1fc82dd5c9bb.png"}},
//                   {"type": "text", "text": "画像に写っている商品は何ですか?"}]
// }
  1. 第 2 ラウンド messages 配列にモデルの応答とユーザーの最新の質問を追加します。
// テキストモデルを使用
[
    {"role": "user", "content": "宇宙探査をテーマにした SF 映画をおすすめしてください。"},
    {"role": "assistant", "content": "『XXX』をおすすめします。これは古典的な SF 作品です。"},
    {"role": "user", "content": "この映画の監督は誰ですか?"}
]

// マルチモーダルモデル(例:Qwen-VL)を使用
//[
//    {"role": "user", "content": [
//                    {"type": "image_url","image_url": {"url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251031/ownrof/f26d201b1e3f4e62ab4a1fc82dd5c9bb.png"}},
//                   {"type": "text", "text": "画像に写っている商品は何ですか?"}]},
//    {"role": "assistant", "content": "画像には 3 点のアイテムが表示されています。ライトブルーのオーバーオール、青と白のストライプの半袖シャツ、白いスニーカーです。"},
//    {"role": "user", "content": "それらのスタイルは何ですか?"}
//]

クイックスタート

  • OpenAI 互換
  • DashScope
Python
import os
from openai import OpenAI

def get_response(messages):
    client = OpenAI(
        # API キーはリージョンによって異なります。API キーの取得方法については、https://www.alibabacloud.com/help/en/model-studio/get-api-key をご参照ください。
        # 環境変数を設定していない場合は、次の行を Model Studio API キーに置き換えてください: api_key="sk-xxx",
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        # シンガポールリージョンの URL です。{WorkspaceId} を実際のワークスペース ID に置き換えてください。URL はリージョンによって異なります。

        base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
    )
    # モデルの一覧については、https://www.alibabacloud.com/help/en/model-studio/getting-started/models をご参照ください。
    completion = client.chat.completions.create(model="qwen-plus", messages=messages)
    return completion

# messages 配列を初期化
messages = [
    {
        "role": "system",
        "content": """あなたはアリババモバイルショップの販売員です。ユーザーにスマートフォンをおすすめすることがあなたの役割です。スマートフォンには 2 つのパラメーターがあります。画面サイズ(6.1 インチ、6.5 インチ、6.7 インチ)と解像度(2K および 4K)です。
        一度に 1 つのパラメーターのみをユーザーに尋ねることができます。ユーザーが完全な情報を提供しない場合、不足しているパラメーターを取得するためにフォローアップ質問をする必要があります。すべてのパラメーターが収集されたら、「購入意図を把握しました。少々お待ちください。」と言う必要があります。""",
    }
]
assistant_output = "アリババモバイルショップへようこそ。どのような画面サイズをお探しですか?"
print(f"モデルの出力: {assistant_output}\n")
while "購入意図を把握しました。" not in assistant_output:
    user_input = input("入力してください: ")
    # ユーザーの質問を messages リストに追加
    messages.append({"role": "user", "content": user_input})
    assistant_output = get_response(messages).choices[0].message.content
    # モデルの応答を messages リストに追加
    messages.append({"role": "assistant", "content": assistant_output})
    print(f"モデルの出力: {assistant_output}")
    print("\n")

マルチモーダルモデルの場合

マルチモーダルモデルは、対話において画像や音声をサポートします。テキストモデルとは次のように実装が異なります。
  • ユーザーのメッセージ構築: マルチモーダルモデルのユーザーのメッセージには、テキストに加えて画像や音声などのマルチモーダル情報が含まれる場合があります。
  • DashScope SDK インターフェイス: DashScope Python SDK を使用する場合は、MultiModalConversation インターフェイスを呼び出します。DashScope Java SDK を使用する場合は、MultiModalConversation クラスを呼び出します。
マルチモーダルモデルについては、「画像および動画理解」、「および「Kimi」をご参照ください。Qwen-Omni については、「非リアルタイム (Qwen-Omni)」をご参照ください。Qwen-VL-OCR および Qwen3-Omni-Captioner は特定のシングルターンタスク用に設計されており、マルチターン対話をサポートしません。
  • OpenAI 互換
  • DashScope
Python
from openai import OpenAI
import os

client = OpenAI(
    # API キーはリージョンによって異なります。API キーの取得方法については、https://www.alibabacloud.com/help/en/model-studio/get-api-key をご参照ください。
    # 環境変数を設定していない場合は、次の行を Model Studio API キーに置き換えてください: api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # シンガポールリージョンの URL です。{WorkspaceId} を実際のワークスペース ID に置き換えてください。URL はリージョンによって異なります。

    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
)
messages = [
        {"role": "user",
         "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251031/ownrof/f26d201b1e3f4e62ab4a1fc82dd5c9bb.png"
                },
            },
            {"type": "text", "text": "画像に写っている商品は何ですか?"},
        ],
    }
]
completion = client.chat.completions.create(
    model="qwen3-vl-plus",  #  他のマルチモーダルモデルに置き換え、必要に応じて messages を修正できます。
    messages=messages,
    )
print(f"第 1 ラウンドの出力: {completion.choices[0].message.content}")

assistant_message = completion.choices[0].message
messages.append(assistant_message.model_dump())
messages.append({
        "role": "user",
        "content": [
        {
            "type": "text",
            "text": "それらのスタイルは何ですか?"
        }
        ]
    })
completion = client.chat.completions.create(
    model="qwen3-vl-plus",
    messages=messages,
    )

print(f"第 2 ラウンドの出力: {completion.choices[0].message.content}")

思考モデルの場合

思考モデルは、reasoning_content(思考プロセス)と content(応答)を返します。messages を更新する際は、content のみを保持し、reasoning_content は無視してください。
[
    {"role": "user", "content": "宇宙探査をテーマにした SF 映画をおすすめしてください。"},
    {"role": "assistant", "content": "『XXX』をおすすめします。これは古典的な SF 作品です。"}, # コンテキストに追加する際に reasoning_content フィールドを追加しないでください。
    {"role": "user", "content": "この映画の監督は誰ですか?"}
]
思考モデルの詳細については、「ディープシンキング」、「画像および動画理解」をご参照ください。
Qwen3-Omni-Flash(思考モード)によるマルチターン対話の実装方法の詳細については、「オムニモーダル」をご参照ください。
  • OpenAI 互換
  • DashScope
  • Python
  • Node.js
  • HTTP

サンプルコード

from openai import OpenAI
import os

# OpenAI クライアントを初期化
client = OpenAI(
    # API キーはリージョンによって異なります。API キーの取得方法については、https://www.alibabacloud.com/help/en/model-studio/get-api-key をご参照ください。
    # 環境変数を設定していない場合は、次の行を Model Studio API キーに置き換えてください: api_key="sk-xxx"
    api_key = os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1"
)

messages = []
conversation_idx = 1
while True:
    reasoning_content = ""  # 完全な思考プロセスを定義
    answer_content = ""     # 完全な応答を定義
    is_answering = False   # 思考プロセスを終了して応答を開始するかどうかを判断
    print("="*20+f"会話ラウンド {conversation_idx}"+"="*20)
    conversation_idx += 1
    user_msg = {"role": "user", "content": input("メッセージを入力してください: ")}
    messages.append(user_msg)
    # チャット補完リクエストを作成
    completion = client.chat.completions.create(
        # 必要に応じて他のディープシンキングモデルに置き換えられます。
        model="qwen-plus",
        messages=messages,
        extra_body={"enable_thinking": True},
        stream=True,
        # stream_options={
        #     "include_usage": True
        # }
    )
    print("\n" + "=" * 20 + "思考プロセス" + "=" * 20 + "\n")
    for chunk in completion:
        # chunk.choices が空の場合は使用量を出力
        if not chunk.choices:
            print("\n使用量:")
            print(chunk.usage)
        else:
            delta = chunk.choices[0].delta
            # 思考プロセスを出力
            if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
                print(delta.reasoning_content, end='', flush=True)
                reasoning_content += delta.reasoning_content
            else:
                # 応答を開始
                if delta.content != "" and is_answering is False:
                    print("\n" + "=" * 20 + "完全な応答" + "=" * 20 + "\n")
                    is_answering = True
                # 応答プロセスを出力
                print(delta.content, end='', flush=True)
                answer_content += delta.content
    # モデルの応答内容をコンテキストに追加
    messages.append({"role": "assistant", "content": answer_content})
    print("\n")

本番環境に適用

マルチターン対話は多くのトークンを消費し、モデルのコンテキスト長を超えてエラーを引き起こす可能性があります。コンテキストを管理しコストをコントロールするために、以下の戦略を使用してください。

1. コンテキスト管理

messages 配列は各ラウンドで増加し、モデルのトークン制限を超える可能性があります。コンテキスト長を管理するために、以下の方法を使用してください。

1.1. コンテキストのトリミング

履歴が長くなりすぎた場合、最新の N ラウンドのみを保持します。実装は簡単ですが、以前の会話情報が失われます。

1.2. ローリングサマリー

会話が進行するにつれてコンテキストを要約し、履歴を圧縮して長さをコントロールし、コア情報を失わないようにします。 a. 履歴が最大コンテキスト長の 70% に達したら、前の部分(最初の半分など)を抽出し、別途 API 呼び出しを行って「メモリサマリー」を生成します。 b. 次のリクエストでは、長い履歴を「メモリサマリー」に置き換え、最新のラウンドを追加します。

1.3. ベクトル化された取得

ローリングサマリーでは一部の情報が失われる可能性があります。大規模な会話履歴からモデルが関連情報を思い出すことができるように、線形のコンテキスト渡しではなく、オンデマンド取得を使用します。 a. 各会話ラウンドの後、会話をベクトルデータベースに保存します。 b. ユーザーが質問をすると、類似性に基づいて関連する会話レコードを取得します。 c. 取得した会話レコードと最新のユーザー入力を組み合わせて、その内容をモデルに送信します。

2. コスト管理

各ラウンドで入力トークンが増加し、コストが大幅に上昇します。以下のコスト管理戦略を使用してください。

2.1. 入力トークンの削減

前述のコンテキスト管理戦略を使用して入力トークンを削減し、コストを下げます。

2.2. コンテキストキャッシュをサポートするモデルの使用

マルチターンリクエストでは、messages 配列が繰り返し処理され、課金されます。Model Studio は、qwen-max や qwen-plus などのモデルに対してコンテキストキャッシュを提供しており、これによりコストを削減し応答速度を向上させます。コンテキストキャッシュをサポートするモデルを優先的に使用してください。
コンテキストキャッシュは自動的に有効化され、コードの変更は不要です。

エラーコード

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