Skip to main content

Deep research (Qwen-Deep-Research)

計画、複数回の Web 検索、構造化されたレポートの生成を通じて、複雑な調査を自動化します。手動での作業を必要とせず、情報を収集し、統合します。

このドキュメントは、中国本土 (北京) リージョンにのみ適用されます。モデルを使用するには、中国本土 (北京) リージョンの API キーを使用してください。

クイックスタート

API キーを取得し、API キーを環境変数としてエクスポートします。SDK を使用して呼び出しを行う場合は、DashScope SDK をインストールします。 モデルは、2 段階のワークフローを採用しています。最初のステップは「フォローアップ質問」で、モデルが調査範囲を明確にします。次のステップは「詳細な調査」で、モデルが検索、分析、レポート生成を行います。フォローアップ質問を行うことで、長時間の調査を開始する前に、調査対象を正確に把握することができます。
現在、このモデルは Java 用 DashScope SDK または OpenAI 互換の API 呼び出しをサポートしていません。
import os
import dashscope

# これは、中国北部 2 (北京) リージョンの URL です。各リージョンの URL は異なります。
dashscope.base_http_api_url = 'https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1'

# API キーを構成します
# 設定されていない場合は、次の行を Model Studio API キー (形式: sk-xxx) に置き換えてください
API_KEY = os.getenv('DASHSCOPE_API_KEY')

def call_deep_research_model(messages, step_name):
    print(f"\n=== {step_name} ===")

    try:
        responses = dashscope.Generation.call(
            api_key=API_KEY,
            model="qwen-deep-research",
            messages=messages,
            # qwen-deep-research モデルは現在、ストリーミング出力のみをサポートしています
            stream=True
            # incremental_output=True 増分出力にはこのパラメーターを追加します
        )

        return process_responses(responses, step_name)

    except Exception as e:
        print(f"API 呼び出し中にエラーが発生しました: {e}")
        return ""

# フェーズのコンテンツを表示
def display_phase_content(phase, content, status):
    if content:
        print(f"\n[{phase}] {status}: {content}")
    else:
        print(f"\n[{phase}] {status}")

