はじめに
LLMを活用したエージェントシステムをチームで開発していると、OpenAI・Anthropic・Tavilyなど複数サービスのAPIキーを扱う場面が増えてきます。
このとき、以下のような課題に直面しました。
- メンバーごとに異なるAPIキーをどう管理するか
- 誤ってAPIキーをリポジトリにコミットしないようにするには?
- 検証環境と本番環境でキーを切り替えるとき、コードを変えずに済む方法は?
調べていく中で pydantic-settings の BaseSettings がこれらをまとめて解決できることがわかりました。
本記事ではその仕組みと、チーム開発における典型的な運用パターンをまとめます。
BaseSettings とは
pydantic-settings が提供する BaseSettings は、Pydantic の BaseModel を拡張したクラスです。
通常の BaseModel との最大の違いは、フィールドの値を環境変数や .env ファイルから自動で読み込む点です。
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
)
OPENAI_API_KEY: str
ANTHROPIC_API_KEY: str = ""
temperature: float = 0.0
Settings() をインスタンス化するだけで、環境変数や .env ファイルから値が自動的にバインドされます。
SettingsConfigDict とは
SettingsConfigDict は model_config に渡す設定の型安全なラッパーです。
単なる dict でも動作しますが、SettingsConfigDict を使うことで補完・型チェックが効くようになります。
主要なオプションは以下の通りです。
| オプション | 説明 |
|---|---|
env_file |
読み込む .env ファイルのパス |
env_file_encoding |
.env ファイルの文字コード |
env_prefix |
環境変数名に付与するプレフィックス |
case_sensitive |
環境変数名の大文字小文字を区別するか(デフォルト: False) |
env_nested_delimiter |
ネストされたモデルを示す区切り文字 |
値の優先順位
デフォルト値・.env ファイル・環境変数の3つが全て設定されている場合、優先順位は以下の通りです。
環境変数 (export) > .env ファイル > デフォルト値
Pydantic 公式ドキュメントにも明記されています。
"environment variables will always take priority over values loaded from a dotenv file"
具体例で確認する
以下の状況を想定します。
-
export API_KEY_C=env-keyが実行済み -
.envにAPI_KEY_D=dotenv-key、API_KEY_E=dotenv-keyが定義済み -
export API_KEY_E=env-keyが実行済み
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
)
API_KEY_A: str # ValidationError(値のソースが存在しない)
API_KEY_B: str = "default_b" # "default_b"(他のソースなし)が設定される
API_KEY_C: str = "default_c" # "env-key"(環境変数が最優先)が設定される
API_KEY_D: str = "default_d" # "dotenv-key"(.envがデフォルト値より優先)が設定される
API_KEY_E: str = "default_e" # "env-key"(環境変数が.envより優先)が設定される
API_KEY_A のエラーはクラス定義時ではなく、インスタンス化時(Settings())に ValidationError として発生します。
The Twelve-Factor App との関連
この設計は The Twelve-Factor App の第3原則「設定を環境変数に格納する」に沿っています。
"アプリケーションの設定はコードとは厳密に分離して管理する。設定はデプロイ(ステージング、本番、開発など)ごとに異なるが、コードは異なるべきではない。"
BaseSettings はこの原則を Python で実現するための実践的なツールといえます。
典型的な運用例
BaseSettings の優先順位を活かすと、コード変更なしに環境を切り替えられます。
開発・検証環境
.env ファイルをプロジェクトルートに置き、.gitignore で管理対象外にします。
# .env(リポジトリに含めない)
OPENAI_API_KEY=sk-xxxx-for-dev
DATABASE_URL=postgresql://localhost/mydb_dev
本番環境
Cloud Run / Kubernetes / Heroku 等のプラットフォーム側で環境変数を注入します。
.env ファイルは存在しなくてもよく、環境変数が自動的に最優先で使われます。
# Cloud Run の例
gcloud run deploy myapp \
--set-env-vars OPENAI_API_KEY=sk-xxxx-for-prod
環境変数が設定されていれば .env の値を上書きし、なければ .env にフォールバックする——この仕組みにより、同じコードをそのまま全環境にデプロイできます。
まとめ
os.environ.get() 直書き |
BaseSettings |
|
|---|---|---|
| 型安全 | × | ✓ |
| 必須チェック | 手動 | 自動(ValidationError) |
| .env 対応 | ライブラリ別途必要 | 組み込み |
| 優先順位管理 | 手動 | 自動 |
設定管理を BaseSettings に集約することで、型安全性・可読性・デプロイの柔軟性を同時に得られることがわかりました。
検証環境は.envファイルで、本番環境では環境変数で設定することで、検証環境と本番環境で設定を書き換えることなく、スムーズに移行ができるので便利ですね。
検証環境での.envファイルの運用方法としては、GitHubでは.env.exampleで環境変数のフィールドだけを定義したものを共通管理し、メンバー各自の環境に.envファイルにコピーしAPIキーを書き込むような運用ができます。