claude-code/docs/agentic-design/06-feature-gating.md
Claude 808d5a61b3
docs: Add comprehensive agentic design documentation (2.5-hour learning session)
新增 docs/agentic-design/ 教育文档,全中文+英文技术术语,覆盖:

- README.md: 总索引,整体架构图,阅读指南
- 00-codebase-tour.md: 代码库全景,递归覆盖所有重要目录
- 01-agent-loop.md: Query loop 状态机,token budget,compaction
- 02-tool-system.md: Tool interface,权限检查,并发执行,sibling abort
- 03-multi-agent-coordination.md: Agent 类型,coordinator 4 阶段,XML 通信
- 04-permission-system.md: Permission mode,rule system,YOLO 分类器,denial tracking
- 05-context-and-memory.md: System prompt 分层,compaction,auto-dream 后台巩固
- 06-feature-gating.md: Compile-time feature,runtime flags,Bun dead-code elimination

总计 ~2.5 小时阅读,每篇含 Design Decision 专栏和常见误解纠正

https://claude.ai/code/session_017Vdqo9B8eTXiEDcqnv9DxM
2026-03-31 16:07:29 +00:00

357 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Feature Gating内部功能和公开功能的隔离
## 为什么需要 Feature Gating?
Claude Code 是一个复杂系统,有很多功能:
- 一些已发布、稳定、所有用户可用
- 一些还在测试、只给内部用户("ant" 用户)
- 一些只给特定高级用户Max/Pro)
- 一些通过实验 A/B 测试
如果不做隔离,代码会变得一团糟:
```typescript
// 不好的做法
if (user.isInternal) {
// KAIROS 模式逻辑
} else if (user.isMax) {
// 高级功能
} else if (featureFlags.has('experimental_search')) {
// A/B 测试
} else {
// 默认行为
}
// ... 这样嵌套太深,难以维护
```
Claude Code 的解决方案:**编译期和运行期双层 gating**。
---
## 编译期 GatingBun 的 `feature()` API
BunJavaScript 运行时)提供了一个编译期特性检测 API
```typescript
if (feature("KAIROS")) {
// 这段代码只在 KAIROS 构建中出现
// 其他构建完全不包含这代码
} else {
// 默认行为
}
```
### 工作原理
```
源代码:
if (feature("KAIROS")) {
launchKAIROS()
} else {
launchDefault()
}
↓ Bun 编译(--feature KAIROS
if (true) {
launchKAIROS() // 只保留这段
} else {
// 被 dead code elimination 删除
}
↓ 输出的二进制
launchKAIROS() // 这是最终的可执行代码
```
### 优势
1. **二进制体积小**:内部功能完全不包含在公开二进制中
2. **安全**:用户不能"解锁"内部功能(不存在于二进制)
3. **性能**:不需要运行时检查这些条件
相关代码散布在整个 codebase 中,比如 `entrypoints/cli.tsx`, `bootstrap/state.ts`
---
## Compile-Time Feature 列表
Claude Code 在构建时支持这些 feature flag
| Flag | 启用时 | 作用 |
|------|--------|------|
| `KAIROS` | 启动 KAIROS modealways-on Claude | 全天候 assistant |
| `PROACTIVE` | 同上(别名) | 同上 |
| `BRIDGE_MODE` | 启用 claude.ai 远程控制 | 在 Web UI 中控制 CLI |
| `VOICE_MODE` | 启用语音输入 | 用话筒说指令 |
| `DAEMON` | 启用 daemon 模式 | 后台运行的 Claude |
| `COORDINATOR_MODE` | 启用 coordinator 多 agent | 复杂任务分解 |
| `BUDDY` | 启用 Tamagotchi 伴侣系统 | 养一个宠物 AI |
| `WORKFLOW_SCRIPTS` | 启用工作流脚本 | 自动化重复任务 |
| `NATIVE_CLIENT_ATTESTATION` | 启用本地证明 | 设备信任 |
| `TRANSCRIPT_CLASSIFIER` | 启用 AFK 自动模式 | 离开电脑时自动工作 |
| `HISTORY_SNIP` | 启用历史压缩优化 | Context 更高效 |
| `EXPERIMENTAL_SKILL_SEARCH` | 启用技能搜索(实验) | 发现新 skill 命令 |
| `ABLATION_BASELINE` | 科学研究 baseline | 论文用 |
默认只编译:`KAIROS=0, BRIDGE_MODE=0, ...`(全是 0最小二进制
内部构建时:编译脚本设置 `--feature KAIROS=1 --feature BRIDGE_MODE=1 ...`
相关文件:构建脚本(如 `scripts/build.sh`,如果存在),或 `bunfig.toml`
---
## 运行期 GatingGrowthBook Feature Flags
编译期 feature 决定"可能性",运行期 flags 决定"激活"。
系统启动时,从 GrowthBook特性管理平台获取动态配置
```typescript
// 启动时
const flags = await growthbook.getFeatures({
userId: currentUser.id,
organization: currentUser.org
})
// 现在可以做运行期决策
if (flags.has('tengu_scratch')) {
// 启用共享 scratchpadcoordinator 模式)
enableScratchpad()
}
if (flags.has('tengu_amber_flint')) {
// 启用 in-process teammate swarms
enableTeammates()
}
if (flags.has('tengu_penguins_off')) {
// 禁用某个实验
disableExperiment()
}
```
### Flag 命名约定
Runtime flags 以 `tengu_` 开头("tengu" 是 Claude Code 的内部代号):
```
tengu_scratch # 共享 scratchpad为 coordinator
tengu_amber_flint # In-process teammate
tengu_onyx_plover # 某个实验
tengu_penguins_off # 禁用什么功能
...
```
这样容易区分:
- `KAIROS`编译期vs `tengu_kairos_v2`(运行期)
相关文件:`bootstrap/state.ts`(初始化),`services/analytics/`GrowthBook 集成)
---
## 两层系统的协作
### 场景 1Compile-Time Only最常见
```
新功能 KAIROSalways-on Claude
↓ 编译
├─ 构建 ant内部--feature KAIROS=1
│ → KAIROS 代码被编译进去
└─ 构建 public公开--feature KAIROS=0
→ KAIROS 代码被 dead-code-elimination 删除
→ 二进制不含任何痕迹
```
### 场景 2Compile-Time + Runtime用于 A/B 测试)
```
新的 memory 系统(已编译进去)
↓ 运行时
├─ 用户在 tengu_new_memory=true 组50%
│ → 使用新系统
└─ 用户在 tengu_new_memory=false 组50%
→ 使用旧系统
→ 收集对比数据
```
### 场景 3运行期特定用户
```
高级功能(编译期编译进去)
↓ 运行时
├─ Max 订阅用户 → 启用计算机使用
├─ Pro 订阅用户 → 启用高级 memory
└─ 免费用户 → 基础功能
```
相关文件:`services/policyLimits/`(根据订阅级别应用 policy
---
## 对 System Prompt 的影响
Feature gating 会改变 system prompt 的内容:
```typescript
const systemPrompt = [
BASE_PROMPT,
// 只有在编译时启用 BRIDGE_MODE 时才包含
feature("BRIDGE_MODE") ? BRIDGE_MODE_INSTRUCTIONS : "",
// 运行时检查:如果用户有 tengu_coordinator flag
flags.get("tengu_coordinator") ? COORDINATOR_INSTRUCTIONS : "",
// 运行时 API beta 特性
BETAS_NEGOTIATED_WITH_API, // 如 "interleaved_thinking"
]
```
这也影响 **prompt cache**
```
缓存键 = MD5(system_prompt_prefix)
如果 flag 变化cache key 变化,旧 cache 失效
```
所以,高频变化的 runtime flag 应该放在 cache boundary 之后(动态部分),而不是之前(静态部分)。
---
## Betas 协商
Claude API 定期发布新特性betaClaude Code 需要:
1. 请求启用这些 beta
2. 如果启用,在 system prompt 中告诉 Claude这个 API 支持什么新功能)
例子:
```typescript
// constants/betas.ts
const BETAS_REQUESTED = [
"interleaved-thinking", // 支持在回复中穿插思考
"structured-outputs", // 支持返回结构化 JSON
"context-1m", // 100 万 token context
"web-search", // 网络搜索能力
]
// API 返回确认
const BETAS_ENABLED = [
"interleaved-thinking", // ✓ 已启用
// "structured-outputs", // ✗ 暂无权限
"context-1m", // ✓ 已启用
"web-search", // ✓ 已启用
]
// System prompt 中加入这些信息
You have access to the following beta features:
- Interleaved thinking: You can output <thinking> blocks
- Context 1M: You can use up to 1,000,000 tokens
- Web search: You can call the WebSearchTool
```
相关文件:`constants/betas.ts`
---
## Design Decision 专栏
### 为什么同时用编译期和运行期?
只用编译期:
```
缺点:无法做快速的 A/B 测试(需要重新编译)
无法根据用户身份动态启用功能
```
只用运行期:
```
缺点:内部功能可能被反编译/逆向工程
内部代码暴露在公开二进制中
启动时需要网络请求拿 flags
```
两者结合:
```
编译期决定"可能性"(物理隔离内部代码)
运行期决定"激活"(灵活的 A/B 测试)
最安全、最灵活
```
### 为什么 Bun 的 feature() 而不是其他工具?
Bun 的 feature() 是编译期指令,会进行 dead code elimination
```
其他工具(如 rollup 的条件编译):
需要额外的 webpack 插件
编译配置复杂
Bun:
原生支持
编译快Bun 本身就快)
输出体积最小
```
---
## 常见误解
**误解 1**"Runtime flag 可以改变编译期行为?"
实际不能。Runtime flag 只能在编译期已包含的代码中做选择。如果代码在编译时被 dead-code-elimination 删除了,运行时再想启用也没办法。
```typescript
// 如果编译时 --feature KAIROS=0这段代码被删除
if (feature("KAIROS")) {
launchKAIROS()
}
// 运行时即使 growthbook.flags.get("enable_kairos") == true也没用
// 代码不存在于二进制中
```
**误解 2**"Feature flag 对性能有开销?"
实际:编译期 feature flag 没有开销(代码级别选择)。运行期 flag 有极小开销map lookup可忽略不计。
**误解 3**"所有用户都能看到内部代码?"
实际:不能。公开二进制中编译时被删除的代码,用户看不到。只有 ant内部用户的二进制才包含这些代码。
---
## 关键要点
1. **编译期 feature**Bun 的 `feature()` APIdead code elimination对二进制体积和安全性的保障
2. **运行期 flags**GrowthBook动态启用特性支持 A/B 测试
3. **两层协作**:编译决定可能性,运行时决定激活
4. **System prompt 影响**:不同 flag 组合 → 不同 system prompt → 不同 cache key
5. **API Beta**:协商启用新的 Claude API 特性,在 system prompt 中告诉 Claude
---
## 深入阅读
- `bootstrap/state.ts`:运行时 flag 初始化56 KB
- `constants/betas.ts`Beta feature 列表
- `constants/system.ts``constants/systemPromptSections.ts`System prompt 组装
- `entrypoints/cli.tsx`:编译期条件编译示例
---
## 后记
这 6 篇文档覆盖了 Claude Code 最核心的 agentic 设计决策。还有很多其他话题Bridge 模式、Voice 输入、Plugin 系统等),但这些是最重要的基础。
如果你想进一步了解,建议:
1. 读完这 6 篇
2. 打开 `query.ts``Tool.ts`,对照源代码
3. 运行 Claude Code`--verbose` flag 看内部日志
4. 探索 `tools/AgentTool/` 的源代码
祝学习愉快!