# レスポンスを処理
def process_responses(responses, step_name):
    current_phase = None
    phase_content = ""
    research_goal = ""
    web_sites = []
    references = []
    keepalive_shown = False  # KeepAlive プロンプトが表示されたかどうかを確認するフラグ

    for response in responses:
        # レスポンスのステータスコードを確認
        if hasattr(response, 'status_code') and response.status_code != 200:
            print(f"HTTP リターンコード: {response.status_code}")
            if hasattr(response, 'code'):
                print(f"エラーコード: {response.code}")
            if hasattr(response, 'message'):
                print(f"エラーメッセージ: {response.message}")
            print("詳細については、https://www.alibabacloud.com/help/model-studio/error-code をご参照ください")
            continue

        if hasattr(response, 'output') and response.output:
            message = response.output.get('message', {})
            phase = message.get('phase')
            content = message.get('content', '')
            status = message.get('status')
            extra = message.get('extra', {})

            # フェーズ変更の検出
            if phase != current_phase:
                if current_phase and phase_content:
                    # フェーズとステップ名に基づいて異なる完了説明を表示
                    if step_name == "ステップ 1: モデルのクエリ確認" and current_phase == "answer":
                        print(f"\n クエリ確認フェーズが完了しました")
                    else:
                        print(f"\n {current_phase} フェーズが完了しました")
                current_phase = phase
                phase_content = ""
                keepalive_shown = False  # KeepAlive プロンプトのフラグをリセット

                # フェーズとステップ名に基づいて異なる説明を表示
                if step_name == "ステップ 1: モデルのクエリ確認" and phase == "answer":
                    print(f"\n クエリ確認フェーズに入ります")
                else:
                    print(f"\n {phase} フェーズに入ります")

            # Answer フェーズでの参照情報の処理
            if phase == "answer":
                if extra.get('deep_research', {}).get('references'):
                    new_references = extra['deep_research']['references']
                    if new_references and new_references != references:  # 重複表示を避ける
                        references = new_references
                        print(f"\n   参考文献 ({len(references)}):")
                        for i, ref in enumerate(references, 1):
                            print(f"     {i}. {ref.get('title', 'タイトルなし')}")
                            if ref.get('url'):
                                print(f"        URL: {ref['url']}")
                            if ref.get('description'):
                                print(f"        説明: {ref['description'][:100]}...")
                            print()

            # WebResearch フェーズでの特別情報の処理
            # 注: qwen-deep-research-2025-12-15 モデルは、streamingQueries と streamingWebResult の代わりに
            # streamingThinking ステータスを使用します
            if phase == "WebResearch":
                if extra.get('deep_research', {}).get('research'):
                    research_info = extra['deep_research']['research']

                    # streamingThinking (スナップショットモデル) または streamingQueries (メインラインモデル) ステータスの処理
                    if status in ("streamingThinking", "streamingQueries"):
                        if 'researchGoal' in research_info:
                            goal = research_info['researchGoal']
                            if goal:
                                research_goal += goal
                                print(f"\n   調査目標: {goal}", end='', flush=True)

                    # streamingWebResult ステータス (メインラインモデル) の処理
                    # スナップショットモデルは、streamingThinking を使用してこのステータスをマージします
                    elif status == "streamingWebResult":
                        if 'webSites' in research_info:
                            sites = research_info['webSites']
                            if sites and sites != web_sites:  # 重複表示を避ける
                                web_sites = sites
                                print(f"\n   {len(sites)} 件の関連 Web サイトが見つかりました:")
                                for i, site in enumerate(sites, 1):
                                    print(f"     {i}. {site.get('title', 'タイトルなし')}")
                                    print(f"        説明: {site.get('description', '説明なし')[:100]}...")
                                    print(f"        URL: {site.get('url', 'リンクなし')}")
                                    if site.get('favicon'):
                                        print(f"        アイコン: {site['favicon']}")
                                    print()

                    # WebResultFinished ステータスの処理
                    elif status == "WebResultFinished":
                        print(f"\n   Web 検索が完了しました。{len(web_sites)} 件の参照ソースが見つかりました。")
                        if research_goal:
                            print(f"   調査目標: {research_goal}")

            # コンテンツを蓄積して表示
            if content:
                phase_content += content
                # コンテンツをリアルタイムで表示
                print(content, end='', flush=True)

            # フェーズのステータス変更を表示
            if status and status != "typing":
                print(f"\n   ステータス: {status}")

                # ステータスの説明を表示
                if status == "streamingThinking":
                    print("   → 調査タスクの分解と Web コンテンツの要約 (WebResearch フェーズ)")
                elif status == "streamingQueries":
                    print("   → 調査目標と検索クエリの生成 (WebResearch フェーズ)")
                elif status == "streamingWebResult":
                    print("   → 検索、Web ページの読み取り、コード実行の実行 (WebResearch フェーズ)")
                elif status == "WebResultFinished":
                    print("   → Web 検索フェーズが完了しました (WebResearch フェーズ)")

            # ステータスが finished の場合、トークン消費量を表示
            if status == "finished":
                if hasattr(response, 'usage') and response.usage:
                    usage = response.usage
                    print(f"\n    トークン消費量の統計:")
                    print(f"      入力トークン: {usage.get('input_tokens', 0)}")
                    print(f"      出力トークン: {usage.get('output_tokens', 0)}")
                    print(f"      リクエスト ID: {response.get('request_id', '不明')}")

            if phase == "KeepAlive":
                # KeepAlive フェーズに初めて入ったときのみプロンプトを表示
                if not keepalive_shown:
                    print("現在のステップが完了しました。次のステップの準備をしています。")
                    keepalive_shown = True
                continue

    if current_phase and phase_content:
        if step_name == "ステップ 1: モデルのクエリ確認" and current_phase == "answer":
            print(f"\n クエリ確認フェーズが完了しました")
        else:
            print(f"\n {current_phase} フェーズが完了しました")

    return phase_content

def main():
    # API キーを確認
    if not API_KEY:
        print("エラー: DASHSCOPE_API_KEY 環境変数が設定されていません")
        print("環境変数を設定するか、コード内の API_KEY 変数を直接変更してください")
        return

    print("ユーザーが対話を開始: 教育における人工知能の応用を調査")

    # ステップ 1: モデルのクエリ確認
    # モデルはユーザーの質問を分析し、調査の方向性を定義するために明確化の質問をします
    messages = [{'role': 'user', 'content': '教育における人工知能の応用を調査'}]
    step1_content = call_deep_research_model(messages, "ステップ 1: モデルのクエリ確認")

    # ステップ 2: 詳細な調査
    # ステップ 1 のクエリ確認に基づいて、モデルは完全な調査プロセスを実行します
    messages = [
        {'role': 'user', 'content': '教育における人工知能の応用を調査'},
        {'role': 'assistant', 'content': step1_content},  # モデルのクエリ確認コンテンツを含む
        {'role': 'user', 'content': '主に個別化学習とインテリジェント評価に焦点を当てています'}
    ]

    call_deep_research_model(messages, "ステップ 2: 詳細な調査")
    print("\n 調査が完了しました!")

