TL;DR: OpenHands(旧OpenDevin)をMac Studio M3 Ultra(96GB)+ Ollama + Qwen3-Coder 30B で動かそうとした。Docker-in-Docker のビルド問題、Playwright依存、ランタイムイメージ手動構築を経てUI起動まで到達したが、30Bモデルのtool calling精度不足で実用には至らなかった。
OpenHands(旧 OpenDevin)は、オープンソースのAIコーディングエージェントプラットフォーム。75以上のLLMプロバイダーに対応し、SWE-bench で Qwen3-Coder 使用時に 69.6% のスコアを記録している。
公式リポジトリ: https://github.com/All-Hands-AI/OpenHands
特徴:
- Web UI でブラウザから操作
- Docker サンドボックスで安全にコード実行
- CodeActAgent による自律的なタスク遂行
- Playwright 統合によるブラウザ操作
前回の実験で Qwen Code(CLI エージェント)を Ollama + Qwen3-Coder 30B で動かしたが、複雑な multi-step タスク(GitHub PR レビューなど)で tool calling が破綻する問題に直面した。
OpenHands は SWE-bench で高スコアを出しており、エージェントスキャフォールディングの力で同じ 30B モデルでも改善されるのでは?という仮説を検証するために試した。
| 項目 | スペック |
|---|---|
| マシン | Mac Studio M3 Ultra |
| メモリ | 96GB 統合メモリ |
| OS | macOS (Darwin 25.3.0) |
| Docker | Docker Desktop 28.5.2 |
| Ollama | ローカル稼働中 |
| モデル | qwen3-coder:30b (18GB) |
# 最初に main タグを試した
docker pull ghcr.io/all-hands-ai/openhands:main
docker pull ghcr.io/all-hands-ai/runtime:main問題1: runtime:main と openhands:main のバージョン不一致
openhands:main は /openhands/micromamba/bin/micromamba を期待するが、runtime:main は miniforge3 に移行済みだった。
exec: "/openhands/micromamba/bin/micromamba": stat: no such file or directory
解決: openhands:0.40(安定版タグ)に切り替え。runtime は自前でビルドする方針に変更。
OpenHands は初回起動時にサンドボックス用のランタイムイメージを コンテナ内から Docker buildx で自動ビルドする設計。しかし macOS Docker Desktop 環境ではこのビルドがゾンビプロセスになり停止。
[docker] <defunct>
--privileged フラグを付けても解決しなかった。
解決: ホスト側で手動ビルドし、環境変数 SANDBOX_RUNTIME_CONTAINER_IMAGE で指定する方式に変更。
OpenHands 0.40 のソースからテンプレート(Dockerfile.j2)を抽出し、手動で Dockerfile を作成。
# ソースコード抽出
CID=$(docker create ghcr.io/all-hands-ai/openhands:0.40)
docker cp "$CID:/app/openhands" ./code_openhands
docker cp "$CID:/app/pyproject.toml" ./pyproject.toml
docker cp "$CID:/app/poetry.lock" ./poetry.lock
docker rm "$CID"
# ビルド
docker build -t ghcr.io/all-hands-ai/runtime:oh_v0.40.0_local .問題2: Debian Trixie パッケージ名変更
nikolaik/python-nodejs ベースイメージが Debian Trixie に更新されており、パッケージ名が変わっていた。
E: Package 'libgl1-mesa-glx' has no installation candidate
E: Package 'ttf-unifont' has no installation candidate
解決: libgl1-mesa-glx → libgl1、Playwright の --with-deps を手動インストールに変更。
RUN apt-get install -y --no-install-recommends \
libnss3 libnspr4 libatk1.0-0 libatspi2.0-0 \
libxcomposite1 libxdamage1 libxrandr2 libxkbcommon0 \
libgbm1 libpango-1.0-0 libcairo2 libasound2 fonts-unifont最初のビルドでは Playwright の依存ライブラリが不足しており、ブラウザ環境の初期化でクラッシュ → メインの Action Execution Server が起動しなかった。
Host system is missing dependencies to run browsers.
Playwright 依存ライブラリを追加して再ビルドし解決。
docker run -d \
--name openhands \
--privileged \
-p 3000:3000 \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:oh_v0.40.0_local \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands:/root/.openhands \
ghcr.io/all-hands-ai/openhands:0.40UIのドロップダウンにローカルモデルが表示されないため、API 経由で設定を注入。
curl -s -X POST http://localhost:3000/api/settings \
-H "Content-Type: application/json" \
-d '{
"llm_model": "ollama/qwen3-coder:30b",
"llm_api_key": "EMPTY",
"llm_base_url": "http://host.docker.internal:11434",
"agent": "CodeActAgent",
"max_iterations": 50,
"sandbox_runtime_container_image": "ghcr.io/all-hands-ai/runtime:oh_v0.40.0_local"
}'ポイント:
- モデル名は
ollama/qwen3-coder:30b(litellm のプレフィックス規則) - Base URL は
host.docker.internal(Docker → ホストのOllama接続) - API Key は空文字不可のため
EMPTYを設定
Web UI(http://localhost:3000)の起動、ランタイムサンドボックスの起動まで到達。チャット入力も可能になった。
しかし、実際にタスクを実行すると:
Agent encountered an error.
Parameter 'is_input' is expected to be one of ['true', 'false'].
原因: OpenHands の execute_bash ツールは is_input パラメータに文字列の "true" / "false" を期待する。30B モデルが以下のいずれかの問題を起こしている:
- パラメータを省略する
- boolean 型(
true/false)で返す(文字列の"true"ではなく) - 不正な値を渡す
これは前回 Qwen Code で確認した「30B モデルは API レベルの tool calling はできるが、複雑なエージェントワークフローでのツールスキーマ遵守が不安定」という制限と同根の問題。
| 問題 | 原因 | 解決策 |
|---|---|---|
| runtime:main 互換性 | micromamba → miniforge3 移行 | バージョンタグを揃える |
| Docker-in-Docker ビルド失敗 | macOS Docker Desktop の制限 | ホスト側で手動ビルド |
| Debian パッケージ名変更 | Trixie 移行 | パッケージ名を修正 |
| Playwright クラッシュ | 依存ライブラリ不足 | 手動インストール |
| UI でモデル選択不可 | litellm リスト固定 | API 経由で設定注入 |
| ツール | 結果 | 失敗パターン |
|---|---|---|
| Qwen Code | 複雑タスクで失敗 | XML テキスト出力(tool_calls API 未使用) |
| OpenHands | エージェントエラー | is_input パラメータのスキーマ違反 |
結論: OpenHands のエージェントスキャフォールディングは優秀だが、モデルの tool calling 精度が十分でなければスキャフォールディングでは救えない。30B ローカルモデルでは:
- 簡単な単発タスク → Qwen Code で実用可能
- 複雑なマルチステップタスク → Claude Code(クラウド API)が必要
- OpenHands → クラウド API(Claude / GPT-4 / Qwen OAuth)と組み合わせれば真価を発揮
┌──────────────────────┐
│ タスクの複雑さ │
├──────────────────────┤
│ 簡単(ファイル編集) │ → Qwen Code + Ollama ローカル
│ 中程度(実装) │ → Claude Code
│ 複雑(PR レビュー) │ → Claude Code / OpenHands + クラウドAPI
└──────────────────────┘