摘要
Claude Code 是一个约 1884 个 TypeScript 文件、超过 50 万行代码的生产级 CLI Agent 系统。本文基于公开资料,从架构概览、核心循环、工具系统、权限机制、子代理架构、上下文管理、MCP 集成到 12 层渐进式安全带机制,全面剖析其设计精髓。
一、项目概览
1.1 规模数据
| 维度 | 数据 |
|---|---|
| 源文件 | ~1,884 个 (.ts/.tsx) |
| 代码行数 | ~512,664 行 |
| 最大单文件 | query.ts (~785KB) |
| 内置工具 | 40+ 个 |
| 斜杠命令 | 80+ 个 |
| 运行时 | Bun(编译为 Node.js >= 18 bundle) |
1.2 核心依赖
- 运行时:Bun → Node.js bundle
- 终端 UI:React + Ink
- API 客户端:Claude API(流式)
- MCP 协议:模型上下文协议集成
- 遥测:GrowthBook + Datadog
二、架构全景图
text
┌─────────────────────────────────────────────────────────────┐
│ 入口层 │
│ cli.tsx ──> main.tsx ──> REPL.tsx (交互式) │
│ └──> QueryEngine.ts (headless/SDK) │
└─────────────────────────────┬───────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 查询引擎 │
│ submitMessage(prompt) ──> AsyncGenerator<SDKMessage> │
│ ├── fetchSystemPromptParts() → 组装系统提示词 │
│ ├── processUserInput() → 处理 /命令 │
│ └── query() → 主代理循环 │
│ ├── StreamingToolExecutor → 并行工具执行 │
│ ├── autoCompact() → 上下文压缩 │
│ └── runTools() → 工具编排 │
└─────────────┬───────────────┬───────────────┬───────────────┘
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 工具系统 │ │ 服务层 │ │ 状态层 │
│ 40+工具 │ │ API/MCP │ │ Store │
└──────────┘ └──────────┘ └──────────┘
三、核心代理循环
3.1 最小循环
这是 Claude Code 最基础的代理循环,所有高级特性都构建于此之上:
text
用户输入 → messages[] → Claude API → 响应
│
stop_reason == "tool_use"?
/ \
是 否
│ │
执行工具 返回文本
追加结果
循环回退
3.2 核心文件职责
| 文件 | 行数 | 职责 |
|---|---|---|
query.ts | ~785KB | 主代理循环,API 调用编排 |
QueryEngine.ts | - | SDK/headless 查询生命周期 |
main.tsx | 4,683 | REPL 引导程序 |
Tool.ts | - | 工具接口 + buildTool 工厂 |
四、工具系统
4.1 工具接口设计
每个工具实现完整的生命周期:
typescript
buildTool(definition) → Tool<Input, Output, Progress>
// 每个工具实现:
- validateInput() // 尽早拒绝无效参数
- checkPermissions() // 工具特定的授权检查
- call() // 执行并返回结果
// 能力特性:
- isEnabled() // 功能开关检查
- isConcurrencySafe() // 是否可并行运行
- isReadOnly() // 是否无副作用
- isDestructive() // 是否不可逆操作
// 渲染 (React/Ink):
- renderToolUseMessage() // 输入显示
- renderToolResultMessage() // 输出显示
- renderToolUseProgressMessage() // 加载状态
4.2 工具分类
| 类别 | 工具示例 |
|---|---|
| 文件操作 | FileRead, FileEdit, FileWrite, NotebookEdit |
| 搜索发现 | GlobTool, GrepTool, ToolSearchTool |
| 执行 | BashTool, PowerShellTool |
| 网络请求 | WebFetchTool, WebSearchTool |
| 代理任务 | AgentTool, SendMessageTool, TeamCreateTool |
| 计划工作流 | EnterPlanModeTool, TodoWriteTool |
| 技能扩展 | SkillTool, ScheduleCronTool |
五、权限架构
5.1 权限检查流程
text
工具调用请求
│
▼
validateInput() ──→ 在任何权限检查前拒绝无效输入
│
▼
PreToolUse Hooks ──→ 用户定义的 shell 命令
│ (批准/拒绝/修改输入)
▼
权限规则 (Permission Rules)
├── alwaysAllowRules → 自动允许
├── alwaysDenyRules → 自动拒绝
└── alwaysAskRules → 总是询问
│
▼ (无规则匹配)
交互式提示 ──→ 用户选择:允许一次/总是允许/拒绝
│
▼
checkPermissions() ──→ 工具特定逻辑(路径沙盒等)
│
▼
已批准 → tool.call()
5.2 权限模式
- default:标准权限检查
- plan:计划模式,仅读操作
- bypass:绕过权限(需显式启用)
六、子代理与多代理架构
6.1 代理类型
text
主代理 (MAIN AGENT)
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌─────────────┐
│FORK代理 │ │ 远程代理 │ │进程内队友 │
├─────────┤ ├──────────┤ ├─────────────┤
│Fork进程 │ │ 网桥会话 │ │ 同一进程 │
│共享缓存 │ │ 完全隔离 │ │ 异步上下文 │
│全新msgs[]│ │ │ │ 共享状态 │
└─────────┘ └──────────┘ └─────────────┘
6.2 生成模式
| 模式 | 说明 |
|---|---|
| default | 进程内,共享对话 |
| fork | 子进程,全新 messages[],共享文件缓存 |
| worktree | 隔离的 git worktree + fork |
| remote | 通过网桥连接远程容器 |
6.3 集群模式(Swarm)
text
领导代理 (Lead Agent)
├── 队友 A ──> 认领任务 1
├── 队友 B ──> 认领任务 2
└── 队友 C ──> 认领任务 3
共享:任务看板、消息收件箱
隔离:messages[]、文件缓存、cwd
七、上下文管理(压缩系统)
7.1 上下文窗口预算
text
┌─────────────────────────────────────────┐
│ 系统提示词 (工具、权限、CLAUDE.md) │
├─────────────────────────────────────────┤
│ 对话历史 │
│ ┌─────────────────────────────────────┐ │
│ │ [旧消息的压缩摘要] │ │
│ │ [compact_boundary 标记] │ │
│ │ [最近的消息 — 完整保真度] │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ 当前轮次 (用户 + 助手响应) │
└─────────────────────────────────────────┘
7.2 三种压缩策略
| 策略 | 说明 |
|---|---|
| autoCompact | token 超阈值时触发,通过 API 总结旧消息 |
| snipCompact | 移除僵尸消息和过时标记 |
| contextCollapse | 重构上下文提高效率 |
八、MCP(模型上下文协议)集成
text
MCPConnectionManager.tsx
├── 服务器发现(来自 settings.json)
│ ├── stdio → 生成子进程
│ ├── sse → HTTP EventSource
│ ├── http → 流式 HTTP
│ ├── ws → WebSocket
│ └── sdk → 进程内传输
├── 客户端生命周期
│ ├── connect → initialize → list tools
│ ├── 通过 MCPTool 包装器调用工具
│ └── disconnect / 退避重连
├── 身份验证
│ ├── OAuth 2.0 流程
│ ├── 跨应用访问 (XAA)
│ └── 通过 headers 传递 API key
└── 工具注册
├── mcp__<server>__<tool> 命名约定
├── 来自 MCP 服务器的动态 schema
└── 资源列表 (ListMcpResourcesTool)
九、12 层渐进式安全带机制
Claude Code 展示了生产级 AI Agent 在基础循环之上所需的 12 层机制:
| # | 机制 | 核心实现 | 目的 |
|---|---|---|---|
| 01 | 核心循环 | query.ts while-true | 一个循环 + Bash 就是全部所需 |
| 02 | 工具调度 | Tool.ts + tools.ts 调度映射 | 添加一个工具 = 添加一个处理程序 |
| 03 | 计划 | EnterPlanModeTool + TodoWriteTool | 先列步骤再执行,使完成率翻倍 |
| 04 | 子代理 | AgentTool + forkSubagent.ts | 拆分大任务,每个子任务清理上下文 |
| 05 | 按需知识 | SkillTool + memdir/ | 需要时加载,而不是塞入系统提示词 |
| 06 | 上下文压缩 | services/compact/ 三层策略 | 上下文满了就腾出空间 |
| 07 | 持久化任务 | TaskCreate/Update/Get/List | 大目标→小任务→磁盘,状态跟踪 |
| 08 | 后台任务 | DreamTask + LocalShellTask | 后台执行慢操作,代理继续思考 |
| 09 | 代理团队 | TeamCreate/Delete + InProcessTeammateTask | 任务太大就委派给队友 |
| 10 | 团队协议 | SendMessageTool | 请求-响应模式驱动所有协商 |
| 11 | 自主代理 | coordinator/coordinatorMode.ts | 队友自己扫描并认领任务 |
| 12 | 工作树隔离 | EnterWorktreeTool + ExitWorktreeTool | 每个人在自己的目录中工作 |
十、关键设计模式
| 模式 | 位置 | 目的 |
|---|---|---|
| AsyncGenerator 流式传输 | QueryEngine, query() | API 到消费者的全链路流式 |
| Builder + Factory | buildTool() | 为工具定义提供安全默认值 |
| 品牌类型 (Branded Types) | SystemPrompt, asSystemPrompt() | 防止字符串/数组混淆 |
| 功能开关 + DCE | feature() from bun:bundle | 编译时死代码消除 |
| 辨识联合 (Discriminated Unions) | Message 类型 | 类型安全的消息处理 |
| 观察者 + 状态机 | StreamingToolExecutor | 工具执行生命周期跟踪 |
| 快照状态 | FileHistoryState | 文件操作的撤销/重做 |
| 环形缓冲区 | 错误日志 | 长会话的有限内存 |
| 即发即弃写入 | recordTranscript() | 保持顺序的非阻塞持久化 |
| 延迟 Schema | lazySchema() | 延迟 Zod 评估以提高性能 |
| 上下文隔离 | AsyncLocalStorage | 共享进程中每个代理的上下文 |
十一、会话持久化
11.1 存储结构
text
~/.claude/projects/<hash>/sessions/
└── <session-id>.jsonl # 仅追加日志
11.2 消息类型
{"type":"user",...}{"type":"assistant",...}{"type":"progress",...}{"type":"system","subtype":"compact_boundary",...}
11.3 恢复流程
text
getLastSessionLog() → 解析 JSONL → 重建 messages[]
├── --continue → cwd 中的最后一次会话
├── --resume <id> → 特定会话
└── --fork-session → 新 ID,复制历史
十二、功能开关系统
12.1 编译时 DCE
typescript
feature('FLAG_NAME') → true → 包含在 bundle
→ false → 从 bundle 剥离
12.2 观察到的标志
| 标志 | 功能 |
|---|---|
COORDINATOR_MODE | 多代理协调器 |
HISTORY_SNIP | 激进历史修剪 |
CONTEXT_COLLAPSE | 上下文重构 |
VOICE_MODE | 语音输入/输出 |
KAIROS | 推送通知、文件发送 |
PROACTIVE | 睡眠工具、主动行为 |
WEB_BROWSER_TOOL | 浏览器自动化 |
MONITOR_TOOL | MCP 监控工具 |
12.3 运行时门控
process.env.USER_TYPE === 'ant'→ 内部功能- GrowthBook feature flags → 运行时 A/B 实验
十三、桥接层(远程/Desktop 集成)
text
Claude Desktop/Web Claude Code CLI
│ │
├─── HTTP ──→ bridgeMain.ts ──┤
│ │ │
│ ├── 会话管理器 │
│ ├── 生成 CLI │
│ ├── 轮询状态 │
│ ├── 中继消息 │
│ └── 容量唤醒 │
│ │
协议: 退避策略:
├── JWT 身份验证 ├── 连接: 2s→2m
├── 工作密钥交换 └── 生成: 500ms→30s
├── 会话生命周期 (create/run/stop)
└── 令牌刷新调度器
十四、总结与启示
14.1 架构核心洞察
- 简单核心,复杂外围:核心代理循环极其简单(一个 while-true + API 调用 + 工具执行),所有复杂性都封装在外围的安全带机制中。
- 渐进式能力扩展:从最简单的 Bash 执行开始,逐步添加计划、子代理、团队、工作树隔离等能力,每一层都是独立的、可组合的。
- 工具优先设计:40+ 工具每个都实现完整的生命周期(验证、权限、执行、渲染),工具系统是整个架构的基石。
- 类型安全第一:品牌类型、辨识联合、延迟 schema 等模式确保编译时错误捕捉。
- 持久化无处不在:会话、任务、消息全部持久化到磁盘,支持恢复、fork、继续等操作。
14.2 可借鉴的设计模式
- AsyncGenerator 全链路流式:从 API 到 UI 的完整流式传输
- 权限规则引擎:三层规则(alwaysAllow/Deny/Ask)+ 交互式提示
- 子代理隔离:每个子代理独立 messages[],避免污染主对话
- 上下文压缩:总结 + 修剪 + 重构的三层策略
- 功能开关 + DCE:编译时死代码消除,生产包精简
14.3 学习价值
对于构建生产级 AI Agent 的开发者,Claude Code 提供了:
- 完整的 Agent 循环实现参考
- 生产级工具系统设计
- 权限与安全机制的最佳实践
- 多代理协作的架构模式
- 上下文管理的实战方案