Summary
在对 .env 配置加载、YAML 合并逻辑和环境变量映射的代码审查中,发现 8 个配置加载系统 bug,分布在 app/config/ 和 app/infra/ 两个并行配置系统中。这些问题会导致运行崩溃、配置忽略和调试困难。
🔴 CRITICAL
Bug 1: _Settings 缺失 rerank_* 属性 → 运行时 AttributeError
- 文件:
app/config/settings.py, app/services/rag/reranker.py, app/test/eval/runner.py
- 症状:
_Settings 类仅定义了 app、server、rdbms、llm、embedding、chunk、agentic、asr、langsmith、session、redis、security 属性,缺少 rerank_enabled、rerank_provider、rerank_model、rerank_top_n 属性
- 后果:
reranker.py:205 访问 settings.rerank_enabled 时抛出 AttributeError;runner.py:343-346 的 _config_snapshot() 同样崩溃
- 修复: 在
_Settings 中添加对应的 rerank_* property
# settings.py 需添加:
@property
def rerank_enabled(self) -> bool:
return bool(_get("rerank", "enabled", default=False))
🟠 HIGH
Bug 2: infra/config.py 中 env_file 为相对路径
- 文件:
app/infra/config.py
- 症状:
model_config 中 env_file=".env" 是相对路径,若从非项目根目录启动应用,pydantic-settings 无法找到 .env 文件
- 对比:
app/config/loader.py 的 _load_dotenv() 正确使用了绝对路径 (root / ".env")
- 影响范围:
app/infra/rdbms.py、app/infra/redis.py、app/infra/mongo.py、app/infra/milvus.py、app/infra/minio.py 等所有 infra 组件
- 修复: 改为相对于
__file__ 的绝对路径,或使用 pydantic-settings 的 env_file 绝对路径
Bug 3: test_config_cleanup.py 测试断言与代码不一致
🟡 MEDIUM
Bug 4: 旧版环境变量无法覆盖 YAML 值
- 文件:
app/config/loader.py
- 症状:
_apply_legacy_env_overrides 仅在 existing is None or existing == "" 时生效。但 YAML 已设置 tracing_v2: true(布尔值),导致用户在 .env 中设置 LANGCHAIN_TRACING_V2=false 被静默忽略
- 后果: 用户无法通过环境变量关闭 LangSmith trace
- 修复: 旧版 env var 的优先级应高于 YAML(与文档声明的配置层级一致)
# loader.py:121 应改为:
if existing is None:
# 环境变量优先级高于 YAML,不存在时才用 YAML 默认值
node[path[-1]] = value
Bug 5: 环境变量字符串未做类型转换
- 文件: [
app/config/loader.py](app/config/loader.py#L111, L129)
- 症状: 新旧两种 env var 映射都直接将
os.environ 字符串存为值。bool("false") 在 Python 中为 True(非空字符串为真)
- 后果:
_Settings 中用 bool() 转换始终返回 True,用户无法通过 env var 设置 false
- 对比:
infra/config.py 的 Pydantic 层正确处理了类型转换
- 修复: 在
_apply_new_style_env_overrides 和 _apply_legacy_env_overrides 中添加类型推断逻辑
Bug 6: 新式 env var(双下划线)可注入任意配置路径
- 文件:
app/config/loader.py
- 症状:
_apply_new_style_env_overrides 对任意包含 __ 的环境变量创建中间字典节点,无白名单/校验
- 后果: 设置
FAKE__NONEXISTENT__KEY=value 会在配置树中静默创建路径,无人读取但占用内存
- 修复: 添加已知配置键白名单校验,或记录未知键的 warning 日志
🟢 LOW
Bug 7: LANGSMITH_API_KEY 命名不一致
Bug 8: minio.bucket 在 default.yaml 和 config.yaml 中不一致
- 文件:
app/config/default.yaml, app/config/config.yaml
- 症状:
default.yaml 中 bucket: drive-videos,config.yaml 中 bucket: bilirag。由于 config.yaml 后加载覆盖,实际使用 bilirag
- 后果: 若启用
BILIRAG_SKIP_CONFIG=1 跳过 config.yaml,bucket 名会静默变为 drive-videos
- 修复: 统一两个文件中的 bucket 值
根因分析
项目存在两套并行配置系统:
app/config/loader.py → 自定义层级 YAML 查看器 + env 覆盖
app/infra/config.py → Pydantic-settings + YamlConfigSettingsSource
两套系统各自加载 .env 和 YAML,但路径解析、类型转换和变量映射逻辑相互独立,容易产生行为分歧。
Summary
在对
.env配置加载、YAML 合并逻辑和环境变量映射的代码审查中,发现 8 个配置加载系统 bug,分布在app/config/和app/infra/两个并行配置系统中。这些问题会导致运行崩溃、配置忽略和调试困难。🔴 CRITICAL
Bug 1:
_Settings缺失rerank_*属性 → 运行时 AttributeErrorapp/config/settings.py,app/services/rag/reranker.py,app/test/eval/runner.py_Settings类仅定义了app、server、rdbms、llm、embedding、chunk、agentic、asr、langsmith、session、redis、security属性,缺少rerank_enabled、rerank_provider、rerank_model、rerank_top_n属性reranker.py:205访问settings.rerank_enabled时抛出AttributeError;runner.py:343-346的_config_snapshot()同样崩溃_Settings中添加对应的rerank_*property🟠 HIGH
Bug 2:
infra/config.py中env_file为相对路径app/infra/config.pymodel_config中env_file=".env"是相对路径,若从非项目根目录启动应用,pydantic-settings 无法找到.env文件app/config/loader.py的_load_dotenv()正确使用了绝对路径 (root / ".env")app/infra/rdbms.py、app/infra/redis.py、app/infra/mongo.py、app/infra/milvus.py、app/infra/minio.py等所有 infra 组件__file__的绝对路径,或使用 pydantic-settings 的env_file绝对路径Bug 3:
test_config_cleanup.py测试断言与代码不一致app/test/test_config_cleanup.py,app/infra/config.pyTestInfraConfigHasNoAgenticSection断言infra_config不含agentic字段,但infra/config.py:366仍定义了agentic: AgenticSectioninfra/config.py中的agentic字段(如果已废弃),要么更新测试断言🟡 MEDIUM
Bug 4: 旧版环境变量无法覆盖 YAML 值
app/config/loader.py_apply_legacy_env_overrides仅在existing is None or existing == ""时生效。但 YAML 已设置tracing_v2: true(布尔值),导致用户在.env中设置LANGCHAIN_TRACING_V2=false被静默忽略Bug 5: 环境变量字符串未做类型转换
app/config/loader.py](app/config/loader.py#L111, L129)os.environ字符串存为值。bool("false")在 Python 中为True(非空字符串为真)_Settings中用bool()转换始终返回True,用户无法通过 env var 设置falseinfra/config.py的 Pydantic 层正确处理了类型转换_apply_new_style_env_overrides和_apply_legacy_env_overrides中添加类型推断逻辑Bug 6: 新式 env var(双下划线)可注入任意配置路径
app/config/loader.py_apply_new_style_env_overrides对任意包含__的环境变量创建中间字典节点,无白名单/校验FAKE__NONEXISTENT__KEY=value会在配置树中静默创建路径,无人读取但占用内存🟢 LOW
Bug 7:
LANGSMITH_API_KEY命名不一致app/config/default.yaml,app/config/config.yaml,.envdefault.yaml:172注释写LANGSMITH__API_KEY(双下划线),config.yaml:234注释写LANGSMITH_API_KEY(单下划线),.env:115使用单下划线形式Bug 8:
minio.bucket在default.yaml和config.yaml中不一致app/config/default.yaml,app/config/config.yamldefault.yaml中bucket: drive-videos,config.yaml中bucket: bilirag。由于config.yaml后加载覆盖,实际使用biliragBILIRAG_SKIP_CONFIG=1跳过config.yaml,bucket 名会静默变为drive-videos根因分析
项目存在两套并行配置系统:
app/config/loader.py→ 自定义层级 YAML 查看器 + env 覆盖app/infra/config.py→ Pydantic-settings +YamlConfigSettingsSource两套系统各自加载
.env和 YAML,但路径解析、类型转换和变量映射逻辑相互独立,容易产生行为分歧。