6.1 三层门控详解:feature() / USER_TYPE / GrowthBook

本章从工程实践角度,深入讲解功能门控体系如何支撑 Claude Code 的安全发布、灰度测试和应急响应。


功能发布的工程挑战

对于 Anthropic 这样的公司,向数百万用户安全地发布 AI 功能面临独特挑战:

  1. 代码级隔离:KAIROS 这类复杂系统在内部测试完成前,外部版二进制里不应包含相关代码
  2. 问题功能立即关闭:语音识别崩溃、电子宠物有 bug,需要秒级全球关闭
  3. 内部调试环境:调试工具、实验功能,只有 Anthropic 内部人员应该能用
  4. 灰度发布:对 10% 用户先放开,对付费用户优先,等等

三层门控系统针对这四个需求分别设计了解决方案。


第一层:编译时 feature()

解决问题:代码级隔离(外部版本里根本不包含内部代码)

// src/tools.ts(真实源码)
const SleepTool =
  feature('PROACTIVE') || feature('KAIROS')
    ? require('./tools/SleepTool/SleepTool.js').SleepTool
    : null

Bun 构建时发生了什么

外部版本构建时,feature('KAIROS')false

// 构建后的外部版代码
const SleepTool =
  false || false    // 两个 feature() 都是 false
    ? require('./tools/SleepTool/SleepTool.js').SleepTool
    : null

// Bundler DCE 优化:条件永远为 false,整个 require 被死代码消除
const SleepTool = null
// SleepTool 模块的内容完全不在外部版二进制中

这是死代码消除(DCE)。外部用户不仅"看不到"这些功能,连代码本身都不在他们下载的二进制文件里。

feature() 的实现原理

这是 Bun 专有的编译时 API,类似 C/C++ 的 #ifdef 预处理指令,但集成在 JavaScript 模块系统中。在开发模式(bun run dev)下,所有 feature() 返回 true,可以看到所有功能。


第二层:USER_TYPE 运行时

解决问题:区分内部员工和外部用户,提供不同的工具集和调试能力

// src/tools.ts(真实源码)
const REPLTool =
  process.env.USER_TYPE === 'ant'
    ? require('./tools/REPLTool/REPLTool.js').REPLTool
    : null

源码中到处可见 "external" === 'ant' 的比较,这永远为 false——因为外部版 USER_TYPE 在构建时被硬编码为 "external"

USER_TYPE含义额外权限
antAnthropic 内部员工REPLTool、200+ 调试检查点、20 分钟 GrowthBook 刷新、全部内部斜杠命令
external外部用户标准功能集、6 小时 GrowthBook 刷新

ant 专属能力

类别能力
GrowthBook调试日志、开关覆盖、20 分钟刷新(vs 6 小时)
调试API 错误详情、prompt dump 工具
命令24+ 个内部专属斜杠命令
CLI 参数--delegate-permissions--afk--tasks--agent-teams
环境变量CLAUDE_INTERNAL_FC_OVERRIDES(JSON 覆盖 GrowthBook)
配置 UI/config Gates 标签页(可视化覆盖 GrowthBook)

第三层:GrowthBook 远程 A/B

解决问题:无需发布新版本,实时控制功能的开关和灰度比例

两种 API

// 布尔型 Feature Gate(开/关)
const isEnabled = checkStatsigFeatureGate_CACHED_MAY_BE_STALE('tengu_kairos')

// 字符串/数值型 Feature Value(配置参数)
const model = getFeatureValue_CACHED_MAY_BE_STALE('tengu_ultraplan_model')
  ?? 'claude-opus-4-5'

缓存策略的差异

// ant 用户(Anthropic 内部)
GrowthBook 刷新间隔 = 20 分钟  // 快速反映配置变化,便于调试

// external 用户(外部)
GrowthBook 刷新间隔 = 6 小时   // 减少 GrowthBook 服务器负载

函数名中刻意包含 _CACHED_MAY_BE_STALE——这是一种"诚实的命名",提醒调用者这个值可能不是最新的(最长有 6 小时的延迟)。

关键 GrowthBook 开关

开关控制内容
tengu_kairosKAIROS 助手模式总开关
tengu_onyx_ploverAutoDream 触发阈值(整合间隔/会话数)
tengu_cobalt_frost语音识别(Nova 3 模型)开关
tengu_ultraplan_modelUltraplan 使用的模型
tengu_max_version_config自动更新 Kill Switch
tengu_frond_boric数据接收器 Kill Switch
tengu_ccr_bridgeBridge 远程控制总开关
tengu_bridge_repl_v2Bridge v2 传输协议开关
tengu_scratchCoordinator Scratchpad 目录
tengu_session_memory会话记忆功能

三层的协同:一个功能被激活需要通过所有层

以 KAIROS 为例:

激活 KAIROS 需要同时满足:

1. ✓ feature('KAIROS') = true    ← 编译时(外部版永远不满足)
           ↓
2. ✓ settings.json: assistant: true  ← 用户手动配置
           ↓
3. ✓ 目录信任检查通过               ← 安全检查
           ↓
4. ✓ GrowthBook: tengu_kairos = true ← Anthropic 远程控制
           ↓
5. → setKairosActive(true)           ← 功能激活

任何一层不通过,功能都不会激活。


Kill Switch 设计原则

GrowthBook 层的存在意义之一是紧急 Kill Switch

场景:KAIROS 的 Dream 功能出现 bug,导致某些用户数据异常
处理:
  1. Anthropic 在 GrowthBook 控制台将 tengu_onyx_plover 的 minSessions 设为极大值
  2. 所有用户(最晚 6 小时后)不再触发 Dream
  3. 不需要发布任何新版本

这是 Anthropic 在 AI 功能发布中总结出的重要经验:每个功能都必须有独立的 Kill Switch


覆盖机制(仅内部用户)

内部用户可以覆盖 GrowthBook 的远程配置,用于本地调试:

# 方法 1:环境变量
CLAUDE_INTERNAL_FC_OVERRIDES='{"tengu_kairos": true}' claude

# 方法 2:/config → Gates 标签页 → growthBookOverrides

下一步