# 配置管理系统说明 ## 概述 本项目采用分层配置管理系统,支持环境变量和配置文件两种方式,实现敏感信息与应用配置的分离。 ## 配置文件结构 ``` autool/ ├── .env # 环境变量配置(敏感信息,不提交) ├── .env.example # 环境变量配置模板(提交到版本库) ├── config/ │ ├── current_env.txt # 当前环境标识(prod/test) │ ├── prod.yaml # 生产环境配置 │ ├── test.yaml # 测试环境配置 │ ├── local.yaml # 本地覆盖配置(不提交) │ └── local.yaml.example # 本地配置示例 ├── config_loader.py # 配置文件加载模块 ├── env_loader.py # 环境变量加载模块 └── config_usage_examples.py # 使用示例 ``` ## 配置优先级 配置加载的优先级从高到低为: 1. **环境变量**(`.env` 文件或系统环境变量) 2. **本地配置**(`config/local.yaml` 或 `config/local.json`) 3. **环境配置**(`config/prod.yaml` 或 `config/test.yaml`) ## 快速开始 ### 1. 配置环境变量(敏感信息) ```bash # 复制模板文件 cp .env.example .env # 编辑 .env 文件,填入实际的 API 密钥 vim .env ``` `.env` 文件示例: ```bash # AI 服务 API 密钥 GEMINI_API_KEY=your_actual_gemini_api_key_here AZURE_API_KEY=your_actual_azure_api_key_here QWEN_API_KEY=sk-your_actual_qwen_api_key_here GLM_API_KEY=your_actual_glm_api_key_here # 通知服务 Token WECHAT_TOKEN_YFZ=your_actual_wechat_token_here WECOM_TOKEN_TEAM1=your_actual_wecom_token_here # 系统认证 IOS_PASSWORD=your_ios_device_password_here ``` ### 2. 配置本地开发环境(可选) 如果需要覆盖环境配置(如修改路径、调试参数等),可创建本地配置文件: ```bash # 复制本地配置模板 cp config/local.yaml.example config/local.yaml # 编辑本地配置 vim config/local.yaml ``` `config/local.yaml` 示例: ```yaml # 本地开发配置覆盖 logging: level: DEBUG # 覆盖生产环境的 INFO output: base_dir: D:/local_output # 使用本地路径 redis: host: 127.0.0.1 # 使用本地 Redis db: 9 # 独立的数据库编号 ``` ### 3. 在代码中使用配置 #### 读取环境变量(推荐用于敏感信息) ```python from env_loader import get_env, get_env_bool, get_env_int # 读取必需的环境变量 gemini_api_key = get_env( "GEMINI_API_KEY", required=True, hint="See .env.example for setup instructions" ) # 读取可选的环境变量(带默认值) azure_api_key = get_env("AZURE_API_KEY", default="") debug_mode = get_env_bool("DEBUG", default=False) timeout = get_env_int("TIMEOUT", default=30) ``` #### 读取配置文件(推荐用于应用配置) ```python from config_loader import load_config # 加载配置(自动根据 current_env.txt 选择环境) config = load_config() # 读取配置项 output_dir = config.get("output", {}).get("base_dir", "./output") log_level = config.get("logging", {}).get("level", "INFO") redis_host = config.get("redis", {}).get("host", "localhost") ``` #### 在配置文件中引用环境变量 配置文件支持 `${ENV_VAR_NAME}` 格式引用环境变量: `config/prod.yaml`: ```yaml notifications: wechat: yfz: "${WECHAT_TOKEN_YFZ}" # 从环境变量读取 wecom: team1: "${WECOM_TOKEN_TEAM1}" ``` 加载后会自动展开: ```python config = load_config() token = config["notifications"]["wechat"]["yfz"] # 自动展开为实际的 token 值 ``` ## 最佳实践 ### 1. 敏感信息 vs 应用配置 **使用 `.env` 文件的场景**: - API 密钥、Token - 数据库密码、Redis 密码 - 系统账户密码 - 其他不应出现在版本库中的敏感信息 **使用配置文件(`config/*.yaml`)的场景**: - 应用功能开关 - 超时设置、重试次数等参数 - 文件路径、目录配置 - 日志级别、输出格式等 - 非敏感的业务配置 ### 2. 环境隔离 ```bash # 切换到测试环境 echo "test" > config/current_env.txt # 切换回生产环境 echo "prod" > config/current_env.txt ``` ### 3. 本地开发配置 本地配置文件(`config/local.yaml`)用于覆盖环境配置,常见用途: - 使用本地路径替代网络共享路径(提升速度) - 启用详细日志(`DEBUG`) - 连接本地数据库/Redis(避免影响生产环境) - 临时关闭某些功能特性 ### 4. 团队协作 **提交到版本库的文件**: - `.env.example` - 环境变量模板,不含真实密钥 - `config/prod.yaml`, `config/test.yaml` - 环境配置 - `config/local.yaml.example` - 本地配置示例 **不提交到版本库的文件**(已在 `.gitignore` 中): - `.env` - 包含真实密钥 - `config/local.yaml`, `config/local.json` - 个人本地配置 ## 迁移指南 ### 从硬编码配置迁移 **旧代码**: ```python # 硬编码在代码中 GEMINI_API_KEY = "AQ.Ab8RN6INSIgaGdgj5hmmYmi35QLw6K3likBz2bP37_I_F6V5aQ" OUTPUT_DIR = "./output" LOG_LEVEL = "INFO" ``` **新代码**: ```python from env_loader import get_env from config_loader import load_config # 敏感信息从环境变量读取 GEMINI_API_KEY = get_env("GEMINI_API_KEY", required=True) # 应用配置从配置文件读取 config = load_config() OUTPUT_DIR = config.get("output", {}).get("base_dir", "./output") LOG_LEVEL = config.get("logging", {}).get("level", "INFO") ``` **配置文件**: `.env`: ```bash GEMINI_API_KEY=AQ.Ab8RN6INSIgaGdgj5hmmYmi35QLw6K3likBz2bP37_I_F6V5aQ ``` `config/prod.yaml`: ```yaml output: base_dir: ./output logging: level: INFO ``` ### 向后兼容处理 如果配置文件不存在,给出友好提示: ```python from config_loader import load_config try: config = load_config() except FileNotFoundError as e: print(f"Configuration file not found: {e}") print("Please set up the configuration files in the config/ directory") # 使用默认配置或退出 config = {} # 使用空配置或默认值 ``` 环境变量不存在时的友好提示: ```python from env_loader import get_env, print_env_setup_guide, check_required_env_vars # 检查必需的环境变量 missing_vars = check_required_env_vars(["GEMINI_API_KEY", "AZURE_API_KEY"]) if missing_vars: print(f"Missing required environment variables: {', '.join(missing_vars)}") print_env_setup_guide() raise ValueError("Please configure environment variables") ``` ## 常见问题 ### Q1: `.env` 文件和 `config/local.yaml` 有什么区别? - `.env` 用于**敏感信息**(API 密钥、密码等),格式固定为 `KEY=VALUE` - `config/local.yaml` 用于**本地配置覆盖**(路径、参数等),支持嵌套结构 ### Q2: 如何验证配置是否生效? ```python from env_loader import get_env from config_loader import load_config # 检查环境变量 print(f"GEMINI_API_KEY: {get_env('GEMINI_API_KEY', default='')}") # 检查配置文件 config = load_config() print(f"Environment: {config.get('environment', {}).get('name', 'unknown')}") print(f"Log level: {config.get('logging', {}).get('level', 'INFO')}") ``` ### Q3: 配置文件支持哪些格式? - **环境变量**:`.env` 文件(`KEY=VALUE` 格式) - **配置文件**:`.yaml`、`.yml`、`.json` 推荐使用 YAML 格式,因为: - 支持注释 - 支持嵌套结构 - 可读性更好 ### Q4: 如何在配置文件中引用环境变量? 使用 `${ENV_VAR_NAME}` 格式: ```yaml notifications: wechat: yfz: "${WECHAT_TOKEN_YFZ}" # 引用环境变量 ``` 加载时会自动展开为环境变量的值。 ### Q5: 环境变量和配置文件冲突时如何处理? 环境变量的优先级最高。例如: `.env`: ``` LOG_LEVEL=DEBUG ``` `config/prod.yaml`: ```yaml logging: level: INFO ``` 如果在配置文件中引用环境变量: ```yaml logging: level: "${LOG_LEVEL}" # 实际值为 DEBUG(环境变量) ``` ## 完整示例 参考 `config_usage_examples.py` 文件,包含: - 环境变量读取示例 - 配置文件读取示例 - 完整的初始化函数 - 配置验证逻辑 - 迁移指南 ## 安全建议 1. **永远不要提交包含真实密钥的文件** - `.env` 已在 `.gitignore` 中排除 - 提交前检查:`git status` 确保 `.env` 不在待提交列表中 2. **定期轮换 API 密钥** - 定期更新 `.env` 中的密钥 - 旧密钥在服务提供商处失效 3. **最小权限原则** - API 密钥只授予必需的权限 - 生产环境和开发环境使用不同的密钥 4. **密钥泄露应急处理** - 立即在服务提供商处撤销泄露的密钥 - 生成新密钥并更新 `.env` 文件 - 检查是否有未授权使用记录 ## 参考资料 - 配置加载模块:`config_loader.py` - 环境变量加载模块:`env_loader.py` - 使用示例:`config_usage_examples.py` - 环境变量模板:`.env.example` - 本地配置示例:`config/local.yaml.example`