跳转至

第二章:Cluade Code架构全景

在上一章我们建立了理论框架。从这一章开始,我们将用一个真实的、正在生产环境运行的系统来验证这些理论。这个系统就是 Claude Code——Anthropic 的官方 AI 编码助手 CLI,拥有超过 50 万行 TypeScript 代码,是目前最完整的生产级 Agent Harness 参考实现。

为什么选择 Claude Code?因为它不是一个教学项目——它是每天被数以万计的开发者使用的真实产品。它的每一个设计决策背后,都有真实的用户痛点和工程取舍。通过逆向工程它的架构,我们能学到”课本上不会写”的实战智慧。

1. 技术栈

类别 技术
Runtime Bun(TypeScript 原生,高性能)
Language TypeScript(严格模式)
UI Framework React + Ink(终端组件)
CLI Parser Commander.js(@commander-js/extra-typings)
Schema Validation Zod v4
Search Engine ripgrep(通过 BashTool 调用)
API Client @anthropic-ai/sdk
Protocols MCP SDK, LSP
State Management 自定义 Zustand-like Store + React Context
Telemetry OpenTelemetry + gRPC
Feature Flags GrowthBook + Bun bun:bundle
Auth OAuth 2.0, JWT, macOS Keychain

图1:Cluade Code各目录代码行数分布

图1:Cluade Code各目录代码行数分布

我们来看下 Claude Code 各个目录的代码行数分布,tools/utils/ 是最大的两个目录,合计占约 32% 的代码量,反映出工具系统和基础设施工具是 Harness 的核心。

图2:各类别模块数量

图2:各类别模块数量

再看一下各类别模块数量,components(144)和 commands(101)数量最多,体现了 Claude Code 作为终端 UI 应用的特征。

2. 规模

  • ~1,884 TypeScript/TSX 文件
  • 512,664 行代码
  • 43+ 工具
  • 100+ Slash 命令
  • 80+ React Hooks
  • 144+ UI 组件
  • 22+ 服务模块
  • 26+ Hook 事件

3. 目录结构

src/
├── main.tsx                    # 入口点,CLI 引导(803 KB)
├── query.ts                    # 核心 Agent 循环(68 KB)
├── QueryEngine.ts              # LLM 查询引擎(46 KB)
├── Tool.ts                     # Tool 基础接口(29 KB)
├── tools.ts                    # Tool 注册表(25 KB)
├── Task.ts                     # 任务类型定义
├── commands.ts                 # 命令注册
├── tools/                      # 43 个工具目录
   ├── BashTool/              # Shell 命令执行
   ├── FileReadTool/          # 文件读取
   ├── FileWriteTool/         # 文件创建
   ├── FileEditTool/          # 部分文件修改
   ├── GlobTool/              # 文件模式匹配
   ├── GrepTool/              # ripgrep 内容搜索
   ├── AgentTool/             # 子 Agent 生成
   ├── SkillTool/             # Skill 执行
   ├── MCPTool/               # MCP 服务器调用
   ├── WebFetchTool/          # URL 内容抓取
   ├── WebSearchTool/         # 网页搜索
   └── ...                    # 更多工具
├── commands/                   # ~101 个命令目录
   ├── commit/                # Git 提交
   ├── review/                # 代码审查
   ├── mcp/                   # MCP 管理
   ├── skills/                # Skill 管理
   └── ...
├── components/                 # 144+ React/Ink 终端组件
├── hooks/                      # 80+ 自定义 React Hooks
├── services/                   # 22 个服务子目录
   ├── api/                   # Anthropic API 客户端
   ├── mcp/                   # MCP 协议连接
   ├── oauth/                 # OAuth 认证
   ├── lsp/                   # 语言服务器协议
   ├── compact/               # 对话压缩
   ├── plugins/               # 插件加载
   └── ...
├── utils/                      # 33+ 子目录,100+ 文件
   ├── permissions/           # 权限逻辑
   ├── hooks.ts               # Hook 执行引擎
   ├── hooks/                 # Hook 配置管理
   ├── sandbox/               # 沙盒适配器
   ├── settings/              # 设置管理
   ├── bash/                  # Shell 工具
   ├── memdir/                # 持久记忆目录
   └── ...
├── state/                      # 应用状态管理
├── entrypoints/                # CLI/MCP/SDK 入口
├── bridge/                     # IDE 双向通信
├── coordinator/                # 多 Agent 编排
├── skills/                     # Skill 系统
├── plugins/                    # 插件系统
├── memdir/                     # 记忆目录系统
├── schemas/                    # Zod 验证 Schema
├── types/                      # 类型定义
└── constants/                  # 应用常量

