Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save hdknr/4103685108dfb6be44f9a0ec050655a7 to your computer and use it in GitHub Desktop.

Select an option

Save hdknr/4103685108dfb6be44f9a0ec050655a7 to your computer and use it in GitHub Desktop.

OpenHands × Ollama ローカルLLM実践記 — Mac Studio M3 Ultra で動かすまでの全記録

TL;DR: OpenHands(旧OpenDevin)をMac Studio M3 Ultra(96GB)+ Ollama + Qwen3-Coder 30B で動かそうとした。Docker-in-Docker のビルド問題、Playwright依存、ランタイムイメージ手動構築を経てUI起動まで到達したが、30Bモデルのtool calling精度不足で実用には至らなかった。


1. OpenHands とは

OpenHands(旧 OpenDevin)は、オープンソースのAIコーディングエージェントプラットフォーム。75以上のLLMプロバイダーに対応し、SWE-bench で Qwen3-Coder 使用時に 69.6% のスコアを記録している。

公式リポジトリ: https://github.com/All-Hands-AI/OpenHands

特徴:

  • Web UI でブラウザから操作
  • Docker サンドボックスで安全にコード実行
  • CodeActAgent による自律的なタスク遂行
  • Playwright 統合によるブラウザ操作

2. 動機 — なぜ OpenHands を試したか

前回の実験で Qwen Code(CLI エージェント)を Ollama + Qwen3-Coder 30B で動かしたが、複雑な multi-step タスク(GitHub PR レビューなど)で tool calling が破綻する問題に直面した。

OpenHands は SWE-bench で高スコアを出しており、エージェントスキャフォールディングの力で同じ 30B モデルでも改善されるのでは?という仮説を検証するために試した。

3. 環境

項目 スペック
マシン Mac Studio M3 Ultra
メモリ 96GB 統合メモリ
OS macOS (Darwin 25.3.0)
Docker Docker Desktop 28.5.2
Ollama ローカル稼働中
モデル qwen3-coder:30b (18GB)

4. セットアップ手順と遭遇した問題

4.1 Docker イメージの選定

# 最初に 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 は自前でビルドする方針に変更。

4.2 Docker-in-Docker ビルド失敗

OpenHands は初回起動時にサンドボックス用のランタイムイメージを コンテナ内から Docker buildx で自動ビルドする設計。しかし macOS Docker Desktop 環境ではこのビルドがゾンビプロセスになり停止。

[docker] <defunct>

--privileged フラグを付けても解決しなかった。

解決: ホスト側で手動ビルドし、環境変数 SANDBOX_RUNTIME_CONTAINER_IMAGE で指定する方式に変更。

4.3 ランタイムイメージの手動ビルド

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-glxlibgl1、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

4.4 ランタイムサーバーが起動しない

最初のビルドでは Playwright の依存ライブラリが不足しており、ブラウザ環境の初期化でクラッシュ → メインの Action Execution Server が起動しなかった。

Host system is missing dependencies to run browsers.

Playwright 依存ライブラリを追加して再ビルドし解決。

4.5 最終的な起動コマンド

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.40

4.6 LLM 設定

UIのドロップダウンにローカルモデルが表示されないため、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 を設定

5. 結果 — UI起動成功、しかし…

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 モデルが以下のいずれかの問題を起こしている:

  1. パラメータを省略する
  2. boolean 型(true/false)で返す(文字列の "true" ではなく)
  3. 不正な値を渡す

これは前回 Qwen Code で確認した「30B モデルは API レベルの tool calling はできるが、複雑なエージェントワークフローでのツールスキーマ遵守が不安定」という制限と同根の問題。

6. 教訓とまとめ

セットアップで学んだこと

問題 原因 解決策
runtime:main 互換性 micromamba → miniforge3 移行 バージョンタグを揃える
Docker-in-Docker ビルド失敗 macOS Docker Desktop の制限 ホスト側で手動ビルド
Debian パッケージ名変更 Trixie 移行 パッケージ名を修正
Playwright クラッシュ 依存ライブラリ不足 手動インストール
UI でモデル選択不可 litellm リスト固定 API 経由で設定注入

30B ローカルモデルの限界(再確認)

ツール 結果 失敗パターン
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
└──────────────────────┘

7. 参考リンク

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