概述
最近在看一个开源项目 cognee ,其中有很多下面类似的pydantic配置文件,由于对 pydantic 没有深入了解,所以对 pydantic 中的 BaseSettings 的作用不是很了解。为了更清楚的了解 BaseSettings 的使用,通过查阅资料,本文记录一下其如何使用和配置。
python
class EmbeddingConfig(BaseSettings):
"""
Manage configuration settings for embedding operations, including provider, model
details, API configuration, and tokenizer settings.
Public methods:
- to_dict: Serialize the configuration settings to a dictionary.
"""
embedding_provider: Optional[str] = "openai"
embedding_model: Optional[str] = "openai/text-embedding-3-large"
embedding_dimensions: Optional[int] = 3072
embedding_endpoint: Optional[str] = None
embedding_api_key: Optional[str] = None
embedding_api_version: Optional[str] = None
embedding_max_tokens: Optional[int] = 8191
huggingface_tokenizer: Optional[str] = None
model_config = SettingsConfigDict(env_file=".env", extra="allow") # 从环境变量或.env文件中填充模型的字段
pydantic 中的 BaseSettings 介绍
在Pydantic库中,BaseSettings是一个特殊的基类,用于定义配置管理模型。它扩展了Pydantic的BaseModel,专门用于处理应用程序的设置或配置,这些配置通常来自多个来源(如环境变量、配置文件、秘密管理等)。使用BaseSettings可以方便地管理和验证应用程序的配置。
主要作用:
- 多来源配置加载 :
BaseSettings可以从多个来源加载配置,包括:
-
环境变量(默认)
-
环境文件(如
.env文件) -
初始化时传入的字典或关键字参数
-
其他自定义来源(通过重写类方法实现)
-
自动类型转换和验证 :和
BaseModel一样,BaseSettings会对配置值进行类型转换和验证,确保配置项符合声明的类型和约束。 -
环境变量优先 :默认情况下,
BaseSettings会优先从环境变量中读取配置,然后才是初始化参数或环境文件。这样便于在部署时通过环境变量覆盖配置。 -
敏感信息管理:支持从秘密管理服务(如Docker Secrets、Kubernetes Secrets)加载敏感数据。
使用示例:
下面是一个简单的BaseSettings使用示例:
python
from pydantic_settings import BaseSettings, SettingsConfigDict
class AppSettings(BaseSettings):
app_name: str = "My App"
host: str = "localhost"
port: int = 8000
debug: bool = False
model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_")
在这个例子中:
-
配置类
AppSettings继承自BaseSettings。 -
定义了四个配置项,并提供了默认值。
-
通过
model_config指定了环境文件为.env,并且环境变量前缀为APP_。
加载顺序:
当创建AppSettings实例时,配置的加载顺序如下(从高优先级到低优先级):
-
初始化参数(如
AppSettings(port=8080)) -
环境变量(如
APP_PORT) -
环境文件(如
.env文件中的APP_PORT) -
类中字段的默认值
环境变量命名规则:
默认情况下,环境变量名由以下方式生成:
-
将字段名转换为大写
-
如果指定了
env_prefix,则添加前缀 -
嵌套模型的环境变量名使用双下号
__分隔(由env_nested_delimiter配置,默认是双下划线)
例如,对于字段database_port,如果env_prefix设置为MYAPP_,则环境变量名为MYAPP_DATABASE_PORT。
与普通BaseModel的区别:
| 特性 | BaseModel |
BaseSettings |
|---|---|---|
| 主要用途 | 数据验证和解析 | 应用程序配置管理 |
| 配置加载来源 | 仅初始化参数 | 环境变量、文件、初始化参数等 |
| 环境变量支持 | 无 | 有(默认) |
| 环境文件支持 | 无 | 有(通过配置) |
| 敏感信息管理 | 无 | 有(通过secrets配置) |
高级用法:
-
自定义来源 :通过重写
customise_sources类方法,可以自定义配置加载的来源和顺序。 -
嵌套模型 :支持嵌套模型,环境变量可以通过分隔符(如
__)来设置嵌套字段。 -
秘密管理 :通过
secrets_dir指定目录,从文件中读取敏感信息(如SettingsConfigDict(secrets_dir="/run/secrets"))。
Pydantic 的 SettingsConfigDict 配置作用解析
在Pydantic中,SettingsConfigDict 是一个用于配置模型行为的类,特别是在处理设置(通常来自环境变量或.env文件)时。它替代了旧版本Pydantic(v1)中的Config内部类。
在前面提供的代码中,EmbeddingConfig类继承自BaseSettings(在pydantic_settings模块中)。 在这个类中,有一个类属性model_config,它被赋值为SettingsConfigDict的一个实例(在代码中是直接赋值,但通常我们会看到它被赋值为一个字典或一个SettingsConfigDict对象)。 这里,SettingsConfigDict的作用是配置EmbeddingConfig类的行为。具体来说:
-
env_file=".env":指定从名为.env的文件中读取环境变量。这意味着Pydantic在加载设置时会读取项目根目录下的.env文件(如果存在的话),并将文件中的变量加载到环境变量中,然后这些环境变量会被用来填充模型的字段。例如:如果.env中有EMBEDDING_API_KEY=sk-xxx,会自动赋值给embedding_api_key字段 -
extra="allow":这个配置表示,如果模型在初始化时遇到了不在模型定义中的额外字段(extra fields),那么允许这些字段存在,并且将它们存储在模型的__pydantic_extra__属性中(而不是引发验证错误)。默认情况下,Pydantic模型会拒绝额外字段(即extra="forbid")。
总结一下,SettingsConfigDict在这里的作用是配置EmbeddingConfig类如何从环境变量(包括从.env文件加载)中获取设置,并且允许模型接受并存储额外的配置项(这些额外配置项虽然不会被用于模型定义的字段,但会被保留,可以通过 model_instance.__pydantic_extra__ 访问)。
注意:在旧版Pydantic(v1)中,我们通常使用内部类Config来设置这些配置,例如:
python
class Config:
env_file = ".env"
extra = "allow"
而在Pydantic v2中,推荐使用model_config属性并赋值为SettingsConfigDict的实例(或者也可以直接赋值为一个字典,因为SettingsConfigDict本质上是一个字典的子类)。所以,这里使用的是Pydantic v2的方式。
另外,由于EmbeddingConfig继承自BaseSettings,它也会自动从环境变量中读取匹配的字段(不区分大小写,但通常使用大写)。例如,embedding_provider字段会尝试从环境变量EMBEDDING_PROVIDER中读取值。
所以,这个配置使得EmbeddingConfig类可以从.env文件中加载环境变量,并且允许在初始化时传入额外的配置项。
完整功能说明:
| 配置项 | 作用 | 示例值 |
|---|---|---|
env_file |
从指定文件加载环境变量 | ".env", [".env", ".prod"] |
extra |
处理未定义字段的策略 | "allow", "ignore", "forbid" |
env_prefix |
环境变量前缀(自动添加) | "APP_" → 读取 APP_API_KEY |
case_sensitive |
环境变量名是否区分大小写 | False (默认不区分) |
env_nested_delimiter |
嵌套环境变量分隔符(如 DB__HOST → db.host) |
"__" |
典型使用场景:
python
# .env 文件内容示例
EMBEDDING_PROVIDER=huggingface
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
UNEXPECTED_SETTING=123 # 会被保留到 __pydantic_extra__
python
# 使用配置
config = EmbeddingConfig() # 自动加载 .env 中的设置
print(config.embedding_provider) # 输出: "huggingface"
print(config.__pydantic_extra__) # 输出: {"unexpected_setting": 123}
注意事项:
-
优先级顺序 :
手动传入参数 > 环境变量 >
.env文件变量 > 类默认值 -
安全建议 :
敏感字段(如 API keys)应通过环境变量传递,避免硬编码在代码或
.env文件中 -
Pydantic 版本:
- v1 使用内部
Config类 - v2 开始使用
model_config = SettingsConfigDict(...)风格
- v1 使用内部
通过这种配置,Pydantic 实现了灵活的环境感知设置加载,非常适合需要多环境部署的应用(开发/测试/生产)。
代码演示
python
from pydantic_settings import BaseSettings, SettingsConfigDict
import os
class AppSettings(BaseSettings):
app_name: str = "My App"
host: str = "localhost"
port: int = 8000
debug: bool = False
model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_")
# 当创建`AppSettings`实例时,配置的加载顺序如下(从高优先级到低优先级):
print(f'默认参数 AppSettings() =====> {AppSettings()}')
# 1. 初始化参数(如`AppSettings(port=8080)`)
print(f'指定初始化参数 AppSettings(port=8080) =====> {AppSettings(port=8080)}')
# 2. 环境变量(如`APP_PORT`)
os.environ['APP_PORT'] = "8888"
print(f'设置环境变量os.environ["APP_PORT"] = "8888",AppSettings() =====> {AppSettings()}')
print(f'设置环境变量os.environ["APP_PORT"] = "8888",AppSettings(port=8080) =====> {AppSettings(port=8080)}')
ini
默认参数 AppSettings() =====> app_name='My App' host='localhost' port=1 debug=False
指定初始化参数 AppSettings(port=8080) =====> app_name='My App' host='localhost' port=8080 debug=False
设置环境变量os.environ["APP_PORT"] = "8888",AppSettings() =====> app_name='My App' host='localhost' port=8888 debug=False
设置环境变量os.environ["APP_PORT"] = "8888",AppSettings(port=8080) =====> app_name='My App' host='localhost' port=8080 debug=False
最佳实践:
-
为敏感字段不设置默认值,强制从环境获取
-
使用
env_prefix避免环境变量命名冲突 -
生产环境使用
secrets_dir代替.env文件pythonmodel_config = SettingsConfigDict( secrets_dir="/run/secrets", env_prefix="DB_" )
总结:
BaseSettings是Pydantic中用于管理应用程序配置的强大工具,它简化了从不同来源加载和验证配置的过程,特别是在云原生和容器化环境中,环境变量是配置的主要来源时非常有用,特别适合需要遵循 12-Factor App 原则的应用程序。