Claude Code 内部源码分析:Agent Loop、四级压缩管道
以 Claude Code 源码(~512,664 行 TypeScript)逆向工程为线索,拆解一个生产级 harness 的全部关键机制。
原始资料:https://wanlanglin.github.io/-awesome-cc-harness/zh/(该指南基于 2025 年中源码;Claude Code 每周发版,2026 年已迭代至 v2.1.x,文末附 2026 年新机制补录)
核心命题
“The model is the agent. The code is the harness. Build great harnesses. The agent will do the rest.”
一、架构全景
技术栈
| 层 | 选择 |
|---|---|
| Runtime | Bun(TypeScript 原生) |
| UI | React + Ink(终端组件) |
| CLI | Commander.js |
| Schema | Zod v4 |
| 搜索 | ripgrep |
| 状态 | 自定义 Zustand-like Store + React Context |
规模
- ~1,884 文件
- 512,664 行代码(分析时版本)
- 43+ 工具
- 100+ Slash 命令
- 80+ React Hooks
- 144+ UI 组件
- 25+ Hook 事件(持续增长中)
六层 Harness 基础设施
- 工具系统(43+)
- 权限模型(5 基础模式 + auto + bubble)
- Hooks 系统(25+ 事件 × 4 类型)
- 沙盒(文件 + 网络 + 进程隔离)
- 上下文工程(
CLAUDE.md+ 记忆 + 四级压缩) - 设置与配置(7 级层级)
二、Harness骨架Agent Loop
位置:src/query.ts 的 queryLoop() 函数
基本架构
- Async Generator:
yield每一个中间事件,支持流式渲染 - 无限循环 + 显式退出:仅
return Terminal时退出 - 单一 State 对象:伪不可变语义,每次迭代解构后整体重赋值
State 类型(10 个字段)
type State = {
messages: Message[]
toolUseContext: ToolUseContext
autoCompactTracking: AutoCompactTrackingState | undefined
maxOutputTokensRecoveryCount: number
hasAttemptedReactiveCompact: boolean
maxOutputTokensOverride: number | undefined
pendingToolUseSummary: Promise<ToolUseSummaryMessage | null> | undefined
stopHookActive: boolean | undefined
turnCount: number
transition: Continue | undefined
}
7 个 Continue 站点(错误恢复)
| 站点 | 触发条件 | 恢复动作 |
|---|---|---|
| 1 | token 超阈值 | autocompact → 新消息 → continue |
| 2 | API 返回 prompt-too-long(413) | context-collapse → reactive compact |
| 3 | 模型输出截断(max_output_tokens) | 升级 8k→64k → 多轮重试(最多 3 次) |
| 4 | FallbackTriggeredError | 切换模型 → 重试请求 |
| 5 | Stop Hook blocking | 注入 Hook 消息 → continue |
| 6 | ImageSizeError/ImageResizeError | 反应式压缩(移除图片)→ continue |
| 7 | 正常工具执行完成 | 收集结果 → 更新状态 → continue |
10 种终止原因
completed | blocking_limit | stop_hook_prevented | aborted_streaming | aborted_tools | hook_stopped | max_turns | prompt_too_long | image_error | model_error
复杂度对比
| 实现 | 行数 |
|---|---|
| 最小实现 | ~30 行 |
| 生产实现 | ~1,800+ 行 |
| 倍数 | 60 倍 |
仅关注代码密度
三、四级压缩管道
| 级别 | 名称 | 机制 | 成本 | 延迟 |
|---|---|---|---|---|
| Level 1 | Snip Compact | 历史截断,追踪释放 token 数 | 极低 | ~0ms |
| Level 2 | Microcompact | 3 轮前工具结果替换为 [Previous: used {tool}],缓存结果 |
低 | ~1ms |
| Level 3 | Context-Collapse | 读时投射(不修改消息数组),按粒度排空可折叠上下文 | 中 | ~5ms |
| Level 4 | Autocompact | 超过默认阈值(约 50k tokens,可配置,随模型上下文窗口变大而调整)时触发,LLM 全对话摘要,保存完整转录到磁盘 | 高 | ~2s |
执行顺序
snip → micro → context-collapse → auto
各级互不排斥,可组合运行。
关键设计细节
- Snip 释放的 token 数必须传递给 Autocompact 的阈值检查
- Context-Collapse 不修改任何数据结构,完全可逆
- Microcompact 的边界消息延迟到 API 响应后(此时才知道 cache 命中情况)
taskBudgetRemaining跨压缩边界追踪预算
四、工具系统
位置:src/Tool.ts(接口)、src/tools.ts(注册表)
Tool 接口(核心字段)
type Tool<Input, Output> = {
// 核心标识
name: string;
aliases?: string[];
userFacingName(): string;
// Schema & 验证
inputSchema: ZodType<Input>;
outputSchema?: ZodType<Output>;
validateInput(input): Promise<ValidationResult>;
// 执行
call(args, context, canUseTool, parentMessage, progressCallback?): Promise<ToolResult>;
// 权限 & 安全
checkPermissions(args, context): Promise<PermissionDecision>;
isConcurrencySafe(args): boolean; // 能否并行
isDestructive(args): boolean; // 不可逆?
isReadOnly(): boolean;
// 行为
isEnabled(): boolean; // 特性门控
shouldDefer: boolean; // 延迟加载
alwaysLoad: boolean; // 永不延迟
// 渲染
renderToolUseMessage(args): ReactElement;
renderToolResultMessage(result): ReactElement;
}
工具注册表机制
- 始终加载:AgentTool, BashTool, FileReadTool, FileEditTool, FileWriteTool, WebFetchTool 等
- 特性门控:通过
feature()函数条件加载(如 SleepTool, ScheduleCronTool, TeamCreateTool) - Dead Code Elimination:Bun 的
bun:bundle在编译时评估feature()调用,false 的工具被 tree-shake 移除
工具池组装(Cache Stability 设计)
内置工具按名称排序形成稳定的缓存前缀,MCP 工具增减时前缀不变,Anthropic API 的 prompt cache 不失效。
工具执行生命周期(7 步管道)
1. Zod Schema 验证(结构验证)
2. tool.validateInput()(业务逻辑验证)
3. PreToolUse Hook(可批准/阻止/修改输入/注入上下文)
4. 权限解析(deny规则 → ask规则 → 模式检查 → 分类器)
5. Sandbox 包装(仅 BashTool,wrapWithSandbox())
6. tool.call()(实际执行)
7. PostToolUse Hook(审计日志/输出修改)
核心安全不变量:deny > settings rules > hook allow。即使 Hook 批准操作,settings.json 中的 deny 规则仍阻止它。
工具执行编排(两种模式)
模式 1: StreamingToolExecutor(默认)
- 模型流式生成时,识别到完整
tool_useJSON 块立即排队执行 - 模型还在生成第二个工具调用时,第一个已在运行
- 子 AbortController:一个 Bash 工具出错时兄弟子进程立即死亡,但不中止父级查询
模式 2: runTools()(回退)
partitionToolCalls()工具分区算法:isConcurrencySafe=true(只读工具 Read/Glob/Grep)→ 并发执行isConcurrencySafe=false(写入工具 Write/Edit/Bash)→ 串行执行
- 上下文修改器(
contextModifier)被收集并延迟应用,确保并发期间上下文一致性
工具分类示例
| 类别 | 工具 | 特性 |
|---|---|---|
| 核心 I/O | BashTool, FileReadTool, FileWriteTool, FileEditTool, GlobTool, GrepTool | 始终加载 |
| Agent | AgentTool, SendMessageTool, TeamCreate/DeleteTool | 子 Agent 管理 |
| 工作流 | WebFetchTool, WebSearchTool, NotebookEditTool | 外部资源 |
| 任务 | TaskCreate/Update/List/Output/StopTool | 任务管理 |
| 计划 | EnterPlanModeTool, ExitPlanModeTool, TodoWriteTool | 计划模式 |
| 高级 | ScheduleCronTool, SleepTool, MonitorTool, REPLTool | 特性门控 |
| MCP | MCPTool, ListMcpResourcesTool, ReadMcpResourceTool | MCP 协议 |
| 搜索 | ToolSearchTool | 延迟工具发现 |
工具延迟加载
shouldDefer: true的工具第一轮不加载到模型上下文- 通过 ToolSearchTool 按需发现
- 第一轮只加载核心工具(~15 个),节省 token 预算
FileEditTool 智能引号匹配
三阶段查找算法:
- 精确匹配
- 引号规范化匹配(智能引号 ↔ 直引号)
- 返回文件中的原始字符串(保留原始引号风格)
替换时使用 () => replace 而非直接传字符串,防止 $1/$& 等特殊模式被误解释。
五、权限模型
权限模式:5 基础 + auto + bubble(共 7 种)
type PermissionMode =
| 'default' // 敏感操作始终询问
| 'acceptEdits' // 自动批准文件编辑,其他询问
| 'bypassPermissions' // 自动批准一切(危险)
| 'dontAsk' // 自动拒绝需要询问的操作
| 'plan' // 计划模式(只读+计划文件)
| 'auto' // AI 分类器自动审批(2026 年已主流化,不再视为实验特性)
| 'bubble'; // 冒泡到父 Agent(子 Agent 用)
三级规则系统
type PermissionRule = {
source: PermissionRuleSource;
ruleBehavior: 'allow' | 'deny' | 'ask';
ruleValue: {
toolName: string; // "Bash", "Write", "mcp__server"
ruleContent?: string; // "git *", "*.ts", "prefix:npm *"
};
};
规则语法示例:
Bash(git *)— 允许所有 git 命令Write(*.ts)— 允许写入 TypeScript 文件mcp__*— 拒绝所有 MCP 服务器工具Bash(rm -rf *)— 拒绝 rm -rf 命令
六层纵深防御模型
| 层级 | 类型 | 机制 | 绕过率 |
|---|---|---|---|
| 1 | 软约束 | CLAUDE.md 指导性约束 | ~5% |
| 2 | 中等约束 | Permission Rules (settings.json allow/deny/ask) | 可配置 |
| 3 | 中等约束 | Hooks (PreToolUse 脚本检查) | 可配置 |
| 4 | 中等约束 | YOLO Classifier (独立 AI 模型审查) | 可配置 |
| 5 | 硬约束 | Sandbox (操作系统级文件/网络隔离) | 极低 |
| 6 | 硬约束 | Hardcoded Denials (不可覆盖) | 0% |
6 层叠加后累积绕过概率:0.05^6 ≈ 1.56×10⁻⁸(约 0.0000016%)。注意:这是量级示意,实际各层并不统计独立,且单层"5% 绕过率"本身无官方出处。
7 级设置优先级(从高到低)
- CLI 参数 (
cliArg) - 会话命令 (
command) —/permissions命令 - Flag 设置 (
flagSettings) - 策略设置 (
policySettings) — 组织策略 - 本地设置 (
localSettings) —.claude/settings.json.local - 项目设置 (
projectSettings) —.claude/settings.json - 用户设置 (
userSettings) —~/.claude/settings.json
加上企业管理设置(MDM):/managed/managed-settings.json + Drop-in 覆盖 + macOS plutil / Windows Registry
权限决策管道
工具调用请求
│
├─ 1a. 整个工具被 Deny? → 拒绝
├─ 1b. 整个工具被 Ask? → 沙盒可自动允许? 否 → ask
├─ 1c. tool.checkPermissions()
├─ 1d. 工具实现拒绝? → 拒绝
├─ 1e. 需要用户交互? → ask
├─ 1f. 内容级 ask 规则? → 必须尊重(即使 bypassPermissions)
├─ 1g. 安全检查(.git/.claude/.vscode/shell 配置)? → 必须提示
├─ 2a. bypassPermissions 模式? → 允许
├─ 2b. 整个工具被 Allow? → 允许
└─ 3. passthrough → ask → 模式转换
├─ dontAsk → deny
├─ auto → YOLO 分类器
└─ default → 用户提示
关键设计
bypassPermissions模式下,内容级 ask 规则和安全检查仍必须提示hasAttemptedReactiveCompact标志在 Stop Hook 恢复中被保留而非重置(防止无限循环)- YOLO 分类器(auto 模式)分两阶段:fast stage(50-200ms,约 $0.001)和 thinking stage(500ms-2s,约 $0.01)。注:以上成本为源码分析的估算值,非官方公布数据
权限决策分布
| 路径 | 占比 | 延迟 |
|---|---|---|
| Rule-based Allow | ~40% | <1ms |
| Mode-based Allow | ~20% | <1ms |
| Safe-tool Allowlist | ~15% | <1ms |
| Tool checkPermissions Allow | ~10% | 1-5ms |
| YOLO Classifier (fast) | ~8% | 50-200ms |
| YOLO Classifier (thinking) | ~3% | 500ms-2s |
| User Prompt | ~3% | 1-30s |
| Deny | ~1% | varies |
六、Hooks 系统
位置:src/utils/hooks.ts(执行引擎)、src/utils/hooks/(配置管理)
26 个 Hook 事件(注:2025 年中版本的)
覆盖 Agent 生命周期的所有关键节点:UserPromptSubmit、PreToolUse、PostToolUse、Stop、SessionEnd 等。2026 年已持续新增事件(见文末补录)。
四种 Hook 类型
- 同步 Hook:阻塞执行,返回前等待完成
- 异步 Hook:不阻塞,后台执行
- 条件 Hook:通过
if字段条件匹配 - 内部回调 Hook:快速路径(~1.8µs/call,比外部 Hook 快 70%)
Hook 输入/输出协议
- Hook 可修改工具输入(
hookUpdatedInput) - Hook 可注入上下文
- Hook 可修改 MCP 工具输出(
updatedMCPToolOutput) - PreToolUse Hook 的
allow不绕过 deny 规则
核心安全不变量
deny > settings rules > hook allow
即使第三方 MCP 服务器提供了返回 allow 的 PreToolUse Hook,settings.json 中的 deny 规则仍然阻止操作。
七、上下文工程
核心原则
“Agent 无法在上下文中访问的信息不存在”
上下文预算分配
上下文窗口分为:系统提示 + 工具定义 + CLAUDE.md + MCP 工具 + 记忆 + 对话历史 + 工具结果
CLAUDE.md — 项目级持久上下文
- 静态上下文:仓库文档、设计文档
- 精心设计的 CLAUDE.md 文件只需 30 分钟,可将 Agent 在特定项目上表现提升 20-40%(数据出自原逆向指南,建议以官方实测为准)
系统提示构建管道
base + tools + CLAUDE.md + MCP + memory
消息规范化管道(normalizeMessagesForAPI)
- 连续用户消息合并(Bedrock 不支持多个连续 user 消息)
- PDF/图片错误内容剥离(防止重复发送)
- 工具名称规范化(别名 → 正式名)
- Tool Reference 处理(ToolSearch 启用时保留引用块)
- 虚拟消息过滤(REPL 内部工具调用的显示消息不发送给 API)
记忆系统
- 位置:
src/memdir/ - 持久记忆目录系统
- 预取机制:
using pendingMemoryPrefetch = startRelevantMemoryPrefetch(...) - 使用 TC39 的
using关键字确保生成器退出时自动清理
四级压缩策略
(见上面第三节)
八、子代理系统
位置:src/tools/AgentTool/、src/coordinator/
Agent Tool
- 子 Agent 生成工具,作为主 Agent 的代理
- 每个子 Agent 有独立的上下文和工具池
Agent 类型
- 探索型 Agent(Explore)
- 通用 Agent
- 自定义 Agent(用户定义)
子 Agent 生成流程
- 独立的 ToolUseContext
- 独立的 AbortController
- 权限模式可
bubble(冒泡到父 Agent)
Coordinator / Swarm 系统
- 多 Agent 编排(Agent Teams,2026 年已正式发布:支持 tmux/iTerm2 分屏 teammate、跨会话 mailbox 消息、
teammateMode设置,不再视为实验特性) - TeamCreate/TeamDelete 工具
- 早期版本通过
feature('COORDINATOR_MODE')特性门控
任务系统
TaskCreate/Update/List/Output/Stop 工具,支持任务的创建、更新、监控和终止。
Worktree 隔离
- EnterWorktreeTool / ExitWorktreeTool
- Git worktree 隔离,每个子 Agent 在独立的 Git 工作树中操作
- 防止并发文件修改冲突
子 Agent 隔离开销与收益
子 Agent 的独立上下文避免污染主 Agent,但有一定的初始化开销和上下文传递成本。
九、MCP 集成
位置:src/services/mcp/
- 6 种传输协议:stdio、SSE、HTTP、WebSocket 等(注:官方 MCP 规范的标准传输为 stdio 与 HTTP 两种,"6 种"为源码中可见的传输封装口径,引用时建议保守表述)
- MCP 配置:支持多服务器配置
- MCP 工具执行:通过 MCPTool 调用,与内置工具统一管理
- 连接生命周期:包含重连、超时、健康检查
- 配置去重策略:避免重复加载相同 MCP 服务器
- MCP Skills 发现:自动发现 MCP 服务器提供的 Skills
- 工具池集成:MCP 工具与内置工具合并,按名称排序,内置优先去重
十、沙盒与安全
位置:src/utils/sandbox/
三大限制维度
- 文件隔离:限制可访问的路径
- 网络隔离:限制网络访问
- 进程隔离:限制可创建的子进程
路径解析(Claude Code 特有约定)
Claude Code 内部的路径解析规则,处理相对路径、符号链接等。
权限规则到沙盒配置的转换
settings.json 中的权限规则自动转换为沙盒限制配置。
dangerouslyDisableSandbox
- 特定命令可绕过沙盒(如需要完整系统访问的工具)
- 即使
bypassPermissions模式下,绕过沙盒的命令仍需遵守 ask 规则
十一、设置与配置
位置:src/utils/settings/
settings.json 结构
支持权限规则、Hook 配置、MCP 配置、沙盒设置、特性门控等。
层级化加载(7 级 + 企业管理)
(见权限模型部分的 7 级优先级)
Schema 验证
使用 Zod v4 进行严格的 Schema 验证。
设置合并算法
深度合并策略,高优先级覆盖低优先级,数组按规则合并。
Managed Settings 的 Drop-in 模式
/managed/managed-settings.d/*.json 支持多个 Drop-in 文件,按字母序加载覆盖。
防御性缓存克隆
设置读取时进行防御性克隆,防止运行时修改影响缓存。
十二、Agent Loop 设计哲学总结
- 弹性优于刚性:7+ 个 continue 站点允许从几乎任何错误中恢复
- 渐进式降级:每种错误先尝试最轻量恢复,逐步升级
- 流式优先:Async Generator 使每个中间状态都可观察
- 状态显式化:单一 State 对象,无隐式全局状态
- 可观测性内建:每个恢复点都有 analytics 和 profiling
核心洞察:生产级 Agent Loop 的复杂性不在于"循环本身",而在于"循环失败时如何优雅恢复"。30 行实现基本循环,1800+ 行处理所有边界情况——这中间的差距就是 Harness Engineering 的全部价值。
十三、Harness Engineering 三大支柱(Claude Code)
┌────────────────────────────────────────────┐
│ Context Engineering (45%) │
│ 静态上下文 + 动态上下文 + 上下文压缩 │
│ ├─ CLAUDE.md / AGENTS.md │
│ ├─ 日志 / Git 状态 / CI 状态 │
│ └─ 四级压缩管道 + 按需加载 + 记忆系统 │
├────────────────────────────────────────────┤
│ Architectural Constraints (35%) │
│ 权限模型 + 工具约束 + 安全边界 │
│ ├─ 5 种模式,7 级规则层级,AI 分类器 │
│ ├─ Schema 验证,并发安全标记,延迟加载 │
│ └─ 沙盒隔离,硬编码拒绝,纵深防御 │
├────────────────────────────────────────────┤
│ Entropy Management (20%) │
│ 定期清理 + 约束验证 + 性能监控 │
│ ├─ 死代码检测,文档一致性 │
│ ├─ 依赖审计,模式强制 │
│ └─ 覆盖率守卫,回归检测 │
└────────────────────────────────────────────┘
ROI 定量证据
| 优化方式 | Terminal Bench 提升 |
|---|---|
| 仅模型优化 | +3-5% |
| 仅 Harness 优化 | +14%(LangChain 案例 52.8%→66.5%) |
| 两者结合 | +18-20% |
附:2026 年新机制补录
- Dynamic Workflows(动态工作流):2026 年最大机制变革——让 Claude 创建一个 workflow,在后台跨数十到数百个 agent 编排工作;配套
/workflows视图、Workflow工具与agent({schema})结构化输出。 - Hook 事件持续新增:2026 年已新增
DirectoryAdded(2.1.219)、PreCompact、PostToolUseFailure、ConfigChange、TaskCreated等事件,总数已显著超过 26。 - 子代理配额:嵌套深度默认放开到 3(曾为 1),每会话子代理上限 200、并发上限 20;
Task工具的mode参数已废弃(2.1.212),子代理默认继承父会话权限模式。 - Sandbox 细分:新增
sandbox.network.strictAllowlist(白名单外主机直接拒绝)与sandbox.filesystem.disabled(跳过文件隔离、只保留网络出口控制)。 - Auto mode 正式化:分类器默认 Sonnet 5(2.1.210),Bedrock/Vertex/Foundry 无需 opt-in(2.1.207),并支持
settings.autoMode.hard_deny硬拒绝规则。
参考来源
- Claude Code 官方 CHANGELOG:https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md
- Claude Code 官方文档(2026 年起文档域名迁移至 code.claude.com):https://code.claude.com/docs/en/overview
- 逆向工程指南原文:https://wanlanglin.github.io/-awesome-cc-harness/zh/