if __name__ == "__main__":
    main()

仕様

モデル

コンテキストウィンドウ (トークン)

最大入力 (トークン)

最大出力 (トークン)

qwen-deep-research

1,000,000

997,952

32,768

qwen-deep-research-2025-12-15

qwen-deep-research: メインラインモデル、継続的に更新されます。qwen-deep-research-2025-12-15: スナップショットバージョンで、深さ、品質、MCP ツール呼び出しが改善されています。どちらも画像入力をサポートしており、個別に課金されます。

主要機能

phase (現在のタスク) と status (タスクの進捗) を介して進捗を追跡します。 フォローアップ質問とレポート生成 (phase: "answer") クエリを分析し、範囲を定義するための明確化の質問をし、最終的な調査レポートを生成します。 ステータス値:
  • typing: テキストコンテンツを生成中
  • finished: テキストコンテンツの生成が完了
調査計画 (phase: "ResearchPlanning") クエリから調査の概要を作成します。 ステータス値:
  • typing: 調査計画を生成中
  • finished: 調査計画が完了
Web 検索 (phase: "WebResearch") 複数回の Web 検索とコンテンツ分析を実行します。WebResultFinished は各ラウンドの終了を示します。finished はフェーズの終了を示します。 ステータス値:
  • streamingThinking: 調査タスクの分解と Web コンテンツの要約 (qwen-deep-research-2025-12-15 に固有、streamingQueries と streamingWebResult を置き換えます)
  • streamingQueries: 検索クエリの生成 (qwen-deep-research のみ)
  • streamingWebResult: Web 検索の実行と Web コンテンツの分析 (qwen-deep-research のみ)
  • WebResultFinished: 検索ラウンドが完了
  • finished: Web 検索フェーズが完了
接続キープアライブ (phase: "KeepAlive") 長時間実行されるタスク間の接続を維持します。このフェーズは無視して、処理を続行してください。

画像入力

両方のモデルが画像入力をサポートしています。モデルは画像を分析し、そのコンテンツを調査に組み込みます。content フィールドには配列フォーマットを使用し、image と text オブジェクトを一緒に渡します。
  • サポートされているフォーマット:JPEG、PNG、BMP、WEBP。画像ごとに最大 10 MB。
  • リクエストごとに最大 5 枚の画像。公開 URL と Base64 エンコーディングをサポートします。
  • レスポンスのフォーマットは、テキストのみのリクエストと同じです。モデルは画像コンテンツに基づいてレポートを生成します。
リクエスト例
import os
import dashscope

# これは、中国北部 2 (北京) リージョンの URL です。各リージョンの URL は異なります。
dashscope.base_http_api_url = 'https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1'

API_KEY = os.getenv('DASHSCOPE_API_KEY')

messages = [
    {
        "role": "user",
        "content": [
            {"image": "https://example.aliyuncs.com/example.png"},
            {"text": "このチャートのデータトレンドを分析し、主要な発見について詳細な調査を行ってください"}
        ]
    }
]

responses = dashscope.Generation.call(
    api_key=API_KEY,
    model="qwen-deep-research",
    messages=messages,
    stream=True
)

for response in responses:
    if hasattr(response, 'output') and response.output:
        message = response.output.get('message', {})
        content = message.get('content', '')
        if content:
            print(content, end='', flush=True)

MCP ツール呼び出し

MCP ツール呼び出しは qwen-deep-research-2025-12-15 のみでサポートされています。qwen-deep-research はこの機能をサポートしていません。
Model Context Protocol (MCP) ツール呼び出しにより、qwen-deep-research-2025-12-15 は、標準の Web 検索と並行して、WebResearch フェーズ中にナレッジベース、内部ドキュメント、または独自のデータベースなどの非公開またはドメイン固有のデータソースから情報を取得できます。research_tools パラメーターを介して MCP サーバー構成を渡します。レスポンスのフォーマットは、標準の呼び出しと同じです。
research_tools と MCP ツールの仕様の詳細については、「Qwen-Deep-Research」をご参照ください。

