1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qwen3.6-35B-A3Bをvllmでサーブしてツール呼び出し付きのコーディングエージェントを動かす

1
Posted at

qiita-qwen36-vllm-thumbnail.png

2026年4月16日にAlibabaのQwenチームがApache 2.0で公開したQwen3.6-35B-A3Bは、総パラメータ35B・アクティブパラメータ約3BのスパースMoEモデルです。SWE-bench Verified 73.4%、MCPMark 37.0と、エージェント的コーディングに特化したチューニングが入っています。

この記事では、vLLMでOpenAI互換APIとしてサーブし、Pythonクライアントからツール呼び出し(Function Calling)付きで使うところまでを動かします。

※ 本記事は公開情報をもとにした個人的なまとめです。

前提

  • vLLM 0.19.0 以上(公式が推奨するバージョン)
  • NVIDIA GPU(RTX 4090 24GB で単体動作可、複数GPUならテンソル並列で大きなコンテキストも扱える)
  • Python 3.12
  • モデルは初回起動時にHugging Faceから自動ダウンロードされる

1. vLLMのインストール

python -m venv qwen36-env
source qwen36-env/bin/activate
pip install vllm>=0.19.0

古いvLLMではQwen3.6のMoEアーキテクチャをサポートしていないため、必ず0.19.0以上を使ってください。

2. vLLMサーバーの起動

基本起動(推論のみ)

vllm serve Qwen/Qwen3.6-35B-A3B \
  --port 8000 \
  --tensor-parallel-size 1 \
  --max-model-len 32768 \
  --reasoning-parser qwen3

--reasoning-parser qwen3 を付けるとthinkingモード(内部推論ステップの生成)が有効になります。コーディング用途ではこれを付けたほうが精度が出ます。

RTX 4090単体の場合は --max-model-len を32768〜65536程度に抑えてください。262144フルに使うにはVRAMが足りません。

ツール呼び出し対応で起動

vllm serve Qwen/Qwen3.6-35B-A3B \
  --port 8000 \
  --tensor-parallel-size 1 \
  --max-model-len 32768 \
  --reasoning-parser qwen3 \
  --enable-auto-tool-choice \
  --tool-call-parser qwen3_coder

--tool-call-parser qwen3_coder は必須です。 このフラグがないと、モデルはツール呼び出しのJSONを生成しますがvLLMがそれをパースできず、構造化されたtool_callオブジェクトとして返ってきません。

複数GPU(例: 4枚)の場合

vllm serve Qwen/Qwen3.6-35B-A3B \
  --port 8000 \
  --tensor-parallel-size 4 \
  --max-model-len 262144 \
  --reasoning-parser qwen3 \
  --enable-auto-tool-choice \
  --tool-call-parser qwen3_coder

起動すると http://localhost:8000/v1 にOpenAI互換のAPIエンドポイントが立ちます。

3. Pythonから基本的なチャット

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="dummy",  # vLLMローカルではAPIキー不要
)

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B",
    messages=[
        {"role": "user", "content": "Pythonでフィボナッチ数列のジェネレータを書いてください"}
    ],
    temperature=0.7,
    max_tokens=2048,
)

print(response.choices[0].message.content)

OpenAI SDKがそのまま使えるので、既存のコードベースからモデルを差し替えるだけで動きます。

4. ツール呼び出し(Function Calling)

ここからが本題です。Qwen3.6-35B-A3Bはツール呼び出しに対応しており、MCPMarkベンチマークではGemma 4-31Bの18.1%に対して37.0%を記録しています。

import json
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="dummy",
)

# ツール定義
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_files",
            "description": "プロジェクト内のファイルをキーワードで検索する",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "検索キーワード"
                    },
                    "file_extension": {
                        "type": "string",
                        "description": "対象の拡張子(例: .py, .ts)"
                    }
                },
                "required": ["query"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "指定パスのファイル内容を読み取る",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "ファイルパス"
                    }
                },
                "required": ["path"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "指定パスにファイルを書き込む",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "ファイルパス"
                    },
                    "content": {
                        "type": "string",
                        "description": "書き込む内容"
                    }
                },
                "required": ["path", "content"]
            }
        }
    }
]

# エージェント的にツールを呼ばせる
response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B",
    messages=[
        {
            "role": "system",
            "content": "あなたはコーディングエージェントです。ユーザーのリクエストに応じてファイルを検索・読み取り・書き込みしてください。"
        },
        {
            "role": "user",
            "content": "プロジェクト内のPythonファイルからデータベース接続を扱っている箇所を探して、接続プールのサイズを5から20に変更してください。"
        }
    ],
    tools=tools,
    tool_choice="auto",
    temperature=1.0,  # thinkingモード推奨値
    max_tokens=4096,
)

