Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save hdknr/9023009193920fd0ad17eda629351b18 to your computer and use it in GitHub Desktop.

Select an option

Save hdknr/9023009193920fd0ad17eda629351b18 to your computer and use it in GitHub Desktop.
Qwen Code ローカル運用実践記 — Mac Studio M3 Ultra で Ollama + qwen3-coder:30b を動かして分かったこと

Qwen Code ローカル運用実践記 — Mac Studio M3 Ultra で Ollama + qwen3-coder:30b を動かして分かったこと

Qwen Code(Alibaba Cloud Qwen チームが開発したオープンソース CLI コーディングエージェント)を Mac Studio M3 Ultra(96GB)上で Ollama と組み合わせてローカル運用を試みた実践記録です。環境構築からツール呼び出しの限界まで、実際に手を動かして検証した結果をまとめます。

背景と目的

Claude Code は強力ですが、コードがクラウドに送信されるためプライバシーの懸念があります。Qwen Code は Apache 2.0 ライセンスのオープンソースで、Ollama と組み合わせれば完全ローカルで動作するため、機密コードベースでの利用が期待されます。

本記事の検証環境:

項目 スペック
マシン Mac Studio M3 Ultra
メモリ 96GB ユニファイドメモリ
メモリ帯域 800 GB/s
Ollama v0.15.6
Qwen Code v0.12.0(Fork からローカルビルド)
モデル qwen3-coder:30b (18GB)

ステップ1: リポジトリの Fork と Clone

調査・改造を前提に、まず QwenLM/qwen-code を Fork しました。

# Fork(GitHub CLI)
gh repo fork QwenLM/qwen-code --clone=false

# devel ブランチを作成してデフォルトに設定
# main は upstream との sync 用にクリーンに保つ
gh api repos/hdknr/qwen-code/git/refs \
  -f ref="refs/heads/devel" \
  -f sha="$(gh api repos/hdknr/qwen-code/git/ref/heads/main --jq '.object.sha')"
gh repo edit hdknr/qwen-code --default-branch devel

# Clone
mkdir -p ~/Projects/qwen
cd ~/Projects/qwen
gh repo clone hdknr/qwen-code

ブランチ戦略:

upstream/main ──sync──→ fork/main ──merge──→ fork/devel(作業用)

main を upstream と同期させ、devel で自由に作業する構成です。

ステップ2: Ollama のモデルダウンロード

Ollama は導入済みだったため、Qwen モデルのダウンロードのみ実行しました。

# メインモデル(96GB なら余裕)
ollama pull qwen3-coder:30b    # 18GB

# 比較用
ollama pull qwen2.5-coder:14b  # 9.0GB
ollama pull qwen2.5-coder:7b   # 4.7GB

メモリ別の推奨モデル

Mac メモリ 推奨モデル 推論速度
M4 16GB qwen3:8b 28-35 tok/s
M4 Pro 24GB qwen3-coder:14b 25-30 tok/s
M4 Pro 48GB qwen3-coder:30b 12-18 tok/s
M3 Ultra 96GB qwen3-coder:30b 25-35 tok/s

M3 Ultra の 800 GB/s メモリ帯域は LLM 推論に大きなアドバンテージがあり、M4 Pro(273 GB/s)の約3倍の速度が出ます。

動作確認

ollama run qwen3-coder:30b "Write a Python function that returns the first n prime numbers."

正常にコードが生成されることを確認しました。

ステップ3: Qwen Code のビルド

cd ~/Projects/qwen/qwen-code

# 依存関係インストール
make install

# ビルド
make build

トラブル: Xcode ライセンス

make install 実行時に以下のエラーが発生しました:

You have not agreed to the Xcode license agreements.
Please run 'sudo xcodebuild -license' from within a Terminal window

sudo xcodebuild -license を実行してライセンスに同意した後、再度 make install で解決しました。

ステップ4: settings.json の設定 — 3回の試行錯誤

ここが最も苦労した部分です。Qwen Code の設定ファイル形式はドキュメントが不十分で、ソースコードを読んで正しい形式を特定する必要がありました。

試行1: 失敗 — 設定形式が不正

{
  "model": { "name": "qwen3-coder:30b" },
  "providers": {
    "ollama": {
      "baseUrl": "http://localhost:11434/v1",
      "apiKey": "EMPTY"
    }
  },
  "security": {
    "auth": { "selectedType": "openai-compatible" }
  }
}

