所属专题簇:控制、扩展与灰度治理
为什么 Claude Code 源码里出现的功能,不等于当前用户就一定能看到或使用?
Claude Code 的功能面不仅受本地代码决定,还受 feature(...) 静态裁剪、GrowthBook 远程灰度、analytics 元数据和可信状态影响;它把“功能是否存在”和“功能是否可见/可用”拆成了多层控制。
这一章解释 Claude Code 如何通过静态 feature gate、GrowthBook、实验分流、事件日志和 kill switch 控制产品行为。
- 看到源码并不等于看到功能。
- Claude Code 同时使用静态编译期开关和动态远程特性控制。
- analytics 在这里只是日志系统的一部分,更重要的是它为灰度、实验和产品治理提供上下文。
一个持续演化的 agent 产品很难把所有能力一次性对所有人开启。Claude Code 显然需要:
- 按用户类型灰度能力
- 紧急关闭某些功能
- 让实验和正式能力共存
- 让外部观测知道某个功能为什么生效或不生效
这就是 feature control 层存在的原因。
- GrowthBook 客户端:src/services/analytics/growthbook.ts
- analytics 目录:src/services/analytics/
- 启动链中的 feature 使用:src/main.tsx
- voice 模式示例:src/voice/voiceModeEnabled.ts
flowchart TD
A["源码中存在某功能"] --> B["bun:bundle feature gate"]
B --> C["GrowthBook 远程特性"]
C --> D["auth / trust / user attributes"]
D --> E["最终是否注册 / 是否可见 / 是否可执行"]
E --> F["analytics / exposure logging"]
src/services/analytics/growthbook.ts 里可直接看到 GrowthBookUserAttributes,其中包括:
sessionIddeviceIDplatformorganizationUUIDaccountUUIDuserTypesubscriptionTyperateLimitTier
这说明远程特性控制不是单纯“开 / 关”开关,而是会根据用户和环境属性做定向灰度。
源码里大量使用 feature('...')。这类开关偏向:
- 编译产物裁剪
- 外部构建差异
- 某些字符串和路径在 bundle 阶段被消除
而 GrowthBook 则更像:
- 运行时实验
- 远程 kill switch
- 功能可见性控制
两者叠加后,读源码时必须区分“编译时不存在”和“运行时没开给你”。
src/services/analytics/ 下的:
firstPartyEventLogger.tsdatadog.tsmetadata.tssink.ts
说明这层不只是简单记录点击,而是在支撑实验曝光、运行时元数据和系统可观测性。
src/voice/voiceModeEnabled.ts 直接显示:
- 需要
VOICE_MODEfeature - 还要检查 GrowthBook kill switch
- 还要检查 Anthropic OAuth token
这很好地展示了 Claude Code 的典型能力控制方式:静态开关、远程开关和鉴权条件三层同时成立才真正可用。
- “源码存在”只是第一层事实。
- Claude Code 用 feature gate + GrowthBook + auth/state 共同决定功能面。
- 研究某个能力是否真实存在时,必须同时看注册点、feature 判断和远程特性控制。