ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Claude Code源码级拆解:从启动到工具执行的核心链路还原

Claude Code源码级拆解:从启动到工具执行的核心链路还原 简介Claude Code开源项目源码包面向想深入理解AI编程工具内部实现的开发者、研究者以及需要 TypeScript 工程范本的中高级学习者。zip压缩包内完整保留1903个文件、约9.43MB其中以1332个ts文件承载核心逻辑与数据处理552个tsx文件对应组件化界面另有js脚本和md文档辅助构建与项目说明。整体采用模块化和面向对象设计将复杂功能拆分为高内聚小模块工具类与辅助函数的高复用设计明显降低了维护成本项目附带大量注释、测试用例、开发者指南、API文档和用户手册既能学习源代码的设计思路也能参照其工程规范进行二次开发与扩展。源码管理遵循Git协作方式目录结构清晰便于跟踪变更与排查问题已有279人学习/下载适合作为前端或全栈方向开发者的源码分析范本。 最近我频繁在群里看到同一类问题Claude Code 源码哪里能看、npm 装完之后到底哪一个是入口文件、claude code 和 opencode 架构源码有什么区别…… 说句实话Claude Code 官方并不开放完整源码npm 包里只有被打包混淆的运行产物你想 clone 一份干净源码自己改改在官方路径上基本做不到。但这个话题依然有解。我研究 Claude Code 半年多了从安装、配置、Skill 到接入第三方模型再到把它嵌进 CI 持续集成踩过的坑足够写几屏。这篇博文我就用源码级拆解的思路不带内部资料只靠公开文档、配置行为、日志缓存以及开源替代品的代码结构把 Claude Code 从启动、会话、模型调用到工具执行的完整链路还原给你。无论你只是想装好它接进 VSCode还是想基于它做二次开发这篇都能给你一套看得懂、能落地的地图。1. 先把Claude Code源码这个话题说透你看到的其实不是源码1.1 全网都在搜一个不存在的东西这里要先把话说清楚。Claude Code 是 Anthropic 推出的命令行 AI 编程助手安装方式很简单npm install -g anthropic-ai/claude-code。但 npm 包不等于源码它就像去店里买了个预制菜包装上有配料表但没有给厨师的完整菜谱。发布到 npm 的代码是经过打包、混淆的 JavaScript 产物变量名都被处理过和真正意义上的可读源码完全是两回事。Anthropic 没有开放它的核心仓库GitHub 上能找到的anthropics/claude-code主要是一些 issue 跟踪和文档不是全部实现。这背后的原因也不难理解Claude Code 的核心竞争力就是那套 Agent 编排逻辑——怎么组装上下文、怎么决定调哪个工具、怎么处理工具结果这些思考过程属于商业护城河开源了等于把自己的底牌亮出来。但矛盾点在于生态需要开发者参与所以它又必须开放配置、Hooks、MCP 这类扩展接口。于是你就看到源码没有但扩展点一堆的局面。这不是缺陷而是商业闭源产品的典型形态。1.2 没有源码源码级拆解照样成立既然官方源拿不到我们怎么研究我一般用两条线并行。第一条线叫行为侧写开一个测试项目盯着 Claude Code 的输入输出、debug 日志、~/.claude/下的缓存文件观察它先执行什么命令、后执行什么命令、报错时读取了什么配置。这些东西虽然是运行时表象但能非常准确地反推出内部模块划分和调用顺序。第二条线是开源替代品对照目前社区里最有代表性的是 opencode一个 TypeScript 写的开源版本源码完整放在 GitHub工具注册、权限校验、模型 Provider 抽象这些核心模块都能看到。两条线合起来你大脑里就能建立起一个逻辑源码——不是逐行抄的代码而是对系统行为的精确建模。我在实际研究里的体会是大多数搜Claude Code源码的人内心真正想要的不是某一堆代码文件而是当它执行某件事时内部到底发生了什么这个答案。只要把行为模型建立起来闭源和开源对你来说差别不大。2. 从命令行输入到模型返回还原主循环里的几个关键模块2.1 入口、会话与上下文管理敲下claude命令后发生的事情我会拆成四层来看。第一层是 CLI 入口解析--model、--continue、--output-format、-p这类参数决定你是进入交互式 REPL 还是只跑一条一次性指令。第二层是会话管理读取~/.claude/projects/下的历史会话记录把之前的多轮对话、当前工作目录、git 分支状态恢复出来。第三层是上下文采集Claude Code 会先扫一遍项目结构读.gitignore、找.claude/目录、执行一组只读命令把项目当前状态打包成上下文。第四层才是模型调用把组装好的 system prompt、tools 定义、历史消息一起发给模型 API。很多新手第一次用 Claude Code 都会问它怎么这么懂我的项目 其实就是因为第三层做足了文章。你可以用claude --debug跑一次简单对话日志里能看到它自动执行了ls、git diff --stat、find之类命令顺手把相关文件读进上下文。这个过程非常像新手程序员接手老项目时先看目录结构、再看 git 历史、再读核心文件只是它把这几步做成了可重复的流水线。2.2 模型路由与请求组装Claude Code 默认走 Anthropic 的 Messages API但在代码结构上它一定有一个模型路由模块专门决定这次请求发给谁、用什么模型名、带什么参数。路由的输入来源按优先级排列CLI 参数、环境变量、项目配置、用户配置。最后解析出来的模型名会填进请求体的model字段。请求体不是只有 messages 那么简单还要附带完整的工具 schema、system prompt、max_tokens、temperature以及各种控制参数。这里就有一个经典翻车点。很多人想给 Claude Code 接 DeepSeek于是设置ANTHROPIC_BASE_URL指向兼容网关再把ANTHROPIC_MODEL改成deepseek-chat结果启动直接报错deepseek-v4-pro is not a model this version of claude code recognizes。这个错误说实话很有迷惑性因为它看起来像是版本不支持这个模型但本质是模型路由模块在启动时拿模型名做了一次白名单校验发现你给的名字不在它认识的枚举列表里。Claude Code 根本不打算支持任意模型名它只认自己家的那几种模型 ID 和别名。想让网关生效正确思路不是教 Claude Code 认识新模型而是在网关层做模型名映射Claude Code 请求时仍然说自己要调用sonnet网关收到后再把这个请求转发给 DeepSeek 或者本地模型返回时再转成 Anthropic 的格式。这种方案才是社区里真正能落地的接入 DeepSeek姿势。具体配置冲突排查我在第 4 节会展开。2.3 工具执行与响应收敛模型流式返回有两种内容块text和tool_use。如果是纯文本直接输出给用户如果出现tool_use主循环会进入工具执行阶段。关键点是它不是拿到工具调用就立刻执行而是要过一个权限闸门。默认情况下只读命令直接放行写操作或危险命令会弹确认框。用户确认后工具真正执行再把结果包装成tool_result塞回 messages带着新内容重新发起模型请求。这个请求-工具-反馈-再请求的循环会一直转直到模型不再要求调用工具。这里有一个特别容易踩的暗坑工具结果太长会被截断或摘要。比如你让 Bash 工具执行cat huge-file.log如果这个文件几万行Claude Code 不会把全部 10 万 token 塞回上下文而是做截断处理只保留头尾或者中间采样一部分。很多文件里明明有答案但 Claude Code 却看不到的诡异情况基本都是这个原因。知道了这点你喂给它的文件最好提前用grep过滤或者直接把关键行读出来而不是让它自己去 cat 大文件。3. 工具系统才是 Claude Code 的灵魂Schema、权限、执行器三件套3.1 内置工具清单与职责边界Claude Code 内置工具大致有这些Bash、Read、Write、Edit、Glob、Grep、WebFetch、WebSearch、TodoWrite、Task。每个工具放进模型请求之前都会先被序列化成 JSON Schema描述工具叫什么、参数有哪些、参数类型是什么。模型看到这堆 schema 后就知道自己可以使用哪些手脚。如果用源码思维去抽象一个工具就是三段式结构Schema 负责描述Execute 负责执行Permission 负责管控。三个模块彼此独立这也是为什么你可以很轻松地加自定义工具。官方通过 MCP 协议开放了工具注册能力你不需要改 Claude Code 的代码只需要提供一个 MCP server它就会在启动时动态把 MCP 工具列表并入已有工具集。这种设计很像浏览器插件机制核心进程不开源但扩展位全部开放。3.2 权限模型哪些操作会弹确认框权限模型是工具系统里最需要认真理解的部分。Claude Code 默认运行在逐步确认模式但我实测发现它并不是每个工具都问而是有一套内置的风险分级。只读类命令比如ls、cat、grep、git diff一般直接执行文件写入类工具比如 Write、Edit会有确认提示危险 Bash 命令比如rm -rf、mv、sudo一定弹框网络请求类工具比如 WebFetch也会在第一次请求时确认。如果你想在 CI 或脚本里无人值守地跑一定要在启动参数里规划好--allowedTools和--disallowedTools。我在真实项目里踩过一次坑写了个自动化脚本忘了配 allowedTools结果 Claude Code 执行到要改文件的那一步权限闸门卡住进程一直等确认CI 超时直接飘红。后来我修改了策略用--allowedTools Bash(cat*) Bash(git*) Edit Write这样的粒度既不会把所有命令都放行又保证自动化流程能往下走。这里多提一句--dangerouslySkipPermissions这个参数我建议只在一次性容器里用平时别碰。3.3 用 MCP 和 Skill 扩展工具面MCP 配置大概长这样项目根目录放一个.mcp.json声明一个本地 server 用npx启动或者远程 server 填 URL。Claude Code 启动时会去读这个文件把 server 往返过来的工具列表并入主工具表。这些 MCP 工具同样走权限闸门可以被 allow/disallow 规则约束。你完全可以把自己团队里的数据库查询接口、构建系统、工单平台都做成 MCP server让 Claude Code 在对话里直接调用。除 MCP 外Skills 是另一个被低估的扩展点。Skill 本质是一个目录里面放SKILL.md和若干辅助文件。SKILL.md用 Markdown 写清楚这个技能什么时候触发、怎么执行、需要调用哪些工具。比如我写了一个代码审查技能规定当用户在对话中触发/review时先执行git diff获取改动再读取项目根目录的规范文档最后按模板输出审查意见。Skill 相比普通 Prompt 的优势是它把工具调用流程也写进了技能文档里模型会按文档步骤走而不是自由发挥。4. 配置文件里的源码级秘密模型白名单和 Hooks4.1 从报错 deepseek-v4-pro 说起模型名校验逻辑前面提到的deepseek-v4-pro is not a model this version of claude code recognizes是最近热词里出现频率很高的报错。很多人收到这个报错后第一反应是升级 Claude Code但升级几轮后依然存在。结合我前面对模型路由的分析这个报错的根源在配置校验层。Claude Code 的模型名解析逻辑会维护一个已知模型集合集合里包含常见的 Claude 模型 ID比如claude-sonnet-4-20250514以及opus、sonnet、haiku这类别名。如果你设置的环境变量或配置项里的模型名不在集合里启动阶段就会直接抛错。要绕过这个限制正经做法是网关映射。我在本地实验用的方案是在本地起一个兼容服务监听某个端口环境变量里写ANTHROPIC_BASE_URLhttp://localhost:9000ANTHROPIC_MODELsonnet。Claude Code 发请求时会带着modelsonnet发给本地服务本地服务收到后把请求转发给 DeepSeek 的 API同时把模型名改成 DeepSeek 认的名字DeepSeek 返回后再按 Anthropic 的消息格式转回给 Claude Code。从 Claude Code 视角看它的确是在和一个官方的 sonnet通话只是那个官方恰好是你的网关。这个方案不涉及任何逆向或破解只是利用配置层面的规范化转换。4.2 settings.json、环境变量和 CLI 参数的优先级Claude Code 的配置体系特别像 git 的层级默认值在最底层往上是用户级配置再往上是项目级配置然后是环境变量最高层是 CLI 参数。我用一张表来总结配置来源示例优先级CLI 参数claude --model sonnet最高环境变量ANTHROPIC_MODELsonnet高项目配置.claude/settings.json中用户配置~/.claude/settings.json低内置默认值官方默认模型和参数最低这个优先级顺序会坑到很多人。我在帮一个朋友排查问题时发现项目.claude/settings.json里明明设置了model: opus但实际跑起来一直用的是 haiku查了很久才发现是 shell 的.zshrc里残留了一行export ANTHROPIC_MODELhaiku。环境变量优先级比项目配置高所以项目配置压根没生效。遇到这种问题最快的方式是跑claude --debug启动日志会打印最终生效的配置项。不要靠猜看日志最直接。4.3 Hooks 机制在工具调用前后插入你的代码Hooks 是 Claude Code 里最像源码级扩展的官方特性。它允许你在工具调用的前后、会话停止时、子代理结束时等生命周期节点上执行外部脚本。配置位置在settings.json的hooks字段每个事件可以配置一个或多个命令。PreToolUse是最常用的事件。脚本会收到一个 JSON 参数里面包含tool_name、tool_input、session_id、prompt等。如果脚本往 stdout 输出{decision: block}工具就不会执行如果输出{decision: allow}就直接放行。我做过一个内部安全插件在PreToolUse里拦截所有 Bash 命令检查命令字符串是否包含rm -rf如果包含就把命令原文、工作目录、会话 ID 发到审计系统并选择 block。效果相当于在闭源工具外面包了一层自己的安全审批层。这个特性特别适合企业环境你在不碰 Claude Code 内部代码的情况下也能实现相当强的管控。5. 自己动手写一个极简 Claude Code看开源项目怎么落地5.1 开源替代品 opencode 的架构借鉴如果你实在想看源码我建议直接从开源替代品入手。opencode 是我目前见过和 Claude Code 设计最接近的开源实现TypeScript 编写仓库结构很清晰cli/管入口参数session/管会话持久化tool/内置各类工具provider/抽象模型接口permission/实现权限引擎。你按照这个目录读一遍再回头用 Claude Code很多之前看不懂的配置项瞬间就通了。它和 Claude Code 的核心差异在于opencode 为了兼容多种模型把 Provider 层做得更厚所以你在它源码里看到的模型路由会比 Claude Code 的复杂得多。但这反而方便学习——你直接看一套完整实现比对着闭源黑盒猜要高效得多。5.2 极简主循环代码骨架我把自己写的极简版主循环贴出来这个骨架对标的就是 Claude Code 的核心闭环去掉了大量边缘逻辑只剩最重要的链路async function agentLoop({ provider, tools, messages, permission }) { for (let turn 0; turn maxTurns; turn) { const res await provider.chat({ messages, tools }); const text extractText(res); const toolUses extractToolUses(res); if (text) process.stdout.write(text); if (toolUses.length 0) break; for (const toolUse of toolUses) { const tool tools.find((t) t.name toolUse.name); if (!tool) continue; const verdict await permission.check(toolUse); if (!verdict.allowed) { messages.push(toolBlockedResult(toolUse)); continue; } const output await tool.execute(toolUse.input); messages.push(toolResultMessage(toolUse, output)); } } }这段代码看着简单但它已经把三个关键机制都体现了循环轮次控制、工具结果回填、权限闸门。你基于这个骨架做二次开发时可以把permission.check换成内部审批接口把tool.execute换成执行你的私有工具链模型层换成任意兼容 OpenAI 或 Anthropic 格式的服务。我实际把这个骨架跑在了本地服务上发现只要模型输出格式稳定整个链路就能撑住日常对话式任务。5.3 本地部署时的权限安全和模型兼容性最后说说落地时最容易翻车的几个点。权限安全是第一位的Bash 工具绝不能默认全放行。我的建议是默认无 Bash 权限只有通过白名单才允许执行特定前缀命令。模型兼容性上建议做一个 Provider 适配层内部统一消息格式对外对接不同模型厂商这样换模型只需改一份配置不用动主循环代码。上下文管理上一定要对长工具结果做截断或摘要否则本地模型稍有上下文限制跑几十轮后就开始失忆。会话持久化也很重要把每次消息记录到 JSONL 文件断点续跑和问题复盘都靠它。我本地部署踩得最狠的坑就是上下文溢出。当时没做工具结果截断一个find命令返回了一万多行文件路径直接塞进 messages下一轮模型就开始答非所问。后来在工具执行结果进入 messages 之前加了个压缩函数超过 3000 字的部分用head和tail各取一段中间标注内容过长已省略既保留关键信息又控制 token 消耗。加了这层之后长时间会话稳定多了。写到这里我个人的体会是与其纠结于拿不到 Claude Code 的完整源码不如把它当作一个黑盒来侧写再用开源项目对照验证。你真正需要的不是那几万行代码而是对 Agent 主循环、工具系统、权限模型的理解。这套心智模型换到任何 AI 编码工具上都成立。最后再分享一个小技巧每次 Claude Code 跑出奇怪结果时先别急着抱怨去~/.claude/和项目.claude/下翻一翻配置、日志和缓存会话记录绝大多数问题在配置层和上下文层就能解释根本不用看到源码。本文还有配套的精品资源点击获取
返回列表