OpenHands（旧OpenDevin）の実装内容をみてみる

完全自律型AIであるDevinの発表が3月にあってから、AIエージェント関連の動向は一気に盛り上がったように思います。
そんな私もOpenHands（旧OpenDevin）の環境構築して、実際にWebアプリ実装してみたり、設計書やユーザマニュアルを書かせてみたりとファイルを作ってくれるので感動しました。
今回、本題の通りGithubにあるOpenHandsプロジェクトのソースコードを少し読みたいと思います。
特には各エージェントの動きやプロンプトの内容をざっくり見たいと思います。

### アーキテクチャ

公式ドキュメントで全体像が確認できます。
https://docs.all-hands.dev/modules/usage/architecture/backend
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472521/c109fcfd-094f-cba7-d6b1-402069bd8b79.png)

AgentHubを中心にAgentがLLMsに問い合わせしてるみたいです。

ちなみに、公式ドキュメントにクラス構成やランタイム環境の説明も図を交えて記述あるので、併せて読むと全体像をより理解できると思います。

### Agent
https://github.com/All-Hands-AI/OpenHands/tree/main/openhands/agenthub
Agentの概要ですが、
・AgentHubは複数Agentをまとめてオーケストレーションする役割がある
・各Agentは特定の指示（プロンプト）や役割を持ち、それぞれに対応する言語モデル（LLM）のチェーンを管理します。
・LLMへの問い合わせは各Agentが実行
・Agentは `Agent.register()` により登録・インスタンスに載る

https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/agenthub/__init__.py#L18-L24
```
__all__ = [
    'codeact_agent',
    'planner_agent',
    'delegator_agent',
    'dummy_agent',
    'browsing_agent',
]
```
これらのエージェントは__init__.pyで登録されています。
https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/agenthub/browsing_agent/__init__.py#L4
```
Agent.register('BrowsingAgent', BrowsingAgent)
```

#### Micro

Microフォルダ配下には最低限のAgent実装がされているようです。
OpenHands/openhands/agenthub/micro/registry.pyでは、
Mcroフォルダ配下のフォルダリストからAgentリストを作成してます。
Agentリストをインスタンスとして登録するのは、`OpenHands/openhands/agenthub/__init__.py` にて実行しています。

【manager】

https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/agenthub/micro/manager/prompt.md
managerフォルダのプロンプトにゴールからAgent役割やアウトプット形式を定義が入ってました。jinja2で展開するため、formatなど一部は別ファイルに展開されています。（詳細は実ファイルを閲覧ください）

```
# Task
You are in charge of accomplishing the following task:
{% set goal = latest_user_message if latest_user_message is not none else state.inputs.task %}
{{ goal }}

In order to accomplish this goal, you must delegate tasks to one or more agents, who
can do the actual work. A description of each agent is provided below. You MUST
select one of the delegates below to move towards accomplishing the task, and you MUST
provide the correct inputs for the delegate you select.

Note: the delegated agent either returns "finish" or "reject".
- If the action is "finish", but the full task is not done yet, you should
continue to delegate to one of the agents below to until the full task is finished.
- If the action is "reject", it means the delegated agent is not capable of the
task you send to. You should revisit the input you send to the delegate, and consider
whether any other delegate would be able to solve the task. If you cannot find
a proper delegate agent, or the delegate attempts keep failing, call the `reject`
action. In `reason` attribute, make sure you include your attempts (e.g. what agent
you have delegated to, and why they failed).

## Agents
{% for name, details in delegates.items() %}
### {{ name }}
{{ details.description }}
#### Inputs
{{ to_json(details.inputs) }}
{% endfor %}

((snip))
```

どんなプロンプトによって、タスク実行につなげているか知りたかったのでとても勉強になりました。
各エージェントフォルダの下にprompt.mdにプロンプト入っているので、そこで役割としてる内容は理解できそうです。

 ### End

各Agentの定義を理解することができました。想定より動作しているAgentが多く、もう少し時間かければAgent間の連動を理解できそうですが、その内容は次の投稿にしようと思います。