nikkie-ftnextの日記

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

Agent Development Kit (Python) で agent のパッケージに置く .env を「システムの環境変数より優先する」から「しない」へ挙動が変わりました

はじめに

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

ADK のソースを読んでたまげた.envの扱いについてです

目次

ADK では agent のパッケージに .env を置く方法が案内される

Python Quickstart for ADK」より、adk create.envも配置されます。
https://google.github.io/adk-docs/get-started/python/#explore-the-agent-project

my_agent/
├── agent.py
├── .env        # この記事はこのファイルについてです
└── __init__.py

.envには Gemini API にリクエストするための情報が書かれます。
このドキュメントは、ADK が依存する google-genai SDK 側にあります。
https://googleapis.github.io/python-genai/#create-a-client

Gemini Developer API: Set the GEMINI_API_KEY or GOOGLE_API_KEY.

Gemini API on Vertex AI: Set GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION.

/runへのリクエストなど)エージェントを実行するタイミングで、この.envは読み込まれます。
一例:https://github.com/google/adk-python/blob/v1.23.0/src/google/adk/cli/adk_web_server.py#L513

class AdkWebServer:
  async def get_runner_async(self, app_name: str) -> Runner:
    # 省略

    # Create new runner
    envs.load_dotenv_for_agent(os.path.basename(app_name), self.agents_dir)
    agent_or_app = self.agent_loader.load_agent(app_name)

    # 省略

私の意見として、.envリポジトリにコミットしたくないです。
API キーを書いた.envのコミットはもってのほかですし、Vertex AI を使う場合であってもあまり好みません。
なので.envを使わずに環境変数での設定を優先してきたのですが、トリッキーな挙動を踏んでおり、やむなく環境変数.envを併用する場合がありました1

.envと同名の環境変数の扱い

v1.17.0 まで:.envが最強

例えばGOOGLE_CLOUD_LOCATION環境変数にも.envにもある場合、エージェント実行時は.envが勝ちます

これはpython-dotenvを使って、load_dotenv(override=True)しているからです2
https://github.com/google/adk-python/blob/v1.17.0/src/google/adk/cli/utils/envs.py#L46

def load_dotenv_for_agent(
    agent_name: str, agent_parent_folder: str, filename: str = '.env'
):
  # 省略
  load_dotenv(dotenv_file_path, override=True, verbose=True)
  # 省略

https://saurabh-kumar.com/python-dotenv/reference/#dotenv.load_dotenv

Whether to override the system environment variables with the variables from the .env file.

ADK ではエージェントを実行する際、.envの値で環境変数を上書きします。
開発者が環境変数で設定した値にならないというのは、予測しづらいですよね

v1.18.0:ADK_DISABLE_LOAD_DOTENV導入

Add ADK_DISABLE_LOAD_DOTENV environment variable that disables automatic loading of .env when running ADK cli, if set to true or 1

(v1.18.0 以降の)v1.22.0 の実装です。
https://github.com/google/adk-python/blob/v1.22.0/src/google/adk/cli/utils/envs.py#L53

def load_dotenv_for_agent(
    agent_name: str, agent_parent_folder: str, filename: str = '.env'
):
  if is_env_enabled(_ADK_DISABLE_LOAD_DOTENV_ENV_VAR):
    return
  # 省略

そもそもload_dotenv(override=True)がまずいのに、それを維持しようとして新たな環境変数を導入するというのは、根本原因に向き合っていないように私には映ってしまいます。

v1.22.0:環境変数.envで上書きしない

Prevent .env files from overriding existing environment variables

しれっと動きが変わっていて既存コードが想定通り動かず、つまづきました。(マイナーバージョンアップとは...)

load_dotenv(override=True)は変更せずに、環境変数を保持しています。
https://github.com/google/adk-python/blob/v1.22.0/src/google/adk/cli/utils/envs.py#L76-L82

explicit_env_keys = _get_explicit_env_keys()
explicit_env = {
    key: os.environ[key] for key in explicit_env_keys if key in os.environ
}
load_dotenv(dotenv_file_path, override=True, verbose=True)
os.environ.update(explicit_env)

この記事にまとめたことで次に考えてみたいと思っているのは、load_dotenv(override=False)で全て解決しないのかという点です。
.envについての ADK の振る舞いが v1.22.0 で180度変わっていると思うのですが、コードを減らして実現できそうなところを、コードを書いて対応したことでかえって複雑にしているように映っています

終わりに

ADK でエージェントを動かす際、システムの環境変数.envとで同名の変数がある場合の動きが変遷しています。

  • v1.21.0 まで:常に.envが上書きして勝つ
    • v1.18.0 からADK_DISABLE_LOAD_DOTENV導入(環境変数が勝つようにできる)
  • v1.22.0 から:常に環境変数が勝つ(.envが上書きしない)テノヒラクルー

これはload_dotenv(override=True)という実装に起因します。
ADK ユーザの皆さま、お気をつけください


  1. どんな課題に直面して併用したのかは別の記事にしようと思います
  2. デフォルト値はFalseなので、環境変数の値のままです(.envで上書きはされません)