Skip to content

[Bug] .env 配置加载系统 8 个 bug — 从类型转换到 AttributeError 崩溃 #22

Description

@T0708H

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 类仅定义了 appserverrdbmsllmembeddingchunkagenticasrlangsmithsessionredissecurity 属性,缺少 rerank_enabledrerank_providerrerank_modelrerank_top_n 属性
  • 后果: reranker.py:205 访问 settings.rerank_enabled 时抛出 AttributeErrorrunner.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.pyenv_file 为相对路径

  • 文件: app/infra/config.py
  • 症状: model_configenv_file=".env" 是相对路径,若从非项目根目录启动应用,pydantic-settings 无法找到 .env 文件
  • 对比: app/config/loader.py_load_dotenv() 正确使用了绝对路径 (root / ".env")
  • 影响范围: app/infra/rdbms.pyapp/infra/redis.pyapp/infra/mongo.pyapp/infra/milvus.pyapp/infra/minio.py 等所有 infra 组件
  • 修复: 改为相对于 __file__ 的绝对路径,或使用 pydantic-settings 的 env_file 绝对路径

Bug 3: test_config_cleanup.py 测试断言与代码不一致

  • 文件: app/test/test_config_cleanup.py, app/infra/config.py
  • 症状: 测试 TestInfraConfigHasNoAgenticSection 断言 infra_config 不含 agentic 字段,但 infra/config.py:366 仍定义了 agentic: AgenticSection
  • 后果: 运行此测试必然失败
  • 修复: 要么移除 infra/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静默忽略
  • 后果: 用户无法通过环境变量关闭 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 命名不一致

  • 文件: app/config/default.yaml, app/config/config.yaml, .env
  • 症状: default.yaml:172 注释写 LANGSMITH__API_KEY(双下划线),config.yaml:234 注释写 LANGSMITH_API_KEY(单下划线),.env:115 使用单下划线形式
  • 后果: 虽然两种形式通过不同路径都能工作,但注释矛盾会误导开发者
  • 修复: 统一注释和文档

Bug 8: minio.bucketdefault.yamlconfig.yaml 中不一致

  • 文件: app/config/default.yaml, app/config/config.yaml
  • 症状: default.yamlbucket: drive-videosconfig.yamlbucket: bilirag。由于 config.yaml 后加载覆盖,实际使用 bilirag
  • 后果: 若启用 BILIRAG_SKIP_CONFIG=1 跳过 config.yaml,bucket 名会静默变为 drive-videos
  • 修复: 统一两个文件中的 bucket 值

根因分析

项目存在两套并行配置系统

  1. app/config/loader.py → 自定义层级 YAML 查看器 + env 覆盖
  2. app/infra/config.py → Pydantic-settings + YamlConfigSettingsSource

两套系统各自加载 .env 和 YAML,但路径解析、类型转换和变量映射逻辑相互独立,容易产生行为分歧。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions