2026 年 3 月 31 日,Claude Code 的源码因为一个低级失误被公开到互联网上。

这件事在开发者社区的反响比预想中复杂——一方面是安全事故,另一方面,所有人都在偷偷看那些代码。原因很简单:这是目前为止唯一一次,我们能完整窥见一个商用级 AI Agent 的内部架构长什么样。

50 万行 TypeScript,25 个模块,六层权限系统,五层上下文压缩管线。不是实验室 demo,是每天被几十万开发者使用、处理生产代码的工具。

我花了两周时间读这些源码(以及 arXiv 上那篇系统性的分析论文),今天把它拆开来聊。核心观点先放这里:Claude Code 的强大不在于它背后的模型,而在于围绕那个简单 while-loop 构建的工程系统

一、核心架构:一个 while-loop 和它的护城河

Claude Code 的核心执行逻辑,简单到让人意外:

// 简化后的核心循环(伪代码)
async function agentLoop(initialMessages: Message[]) {
  let messages = initialMessages;
  
  while (true) {
    // 1. 调用模型
    const response = await callModel(messages);
    
    // 2. 如果没有工具调用,结束
    if (!response.toolCalls?.length) {
      return response.text;
    }
    
    // 3. 执行工具,收集结果
    const toolResults = await executeTools(response.toolCalls);
    
    // 4. 把结果追加到消息列表,继续循环
    messages = [...messages, response, ...toolResults];
  }
}

就这?对,就这。一个 while-loop,调模型 → 跑工具 → 把结果喂回去 → 再调模型。任何写过 LangChain 的人都能在 20 行代码里实现同样的逻辑。

但 Claude Code 的 50 万行代码里,95% 不在这个循环本身,而在围绕它构建的一系列基础设施。这就像说"HTTP 服务器的核心就是监听端口 + 处理请求"——技术上没错,但 Nginx 和你用 Python 写的 3 行服务器之间,差了一个量级的工程。

这些"护城河"可以归纳为五个子系统:

权限系统:七种模式 + ML 分类器,决定每个工具调用是否被允许执行

上下文管线:五层压缩策略,解决长对话的 token 爆炸问题

扩展机制:MCP + Plugins + Skills + Hooks,四种方式扩展能力边界

子代理编排:Worktree 隔离的并行任务分发

会话存储:Append-only 的状态持久化,保证断点恢复

接下来逐个拆解。

二、权限系统:七层审批 + ML 守门员

这是我认为 Claude Code 架构中最被低估的部分。大多数开源 Agent 框架对安全的态度是"加个确认弹窗",而 Claude Code 构建了一套完整的分级权限体系。

2.1 七种权限模式

Claude Code 的权限不是简单的"允许/拒绝"二值判断,而是根据操作类型和用户配置,进入不同的审批流:

1. Always Allow — 读文件、搜索代码等只读操作,默认放行

2. Auto Allow (Safe Pattern) — 匹配白名单的写操作(如 git commit),自动通过

3. ML Classifier Gate — 用训练过的分类器判断命令危险性

4. Per-Session Allow — 用户在当前会话中授权过的操作模式

5. Explicit Confirm — 高危操作必须用户逐一确认(rm -rf、网络请求等)

6. Directory Scoped — 限制在项目目录内操作,越界即拦截

7. Global Deny — 硬编码的禁止列表,任何情况下都不执行

2.2 ML 分类器:不只是正则匹配

最有意思的是第三层。传统的 Agent 安全方案要么靠正则黑名单(rm、curl、wget 等关键词),要么让 LLM 自己判断"这个操作安不安全"。前者绕不过变形(r\m、base64 编码),后者本身就不可靠。

Claude Code 的方案是训练了一个专用的轻量分类模型,输入是完整的 bash 命令 + 当前上下文,输出是风险评分。这个模型的训练数据来自真实的用户交互日志——哪些命令被用户拒绝了,哪些被接受了,反向标注。

