はじめに
七尾百合子さん、お誕生日 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
.envfile.
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.18.0 から
- v1.22.0 から:常に環境変数が勝つ(
.envが上書きしない)テノヒラクルー
これはload_dotenv(override=True)という実装に起因します。
ADK ユーザの皆さま、お気をつけください