ローカル環境でOpenHandsを立ち上げるまで

# はじめに

本記事は手元の使用していないPCを有効活用するために、ローカル環境でAIエージェントのOpenHandsを動作させるまでの手順について解説しています。あくまで備忘録程度のものなので、他の環境下での動作を保証できるものではないです。
もともとは以下の記事を参考に環境を構築していたのですが、色々とうまくいかない部分があったので記事として残しておくことにしました。

https://bwgift.hatenadiary.jp/entry/2025/02/24/233957

# OpenHandsとは

OpenHandsの概要については以下の記事で説明されています。

https://qiita.com/k-kanno/items/b15760ef33d288ac845b

概要を説明すると、ソフトウェア開発を支援するためのAIエージェントで、コードの作成から実行、テストまで行うことができます。AIスタートアップのCognitionが2024年3月に発表したDevinというサービスを参考に作られており、DevinのOSSクローンのような立ち位置となっています。
Devinでは月額500ドルの費用がかかるのに対して、OpenHandsをローカル環境上で立ち上げることによって比較的安価に導入することが可能です（自分でソフトウェアアップデートしたりハードウェアを管理したりする手間は発生しますが…）

# 環境構築

環境構築方法として、手軽に環境を破棄できるDocker環境で実行しようと思います。
コンテナとして、OpenHands本体とOpenHandsが利用するローカルLLMの2つのコンテナを立ち上げる必要があります。
今回、ローカルLLMの実行にはOllamaというツールを使用しています。
2つのコンテナを同時に扱うため、docker-composeを用いて2つのコンテナの設定を記述します。
設定ファイル（docker-compose.yaml）の内容は以下のとおりです。

:::note info
ollamaが外部のネットワークからLLMをダウンロードできるように、network_mode: hostとする必要がありました。セキュリティの問題でホストのネットワークと紐付けるのが難しい場合には、使用しているポートを調べて必要なもののみをportsに記載したり、共通のvolumeを使用してダウンロードだけを別のコンテナで実行するなどの対策を実施してください。
:::

```yaml:docker-compose.yaml
version: "3.9"

services:
  openhands-app:
    image: docker.all-hands.dev/all-hands-ai/openhands:0.26
    container_name: openhands-app
    environment:
      SANDBOX_RUNTIME_CONTAINER_IMAGE: "docker.all-hands.dev/all-hands-ai/runtime:0.26-nikolaik"
      LOG_ALL_EVENTS: "true"
      LLM_API_KEY: "ollama"
      LLM_BASE_URL: http://host.docker.internal:11434
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ~/.openhands-state:/.openhands-state
    ports:
      - "3000:3000"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    stdin_open: true
    tty: true
    pull_policy: always

  ollama:
    image: ollama/ollama
    container_name: ollama
    network_mode: host      # --network=host と同等
    gpus: all               # --gpus=all と同等
    volumes:
      - ollama:/root/.ollama  # 名前付きボリューム "ollama" を /root/.ollama にマウント
    ports:
      - "11434:11434"       # host ネットワークの場合、通常ポート指定は不要ですが記述例として
    restart: unless-stopped

volumes:
  ollama:
```

本設定ファイルを適当なディレクトリに格納し、格納したディレクトリで以下のコマンドを実行することで、コンテナを立ち上げることができます。

```bash
docker compose up -d
```

Dockerイメージが取得でき、コンテナが起動したことを確認したら、以下のURLにアクセスしてOpenHandsとOllamaがそれぞれ正しく起動していることを確認してください。
```http
localhost:3000
```
![Screenshot from 2025-02-27 00-37-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/d0861d4e-48a4-49d5-b93f-6caa2234290a.png)


```http
localhost:11434
```
![Screenshot from 2025-02-27 00-28-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/10ac2a7d-7c83-483b-8a0c-82a1ce80e0ae.png)

# 初期設定

通常のOpenHandsではLLM Providerとしてクラウドを使用するようになっており、ローカルLLMのURLにリクエストを送るには以下の手順を実行する必要があります。

1. 初期設定画面で"see advanced settings"のリンクをクリックする
   ![Screenshot from 2025-02-27 00-37-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/d0861d4e-48a4-49d5-b93f-6caa2234290a.png)

2. 設定画面でLLM Settings横のラジオボタンからAdvanced設定に変更する
   ![Screenshot from 2025-02-27 00-41-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/5e94e06d-14d8-4c8f-9cc2-e5cc8fcc10c6.png)

3. Advanced設定の各項目を以下のように設定する

   Custom Model: ollama/deepseek-r1:8b (お好みのモデルに設定する)
   Base URL: http://host.docker.internal:11434
   API Key: dummy (適当な文字列で良い、何もないと実行時にエラーが生じる)

   ![Screenshot from 2025-02-27 00-43-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/bf77817b-4648-461c-8d64-18cf47342970.png)

4. "Save Changes"をクリックして保存する

5. ~/.openhands-state/settings.jsonを開き、設定が正しく保存されていることを確認する

   参考：
   ```json
      {"language":"en","agent":"CodeActAgent","max_iterations":null,"security_analyzer":"","confirmation_mode":false,"llm_model":"ollama/deepseek-r1:8b","llm_api_key":"dummy","llm_base_url":"http://host.docker.internal:11434","remote_runtime_resource_factor":1,"github_token":null,"enable_default_condenser":true,"user_consents_to_analytics":false}
   ```

   :::note info
   私の場合、Custom Model(jsonファイルではllm_model)の設定が正しく反映されなかったので、管理者権限でファイルを開いて直接変更しました。
   :::

6. 以下のコマンドで使用するLLMをダウンロードしておく

   ```bash
   docker exec -it ollama ollama pull deepseek-r1:8b
   ```

   :::note info
   私の場合、自動でダウンロードが走らなかったので、上記の手順が必要でした。
   :::

# 実行確認

画面左上の丸で囲われた＋マークをクリックして、プロジェクト作成画面に遷移します。
![Screenshot from 2025-02-27 00-27-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/f4afc457-8f07-4d1d-9925-eec171c65fe5.png)

画面真ん中付近の入力欄にOpenHandsにやらせたいことを記載してエンターキーを押します。
（今回は"Write python hello world"としました。）

しばらく待って画面左側のチャット欄でOpenHandsが回答を返してくれれば成功です（返答はちょっと的はずれな感じですが…）。
![Screenshot from 2025-02-27 00-59-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326389/e94a98c8-5602-4bd5-a112-6607bde9fcd2.png)

# まとめ

今回はローカル環境でAIエージェントであるOpenHandsを設定する方法について解説しました。PCのスペックによっては更に大きなモデルを用いて、より高度な仕事を任せることもできそうなので普段利用されていないPCを使った人手不足解消手段として活用していきたいと思います。
今回はGUIの設定が反映されないといったハマりポイントがあったので、もし同じようにローカル環境でOpenHandsを活用しようとしている方の参考になれば幸いです。