// 权限检查的核心流程(简化)
async function checkPermission(tool: ToolCall): Promise<PermissionResult> {
  // Layer 1: 全局禁止列表
  if (GLOBAL_DENY_LIST.matches(tool)) return { denied: true };
  
  // Layer 2: 目录边界检查
  if (!isWithinProjectScope(tool.targetPath)) return { denied: true };
  
  // Layer 3: 只读操作直接放行
  if (tool.isReadOnly) return { allowed: true };
  
  // Layer 4: 白名单模式匹配
  if (SAFE_PATTERNS.matches(tool.command)) return { allowed: true };
  
  // Layer 5: ML 分类器评分
  const riskScore = await classifyRisk(tool, context);
  if (riskScore  0.8) return { denied: true, reason: 'high_risk' };
  
  // Layer 6: 中间地带,请求用户确认
  return { needsConfirm: true, riskScore };
}

这个设计的精妙在于分层降级:大部分操作在前几层就决定了结果,只有少量边缘 case 才需要打扰用户。实际使用中的体验是——你很少被弹确认框,但真正危险的操作一定会被拦下来。

三、上下文管线:五层压缩的艺术

任何做过 AI Agent 的人都知道一个痛点:对话越长,模型越蠢。Token 限制是硬约束,但即使没有限制,过长的上下文也会让模型注意力稀释,容易"忘记"早期的关键信息。

Claude Code 用了一个五层压缩管线来解决这个问题:

3.1 五层管线详解

Layer 1: Tool Output Truncation — 工具输出超过阈值时,只保留头尾 + 中间摘要

Layer 2: Message Pruning — 保留最近 N 条完整消息 + 早期消息只保留标题

Layer 3: Conversation Summary — 每隔一定轮次生成一次对话摘要,替换原始历史

Layer 4: Context Window Sliding — 当总 token 接近限制时,滑动窗口裁剪最旧的内容

Layer 5: Semantic Dedup — 语义相似的工具调用结果去重(比如重复查看同一文件)

这里的关键洞察是:不是所有历史信息的重要性相等。用户最初的需求描述、最近的操作结果、报错信息——这些是高权重的。而中间的一大堆"读取文件 A 的内容"→"文件 A 的第 1-50 行是…"之类的工具调用结果,过了时效就可以压缩。

// 上下文压缩示意(简化)
function compactContext(messages: Message[], maxTokens: number): Message[] {
  let tokenCount = countTokens(messages);
  
  if (tokenCount  {
    if (m.role === 'tool' && m.content.length > TOOL_TRUNCATE_THRESHOLD) {
      return { ...m, content: truncateWithSummary(m.content) };
    }
    return m;
  });
  
  // Step 2: 早期消息只保留摘要
  const recentCount = 8;
  const recent = messages.slice(-recentCount);
  const older = messages.slice(0, -recentCount);
  const olderSummary = summarizeMessages(older);
  
  // Step 3: 组合
  return [
    { role: 'system', content: `Earlier context summary:\n${olderSummary}` },
    ...recent
  ];
}

3.2 与其他方案的对比

Cursor 的做法更偏"即用即弃"——每次对话相对独立,跨对话的上下文主要靠 codebase indexing 来补充。这在短任务上效果不错,但对于持续 30 分钟的重构任务,Claude Code 的方案明显更有优势。

OpenClaw(另一个被 arXiv 论文拿来对比的开源项目)走的又是另一条路:它不在 Agent 层做压缩,而是在 Gateway 层做全局的上下文管理,因为它面对的是多渠道、长周期的个人助手场景,上下文的生命周期和 Claude Code 的单次任务场景完全不同。

四、四种扩展机制:从 MCP 到 Hooks

Claude Code 提供了四种方式来扩展自身能力,这四种机制的抽象层次和使用场景各不相同:

4.1 MCP (Model Context Protocol)

标准化的外部工具协议。通过 stdio 或 HTTP 与外部服务通信,Claude Code 支持七种传输方式。这是最"正式"的扩展机制,适合接入第三方服务(数据库、CI/CD、项目管理工具等)。

// .claude/mcp.json 配置示例
{
  "servers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "..." }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": { "DATABASE_URL": "postgresql://..." }
    }
  }
}

4.2 Skills(技能文件)

项目级的知识注入。通过 CLAUDE.md 文件(放在项目根目录或 ~/.claude/),你可以告诉 Claude Code 项目的约定、代码风格、架构决策。这些内容会被注入到每次对话的 system prompt 中。