リクエスト例

import os
import dashscope

# これは、中国北部 2 (北京) リージョンの URL です。各リージョンの URL は異なります。
dashscope.base_http_api_url = 'https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1'

API_KEY = os.getenv('DASHSCOPE_API_KEY')

messages = [
    {
        "role": "user",
        "content": "ナレッジベースを使用して最近公開されたプロダクト更新のお知らせを検索し、調査レポートにまとめてください"
    }
]

responses = dashscope.Generation.call(
    api_key=API_KEY,
    model="qwen-deep-research-2025-12-15",
    messages=messages,
    stream=True,
    enable_feedback=False,
    research_tools=[{
        "type": "mcp",
        "server_label": "my-server",
        "server_url": "https://your-mcp-server.example.com/sse",
        "allowed_tools": ["search", "fetch"],
        "authentication": {
            "bearer": "your_jwt_token_here"
        }
    }]
)

for response in responses:
    if hasattr(response, 'output') and response.output:
        message = response.output.get('message', {})
        content = message.get('content', '')
        if content:
            print(content, end='', flush=True)

課金

モデル

入力コスト (1K トークンあたり)

出力コスト (1K トークンあたり)

無料クォータ

qwen-deep-research

$0.007742

$0.023367

無料クォータなし

qwen-deep-research-2025-12-15

未定

未定

無料クォータなし

課金は、入力トークン (ユーザーメッセージとシステムプロンプト) と出力トークン (フォローアップ質問、調査計画、目標、検索クエリ、最終レポート) に基づいて行われます。2 つのモデルは個別に課金されます。

本番環境に適用

ストリーミング出力の使用 モデルはストリーミング出力 (stream=True) のみをサポートしています。単一の調査タスクは、数十回の反復的な検索と読み取りサイクルにわたって数分間実行される可能性があり、これは同期リクエストのタイムアウトを超えます。ストリーミングを使用して接続を開いたままにし、phase および status フィールドを介して進捗を追跡します。 エラー処理 各チャンクでレスポンスのステータスコードを確認します。200 以外のステータスコードの場合は、code および message フィールドを読み取り、適切に処理します。 トークン使用量の監視 status が finished の場合、response.usage (入力トークン、出力トークン、リクエスト ID) からトークン使用量を取得します。 接続キープアライブの処理 KeepAlive フェーズは、長時間実行されるタスク間の接続を維持します。このフェーズは無視して、ストリームの処理を続行してください。

よくある質問

  • 一部のレスポンスチャンクで output フィールドが空なのはなぜですか? 初期のチャンクにはメタデータのみが含まれます。コンテンツは、モデルが生成するにつれて後続のチャンクで届きます。
  • フェーズが完了したかどうかを判断するにはどうすればよいですか? フェーズは、status が finished に変更されたときに完了します。
  • モデルは OpenAI 互換の API 呼び出しをサポートしていますか? いいえ。OpenAI 互換の API 呼び出しはサポートされていません。
  • 入力トークンと出力トークンはどのように計算されますか? 入力トークン:ユーザーメッセージとシステムプロンプト。出力トークン:フォローアップ質問、調査計画、目標、検索クエリ、最終レポート。
  • qwen-deep-research と qwen-deep-research-2025-12-15 の違いは何ですか? qwen-deep-research: メインラインモデル、継続的に更新されます。qwen-deep-research-2025-12-15: スナップショットバージョンで、深さ、品質、MCP サポートが改善されています。どちらも画像入力をサポートしており、個別に課金されます。
  • 調査のために画像を渡すにはどうすればよいですか? content には配列フォーマットを使用します:配列内のオブジェクトとして {"image": "URL"} と {"text": "description"} を渡します。両方のモデルが画像入力をサポートしています。
  • フォローアップ質問をスキップして、直接調査に進むにはどうすればよいですか? parameters で enable_feedback を false に設定します。モデルはフォローアップ質問をスキップし、すぐに調査を開始します。

API リファレンス

入力および出力パラメーターについては、「Qwen-Deep-Research」をご参照ください。

エラーコード

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

レート制限

「レート制限」をご参照ください。