Skip to content

环境变量、凭据与降级开关

本章目标:

  1. 知道凭据/配置 .env 分布在哪几处、各管什么、为什么不入库
  2. 拿到一张完整的"紧急降级开关"速查表,生产出事时知道关哪个
  3. 理解 env 变更的部署铁律(为什么 restart 不行、必须 --force-recreate)

TL;DR

a-cdm 的敏感凭据走 .env,被 .gitignore 排除不入库,分三处:acdm-backend/.env(DB/Nextcloud/Keycloak/SECRET_KEY/网关 key)、deer-flow/.env(引擎 key + RUNTIME_BACKEND)、deer-flow/frontend/.env.local(可选)。控制面配置 schema 在 acdm-backend/app/config.pySettings(pydantic BaseSettings)。一组以 ACDM_*_ENABLED / COOKIE_SECURE / RUNTIME_BACKEND 命名的开关构成"紧急降级层":出事时改 .env 关掉对应能力即可回退,但改 .env 后必须 up -d --force-recreate,restart 不重读 .env

Overview(为什么要有一层"降级开关")

a-cdm 把鉴权、授权、可逆操作、速率限制、Aegra 运行时等高风险能力逐个做成可一键关闭的开关,核心理由是生产事故响应:这些能力任何一个出 bug 都可能让全站不可用,而完整回滚代码 + 重新 CI + 部署要十几分钟。降级开关让运维能在 1 分钟内把出问题的能力降级到"上一个已知好状态",争取排查时间 —— 这是"安全要能快速关掉"的工程化。

每个开关都遵循同一约定:默认开启(生产行为),设为 false/0/no 降级到旧行为,且 dev 与 prod 同一套开关无后门。

Architecture:.env 分布与不入库约束

.gitignore:2-5 排除 .env / .env.* / *.env.local,只放行 .env.example。三处 .env(CLAUDE.md:16):

文件管什么加载方式Source
acdm-backend/.envDATABASE_URL、NEXTCLOUD_、KEYCLOAK_、SECRET_KEY、JOINTPILOT/AICC/VOLCENGINE key、GITLAB_WIKI_PATpydantic Settings,env_fileacdm-backend/app/config.py:240-242
deer-flow/.env引擎 LLM key、RUNTIME_BACKEND、Aegra DB URLdocker compose env_file / 进程环境deploy/prod/deer-flow-backend/compose.yml:114
deer-flow/frontend/.env.local前端可选环境变量(NEXT_PUBLIC_*)Next.js 编译/运行期CLAUDE.md:16