# CLAUDE.md 示例
## 项目约定
- 使用 pnpm 作为包管理器
- 测试用 Vitest,不用 Jest
- 组件命名用 PascalCase,hooks 用 camelCase
- 新功能必须先写测试

## 架构说明
- src/core/ 是核心业务逻辑,不依赖框架
- src/adapters/ 是外部服务适配层
- 所有 API 调用走 src/services/api-client.ts

这个设计看似简单,但效果惊人。它解决了一个长期痛点:AI 不了解你项目的"潜规则"。代码风格可以靠 lint 规则,但架构约定、业务逻辑、团队协作习惯这些隐性知识,只有写进 CLAUDE.md 才能让 AI 理解。

4.3 Hooks(生命周期钩子)

这是最底层的扩展点。Hooks 允许你在 Agent 循环的关键节点插入自定义逻辑——比如每次工具调用前做额外检查、每次生成代码后自动跑 lint、会话结束时自动提交 git 等。

// .claude/hooks.json
{
  "afterToolCall": {
    "bash": {
      "command": "if echo '$TOOL_OUTPUT' | grep -q 'error'; then echo 'HOOK_WARN: 检测到错误输出'; fi"
    }
  },
  "onSessionEnd": {
    "command": "git add -A && git commit -m 'auto: claude code session changes' --no-verify"
  }
}

4.4 Plugins(实验性)

介于 MCP 和 Hooks 之间的机制,允许注入自定义的工具定义和行为。目前还在演进中,API 不太稳定,但方向很清晰——让高级用户可以深度定制 Agent 的行为,而不需要 fork 源码。

五、子代理编排:Git Worktree 的妙用

当任务比较复杂(比如"把这个模块从 JavaScript 重构为 TypeScript"),Claude Code 会自动拆分为多个子任务,并分发给子代理并行执行。这里的关键工程选择是——用 Git Worktree 实现任务隔离

每个子代理在自己的 worktree 中工作,互不干扰。完成后主代理审查各个 worktree 的 diff,合并结果。如果某个子任务失败了,直接丢弃对应 worktree,不影响其他部分。

// 子代理分发逻辑(简化)
async function delegateToSubagents(plan: TaskPlan) {
  const subtasks = plan.decompose();
  
  // 为每个子任务创建独立的 worktree
  const worktrees = await Promise.all(
    subtasks.map(task => createWorktree(task.branchName))
  );
  
  // 并行执行
  const results = await Promise.allSettled(
    subtasks.map((task, i) => 
      runSubagent(task, { cwd: worktrees[i].path })
    )
  );
  
  // 合并成功的结果
  for (const [i, result] of results.entries()) {
    if (result.status === 'fulfilled') {
      await mergeWorktree(worktrees[i]);
    } else {
      await discardWorktree(worktrees[i]);
      logger.warn(`Subtask ${i} failed, discarded`);
    }
  }
}

这个设计比简单的"多线程"优雅得多。Git 本身就是一套完善的版本管理系统,worktree 提供了天然的文件系统隔离 + 版本追踪 + 冲突检测能力。Claude Code 相当于复用了 Git 的基础设施来做任务编排。

六、技术栈选择:为什么是 Bun + React + Ink?

Claude Code 的技术栈选择很有意思:

Runtime: Bun — 不是 Node.js。Bun 的启动速度和 TypeScript 原生支持让 CLI 体验更流畅

UI: React + Ink — 在终端里用 React 渲染!Ink 是一个把 React 组件模型映射到终端字符的库

状态管理: Zustand-like Store — 类似 Zustand 的单向数据流

Schema 验证: Zod — 运行时类型安全

构建: 编译时 Feature Flags + DCE — Dead Code Elimination 做构建优化

用 React 来渲染终端 UI,听起来像"杀鸡用牛刀",但实际上非常合理。Claude Code 的终端界面不是简单的 readline——它有实时的流式输出、diff 高亮、多区域布局、进度动画。用传统的 ANSI escape + readline 来做这些,代码会变成一团浆糊。React 的声明式 UI + 组件复用在这里的优势很明显。

