ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code源码拆解:从入口到工具调用的完整分析

Claude Code源码拆解:从入口到工具调用的完整分析 简介claude-code源码是一套面向人工智能开发者的TypeScript/TSX程序包聚焦AI编程助手的底层实现适合具备前端或Node.js基础、希望深入理解智能代码生成与指令交互机制的中高级研发人员。压缩包内共1903个文件以1332个ts源文件与552个tsx组件文件为主体辅以少量js脚本及md说明文档整体约9.43MB目录结构清晰从入口文件出发便能追踪模块划分与复用路径覆盖状态管理、算法调用和结果输出等主要环节。目前已有1112人学习下载。研读这套源码不仅可以学习大规模TS项目的类型定义、依赖组织与状态管理实践还能在工具调用、上下文传递、错误恢复等细节中体会AI产品落地的工程权衡对于想基于CLAUDE能力做二次开发或进入大模型应用层研究的读者是一份难得的一手代码样本也为后续扩展或重构提供了清晰的参考基线。1. 拆包之前先纠正一个认知claude-code 的“源码”到底在哪很多人都以为 claude-code 是纯云端服务本地只有一个壳。其实只要你在终端跑过npm install -g anthropic-ai/claude-code完整的可执行产物就已经躺在本地了。这不是传统意义的开源项目但它的确是一份可以拆解的、自包含的 JS 产物读这份产物的过程跟逆向一个打包后的前端应用非常像。先确认你机器上的实际路径# Linux / macOS which claude readlink -f $(which claude) # Windowsnvm4w 环境下常见路径 # C:\nvm4w\nodejs\node_modules\anthropic-ai\claude-code\bin\claude.e...用 nvm4w 装过 claude-code 的人应该对上面这个路径很眼熟不少报错信息里都会带出它。找到node_modules/anthropic-ai/claude-code之后用ls -la看一下目录结构你会看到大致这样几类东西package.json记录了入口、命令名、依赖关系是逆向的第一手情报。cli.jsnpm 的 bin 字段指向的入口脚本。vendor/真正干活的打包产物体积巨大里面是压缩混淆过的业务代码。若干.cjs/.js文件负责启动、版本检查、更新提示之类的杂活。我建议你先把package.json完整读一遍。bin字段能告诉你命令映射到哪个文件dependencies能告诉你它依赖了哪些上层 SDK比如anthropic-ai/sdk、yargs之类的解析库。这些信息拼起来基本就能还原出这个工具的项目骨架。2. 入口文件 cli.js 的背后命令分发与一次会话的启动流程2.1 bin 软链与 wrapper 的真实作用npm 全局安装后bin目录里的claude并不是真实代码它只是一个软链或者 wrapper。Linux/macOS 下一般是符号链接Windows 下是由 npm 生成的.cmd/ shell 包装器最终都会跳转到vendor目录里那个真正的启动文件。这一点看起来不起眼但排查问题的时候特别关键。比如 Windows 下常见的“无法加载 claude因为在此系统上禁止运行脚本”之类的报错本质是 PowerShell 执行策略拦截了.ps1包装器跟 claude-code 本身的代码没有任何关系。理解了这层启动链路你就能快速判断报错到底出在 npm 包装层、Node 运行时还是 claude-code 自己的逻辑里。2.2 参数分流从 process.argv 到交互式与非交互模式真正进入业务代码后第一件事就是解析process.argv。claude-code 有两条完全不同的执行路径直接运行claude进入交互式 TUI终端界面等待用户输入循环处理消息。运行claude -p 你的问题走非交互的 print 模式单次请求后直接输出结果并退出适合写在 CI 脚本或自动化流水线里。源码里对参数的分流逻辑非常清晰-p/--print会触发流式响应并输出到 stdout-c/--continue会加载上次会话的历史记录--model直接覆盖默认模型。这些参数看起来简单但它是理解 claude-code 自动化能力的基础。比如我在做批量代码审查时就是用claude -p配合 shell 循环把每个文件的 diff 喂进去再汇总结果。没有这层参数解析工具就只是一个聊天框没法嵌入工作流。顺带一提入口文件里还有版本自检逻辑每次启动会比对本地版本和远端版本如果有更新会提示。这个逻辑本身不影响使用但如果你在离线环境或者内网环境用它可能会拖慢启动速度。源码里能看到对应的超时设置实测下来如果网络不通启动会卡几秒别慌这不是死锁。3. 核心机制拆解工具调用、系统提示词与会话上下文窗口3.1 内置工具的注册表与权限约束claude-code 之所以能改代码、跑命令不是因为它接了什么黑魔法而是源码里注册了一组工具每个工具都以 JSON Schema 的形式描述自己的入参。比如读文件工具schema 里定义了path参数写文件工具定义了path和content参数执行命令工具则允许传入 shell 命令字符串。这些工具描述会在每次请求时被拼进发给模型的系统提示词里模型根据用户的意图选择调用哪个工具然后以结构化 JSON 的形式返回工具调用结果。claude-code 本地再执行对应的工具函数把执行结果拼进上下文继续下一轮模型调用。权限系统也藏在这一层。源码里有权限模式的概念默认模式之下敏感操作会弹确认提示你也可以用--allowedTools或配置文件把某些命令列入白名单让它自动执行。理解了这个机制你就知道为什么 claude-code 敢直接操作文件系统——它本质上是一个套了权限闸门的工具调度器。风险控制不是没有而是分布在这层工具注册表里。3.2 系统提示词的组装顺序与 CLAUDE.md 的加载优先级claude-code 的“人格”和“技能边界”完全由系统提示词决定。源码里有一段很长的模板字符串通常被压缩成一行但通过搜索关键词可以定位到。它定义了 claude-code 的角色定位、行为边界、回答风格甚至包括“不要编造不存在的内容”这类约束条件。真正值得关注的是 CLAUDE.md 文件的加载逻辑。源码里会递归查找当前工作目录及其父目录中的 CLAUDE.md把它作为额外的项目上下文注入系统提示词。这里有个优先级顺序用户级配置~/.claude/CLAUDE.md作为基础项目级 CLAUDE.md 覆盖在其上子目录里的 CLAUDE.md 则会追加加载。我在实际项目里测试过一个场景在仓库根目录写了一份 CLAUDE.md在里面定义了代码风格约定然后在src/modules/子目录里放了一份更细的模块说明。claude-code 执行到那个子目录时会自动把两份文档都拼进去。这个递归加载逻辑对团队协作非常有用但也要注意CLAUDE.md 文件越长系统提示词越大每次请求的输入 token 消耗就越高。3.3 会话历史的压缩策略还有一个很容易被忽略的机制是上下文裁剪。普通用户的会话可能持续几十轮如果全量把历史消息塞给模型token 消耗会爆炸。源码里有一套处理逻辑当消息数量或 token 总量超过阈值时会触发上下文压缩把早期的对话总结成摘要只保留摘要和最近几轮完整消息。我印象里这套压缩逻辑还会结合消息类型做取舍工具执行结果这类大块文本更容易被优先压缩而用户的核心指令会尽量保留。理解这一点相当重要当你发现 claude-code 在长会话里“忘了”前面的细节通常不是模型变笨了而是上下文压缩把早期内容变成了摘要细节丢失了。这时候果断开新会话把必要信息重新写清楚比在旧会话里继续追问更高效。4. 计费与第三方接入从源码读透 claude-code 调用 DeepSeek 的价格逻辑4.1 API 端点与环境变量的读取位置源码里最值得搜的一段逻辑就是环境变量读取。claude-code 在构建请求时会按固定优先级读取一组配置项其中有两个直接决定请求发往哪里ANTHROPIC_BASE_URLAPI 端点地址默认是 Anthropic 官方域名改成任何兼容端点后流量就会发往那个地址。ANTHROPIC_AUTH_TOKEN认证令牌默认对应 Anthropic API Key改成第三方服务商提供的令牌后鉴权也会随之切换。换句话说claude-code 本身并不绑定 Anthropic 的服务。它在设计上就是一个 API 客户端只要目标端点能讲 Anthropic 的 Messages API 协议它就能工作。这就是社区里大量“claude-code 接入 DeepSeek”、“claude-code 接入国内模型”做法的底层原理——用一个兼容层或中转服务把 Anthropic 格式的请求转换为目标服务商能理解的格式。4.2 真正决定计费的是端点对应的服务商源码层面没有“计费”这个概念。claude-code 不生产 token也不负责计价它只负责发送请求和接收响应。所谓“claude-code 调用 DeepSeek 如何计费”实际问的是DeepSeek 的服务端按什么标准收钱。DeepSeek 这类第三方模型服务商计费通常是按输入 token 和输出 token 分别计价价格远低于 Anthropic 官方模型。但要注意计费口径并不完全一致比如是否计入缓存命中、是否对上下文缓存有折扣各家的实现都不一样。下面是两种计费逻辑的核心差异计费维度Anthropic 官方 APIDeepSeek 等第三方服务计价单位输入/输出 token 分别计价输入/输出 token 分别计价缓存机制有提示词缓存命中部分价格更低取决于服务商是否支持缓存计费模型定价由 Anthropic 官方统一定价由第三方服务商独立定价计费透明度官方控制台可查取决于服务商后台这里有一个容易踩坑的点很多人以为接入 DeepSeek 之后模型名还叫claude-sonnet-...于是按照官方定价估算成本结果账单完全对不上。实际上第三方服务商通常会有自己的一套模型名映射真实计费严格按照它服务端收的单价和实际 token 消耗来算。跟源码相关的只有一点请求头里带了哪些字段、max_tokens设了多少这直接影响单次请求的 token 量。4.3 从源码视角看成本控制的关键点既然 claude-code 按 token 消耗付费那控制成本的关键就是控制 token。有三个位置是源码层面就能看出来的“吃 token 大户”。第一是系统提示词本身。每次请求都会打包一份完整的系统提示词CLAUDE.md 越多这部分输入 token 就越高。我实测过一个写了很多背景文档的仓库单次请求光系统提示词就可能吃掉几千 token。第二是工具描述。每个注册的工具都会带 JSON Schema 描述工具越多请求体越长。第三是工具执行结果。claude-code 会把工具读取的文件内容、命令输出原样拼进上下文读一个大文件等于把整个文件都付了一遍 token 钱。所以实操上的建议是CLAUDE.md 里只写最有价值的项目约定别把文档正文都塞进去大文件让 claude-code 用grep之类的方式定位关键内容而不是cat整个文件如果需要跑长会话适当开新会话避免上下文压缩前的 token 堆积。5. 对产物动手本地定制与调试的一些实际操作5.1 格式化产物与定位关键代码读压缩混淆过的代码前建议先做一次格式化。用npx prettier或者 Node 自带的--print逻辑把 vendor 目录里的 JS 文件重新排版可读性会大幅提升。格式化之后直接搜索关键字# 在 vendor 产物里搜索环境变量名 grep -n ANTHROPIC_BASE_URL vendor/*.js | head -20 # 搜索系统提示词的特征片段 grep -n You are Claude Code vendor/*.js | head -10定位到这些字符串所在的位置再往上翻函数定义你就能看到变量读取、默认值、以及如何拼进请求体的完整链路。我用这个方法确认过几个问题比如某个环境变量到底支不支持、某个配置项的实际作用范围是什么。比对着文档猜要准确得多。5.2 常见定制玩法的风险与替代方案有些人会直接改打包产物比如改默认模型名、删掉某个内置工具、修改系统提示词。这类操作确实能生效因为 claude-code 的很多配置是在本地解析后拼进请求的。但要注意npm 包升级后所有改动都会丢失而且改混淆过的产物一旦格式或上下文对不上可能就是运行时报错。更稳妥的做法是用环境变量和 CLAUDE.md 完成定制。绝大多数你能想到的配置项其实都已经通过环境变量暴露出来了不需要动代码。如果真到了非改不可的地步我建议锁定版本号npm install -g anthropic-ai/claude-code具体版本然后对 vendor 目录做备份至少保证升级时能回滚。这里不讨论商业条款问题但从工程维护角度讲直接改闭源产物会让你失去官方升级的兼容性保障升级前必须做好充分测试。6. 读完整份产物之后我对 claude-code 的理解如果你只是把它当一个命令行工具用那读源码的意义不大但如果你想搞明白它为什么能改代码、为什么能接第三方模型、为什么每次请求那么贵源码就是唯一可靠的答案来源。我现在的习惯是遇到一个不熟悉的 CLI 工具先看它的 package.json再看环境变量读取逻辑基本就能判断出这个工具的架构风格和扩展边界。claude-code 这套设计里最值得借鉴的是把客户端与模型服务解耦的思路客户端只负责工具调度和上下文管理模型服务只负责文本生成两边通过标准协议通信。这种架构让工具本身变得非常灵活——后端模型可以换前端交互可以换但中间那层工具注册表和权限控制始终是核心资产。最后分享一个我自己调试时的小技巧开一个临时目录把ANTHROPIC_BASE_URL指向一个本地记录请求的 mock 服务然后让 claude-code 跑一个简单任务你就能看到完整请求体里到底装了什么。这个方法比读一百行源码都直观——系统提示词怎么拼的、工具描述占多大、历史消息如何组织一目了然。我每次研究一个新的 AI 编程工具第一件事永远是抓包看请求体这比任何文档都诚实。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进