生产 /data/apps/*/.env 手工 scp,不进库(CLAUDE.md:16)。已废字段:API_SECRET_TOKEN / NEXT_PUBLIC_ACDM_TOKEN(CLAUDE.md:16)。

控制面配置由 acdm-backend/app/config.py:17Settings(BaseSettings) 集中声明,model_config = SettingsConfigDict(env_file=...)(config.py:240-242)指向 acdm-backend/.envDATABASE_URL 是唯一必填(Field(...),config.py:19),其余多有默认值;敏感字段留空时不崩,而是相关端点返 503(如 KEYCLOAK_CLIENT_SECRET 空 → /auth/login 503,config.py:42-44;GITLAB_WIKI_PAT 空 → /wiki/* 503,config.py:113-115)——与 ai_registry 的 graceful degradation 同一哲学。

关键凭据清单

env用途空时行为红线Source
DATABASE_URLasyncpg 连接串(必填)启动失败config.py:19
SECRET_KEYHS256 JWT 签发密钥❌ 禁入库,openssl rand -hex 32config.py:54-56
KEYCLOAK_CLIENT_SECRETKeycloak OAuth client secret/auth/login 503❌ 禁入库config.py:42-44
JOINTPILOT_API_KEY主网关 LLM 凭据相关 role 503(graceful)先改 .env 再 mergeconfig.py:122-124
GITLAB_WIKI_PATllm-wiki GitLab PAT/wiki/* 503❌ 禁入库config.py:113-115
ACDM_MCP_SERVICE_TOKENservice-to-service token/mcp/* 拒所有请求config.py:177-179
NEXTCLOUD_PASSWORDWebDAV 凭据存储操作失败❌ 禁入库config.py:25

红线 CLAUDE.md(红线段)三条相关:不把 KEYCLOAK_CLIENT_SECRET/SECRET_KEY/BETTER_AUTH_SECRET 写进库;新增/rotate xxx_API_KEY 必须先 ssh prod 加 .env → 再 merge → 再 force-recreate(L94 教训)。

紧急降级开关速查表

这是本章最该收藏的一张表 —— 生产出事时按现象关对应开关:

开关 env默认降级到关掉用于读取点Source
ACDM_PROJECT_ACCESS_ENABLEDtruePhase 1(所有成员校验放行)三级授权出 bug 锁死用户acdm-backend/app/auth/dependencies.py:38acdm-backend/app/auth/dependencies.py:13
ACDM_THREAD_AUTH_ENABLEDtrue所有 thread auth handler 立即放行owner_sub 隔离误伤deer-flow/backend/.../auth/acdm_auth.py:40 + app/gateway/acdm_thread_auth.py:42acdm_auth.py:20
RUNTIME_BACKENDlanggraph(compose 默认)langgraph ← 从 aegra 回退Aegra 0.9.4 出问题deploy/prod/deer-flow-backend/compose.yml:84compose.yml:70-73
COOKIE_SECURETrue(生产)False(允许 HTTP cookie)HTTPS 故障需走 HTTP IP 兜底config.py:61-63config.py:61-63
ACDM_RATE_LIMIT_ENABLEDtrue/auth/login 限速限速误伤正常登录config.py:81-83config.py:81-88
ACDM_PUBLIC_HOSTS三 host 白名单空 = 不做 host 白名单公网边缘加固误拦config.py:69-71config.py:69-79
ACDM_AI_NC_WRITES_ENABLEDtruevia_agent 写 NC 被拒(40310)AI 误写文件需紧急止血config.py:184-186config.py:184-190
ACDM_REVERSIBLE_STORAGE_BYPASSfalseReversibleStorageClient 退化为直代理可逆框架本身出 bugconfig.py:217-219config.py:217-219

说明:RUNTIME_BACKENDcompose.yml:114 的默认是 langgraph,但生产 .env 实际设为 aegra(2026-04-25 起,见 CLAUDE.md:14);"降级"指把 .env 改回 langgraph 或删该行让 cron 自动重启回退(compose.yml:22)。

配额与保留期配置(可逆操作相关)

env默认含义Source
ACDM_AI_NC_DAILY_BYTES_CAP10 GBvia_agent 每日写入上限,超出返 40312config.py:192-194
ACDM_AI_NC_TRASH_RETENTION_DAYS90.acdm-trash 保留天数,超期 cron 清理config.py:197-199
ACDM_DB_PRUNE_RETENTION_DAYS90软删行保留天数,0=关闭 auto pruneconfig.py:204-206
ACDM_AI_NC_BACKUP_THRESHOLD_MB(见字段)小文件备份到 .acdm-versions 的大小阈值config.py:209-211
MAX_UPLOAD_BYTES200 MB单文件上传上限config.py:226

这些在"可逆 DB 操作与存储层"章详解。

Common Pitfalls / 实战 Tips

  • restart 不重读 .env(L88):改完 .envdocker compose up -d --force-recreate <svc>,不是 restart。这是最高频踩坑(CLAUDE.md:14)。
  • 新增/rotate API key 顺序:先 ssh prod 加 .env → 再 merge → 再 force-recreate。反过来会触发 fail-fast/503(L94,CLAUDE.md 红线)。
  • COOKIE_SECURE=True 的副作用是预期:HTTP IP 路径业务不可用(cookie 不发)是有意设计,不是 bug —— IP 路径仅作 HTTPS 故障时静态资源兜底(CLAUDE.md:15)。
  • 降级开关不是常开配置:它们是"出事临时关、修好再开"的应急阀门,长期 false 等于带病运行。
  • dev 与 prod 同一套开关:本地不起 Caddy 不代表开关失效,前端 proxy 仍按同一逻辑工作。

References

  • acdm-backend/app/config.py:17-242 — 控制面 Settings 全字段(本章主源)
  • .gitignore:2-5.env 不入库规则
  • acdm-backend/app/auth/dependencies.py:13-42ACDM_PROJECT_ACCESS_ENABLED 降级读取
  • deer-flow/backend/packages/harness/deerflow/auth/acdm_auth.py:20-40ACDM_THREAD_AUTH_ENABLED 降级读取
  • deploy/prod/deer-flow-backend/compose.yml:14-114RUNTIME_BACKEND 切换/回退机制
  • CLAUDE.md:14-16 — 凭据分布、降级开关清单、env 部署铁律(线索,已回源核实)
PageRelationship
AI 角色注册表与模型矩阵本章网关凭据为该章 graceful degradation 提供输入
鉴权与授权双层体系本章 ACDM_PROJECT_ACCESS_ENABLED/ACDM_THREAD_AUTH_ENABLED 是该章两层的降级阀
Aegra 运行时与 LangGraph本章 RUNTIME_BACKEND 切换在该章详解
可逆 DB 操作与存储层本章配额/保留期/bypass 开关在该章对应到机制
CI/CD 与生产部署运维本章 --force-recreate 铁律是该章部署流程的一部分

公司内部参考 · 由 claude-wiki-gen 基于源码自动生成的二次分析