4. 入口点流程

设计哲学:Claude Code 的入口点 main.tsx(803 KB)采用延迟加载策略。重型模块(OpenTelemetry, gRPC, analytics)在需要时才加载,而关键路径(MDM 设置、Keychain)则并行预取,确保启动速度。

flowchart TD
    A["main.tsx 入口"] --> B["并行预取"]
    B --> B1["MDM 设置<br/>(macOS plutil / Windows reg)"]
    B --> B2["Keychain 读取<br/>(OAuth + API key)"]
    B --> B3["API 预连接"]
    B1 & B2 & B3 --> C["Commander.js CLI 解析器"]
    C --> D["preAction Hook"]
    D --> D1["init()"]
    D --> D2["遥测初始化"]
    D --> D3["插件加载"]
    D --> D4["迁移执行"]
    D --> D5["远程设置"]
    D1 & D2 & D3 & D4 & D5 --> E["React/Ink 渲染器"]
    E --> F["交互式 REPL 循环"]

5. 核心数据流全景图

┌─────────────────────────────────────────────────────────────────────
│                    Claude Code 数据流全景                             
│  用户输入 ──→ UserPromptSubmit Hook ──→ Slash Command 解析           
│     │                                                               
│     v                                                               
│  QueryEngine.submitMessage()                                        
│     │                                                               
│     ├─→ 系统提示构建: base + tools + CLAUDE.md + MCP + memory        
│     ├─→ 消息规范化: normalizeMessagesForAPI()                        
│     │   ├─ 重排序 attachment 消息                                    
│     │   ├─ 合并连续 user/assistant 消息                              
│     │   ├─ 剥离 PDF/图片错误的重复内容                               
│     │   ├─ 规范化工具名称(别名→正式名)                             
│     │   └─ 工具搜索引用块处理                                        
│     │                                                                
│     v                                                                
│  queryLoop() [while(true)]                                           
│     │                                                                
│     ├─→ 压缩管道: snip → micro → collapse → auto                     
│     ├─→ API 调用: deps.sample() [流式]                               
│     │                                                                
│     ├─→ 工具执行: StreamingToolExecutor (并发) / runTools (顺序)     
│     │   │                                                            
│     │   ├─→ 工具分区: partitionToolCalls()                           
│     │   │   ├─ isConcurrencySafe=true → 并发执行                     
│     │   │   └─ isConcurrencySafe=false → 串行执行                    
│     │   │                                                            
│     │   └─→ 每个工具:                                                
│     │       ├─ Zod schema 验证                                       
│     │       ├─ tool.validateInput()                                  
│     │       ├─ PreToolUse Hook                                       
│     │       ├─ 权限检查 (rules → mode → classifier)                 
│     │       ├─ Sandbox 包装 (BashTool)                               
│     │       ├─ tool.call() [实际执行]                                
│     │       └─ PostToolUse Hook                                      
│     │                                                               
│     ├─→ 错误恢复: 7 个 continue 站点                                 
│     └─→ Stop Hook → 终止或继续                                       
│  终止 → SessionEnd Hook → 转录保存 → 退出                              
└─────────────────────────────────────────────────────────────────────

6 消息类型系统

Claude Code 定义了丰富的消息类型系统,每种类型在 Agent Loop 中有不同的处理路径:

src/types/message.ts
type Message =
  | UserMessage           // 人类输入(或工具结果)
  | AssistantMessage      // 模型响应(文本 + 工具调用)
  | AttachmentMessage     // 记忆/资源附件
  | SystemMessage         // 系统消息
  | SystemLocalCommandMessage  // 本地工具结果(bash, read 等)
  | ToolUseSummaryMessage // 压缩后的工具历史
  | TombstoneMessage      // 已删除消息标记
  | ProgressMessage       // 流式进度更新

消息规范化(normalizeMessagesForAPI)是一个复杂的管道,处理包括:

  • 连续用户消息合并:Bedrock 不支持多个连续 user 消息,API 层面将它们合并。
  • PDF/图片错误内容剥离:如果上传的 PDF 太大触发错误,后续轮次中自动剥离该内容,防止重复发送。
  • 工具名称规范化:别名(如旧名称)映射到当前正式名称。
  • Tool Reference 处理:当 Tool Search 启用时保留引用块,禁用时剥离。
  • 虚拟消息过滤:REPL 内部工具调用的显示消息不发送给 API。