从源码看Claude Code:代码 Agent 的架构、循环与扩展机制
目录
-
1. 整体架构与系统定位 -
2. 核心抽象与代码组织 -
3. 一次请求的完整执行链路 -
4. Prompt、Agent Loop 与决策机制 -
5. 工具系统与环境交互 -
6. 文件编辑、上下文管理与检索机制 -
7. Skill机制:任务方法的封装 -
8. Compact机制:长任务中的上下文压缩 -
9. Hooks机制:执行生命周期的扩展点 -
10. 安全、鲁棒性与工程设计取舍 -
11. 总结
1. 整体架构与系统定位
Claude Code的本质不是“带终端的聊天程序”,而是一个以模型决策为中心、以工具调用为执行手段、以代码仓库和本地环境为操作对象的交互式代码 Agent。
它和普通 LLM 应用的差别在于:
-
• 输入不只是自然语言,还包括 cwd、git 状态、CLAUDE.md、历史消息、权限模式、MCP 服务、技能与 hooks。 -
• 输出不只是文本,还可能是读文件、搜索代码、修改文件、运行命令、连接远端会话、调用 MCP 工具。 -
• 核心流程不是一次生成,而是持续执行 观察 -> 决策 -> 行动 -> 再观察。
从分层上看,这个系统大致可以分成:
-
• 用户交互层:CLI、REPL/TUI、headless/SDK、remote session viewer。 -
• 会话与状态层:session id、消息历史、AppState、转录存储、任务与后台 agent 状态。 -
• Agent 核心层:prompt 构造、 query()主循环、QueryEngine、工具调度。 -
• 能力扩展层:skills、hooks、compact、memory、MCP、agents/swarm。 -
• 工具执行层:Bash、文件读写编辑、搜索、Web、任务、MCP tools。 -
• 模型接入层:Anthropic API 请求构造、流式返回、token/cost/usage 统计。 -
• 外部环境层:本地文件系统、shell、git、网络、远端 session、MCP server。
一句话概括:它不是模型外壳,而是围绕“代码任务闭环”构建的 Agent 执行系统。
2. 核心抽象与代码组织
2.1 源码阅读地图
如果按理解优先级来读,建议顺序是:
-
1. src/main.tsx -
2. src/setup.ts -
3. src/query.ts -
4. src/Tool.ts与src/tools.ts -
5. src/services/tools/* -
6. src/QueryEngine.ts -
7. src/constants/prompts.ts、src/utils/systemPrompt.ts、src/utils/queryContext.ts -
8. src/skills/*、src/utils/hooks.ts、src/services/compact/* -
9. src/services/mcp/*、src/remote/*、src/bridge/*
2.2 关键目录职责
-
• src/main.tsx:CLI 主入口,负责参数解析、模式切换、初始化和启动 REPL 或其他运行路径。 -
• src/setup.ts:进程级与会话级初始化,加载配置、session、hooks、memory、插件、工作区状态。 -
• src/query.ts:单轮请求的核心 Agent loop。 -
• src/QueryEngine.ts:面向 SDK/headless 模式的会话封装,对外暴露稳定的提交消息接口。 -
• src/Tool.ts:工具抽象、工具上下文、权限上下文等核心类型定义。 -
• src/tools.ts:内建工具目录和最终工具池组装。 -
• src/services/tools/*:工具编排、执行、hook 集成、流式调度。 -
• src/constants/prompts.ts、src/utils/systemPrompt.ts:系统提示词的模块化装配。 -
• src/skills/*:skill 加载、技能目录扫描、MCP skill 对接。 -
• src/utils/hooks.ts:hook 框架,负责在生命周期节点执行外部命令或函数回调。 -
• src/services/compact/*:长上下文压缩、自动 compact、session memory 结合。 -
• src/services/mcp/*:MCP 连接、鉴权、资源/工具发现与封装。 -
• src/remote/*、src/bridge/*:远程 session 和 bridge 通道。 -
• src/screens/REPL.tsx:交互式主界面上的高层调度器。
2.3 核心抽象
Claude Code最重要的抽象不是 UI 组件,而是以下对象:
-
• Session / Conversation:由消息序列、session id、转录存储、usage 和当前上下文共同构成, QueryEngine是 headless 形态下的主要承载体。 -
• Message:统一表示 user、assistant、tool_result、system、attachment、hook result 等事件。 -
• Tool:系统能力的统一描述,定义在 src/Tool.ts,内建工具和 MCP 工具都落到这一抽象上。 -
• ToolUseContext:工具运行时所需的共享环境,包含工具池、模型、MCP 连接、AppState、文件缓存、消息列表、权限上下文等。 -
• Agent / Runner: query()是最核心的执行循环,QueryEngine和 REPL 在其外层做会话管理。 -
• Model Prompt:由默认 prompt、agent prompt、用户自定义 prompt、skills/memory/MCP 指令共同拼装。 -
• Edit / Patch:虽然编辑行为分散在具体工具里,但“对工作区施加可验证变更”是整个系统的核心能力之一。
2.4 最关键的五个对象
如果只抓五个骨架点,应优先理解:
-
• query() -
• QueryEngine -
• Tool/ToolUseContext -
• getTools()/assembleToolPool() -
• buildEffectiveSystemPrompt()与getSystemPrompt()
3. 一次请求的完整执行链路
可以用“请修复当前仓库里的失败测试”来理解这条链路。
3.1 请求进入系统
用户从 CLI 或 SDK 提交请求后:
-
• src/main.tsx解析命令行与模式。 -
• src/setup.ts建立当前 session 环境。 -
• 交互模式下交给 src/screens/REPL.tsx。 -
• headless 模式下交给 src/QueryEngine.ts。
3.2 初始上下文收集
在真正调用模型前,系统会收集:
-
• 当前工作目录与 git 状态,见 src/context.ts -
• 用户上下文,如 CLAUDE.md 与日期,见 src/context.ts -
• 当前工具集合,见 src/tools.ts -
• skills、命令、MCP 工具与资源 -
• 会话历史消息和文件读取缓存 -
• 权限模式、沙箱、AppState
3.3 Prompt 构造
系统提示词不是一段静态文本,而是多段拼接:
-
• 默认系统 prompt 由 src/constants/prompts.ts动态生成 -
• 最终生效 prompt 由 src/utils/systemPrompt.ts决定 -
• src/utils/queryContext.ts同时抓取defaultSystemPrompt + userContext + systemContext -
• query.ts中再把userContext前置到消息里,把systemContext追加到 system prompt
这一步还会受以下因素影响:
-
• main thread agent 的专用 prompt -
• --system-prompt/--append-system-prompt -
• memory prompt -
• MCP server instructions -
• skill 发现结果与 attachment 注入
3.4 模型第一次决策
query() 发起 API 调用后,模型可能:
-
• 直接输出答案 -
• 请求读取文件 -
• 搜索代码 -
• 执行命令 -
• 调用 skill -
• 调用 MCP tool
这说明系统是 function-calling / tool-using agent,而不是一次性回答器。
3.5 工具执行
当 assistant message 中出现 tool_use block 后:
-
• runTools()会先按isConcurrencySafe()分批 -
• 只读工具可并发 -
• 修改类工具串行执行 -
• runToolUse()负责解析工具名、校验 schema、权限检查、执行 hooks、调用真正的tool.call()
这条路径主要落在:
-
• src/services/tools/toolOrchestration.ts -
• src/services/tools/toolExecution.ts -
• src/services/tools/StreamingToolExecutor.ts
3.6 循环推进
工具结果会被重新写回消息流,然后进入下一轮 query() 内部循环。于是形成典型闭环:
-
1. 跑测试 -
2. 读取报错文件 -
3. 搜索相关实现 -
4. 修改代码 -
5. 再跑测试 -
6. 最后总结
这就是仓库里最核心的 Agent 行为模式。
3.7 终止条件
一次 turn 在以下情况结束:
-
• 模型给出 final answer,没有新的 tool_use -
• 达到 turn/token/budget 限制 -
• 发生不可恢复错误 -
• 用户中断 -
• compact/recovery 之后仍无法继续
4. Prompt、Agent Loop 与决策机制
4.1 System prompt 的角色
Claude Code把很多“产品行为”写进了 system prompt,而不是硬编码成流程机:
-
• 行为规范 -
• 工具使用约束 -
• 输出风格 -
• 安全限制 -
• 长任务策略 -
• memory 与 MCP 使用说明
因此,源码中的能力很大程度是“prompt + tool runtime”协同得到的。
4.2 用户指令如何被增强
用户看到的是一句请求,但模型看到的是:
-
• 默认系统 prompt -
• agent 或自定义 prompt -
• 当前日期、CLAUDE.md、git status -
• 可用工具 schema -
• MCP instructions -
• skill discovery/system reminders -
• 历史消息与附件
所以“用户原话”和“模型真实输入”之间有一层很厚的运行时增强。
4.3 Agent Loop 的控制方式
src/query.ts 体现了该系统的主循环控制:
-
• 每一轮先调用模型 -
• 解析 assistant 输出中的 tool_use -
• 执行工具并追加 tool_result -
• 必要时自动 compact 或做 max token recovery -
• 继续下一轮,直到满足终止条件
它不是传统 planner-executor 两阶段系统,而更接近混合式 ReAct/function-calling:边做边修正。
4.4 自我修正机制
系统的纠错能力主要来自环境反馈:
-
• 工具错误会回流给模型 -
• 权限拒绝会回流给模型 -
• prompt too long 会触发 compact/recovery -
• patch/命令/测试失败后会继续读文件并重新决策
这让系统不是“第一次必须做对”,而是通过闭环逼近正确结果。
4.5 上下文膨胀控制
长对话会遇到上下文膨胀,因此系统内置:
-
• token 预算跟踪 -
• tool output 裁剪 -
• auto compact -
• session memory compact -
• micro compact / post-compact cleanup -
• attachment 与 reinjection 策略
这部分对应后面的 compact 章节,是整个工程能跑长任务的关键。
5. 工具系统与环境交互
5.1 Tool 抽象
src/Tool.ts 定义的 Tool 接口统一了:
-
• 名称与 schema -
• call() -
• 只读/并发安全属性 -
• 权限检查 -
• MCP 元信息 -
• 延迟加载/总是加载等策略
这使得 Bash、文件编辑、MCP tool 在调度层面拥有统一协议。
5.2 工具注册与组装
工具不是散落加载的,核心入口在 src/tools.ts:
-
• getAllBaseTools()定义内建工具全集 -
• getTools()根据模式、feature flag、deny 规则做过滤 -
• assembleToolPool()把内建工具和 MCP 工具合并成最终工具池
这种集中式工具池设计让 prompt、权限、调度都能基于统一视图工作。
5.3 工具执行管线
完整执行链可以概括成:
tool_use -> 找工具 -> schema 校验 -> 权限判断 -> hooks -> 真正调用 -> tool_result -> 回写消息
其中最重要的执行点是 checkPermissionsAndCallTool()。
5.4 权限、沙箱与 Bash
工具系统最复杂的工程点集中在 Bash:
-
• 规则匹配和权限模式在 src/utils/permissions/* -
• UI/交互式授权在 src/hooks/useCanUseTool.tsx -
• Bash 自己还有更细的命令分类、危险操作识别、沙箱决策 -
• 真正的 shell 进程由 src/utils/Shell.ts启动
这说明仓库并不是“模型随便跑命令”,而是把 Bash 视为高风险能力进行特殊治理。
5.5 MCP 的地位
MCP 不是旁路系统,而是被标准化成普通 Tool:
-
• 连接和发现由 src/services/mcp/client.ts -
• 远端工具被包装成 MCPTool -
• 最后进入同一个 tool pool、同一套权限/编排路径
这是该仓库可扩展性的关键设计之一。
6. 文件编辑、上下文管理与检索机制
6.1 文件操作能力
仓库内建的核心工作能力包括:
-
• FileReadTool -
• FileEditTool -
• FileWriteTool -
• NotebookEditTool -
• GlobTool -
• GrepTool
这些工具组合起来,形成了“读代码 -> 定位 -> 修改 -> 验证”的最小闭环。
6.2 文件与上下文缓存
ToolUseContext 内部有 readFileState 等缓存结构,用于:
-
• 避免重复读取大文件 -
• 维持当前会话对文件的理解 -
• 支持 compact 后的部分恢复
此外,QueryEngine 还维护消息历史、文件历史和 attribution 状态,说明这个系统把“连续任务”而不是“单轮问答”当作一等公民。
6.3 上下文注入机制
这里的上下文管理不是单纯堆消息,而是分层处理:
-
• userContext:CLAUDE.md、日期等,以用户消息形式前置 -
• systemContext:git 状态等,以系统 prompt 尾部附加 -
• memory prompt:作为 system prompt section 注入 -
• attachments:把技能发现、delta 信息等作为系统提醒加入
这是一种“多通道上下文拼接”设计,而不是只有 messages 一条总线。
6.4 检索机制
仓库对代码检索至少有三层:
-
• 文件系统级搜索:Glob/Grep -
• 工具层搜索:ToolSearch,用于延迟暴露工具 -
• MCP/LSP/远端资源检索
这意味着系统并不假设“所有能力都必须一开始暴露给模型”,而是支持按需发现。
7. Skill 机制
Skill 是Claude Code里非常重要的“方法级扩展单元”,本质上是可被模型调用的专业化操作说明和工作流模板。
7.1 Skill 的数据来源
skills 主要由 Markdown + frontmatter 描述,src/skills/loadSkillsDir.ts 负责:
-
• 扫描用户、项目、managed、plugin、bundled skill 目录 -
• 解析 frontmatter -
• 生成运行时 Command -
• 去重、过滤、路径匹配激活
frontmatter 可表达:
-
• 名称与描述 -
• 适用场景 -
• 允许工具 -
• 参数 -
• hooks -
• 执行上下文,如 inline/fork
7.2 Skill 与命令系统的关系
在Claude Code里,skill 并非完全独立于命令系统,而是会被融合到 commands/slash-command 可见层里。因此它既是“提示模板”,也是“运行时能力入口”。
7.3 Skill 的动态发现
一个很有代表性的设计是:读文件、写文件、编辑文件时都可能触发 skill discovery。也就是说,技能发现不是只靠用户显式输入,而是和当前正在操作的文件路径绑定。
这使得系统能根据工作区上下文主动提示更合适的工作流。
7.4 Skill 的实际作用
skill invocation 并不只是把一段文本喂给模型,它还会:
-
• 加载 skill 正文 -
• 注册 skill 附带 hooks -
• 记录已调用 skill,以便 compact 后重注入 -
• 更新 command permissions 等状态
所以 skill 实际上会改变运行时行为。
8. Compact 机制
Compact 是Claude Code支撑长时会话的核心工程能力之一。
8.1 为什么需要 compact
Agent 任务往往是多轮的:
-
• 工具输出很多 -
• 历史消息长 -
• skill 内容也会占上下文 -
• MCP 指令和 memory 也占空间
如果没有 compact,任务很容易在上下文窗口里“自我撑爆”。
8.2 Compact 的实现思路
src/services/compact/compact.ts 负责对历史消息做总结和压缩。关键思路包括:
-
• 去掉图像/文档等对总结无帮助的块 -
• 根据 API round 分组截断旧消息 -
• 生成 compact boundary -
• 把精简后的摘要重新放回会话
8.3 Auto Compact
src/services/compact/autoCompact.ts 负责:
-
• 根据模型 context window 计算阈值 -
• 判断是否应自动 compact -
• 在失败时做 circuit breaker,避免反复无效 compact
这说明 compact 不是一个按钮功能,而是 query loop 的一部分。
8.4 Compact 之后如何保住关键信息
仓库用了几个补偿机制:
-
• session memory first -
• post-compact cleanup -
• 已调用 skill 的限额重注入 -
• 必要 attachment 的重建
这套设计的重点不是“摘要历史”,而是“在压缩后仍保留继续工作的关键操作上下文”。
9. Hooks 机制
Hooks 是系统对外部流程的另一条扩展总线。
9.1 Hook 的角色
src/utils/hooks.ts 支持在多个生命周期节点执行用户定义逻辑,例如:
-
• session start / end -
• setup -
• pre tool use / post tool use -
• permission denied -
• pre compact / post compact -
• stop / stop failure
因此 hooks 不是单一“命令前后回调”,而是贯穿整个 Agent 生命周期。
9.2 Hook 的执行方式
hook 可以通过 shell 命令、函数或 HTTP 等方式触发。它们有自己的:
-
• 输入 schema -
• 环境变量注入 -
• 后台执行模式 -
• timeout -
• 事件上报和 tracing
这使 hooks 更像一个轻量自动化框架。
9.3 Hook 与权限的关系
一个关键工程细节是:hook 的 allow 结果并不能越过 deny/ask/safety check。也就是说,hook 可以辅助决策,但不会破坏底层安全边界。
9.4 Hook 与 Skill 的关系
skill frontmatter 可以带 hooks,调用 skill 时会把这些 hooks 注入 session 级注册表。于是 skill 提供方法论,hook 提供执行时机,两者组合成更强的流程编排能力。
10. 安全、鲁棒性与工程设计取舍
10.1 安全边界
Claude Code在安全上不是靠“相信模型”,而是靠多层约束:
-
• 工具 schema 校验 -
• rule-based permissions -
• ask/deny/allow 模式 -
• Bash 专项安全分类 -
• sandbox runtime -
• subprocess env 清洗 -
• MCP 鉴权与会话失效处理
10.2 鲁棒性设计
系统做了很多工程上的防御:
-
• 工具并发与串行分离 -
• max output / prompt too long 恢复 -
• auto compact 失败熔断 -
• session transcript 持久化 -
• background/remote session 支持 -
• tool output 截断与存储
这些机制一起保证系统能在真实仓库里跑较长任务,而不是只适合 demo。
10.3 设计取舍
Claude Code的一些明显取舍是:
-
• 重 prompt 编排,而非重规则引擎 -
• 重统一 Tool 抽象,而非为不同能力写多套执行框架 -
• 重运行时扩展,skills/hooks/MCP 都尽量接到同一主循环 -
• 在 Bash 上投入大量治理,因为它是最强也最危险的工具
代价也很明显:
-
• 入口和模式较多, main.tsx很重 -
• feature flag 较多,理解成本高 -
• prompt、attachments、hooks、memory 共同作用后,行为路径较复杂
11. 总结
11.1 总体判断
从源码组织看,Claude Code的核心不是 UI,也不是单个模型 API 封装,而是一个统一的 Agent runtime:
-
• 以 query()为核心回路 -
• 以 Tool为统一执行接口 -
• 以 QueryEngine/ REPL 为两种主要承载形态 -
• 以 skills、hooks、compact、MCP 为扩展层 -
• 以 permissions/sandbox 为安全底盘
11.2 这个架构最成功的地方
-
• 把 built-in tools 和 MCP tools 统一进同一抽象 -
• 把长任务问题通过 compact/memory 机制工程化解决 -
• 把 skills/hooks 做成运行时扩展,而不是散落脚本 -
• 让 REPL、SDK、remote session 共用核心 query runtime
夜雨聆风