// React + Ink 渲染终端 UI 的示例
function AgentOutput({ messages, isStreaming }) {
  return (
    <Box flexDirection="column" padding={1}>
      {messages.map((msg, i) => (
        <MessageBlock key={i} message={msg} />
      ))}
      {isStreaming && <StreamingIndicator />}
      <PermissionPrompt />
    </Box>
  );
}

七、设计哲学:五个驱动架构的核心价值观

arXiv 论文总结出 Claude Code 架构背后的五个核心价值观,我觉得对所有做 AI Agent 的团队都有参考价值:

1. Human Decision Authority(人类决策权)— 所有不可逆操作必须人类授权,AI 只是执行者

2. Safety and Security(安全第一)— 宁可误拒绝也不误执行,安全是硬约束不是软目标

3. Reliable Execution(可靠执行)— 幂等性、断点恢复、错误隔离,任务不能执行一半就挂

4. Capability Amplification(能力放大)— AI 是"倍增器"不是"替代者",放大人类能力而非取代

5. Contextual Adaptability(上下文自适应)— 同样的指令在不同项目、不同阶段应有不同行为

这五条不是空话。每一条都能在代码里找到对应的实现。比如"Reliable Execution"直接对应了 append-only 的会话存储设计——每一步操作都被持久化,进程挂了可以从任何节点恢复。

八、对工程师的启示:做 Agent 不是堆 prompt

从 Claude Code 的架构里,我提炼出几个对实际开发 AI Agent 最有价值的经验:

1. 循环本身不值钱,围绕循环的基础设施才值钱。任何人都能写一个 while-loop 调 API,但权限系统、上下文管理、错误恢复、任务编排——这些才是产品和 demo 的距离。

2. 安全不能后加,必须是架构的第一层。Claude Code 的权限系统不是 v2 才加的 feature,它从 day one 就嵌入了执行管线的核心路径。

3. 上下文管理是 Agent 的心脏问题。不解决上下文膨胀,你的 Agent 在第 5 轮对话后就会开始犯蠢。五层压缩管线看着复杂,但每一层解决的是不同颗粒度的问题。

4. 复用现有基础设施。用 Git Worktree 做任务隔离,用 React 做终端 UI,用 Zod 做运行时校验——不重复造轮子,把精力放在真正的差异化能力上。

5. 可观测性决定可调试性。每个工具调用都有结构化日志、每次决策都有 trace、每个会话都可回放。没有这些,你的 Agent 就是一个黑盒,出了 bug 无从下手。

九、未来方向:Agent 竞赛的下半场

Claude Code 的架构暴露了一个行业趋势:AI Agent 的竞争正在从"模型能力"转向"工程能力"

当 Claude、GPT、DeepSeek 的底层模型能力逐渐趋同,决定产品体验差异的就是上面这些工程选择。谁的权限系统更不打扰用户、谁的上下文管理更聪明、谁的扩展机制更灵活、谁的错误恢复更无感——这些才是壁垒。

论文最后提出的六个开放方向也很有前瞻性:

• 多 Agent 之间的协议标准化(不只是 MCP,还包括 Agent-to-Agent 通信)

• 权限系统的自适应学习(根据用户行为自动调整安全阈值)

• 跨会话的长期记忆(不只是单次任务内的上下文,而是跨天、跨项目的知识积累)

• 形式化验证(在执行前证明操作的安全性,而不是事后检查)

• 可解释的决策路径(不只是给结果,还能解释"为什么选择这个方案")

• 资源受限环境的适配(移动端、嵌入式设备上的 Agent 运行)

总结

Claude Code 给整个行业的最大启示不是"怎么做一个好的编程助手",而是怎么把一个简单的 AI 循环打造成工业级产品。50 万行代码里 95% 是"无聊的"基础设施——权限、压缩、编排、存储、可观测。但正是这些"无聊的"工程决定了产品是"能 demo"还是"能用于生产"。

对于正在做或打算做 AI Agent 的团队:不要把精力全放在 prompt engineering 上。你的模型调用可能只占代码量的 5%,但围绕它的工程系统决定了产品的天花板。

参考资料:

• arXiv:2604.14228 “Dive into Claude Code: The Design Space of Today’s and Future AI Agent Systems”

• GitHub: sawzhang/deep-dive-claude-code —《深入理解 Claude Code 源码》

• Anthropic 官方文档:Claude Code Permission System

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