Claude Code 是什么
你输入一条消息,它给你回复——但中间发生了什么?
你在终端输入一条消息
想象你有一个超级聪明的同事,坐在你旁边。你跟他说一句话,他不仅回答你,还能自己打开文件、运行命令、修改代码——然后回来跟你汇报结果。
Claude Code 就是这样的一个存在,只不过它住在你的终端里。它不是网页应用,不是 IDE 插件——它是一个完整的 TUI 程序,直接跑在你电脑上。
因为 Claude Code 跑在你本地,所以它能直接访问你的文件系统、运行 shell 命令、读写代码——这些是普通聊天机器人做不到的。理解这一点,你就知道为什么它有时候能做很厉害的事,有时候又会"动手动脚"改你的文件。
通过 npm install -g @anthropic-ai/claude-code 安装,在你的 CLI 中运行,不需要浏览器或 IDE
你打字、它回复,看起来像聊天——但每一轮对话背后都是一系列复杂操作
不仅能说,还能做:读文件、写文件、运行命令、搜索代码——它是一个真正的 Agent
Claude Code 不是聊天机器人
大多数人以为 Claude Code 就是"在终端里跟 AI 聊天"。但实际上,它是一个完整的本地 Agent 平台,有六层架构,每一层各司其职。点击下面的组件,了解每一层做了什么。
点击任意组件查看详细说明
Claude Code 不是"API 包装器"。它有自己完整的执行引擎、权限系统、记忆机制和扩展框架。理解这六层,你就理解了后面所有内容的基础。
代码翻译:入口的秘密
让我们看看 Claude Code 源码的真实入口。这段来自
TypeScript
文件 src/entrypoints/cli.tsx,它是一切的起点。左边是代码,右边是逐行翻译的中文解释。
main(),没有返回值注意 import() 是动态导入——只有真正需要时才加载模块。这种"快速通道 + 惰性加载"的模式贯穿整个 Claude Code 源码。每一个 if 分支都是一条短路,让你不需要的功能零成本。
完整旅程:从输入到回复
当你在终端输入 claude 并打出一句话,背后发生了一系列精心编排的步骤。这是一条从启动到回复的完整数据流。
入口函数先做最轻量的检查:你只是在查版本号吗?如果是,零模块加载,秒回。否则进入完整启动流程。
加载配置系统、设置遥测(source map)、初始化进程信号处理。还会设置 NODE_OPTIONS 等运行时参数。
检查当前目录是否受信任(首次使用会弹出确认)、验证 API 认证信息、加载安全策略、检测 Git 仓库。
收集所有可用工具:15+ 个内置工具(读文件、写文件、搜索、Bash 等)+ MCP 外部工具 + 预定义技能。这些工具就是 Agent 的"手脚"。
用 React + Ink 渲染终端 UI。显示欢迎信息、加载对话历史、准备好接受你的输入。从此刻起,你看到的就是一个完整的 REPL 界面。
你的消息被组装成 API 请求(包含系统提示词、对话历史、可用工具列表),发送到 Anthropic 云端。AI 模型在那里"思考"并返回结果。
如果 AI 回复中包含工具调用请求("我需要读取 X 文件"),Claude Code 执行该工具,把结果返回给 AI,AI 继续思考——这个循环会一直进行,直到 AI 不再请求工具,给出最终回复。
当 Claude Code 出问题时,你可以根据这个流程快速定位:是启动阶段出了问题?还是 API 调用失败?还是工具执行被权限拦截了?理解流程就是拥有 debug 的地图。
知识检验
试试看你是否理解了 Claude Code 的架构。选择你认为正确的答案。
1. 当你在终端输入 claude --version 时,cli.tsx 入口函数做了什么?
2. Claude Code 的 Agent Loop 是什么?
3. 如果让你设计 Claude Code 的 CLI 引导层,它的核心设计原则应该是什么?
4. 场景题:Claude Code 想要修改你项目中的一个文件。根据六层架构,哪个层会负责检查这次修改是否被允许?
认识核心角色
每一次 Claude 回复的背后,都有一整组组件在协同工作。
认识它们,就像认识一出戏剧里的演员表。
演员表 — 六个核心角色
想象 Claude Code 是一出舞台剧。你的每一次对话就是一场演出,而这些文件就是各自分工明确的演员。它们各司其职,缺一不可。
当某个功能不正常时,知道"这是哪个演员的台词"能让你快速定位问题。理解了分工,你就能对 AI 说"把这个逻辑放在 X 里,而不是 Y"。
程序的起点。它读取你的命令行参数,快速判断你要做什么(交互模式、--print 单次执行、--resume 恢复会话),然后把控制权交给正确的路径。
初始化一切:注册所有工具、建立 MCP 连接、设置权限上下文、加载技能。准备就绪后,启动 REPL。
你看到的聊天窗口。管理消息列表、输入框、权限弹窗、进度展示。所有状态都在这里汇聚和展示。
核心循环:发消息给 AI → 收到工具调用 → 执行工具 → 结果回流给模型 → 循环。这个异步循环是整个系统的心跳。
每个工具的统一接口:权限检查、输入校验、执行、结果格式化。BashTool、ReadTool、EditTool 都实现这个协议。
文件夹 + Markdown。跨会话记住你的偏好、项目知识、常用规则。下次启动时,Claude 会先读取这些记忆,就像演员上场前温习剧本。
组件对话 — 一次典型交互的幕后
点击下方的按钮,看这些组件在一次典型的用户交互中如何"群聊"。每条消息就是一个组件在说自己的台词。
代码翻译 — Tool 接口长什么样?
左边是真实的源码片段,右边是逐行翻译成"人话"的版本。这就是所有工具(BashTool、ReadTool、EditTool 等)共同遵守的协议。
所有工具共用同一个接口,意味着添加新工具只需要实现 call() 方法定义输入 Schema。系统的其他部分(权限、调度、结果处理)完全不用改。这就是接口隔离的威力。
AppState — 共享状态总线
REPL 不仅仅是一个界面,它还是整个应用的状态总线。所有关键数据都挂在它上面,任何组件都可以通过这些共享状态来了解"现在系统处于什么情况"。
所有对话消息的数组。包括你的输入、AI 的回复、工具调用的结果。这是对话历史的完整记录。
当前的权限上下文 — 哪些工具可以自动执行,哪些需要用户确认。动态更新,取决于你的设置和对话进展。
所有已连接的 MCP(Model Context Protocol)服务器。每个 MCP 服务器提供额外的工具和资源,扩展 Claude 的能力。
可用的 Agent 定义列表。Agent 是带有特定人格和能力的子 AI,可以并发启动来处理子任务。
通知队列。当工具完成、权限被请求、或 Agent 汇报时,通知会排队显示在这里。
如果 Claude Code 是一个剧组,AppState 就是后台的公告板。所有演职人员(组件)都看同一块公告板,知道"现在演到第几幕"、"谁在台上"、"接下来轮到谁"。
场景测试 — 你会找谁?
下面是三个真实场景。根据你刚学到的组件分工,选择最合适的答案。
rm -rf /tmp/test,系统需要先确认这个命令是否安全。这个权限检查的逻辑属于哪个组件的职责?工具执行流水线
从 AI 建议到真实执行 —— 每一次工具调用都要经过同一条质检流水线
总链路:一次工具调用的完整旅程
当 Claude 说 "让我运行这个命令" 的时候,它并不是直接在你的电脑上执行。相反,这个请求要经过一整条 流水线, 每个环节都有自己的职责 —— 就像工厂里的质检站,零件必须逐个通过才能出厂。
模型输出
收集调用
分区调度
执行引擎
结果封装
回流循环
工具调用不是直接的函数调用 —— 它们要经过 Schema校验、 权限检查、 Hook钩子 然后才真正执行,执行结果再通过 tool_result 流回模型。理解这条链路,是调试 "为什么我的工具没执行" 的关键。
并发 vs 串行:partitionToolCalls() 的智慧
模型可能一次性输出多个工具调用。但并不是所有工具都能同时执行 —— 有的只读不写,安全无副作用;有的会修改文件或运行命令,必须排队。这就是
partitionToolCalls() 要解决的问题。
标记为 isConcurrencySafe 的工具 —— 如 FileRead、Glob、Grep —— 只读不写,可以安全地
批处理
并行执行。
会修改状态的工具 —— 如 FileEdit、Bash —— 必须排队执行,防止并发冲突(两个工具同时改一个文件)。
partitionToolCalls() 把工具调用列表分成若干"批次"(Batch)。相邻的并发安全工具合并在同一批次里并行执行;一旦遇到非并发安全的工具,就开一个新批次串行执行。这样既保证了安全,又最大化了效率。
代码解读:partitionToolCalls
下面这段来自 src/services/tools/toolOrchestration.ts 的代码,就是分区逻辑的核心。左边是源码,右边是逐行中文解释。
因为分区逻辑需要"看前一个":只有相邻的并发安全工具才能合并。reduce 天然适合这种"一边遍历一边累积"的模式。一次遍历就完成分区,时间复杂度 O(n)。
单次工具执行:6 个检查站
当一个工具调用被分到某个批次后,它还要经过 6 个 "质检站" 才能真正执行。每个检查站都可能阻止执行 —— 这是 Claude Code 安全模型的核心。
输入参数是否符合该工具定义的 JSON Schema?比如 file_path 必须是字符串,command 不能为空。不符合就直接报错。
某些工具有额外的自定义校验逻辑。比如 FileEdit 工具会检查 old_string 是否真的出现在文件里。
用户配置的前置钩子在这里执行。例如你可以配置一个 hook,在每次 Bash 执行前自动检查是否包含危险命令。
ask / deny / auto —— 权限规则决定这个工具调用是否需要用户确认。如果是 ask,会弹出确认对话框;如果是 deny,直接拒绝执行。
通过了前面所有检查站后,才调用工具自身的 call() 方法。每个工具都实现了自己的 call(),比如 Read 工具读取文件内容、Bash 工具启动子进程。
执行结果被格式化为 tool_result 消息块。无论成功还是失败,都会生成结果 —— 错误信息同样会反馈给模型。
注意第 1-4 步都是"防御性"的 —— 它们只做检查,不执行任何实际操作。真正的执行只有第 5 步。这种 "先检查、后执行" 的模式是 Claude Code 安全模型的核心原则。
结果回流:工具执行结果的旅程
工具执行完毕后,结果并不是 "到此结束"。它要经过一个叫 回流 的过程,重新回到 异步生成器 的 query 循环里。
tool.call() 返回结果
封装为 tool_result 块
追加到对话历史
发给模型重新推理
继续调用工具 / 回复用户
模型看到 tool_use 的结果后,会做出判断:
如果结果不完整或需要更多信息,模型会再输出新的 tool_use,重新进入流水线。
如果信息足够,模型直接输出文本回复,query 循环结束,用户看到结果。
如果工具执行失败,错误信息也会回流到模型,模型会据此调整策略或向用户报告。
工具调用 -> 结果回流 -> 模型推理 -> 可能再次调用工具 —— 这个循环可以反复进行多次。这就是 Claude Code 能完成复杂任务的原因:它不是一次性给答案,而是一步步探索、验证、调整,直到完成目标。
测验:工具执行流水线
partitionToolCalls() 会怎么处理?
tool_result。接下来会发生什么?
记忆与上下文系统
Claude Code 不会每次从零开始。它有一套归档系统。
四层记忆系统
想象一个记者的工作台:每日速记本用来记当天发生的事, 参考卡片盒存长期有用的知识, 团队公告板共享给所有人看, 个人日记本只写自己的心得。 Claude Code 的记忆系统也是四层,每层有不同的生命周期和可见性。
自动提取的长期记忆,存放在
memory 目录。
MEMORY.md 是
索引,
具体记忆写在独立的 *.md 文件里。
当前会话摘要,辅助
compact
和长会话持续运行。
阈值触发后才启用,由后台 subagent 维护,权限严格(0o600)。
绑定到特定 agent 类型的持久记忆。分 user / project / local 三个 scope。 在 agent 的 system prompt 中直接注入,从第一轮就知道自己的记忆目录。
团队共享的 repo 级知识同步。带 pull / push、 watcher、 checksum、secret scanning 的受控同步层。
记忆不是数据库,是 Markdown 文件夹。用户可以直接打开目录查看、编辑、删除。透明、可治理、可组合。
代码翻译:记忆常量
源码 src/memdir/memdir.ts 里定义了记忆系统的核心参数。
这几行代码决定了模型"看什么、看多少"。
因为文件是用户可以直接打开看的。透明、可治理、可手动编辑。用户可以删掉一条错误记忆,也可以手动补充一条。这比一个黑盒 KV 存储更能让人信任。
文件即记忆
Auto Memory 的存储不是写死的,而是通过路径计算函数动态解析。 以下是最常见的本地安装时的目录布局:
系统设计了规则防止记忆膨胀(200 行上限、相关性召回),但错误记忆、过时记忆、重复记忆仍会持续影响 agent 行为。建议定期检查 MEMORY.md 和 memories 目录。
上下文组装:每次 API 调用都装了什么
每次向模型发 API 请求时,Claude Code 会把以下材料按层叠入 上下文窗口。 这不是随意堆砌,而是有明确的组装顺序。
技能描述、规则文件(CLAUDE.md)、工具 schema、角色定义。这是每一轮对话的"宪法"。
前 200 行的记忆索引。模型永远能看到这份清单,知道"自己知道什么"。
按相关性选出最多 5 个记忆文件的内容。不是全塞,是轻量检索器用 sideQuery 做选择。
当前会话的历史消息。如果经过 compact,这里会变成精简后的摘要 + 最近几轮完整对话。
上一轮工具调用的返回结果。文件内容、命令输出、搜索结果等都在这里。
所有层叠好之后,组成一个消息数组,发送给 Anthropic API。模型看到的就是这个完整的上下文。
理解上下文组装的顺序和限制,你就知道为什么 Claude Code 有时候会"忘记"之前说过的话——不是因为记忆坏了,而是那条信息被 compact 掉了,或者没有被写入记忆文件。把重要的事写进 MEMORY.md,是让模型持续记住的关键。
Compact — 上下文压缩
对话越来越长,上下文窗口终归会满。 Claude Code 不用暴力截断,而是设计了一套精密的 compact 机制。
shouldCompact() 检查当前消息的 Token 长度。
当接近上下文窗口上限时(预留约 13,000 Token 缓冲区),自动触发压缩。
用户也可以随时手动输入 /compact 触发。
系统先把图片和冗余附件剔除(脱水),然后交给一个 Forked Subagent 生成摘要。 摘要完成后,旧消息被替换成一条短的 Summary Message。 但关键状态会被重新注入:当前查看的文件、激活的工具列表、进行中的 Plan。
如果会话已经很长,Session Memory 会自动提取摘要。 Compact 时直接读取这份摘要作为断点,不再额外调 API 浪费 Token。 这是整个 compact 设计中最巧妙的工程细节之一。
测验:你会用记忆系统吗?
你希望 Claude Code 记住"我喜欢用 TypeScript 写后端"。它把这个信息保存后,下次新会话时模型是如何看到这条记忆的?
你定义了一个自定义 agent 叫 code-reviewer,希望它在所有项目中都能记住"团队偏好用函数式写法"。你应该选哪个 scope?
你正在做一个大型重构任务,对话已经进行了 50 轮,上下文快要满了。系统自动触发了 compact。
安全沙箱与扩展能力
一个能在你电脑上执行命令的 AI 是危险的。Claude Code 如何保护你——以及你如何扩展它。
沙箱不是开关,是链条
想象一个银行金库:不是一道门,而是门卫 → 存款箱 → 警报系统多层防护。Claude Code 的 沙箱 也一样——四个环节环环相扣,缺一不可。
沙箱不是安全边界——权限系统才是真正的防线。沙箱只是其中一层隔离手段。
判断当前命令是否需要进入 隔离 环境。它会检查命令内容、用户设置和 特性开关, 返回 true 或 false。
把高层的用户设置("我要用沙箱")翻译成底层 运行时 配置——告诉底层隔离工具具体怎么限制文件访问、网络权限等。
定义哪些命令自动放行、哪些需要拒绝、哪些需要询问用户。即使进了沙箱,这层 权限 规则依然生效。
真正的隔离执行。命令在受限环境中运行,执行完毕后自动 清理 临时文件和进程句柄,不留痕迹。
需要沙箱?
翻译配置
权限检查
隔离执行 + 清理
权限系统 — 四种命运
每一条命令在执行前都要经过
权限
系统的审判。你的 .claude/settings.json 中可以精确控制每条规则:
allow
自动允许 — 这个命令被无条件放行,不询问用户
deny
永远拒绝 — 不管什么情况,这条命令绝对不会执行
ask
每次都问你 — 弹出确认对话框,由你亲自决定放行与否
sandbox
在沙箱中执行 — 命令可以跑,但被隔离在受限环境里
在 .claude/settings.json 的 permissions 字段中,你可以为特定命令模式设置规则。例如:"Bash(git log *)": "allow" 让所有 git log 命令自动通过。
Skills — 技能系统
Skills 是 Claude Code 的插件机制。一个 Markdown 文件 + YAML frontmatter = 一个技能。技能被 注入 到 system prompt,不需要修改源码。
用户级技能
~/.claude/skills/ — 跨项目通用,所有项目都能用
项目级技能
.claude/skills/ — 团队共享,跟随项目仓库
内建技能
Claude Code 自带,开箱即用
发现路径的优先级:用户级 → 项目级 → 内建。加载过程使用 memoize 缓存 + Promise.all 并行读取:
技能不修改源码、不编译、不安装依赖——纯文本声明式扩展。这降低了扩展门槛,也让团队协作时可以通过 Git 同步项目级技能。
MCP — 模型上下文 协议
MCP(Model Context Protocol)让 Claude Code 连接外部工具服务器。每个 MCP 服务器暴露一组工具,Claude Code 按约定格式调用。工具名的命名遵循严格的规则:
filesystem
安全文件读写,限制在指定目录范围内
puppeteer
浏览器自动化——截图、填表、爬取
自定义服务器
用 npm 包或 Docker 镜像运行自己的 MCP 工具
源码解读 — shouldUseSandbox
这段代码决定一个命令是否需要进入沙箱。注意那个关键注释——排除列表是用户便利功能,不是安全边界。
注意 getFeatureValue_CACHED_MAY_BE_STALE 这个函数名——开发者故意把"缓存可能过期"写进函数名,而不是藏起来。这种命名方式本身就是一种文档。还有那个 dangerouslyDisableSandbox,用 dangerously 前缀警告调用者三思。
多 Agent 形态 — 一个代码库,六种运行方式
Claude Code 不仅仅是你在终端里用的那个聊天界面。同一套代码可以以六种不同形态运行:
默认终端交互模式——你在命令行里跟 Claude 对话
无 UI 模式——编程调用,用于自动化流水线和 CI/CD
对外暴露能力——其他 AI 客户端可以通过 MCP 协议 调用 Claude Code 的工具
远程控制 模式——连接远程机器上的 Claude Code 实例
后台常驻——以 守护进程 方式运行,随时接受任务
后台任务 ——启动后可以切换去做别的事,回来查看结果
这不是"六个产品",而是"一个核心 + 六个入口"。所有形态共享同一套工具系统、 权限 系统和上下文管理。这就是为什么理解核心架构如此重要——掌握了核心,就掌握了全部形态。
知识检验
一个命令通过了沙箱检测,被允许在隔离环境中执行。这意味着它是安全的吗?
你想给 Claude Code 添加一个自定义技能。你需要做什么?
mcp__filesystem__read_file 这个工具名中,各部分的含义是?