message = response.choices[0].message

# ツール呼び出しの結果を確認
if message.tool_calls:
    for call in message.tool_calls:
        print(f"Tool: {call.function.name}")
        print(f"Args: {call.function.arguments}")
        print("---")
else:
    print(message.content)

5. ツール呼び出しループ(マルチターン)

実用的なエージェントでは、ツール呼び出し → 結果をモデルに返す → 次のアクション、というループが必要です。

def run_agent(user_request: str, tools: list, max_steps: int = 10):
    messages = [
        {
            "role": "system",
            "content": "あなたはコーディングエージェントです。必要なツールを呼び出してタスクを完了してください。"
        },
        {"role": "user", "content": user_request}
    ]

    for step in range(max_steps):
        response = client.chat.completions.create(
            model="Qwen/Qwen3.6-35B-A3B",
            messages=messages,
            tools=tools,
            tool_choice="auto",
            temperature=1.0,
            max_tokens=4096,
        )

        assistant_message = response.choices[0].message
        messages.append(assistant_message)

        if not assistant_message.tool_calls:
            # ツール呼び出しなし = 完了
            print(f"[完了] {assistant_message.content}")
            return assistant_message.content

        # 各ツール呼び出しを実行
        for call in assistant_message.tool_calls:
            tool_name = call.function.name
            tool_args = json.loads(call.function.arguments)

            print(f"[Step {step+1}] {tool_name}({tool_args})")

            # ここに実際のツール実行ロジックを入れる
            result = execute_tool(tool_name, tool_args)

            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": json.dumps(result, ensure_ascii=False),
            })

    return "最大ステップ数に到達しました"


def execute_tool(name: str, args: dict) -> dict:
    """実際のツール実行(ここではダミー)"""
    if name == "search_files":
        return {
            "files": [
                {"path": "src/db/connection.py", "match": "pool_size=5"},
                {"path": "src/db/config.py", "match": "POOL_SIZE = 5"},
            ]
        }
    elif name == "read_file":
        return {"content": f"# {args['path']} の内容がここに入る"}
    elif name == "write_file":
        return {"status": "ok", "path": args["path"]}
    return {"error": "unknown tool"}

execute_tool の中身を実際のファイルシステム操作に差し替えれば、ローカルで動くコーディングエージェントになります。

6. thinkingモードの切り替え

Qwen3.6にはthinkingモード(内部推論を生成してから回答)と非thinkingモード(直接回答)があります。

モード temperature 用途
thinking(推奨) 1.0 複雑なコーディング、デバッグ、設計判断
non-thinking 0.7 シンプルな質問、コード補完

vLLMの起動時に --reasoning-parser qwen3 を付けている場合、thinkingモードがデフォルトで有効です。APIリクエスト側で無効にしたい場合は、vLLM 0.19.0以降で extra_body パラメータを使います。

ハードウェア目安

構成 max-model-len 備考
RTX 4090 (24GB) × 1 32,768 基本的なコーディングタスクには十分
RTX 4090 × 2(TP=2) 65,536 リポジトリ全体を読み込む用途
A100 80GB × 1 131,072 余裕のある単体構成
H100 × 4(TP=4) 262,144 フルコンテキスト、本番運用

FP8量子化版(Qwen/Qwen3.6-35B-A3B-FP8)を使えばVRAM使用量をさらに抑えられます。性能はほぼ同等と報告されています。

まとめ

  • vLLM 0.19.0以上で Qwen/Qwen3.6-35B-A3B をサーブすると、localhost:8000/v1 にOpenAI互換APIが立つ
  • ツール呼び出しには起動時に --enable-auto-tool-choice --tool-call-parser qwen3_coder が必須
  • OpenAI SDK でそのまま叩けるので、既存コードのモデル差し替えだけで動く
  • thinkingモード(temperature=1.0)でコーディング精度が上がる
  • Apache 2.0ライセンスなので商用利用も自由

3日前に出たばかりのモデルなので、ツール呼び出し周りの安定性はまだコミュニティで検証中です。本番投入前にはご自身のワークロードでテストすることをお勧めします。

参考

  • Qwen/Qwen3.6-35B-A3B - Hugging Face
  • Qwen3.5 & Qwen3.6 Usage Guide - vLLM Recipes
  • QwenLM/Qwen3.6 - GitHub
  • vLLM Tool Calling Documentation
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?