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) |
調査・改造を前提に、まず 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 で自由に作業する構成です。
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."正常にコードが生成されることを確認しました。
cd ~/Projects/qwen/qwen-code
# 依存関係インストール
make install
# ビルド
make buildmake 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 で解決しました。
ここが最も苦労した部分です。Qwen Code の設定ファイル形式はドキュメントが不十分で、ソースコードを読んで正しい形式を特定する必要がありました。
{
"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。
{
"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 が外部プロセスによって削除される現象も発生。
ヘッドレスモードで --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.ts、packages/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
毎回 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コードが生成される日本語の指示理解、コード生成ともに問題なく動作しました。
対話モードで以下を指示しました:
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 モデルではツール呼び出しのチェーンを正確に制御できません。
| 構成 | スコア |
|---|---|
| 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)を読み解く必要があった。
modelProviders(providersではない)、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 フレームワークでのカスタムエージェント構築