エラー: TypeError: Cannot read properties of undefined (reading 'model')

原因: providers というキーは存在せず、modelProviders が正しいキー名。selectedType の値も openai-compatible ではなく openai

試行2: 失敗 — ログインを求められる

{
  "model": { "name": "qwen3-coder:30b" },
  "modelProviders": {
    "openai": [
      { "id": "qwen3-coder:30b", "baseUrl": "http://localhost:11434/v1" }
    ]
  },
  "security": {
    "auth": {
      "selectedType": "openai",
      "apiKey": "EMPTY",
      "baseUrl": "http://localhost:11434/v1"
    }
  }
}

問題: 起動時に Qwen OAuth のログイン画面が表示される。selectedType が外部プロセスによって削除される現象も発生。

試行3: 失敗 — envKey 不足

ヘッドレスモードで --auth-type openai を明示的に指定しても:

Missing credentials for modelProviders model 'qwen3-coder:30b'.
Configure modelProviders.openai[].envKey and set that environment variable.

最終的な正解の設定

ソースコード(packages/cli/src/config/settingsSchema.tspackages/core/src/models/modelConfigResolver.ts)を読み解いた結果、以下の設定に到達しました。

{
  "model": {
    "name": "qwen3-coder:30b"
  },
  "modelProviders": {
    "openai": [
      {
        "id": "qwen3-coder:30b",
        "name": "Qwen3-Coder 30B (Ollama)",
        "baseUrl": "http://localhost:11434/v1",
        "envKey": "OPENAI_API_KEY"
      },
      {
        "id": "qwen2.5-coder:14b",
        "name": "Qwen2.5-Coder 14B (Ollama)",
        "baseUrl": "http://localhost:11434/v1",
        "envKey": "OPENAI_API_KEY"
      },
      {
        "id": "qwen2.5-coder:7b",
        "name": "Qwen2.5-Coder 7B (Ollama)",
        "baseUrl": "http://localhost:11434/v1",
        "envKey": "OPENAI_API_KEY"
      }
    ]
  },
  "security": {
    "auth": {
      "selectedType": "openai",
      "apiKey": "EMPTY",
      "baseUrl": "http://localhost:11434/v1"
    }
  },
  "env": {
    "OPENAI_API_KEY": "EMPTY"
  }
}

設定のポイント

キー 正しい値 間違いやすい値
modelProviders authType をキーにした配列 providers は不正
security.auth.selectedType openai(AuthType enum 値) openai-compatible は不正
modelProviders[].envKey OPENAI_API_KEY(必須) 省略するとエラー
env.OPENAI_API_KEY EMPTY(Ollama はキー不要だがフィールドは必須) 省略するとエラー

ソースコードから読み解いた設定の優先順位

modelProvider > CLI引数 > 環境変数 > settings.json > デフォルト値

API キーの解決順序(packages/cli/src/utils/modelConfigUtils.ts):

argv.openaiApiKey > env[modelProvider.envKey] > OPENAI_API_KEY > settings.security.auth.apiKey

ステップ5: 起動と動作確認

エイリアスの設定

毎回 OPENAI_API_KEY=EMPTY を付けるのは面倒なので、.zshrc にエイリアスを追加しました。

# ~/.zshrc に追加
alias qwen-local='OPENAI_API_KEY=EMPTY qwen'

グローバルに OPENAI_API_KEY=EMPTY を設定すると、将来 OpenAI API を使う際に影響するため、エイリアス方式を選択しました。

動作確認

# ヘッドレスモード
qwen-local -p "Say hello in Japanese" --auth-type openai
# → こんにちは!

# コード生成
qwen-local -p "Pythonでフィボナッチ数列を返す関数を書いてください" --auth-type openai
# → 正常なPythonコードが生成される

日本語の指示理解、コード生成ともに問題なく動作しました。

ステップ6: 複雑なタスクでの限界 — ツール呼び出しの問題

PRレビューを依頼した結果

対話モードで以下を指示しました:

gh pr diff 8891 の内容を取得して、コードをレビューしてください

期待した動作: Qwen Code の shell ツールで gh pr diff 8891 を実行し、差分を取得してレビュー

