本文是 Claude Code 源码分析的浓缩版。每个主题都附有深入阅读链接。
无论你是想了解 Claude Code 的内部机制,还是想借鉴它的设计思路来构建自己的 coding agent,这篇文章都会帮你快速建立全局认知。我们不会深入每一行代码,而是聚焦于关键设计决策——那些让 Claude Code 从"能用"变成"好用"的工程选择。
Claude Code 是 Anthropic 的 CLI 编程 Agent。它不是代码补全工具,而是一个受控工具循环 Agent——能理解代码库、编辑文件、执行命令、管理 git 的自主编程助手。
你可能会问:一个 CLI 工具为什么需要 512K+ 行代码?这正是它有趣的地方。Claude Code 解决的不是"如何调用大模型 API"这个简单问题,而是一系列工程挑战:
- 如何让 Agent 自主完成复杂任务? → Agent Loop 的多轮决策与错误恢复
- 如何在有限的上下文窗口里高效工作? → 4 级渐进式上下文压缩
- 如何让 AI 安全地执行 Shell 命令? → 7 层纵深防御 + AST 级命令分析
- 如何让 Agent 跨会话学习? → 记忆系统 + 技能系统
- 如何处理超出单 Agent 能力的任务? → 3 种多 Agent 协作模式
这些问题的答案构成了一套完整的 Agent 工程方法论——这正是本系列文档想帮你理解的。
深入阅读:概述
Agent Loop 是 Claude Code 的灵魂——理解了它,就理解了所有 coding agent 的核心模式。
它本质上是一个 while(true) 循环:
用户输入 → 组装上下文 → 调用模型 → 模型决策
↓
有工具调用? → 执行工具 → 注入结果 → 继续循环
↓
无工具调用? → 返回文本响应 → 结束
这个流程看起来简单,但魔鬼在细节里。想象你让 Claude Code "重构这个文件里的所有函数名为 snake_case"——模型会先读取文件(工具调用),分析当前命名(文本推理),然后逐个编辑函数名(多次工具调用),每次编辑后检查是否有遗漏(继续循环),直到确认全部完成才返回结果。整个过程可能循环十几次,但对用户来说只是一条指令。
实现为 async function* 异步生成器,采用双层设计:
- QueryEngine(外层):管理对话生命周期——持久化、预算检查、用户中断。它关心的是"这个对话要不要继续"
- query()(内层):管理单次循环——API 流式、工具执行、错误恢复。它关心的是"这一轮怎么跑完"
为什么要分两层?因为会话管理和查询执行的关注点完全不同。会话层需要处理用户中断、Token 预算耗尽、对话持久化等生命周期问题;而查询层只需要专注于"调 API → 解析响应 → 执行工具 → 拼装结果"这个紧凑循环。分层让每一层的逻辑都保持清晰。
query() 有 7 个 Continue Sites,每种对应一种故障恢复路径——这就是为什么用 Claude Code 时很少遇到报错:
- 模型输出被截断?→ 自动用更高的 Token 限制重试
- 上下文快满了?→ 触发压缩后继续
- API 返回错误?→ 按退避策略重试
核心设计原则是错误扣留——可恢复的错误不暴露给调用者,自动修复后继续。Agent 应该像一个靠谱的同事,遇到小问题自己解决,而不是每次都来问你。
- 工具预执行——模型还在生成输出时,已完成解析的工具调用就立即开始执行,把约 1 秒的工具延迟藏在模型生成的 5-30 秒窗口里。用户感受到的是工具"瞬间完成"
- StreamingToolExecutor——边流式解析边并发执行,只读工具自动并行。当模型同时调用多个只读工具(比如同时读三个文件),它们会并发执行而不是排队等待
深入阅读:系统主循环
如果说 Agent Loop 是 Claude Code 的骨架,那上下文工程就是它的血液。大模型的能力完全取决于它"看到了什么"——同样的模型,给它精心组织的上下文和随意堆砌的上下文,表现可能天差地别。
每次 API 调用的上下文由三部分组成:
- 系统提示词(最稳定,缓存效率最高):Agent 身份、行为指引、工具描述
- 系统/用户上下文(会话级稳定):Git 状态、CLAUDE.md 项目指令、当前日期
- 消息历史(最易变):对话记录、工具调用结果
上下文窗口是有限的。一个复杂的编程任务可能需要几十轮对话,每轮都会产生新的消息、工具调用结果、文件内容——上下文很快就会被撑满。Claude Code 的解决方案是一条从轻量到激进逐级启动的压缩流水线:
Snip(剪裁)→ Microcompact(微压缩)→ Context Collapse(折叠)→ Autocompact(全量摘要)
- Snip:把大块工具输出替换成占位符——最轻量,几乎无信息损失
- Microcompact:对工具结果做局部压缩——保留关键信息,去掉冗余
- Context Collapse:把整段对话折叠成摘要——显著释放空间
- Autocompact:最后手段,在 Token 使用达到约 87% 时触发,fork 一个子 Agent 来生成结构化摘要
每一级都比上一级"丢失"更多细节,但也释放更多空间——系统会尽可能用最轻量的方式解决问题。
压缩不只是删信息,还会主动恢复关键上下文。想象你让 Claude Code 编辑五个文件,编辑到第三个时上下文被压缩了,前面读过的文件内容被删除了。如果不做任何处理,模型可能忘记前两个文件的修改细节。所以系统会:
- 自动重新读取最近编辑的 5 个文件(每个 ≤5K tokens)
- 重新激活活跃的技能上下文(≤25K tokens)
- 重置 Context Collapse 标记
每次 API 调用都要发送完整上下文,但大部分内容在相邻调用之间是不变的。通过缓存断点标记让 API 服务端复用已处理的前缀,显著降低延迟和成本。系统还能自动检测缓存断裂(cache miss 率突增),归因到是 CLAUDE.md 变更、对话压缩还是工具结果过大导致的。
深入阅读:上下文工程
工具是 Agent 与真实世界交互的手段。没有工具,大模型只能生成文字;有了工具,它才能真正地读文件、写代码、跑测试。
Claude Code 包含 66+ 内置工具,全部统一为 Tool 接口。核心设计是 fail-closed 默认值——新工具如果不显式声明安全属性,默认被当作不安全处理。这意味着遗漏声明不会导致安全漏洞,只会导致功能受限。
| 核心工具 | 功能 |
|---|---|
| BashTool | Shell 命令执行(最复杂,7 层安全验证) |
| FileEditTool | search-and-replace 精确编辑 |
| FileReadTool | 文件读取(支持图片/PDF/Jupyter) |
| GrepTool | ripgrep 驱动的内容搜索 |
| AgentTool | 派生子 Agent(支持 worktree 隔离) |
并发规则遵循一个简单原则:只读工具并行,写入工具串行。通过 isReadOnly() 和 isConcurrencySafe() 两个方法声明式地判断——模型可以同时读三个文件而不冲突,但写入操作会严格排队。
工具执行遵循 8 阶段管道:查找 → 校验 → 并行启动 → 权限检查 → 执行 → 结果处理 → 后置 Hook → 事件发射。当工具输出超过 100K 字符时自动落盘到临时文件,模型只拿到摘要和文件路径,避免超大输出撑爆上下文。
MCP(Model Context Protocol)让 Claude Code 不再是一个封闭系统。通过 MCP,第三方开发者可以为 Claude Code 添加任意能力——连接数据库、调用内部 API、操作 Kubernetes 集群——而无需修改 Claude Code 本身的代码。MCP 工具和内置工具遵循同一套权限检查、输入校验、并发控制的规则。
深入阅读:工具系统
代码编辑是 coding agent 最核心也最危险的能力。一个常见做法是让模型生成整个文件然后覆盖写入,但这在实际项目中问题很大:一个 500 行的文件,模型可能只需要改 3 行,但全文件重写意味着它需要完美复现其余 497 行——任何遗漏都会引入 bug。
Claude Code 选择了 search-and-replace 策略,这不只是一种编辑方式,而是一个深思熟虑的设计决策:
- 位置无关:不依赖行号,文件被修改后不会错位——行号方案在多轮编辑中极易出错
- 抗幻觉:
old_string必须精确匹配且在文件中唯一,不存在的代码会导致编辑失败而非静默写入 - Token 高效:只需发送修改点附近的上下文,而不是整个文件
- Git 友好:产生最小精确 diff,便于 code review
编辑前必须先读取文件——这不是提示词里的建议,而是代码层面的强制检查(hasReadFileInSession 标志位)。模型如果试图编辑一个它还没读过的文件,工具会直接拒绝执行。
编辑验证经过 14 步校验管道:文件存在性、编码检测、权限检查、配置文件安全、引号规范化(自动转换弯引号为直引号)、唯一性约束等。
深入阅读:代码编辑策略
一个能执行任意 Shell 命令、读写任意文件的 AI Agent,如果没有严格的安全控制,就是一颗定时炸弹。Claude Code 采用纵深防御策略,7 层保护层层递进,每层使用不同技术(正则、AST 解析、ML 分类、人工判断),确保单点故障不会击穿整个防线:
Trust Dialog → 权限模式 → 规则匹配 → Bash AST 分析 → 工具级校验 → 沙箱隔离 → 用户确认
整个系统中最复杂的部分——使用 tree-sitter 对命令进行 AST 级别的分析,加上 23 项静态检查,覆盖命令注入、环境变量泄露、Shell 元字符等攻击向量。它不是简单的黑名单匹配,而是真正"理解"命令的结构。
权限确认使用竞速机制:UI 对话框、Hook 和 ML 分类器同时运行,第一个完成的决定生效。对于明显安全的操作(分类器快速判定),用户不需要等待;需要人工判断的操作,UI 对话框会弹出。用户交互始终优先于自动结果。有 200ms 防误触宽限期。
支持三种匹配模式(精确匹配、前缀 :*、通配符 *),规则可在项目级、用户级分别配置。拒绝规则永远优先——即使在最宽松的权限模式下,deny 规则也会生效。
PermissionRequest Hook 是最强的扩展点——企业团队可以实现自定义审批逻辑,比如"所有 git push 必须经过团队 lead 审批"或"自动给 rm 加 --dry-run"。
深入阅读:权限与安全
每个团队都有自己的工作流。Hook 系统让用户不修改源码就能定制 Agent 的行为。
Claude Code 提供 25 种 Hook 事件,覆盖 Agent 完整生命周期(工具调用前后、权限判定、会话管理、压缩等)。
四种 Hook 类型覆盖从简单脚本到企业服务的所有场景:
| Hook 类型 | 适用场景 | 示例 |
|---|---|---|
| Command | 简单 Shell 命令 | CI 构建检查、日志记录 |
| Prompt | 需要 AI 处理的逻辑 | 自定义 Linter 反馈 |
| Agent | 复杂多步决策 | 安全审计流程 |
| HTTP | 企业 HTTP 服务集成 | 团队审批系统 |
Hook 执行引擎有关键的快路径优化:当所有匹配的 Hook 都是 callback/function 类型时,框架跳过 JSON 序列化和进度事件,延迟降低约 70%。
深入阅读:Hooks 与可扩展性
单个 Agent 在处理简单任务时游刃有余,但面对大型项目——比如"重构这个微服务的 API 层并更新所有调用方"——单 Agent 就会遇到瓶颈:上下文窗口不够用、任务太复杂、或者多个文件的修改需要并行进行。
Claude Code 支持三种多 Agent 模式:
最常用。通过 AgentTool fork 出独立子任务,每个子 Agent 有自己的上下文窗口和工具集。关键设计:
- 上下文隔离:子 Agent 不继承父对话历史,只接收自包含的任务描述。这确保了隔离性和成本可控
- 工具过滤:4 层过滤管道(移除元工具 → 自定义限制 → 异步白名单 → Agent 级禁止列表),不同类型的子 Agent 获得不同的工具集
- Git Worktree 隔离:每个子 Agent 可以获得独立的代码副本,多 Agent 同时编辑不同文件不会冲突
- 3 种内置类型:Explore(只读,用 Haiku 模型降低成本)、Plan(只读,结构化输出)、General-purpose(完整工具集)
纯指挥官——只能分配任务,不能自己读文件、写代码。这个设计看似限制,实际上防止了协调器"顺手"做本该交给 worker 的事情,确保职责清晰。标准 4 阶段工作流:研究 → 综合 → 实施 → 验证。
最灵活也最复杂。命名 Agent 间通过对等信箱通信,不需要中央协调器。适合多个 Agent 长时间并行工作的场景。
深入阅读:多 Agent 架构
你有没有这样的经历:每次开新会话都要重新告诉 AI"这个项目用的是 monorepo"、"测试框架用 Vitest 不要用 Jest"?这就是缺乏跨会话记忆的痛点。
Claude Code 的记忆系统是一个有结构、有分类、有智能召回的知识库:
- 4 种封闭记忆类型:user(用户画像)、feedback(行为校正)、project(项目上下文)、reference(外部资源指针)。封闭分类防止标签膨胀
- 语义召回:不是关键词匹配,而是用 Sonnet 模型评估每条记忆与当前任务的相关性
- 明确的"不记什么":代码模式、git 历史、已有文档里的内容——这些可以从当前项目状态推导出来,记下来只会变成过时信息
- 与 CLAUDE.md 互补:CLAUDE.md 是团队共享的项目规则(签入 git),记忆是个人的跨会话学习(本地存储)
如果说记忆是 Agent 的"长期知识",技能就是它的"可复用能力"——可以理解为"AI Shell 脚本"。
- 用户可通过
/commit这样的斜杠命令手动调用,模型也可以根据上下文自动触发(用户说"帮我提交"时,模型判断应该调用 commit 技能) - 6 层优先级加载(托管 > 项目 > 用户 > 插件 > 内置 > MCP),团队可在项目级别定义共享技能,个人用户可以覆盖或扩展
- 懒加载:注册时只读 frontmatter 元数据,技能内容在真正调用时才加载,保持启动速度
- Token 预算分配:3 阶段算法——全量描述 → 分区描述(内置技能保留完整,其余共享剩余) → 仅名称。确保技能列表不会挤占上下文空间
看完上面的介绍,你可能觉得构建一个 coding agent 是一件非常复杂的事。但好消息是:核心概念其实很简单。一个最小可用的 coding agent 只需要 7 个组件:
- Prompt Orchestration — 运行时组装环境信息 + git 上下文 + 项目规则
- Tool Registry — JSON Schema 声明 + switch/case 分发
- Agent Loop — async generator 状态机,循环直到模型不再调用工具
- File Operations — 读文件、搜索文件
- Shell Execution — 执行命令、捕获输出
- Edit Strategy — search-and-replace 精确编辑
- CLI UX — readline 交互、流式输出
~3000 行代码就能实现一个可运行的最小版本(含记忆、技能、多 Agent 等进阶能力)。Claude Code 的 512K+ 行覆盖了生产级需求:Hooks 系统、Coordinator/Swarm 多 Agent 模式、MCP 集成、OAuth 认证等。从 3000 行到 512K 行的差距,就是"功能完整"和"企业级生产"之间的工程距离。
如果你想动手实践,可以跟着我们的分步教程从零构建:claude-code-from-scratch
深入阅读:最小必要组件
下图展示了 Claude Code 各模块的关系。Agent Loop(绿色)是整个系统的枢纽,连接着上下文压缩(蓝色)、安全系统(红色)、记忆系统(橙色)和 Hook 系统(紫色):
graph TB
User[用户] --> REPL[REPL 终端UI]
REPL --> QE[QueryEngine<br/>会话管理]
QE --> Loop[query 循环<br/>async generator]
Loop --> Compress[4级压缩<br/>Snip→MC→CC→AC]
Loop --> API[Anthropic API<br/>流式响应+缓存]
Loop --> Tools[66+ 工具]
Tools --> Read[FileRead<br/>Grep/Glob]
Tools --> Edit[FileEdit<br/>search-replace]
Tools --> Bash[BashTool<br/>7层安全]
Tools --> Agent[AgentTool<br/>子Agent/协调器/Swarm]
Tools --> MCP[MCP桥接<br/>7种传输+OAuth]
Bash --> Security[安全验证<br/>AST + 23项检查]
Security --> Perm[权限系统<br/>规则+分类器+Hook]
Loop --> Memory[记忆系统<br/>4类型+语义召回]
Loop --> Skills[技能系统<br/>6层优先级+懒加载]
Loop --> Hooks[25 Hook事件<br/>4种类型+快路径]
style Loop fill:#e8f5e9
style Security fill:#ffebee
style Compress fill:#e3f2fd
style Memory fill:#fff3e0
style Hooks fill:#f3e5f5
| 文件 | 行数 | 职责 |
|---|---|---|
src/query.ts |
1,728 | 核心查询循环 |
src/QueryEngine.ts |
1,155 | 会话引擎 |
src/Tool.ts |
~400 | 工具接口定义 |
src/tools.ts |
~200 | 工具注册 |
src/context.ts |
190 | 上下文构建 |
src/services/api/claude.ts |
3,419 | API 调用逻辑 |
src/services/compact/compact.ts |
1,705 | 压缩引擎 |
src/hooks/ |
— | Hook 执行引擎与权限处理 |
src/coordinator/ |
— | 多 Agent 协调器 |
src/memdir/ |
— | 记忆系统 |
src/skills/ |
— | 技能系统 |
本文档基于 Claude Code 源码分析。完整分析文档见项目根目录。