nikkie-ftnextの日記

イベントレポートや読書メモを発信

Agent Development Kitはsite-packages下にインストールしたエージェントもロードできるか?

はじめに

七尾百合子さん、お誕生日 85日目 おめでとうございます! nikkieです。

GoogleADKを使っていて「ADKで実装したエージェントを配布できないのかな」という疑問がむくむくと頭をもたげてきました。
そこで実験してみました。

目次

Agent Development Kitはディレクトリで指定したエージェントをロードする

ADKの実装を見ると、AgentLoaderディレクトリを指定して、その中のエージェントの実装をロードします。
先日どんなディレクトリ構造に対応しているか調べました。

当ブログではADKでエージェントを実装する記事をいくつか書いてきました。
ADKが指定するディレクトリ構造でファイルを作る中で思ったのです。「開発者がサンプルコードを手元にコピペしてるけど、配布してこの状況を打開できるんじゃない?」
配布とはpip installでエージェントを(仮想環境のsite-packages下に)インストールして、それを動かすということです。

「このアイデアが成立するのでは」という勝算がありました。
AgentLoaderの実装で、importlib.import_module()を使っているのです。
https://github.com/google/adk-python/blob/v1.2.1/src/google/adk/cli/utils/agent_loader.py#L53

module_candidate = importlib.import_module(agent_name)

Sphinxの拡張はimportlib.import_module()でsite-packages下からロードされます1
ADKでも同様なのでは?」と、ADKで実装したエージェントをインストールして実験します。

結論:adk api_serverに限れば、できる

adk v1.2.1時点での話です。

読みなよ... 俺の記事の続きを...

ADKで実装したエージェントをインストールし、adk api_server

コマンドの選択について

adk api_serveradk webはどちらもFastAPIアプリを起動します。
APIを直接呼べたほうが検証しやすいと考えて、adk api_serverを選びました。

adk runAgentLoaderを使っているのですが、adk run third_party_agentとsite-packages下のエージェントは指定できません。

Error: Invalid value for 'AGENT': Directory 'third_party_agent' does not exist.

これはclick.Path(exists=True)2で存在するディレクトリに限っている3ためです。
AgentLoaderにsite-packages下のエージェントが渡らないんですね(プルリクチャンスかも)

ADKで実装したエージェントをインストール可能にする

こちらに用意しています。
https://github.com/ftnext/agent-practice/tree/afdcd43e19980df8b4040da5dd72ab33120c01d9/packaging/adk_stop_loop_agent

adk_stop_loop_agent/
├── src/
│   └── adk_stop_loop_agent/
│       ├── __init__.py
│       └── agent.py  # root_agent を用意
└── pyproject.toml  # インストールするために用意

過去に作ったループを抜けるエージェント4を選択しました。
環境変数の指定不要で動かせるので、まず試しやすいのです。
元の実装との区別のために、ループを抜けるまでのカウントを変えています。

ADKの入っている仮想環境に(相対パス指定で)インストール

(.venv) % pip install ../packaging/adk_stop_loop_agent 

site-packagesの下にadk_stop_loop_agentが入りました。
pip list | grep adk_stop_loop_agentでも確認できます)

importもできます!

>>> import adk_stop_loop_agent

adk api_serverで立てたサーバに、site-packages下のエージェントを指定してリクエス

(.venv) % adk api_server

FastAPIなので、ドキュメントが http://127.0.0.1:8000/docs で見られます。

私はヘルスチェック代わりにアプリの一覧を取得します。
これはadk api_server起動したディレクトリにあるディレクトリ一覧です。
site-packages下のadk_stop_loop_agentは含まれません。

% curl http://127.0.0.1:8000/list-apps
["refine-loop","stop-loop"]

ここからの手順ですが

  1. Create Session (POST /apps/{app_name}/users/{user_id}/sessions)
  2. adk_stop_loop_agentをRun (POST /run)

となります。

Create Session

% curl -X POST http://127.0.0.1:8000/apps/adk_stop_loop_agent/users/nikkie/sessions | jq .

{
  "id": "085aef5e-908f-4c27-bb68-a1cdf12dbef5",
  "appName": "adk_stop_loop_agent",
  "userId": "nikkie",
  "state": {},
  "events": [],
  "lastUpdateTime": 1749467551.046664
}

Run

1のレスポンスの.idを使って2のリクエストを組み立てて

{
  "appName": "adk_stop_loop_agent",
  "userId": "nikkie",
  "sessionId": "085aef5e-908f-4c27-bb68-a1cdf12dbef5",
  "newMessage": {
    "parts": [
      {
        "text": "こんにちは"
      }
    ],
    "role": "user"
  },
  "streaming": false
}
% curl -H 'Content-Type: application/json' -d@packaging/adk_stop_loop_agent/run_request.json http://127.0.0.1:8000/run | jq .

[
  {
    "content": {
      "parts": [
        {
          "text": "Counter: 1"
        }
      ],
      "role": "model"
    },
    "invocationId": "e-102b7187-7776-4472-938c-0b82134bac61",
    "author": "counter_agent",
    "actions": {
      "stateDelta": {},
      "artifactDelta": {},
      "requestedAuthConfigs": {}
    },
    "id": "NdRCMC7U",
    "timestamp": 1749467751.870142
  },
  {
    "content": {
      "parts": [
        {
          "text": "Counter: 2"
        }
      ],
      "role": "model"
    },
    "invocationId": "e-102b7187-7776-4472-938c-0b82134bac61",
    "author": "counter_agent",
    "actions": {
      "stateDelta": {},
      "artifactDelta": {},
      "requestedAuthConfigs": {}
    },
    "id": "644EcPgG",
    "timestamp": 1749467751.870288
  },
  {
    "content": {
      "parts": [
        {
          "text": "Send STOP signal"
        }
      ],
      "role": "model"
    },
    "invocationId": "e-102b7187-7776-4472-938c-0b82134bac61",
    "author": "counter_agent",
    "actions": {
      "stateDelta": {},
      "artifactDelta": {},
      "escalate": true,
      "requestedAuthConfigs": {}
    },
    "id": "SovTGW8W",
    "timestamp": 1749467751.870328
  }
]

Counterが2で止まりました!
site-packages下にインストールしたADK実装のエージェントを、動かせています🙌

終わりに

ADKで実装したエージェントをsite-packages下にインストールし、それをadk api_serverで動かせるか実験しました。
エージェントをロードするAgentLoaderimportlib.import_module()を使っているため、site-packages下のエージェントもロードできます!
adk api_serveradk runadk web(後述)と比べてエージェント指定の検証ロジックが緩いため、site-packages下のエージェントを指定してリクエストを送ることができました

公式ドキュメントには今のところ記載がないですし、関係するissueやdiscussionは未調査ですが、ひとまず私はadk api_serverで使い倒そうと思っています。
PyPIに置いていくぞ〜

ちなみに、adk webも同様のFastAPIアプリケーションなので同じように動くかと期待しましたが、 http://127.0.0.1:8000/dev-ui/?app=adk_stop_loop_agent というURLをブラウザに直接入力したところ

Agent 'adk_stop_loop_agent' not found

と表示されて進めませんでした。