実際の動作: モデルが XML テキストを出力

<function=run_shell_command>
<parameter=command>
gh pr diff 8891
</parameter>
<parameter=description>
Fetching the actual code changes from the pull request
</parameter>
</function>

モデルがツール呼び出し API を使わず、Claude のツール呼び出し形式をテキストとして模倣してしまいました。

原因の調査

Ollama の API レベルではツール呼び出しが正常に動作することを確認済みです:

# ネイティブ API(/api/chat)→ 正常
curl http://localhost:11434/api/chat -d '{
  "model": "qwen3-coder:30b",
  "tools": [{"type":"function","function":{"name":"calculator",...}}],
  ...
}'
# → tool_calls が正しく返る

# OpenAI 互換 API(/v1/chat/completions)→ 正常
curl http://localhost:11434/v1/chat/completions -d '{
  "model": "qwen3-coder:30b",
  "tools": [{"type":"function","function":{"name":"calculator",...}}],
  ...
}'
# → tool_calls が正しく返る

API レベルでは問題ないのに、Qwen Code 上では XML テキストが出力される。

根本原因

30B モデルの推論能力の限界です。

タスクの複雑度 30B ローカル Claude Code
単純なコード生成 正常にツール使用 正常
ファイル編集 正常にツール使用 正常
「PRを取得してレビュー」 ツール呼び出しに失敗(XML模倣) 正常
マルチステップの調査 困難 正常

単純なタスクではツール呼び出し API を正しく使えますが、「PRを取得 → diff を解析 → レビューコメントを生成」のようなマルチステップのエージェントタスクになると、30B モデルではツール呼び出しのチェーンを正確に制御できません。

Qwen Code と Claude Code — 実用上の比較

ベンチマーク(SWE-bench)

構成 スコア
Claude Sonnet 4 + Claude Code 70.4%
Qwen3-Coder + OpenHands(500ターン) 69.6%
Qwen3-Coder(標準) 67.0%

ベンチマークスコアは近いですが、実際のエージェントタスクでの体験は大きく異なります

実用比較

タスク Qwen Code(ローカル30B) Claude Code
関数の生成・編集 実用的 優秀
テスト作成 実用的 優秀
日本語での指示理解 良好 優秀
バグ修正 簡単なものは可能 複雑なものも対応
PR レビュー(gh連携) 不可(ツール呼び出し失敗) 正常動作
複数ファイルの横断調査 不安定 安定
MCP サーバー連携 未検証 安定

使い分けの指針

タスクの複雑度
  │
  ├── 単純(コード生成、ファイル編集、テスト作成)
  │     └── Qwen Code(ローカル)で十分
  │           メリット: 無料、プライバシー、オフライン対応
  │
  └── 複雑(PR レビュー、マルチステップ調査、大規模リファクタ)
        └── Claude Code を使用
              メリット: 高い推論能力、安定したツール呼び出し

まとめ

  • Mac Studio M3 Ultra(96GB)で Qwen Code + Ollama のローカル運用環境を構築: Fork → ローカルビルド → Ollama 接続まで約1時間で完了
  • settings.json の設定が最大のハードル: ドキュメントが不十分で、ソースコード(settingsSchema.ts、modelConfigResolver.ts)を読み解く必要があった。modelProvidersproviders ではない)、selectedType: "openai"openai-compatible ではない)、envKey 必須がポイント
  • 単純なコード生成は実用的: 日本語指示の理解、Python/TypeScript のコード生成は問題なく動作
  • 複雑なエージェントタスクは30Bモデルの限界: PR レビューのようなマルチステップタスクでは、ツール呼び出しに失敗しテキストで XML を模倣する現象が発生
  • API レベルではツール呼び出しは正常: Ollama の /v1 エンドポイントでの tool_calls は正しく動作しており、問題はモデルの推論能力
  • Claude Code との使い分けが現実的: 単純タスク(プライバシー重視)→ Qwen Code ローカル、複雑タスク → Claude Code

今後の検証予定

  • Qwen OAuth(クラウドの大規模モデル)での PR レビュー動作確認
  • MCP サーバー(GitHub)追加によるツール能力の補完
  • qwen3-coder の更新版での改善確認
  • Qwen-Agent フレームワークでのカスタムエージェント構築

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment