游乐游手机版
首页/AI教程/文章详情

一天读完Claude Code全部泄露源码,我的发现

时间:2026-06-04 17:34
2026年3月31日,Anthropic旗下Claude Code的完整源码因意外泄露而公之于众。事件起因颇具戏剧性:有开发者在npm上发现`@anthropic-ai claude-code`包的残留` map`文件中,隐藏着一个指向Anthropic R2存储桶的下载链接,且该链接未设任何鉴权,
2026年3月31日,Anthropic旗下Claude Code的完整源码因意外泄露而公之于众。事件起因颇具戏剧性:有开发者在npm上发现`@anthropic-ai/claude-code`包的残留`.map`文件中,隐藏着一个指向Anthropic R2存储桶的下载链接,且该链接未设任何鉴权,直接访问即可下载。解压后,1903个文件、51万行TypeScript代码毫无保留地暴露在公众视野中。 我花了一天读完 Claude Code 泄露的全部源码,这是我发现的 作为Claude Code的资深用户(同时也是AI Agent工程师),我在消息曝光后第一时间将代码克隆并通读了一遍。网上已有大量文章复述目录结构和技术栈,本文将跳过这些常规内容,专注于那些“读后觉得真正有意思”的细节。 --- ### 首先聊聊技术栈 Bun + TypeScript + React + Ink。用React构建TUI层并不新鲜,Ink早在2017年就已诞生,Gatsby CLI、Prisma CLI均在使用。但Claude Code的场景远比普通CLI复杂:多Agent并行、流式输出、工具执行中用户可随时中断、权限弹窗频繁出现。状态管理复杂度达到如此级别,采用React确实比手动管理要合理得多。 --- ### Agentic Loop:一个while(true)撑起整个Agent Claude Code最核心的文件是`src/query.ts`,共1729行。注意,并非`QueryEngine.ts`(那是外层会话管理),真正的“大脑”位于query.ts内部——一个while(true)循环。 ```typescript async function* queryLoop(params) { let state = { messages, toolUseContext, turnCount: 1, ... } while (true) { // 1) 一堆预处理:裁历史、压缩上下文、预取 memory 和 skills // 2) 调 Claude API(流式) // 3) 一边收流一边看有没有 tool_use block // 4) 有的话 → 检查权限 → 执行 → 结果塞回 messages → 回到 while // 5) 没有工具调用 → 退出 } } ``` 结构看似简单,但所有的精妙之处都隐藏在细节中。 --- ### 上下文管理:并非单一策略,而是四把手术刀协同工作 用过Claude Code的用户都知道,长对话进行到一定程度后,系统会自动执行“压缩”操作。此前我以为是简单地将早期对话生成摘要,但阅读源码后发现,实际上共有四种不同粒度的压缩机制同时运作: 1. **HISTORY_SNIP**:最精细的层级,直接删除某些消息而不做任何摘要。例如,某个工具返回了500行搜索结果,模型仅使用了其中的3行,剩余497行就是纯噪声。保留它们会浪费token,对它们做摘要同样浪费token,直接删除最为高效。 2. **Microcompact**:利用API层的`cache_deleted_input_tokens`能力,在缓存层面进行编辑。不修改消息内容,而是告知API“这些token你缓存里有但不要再使用了”。相当于在不改变消息的前提下降低token数量。 3. **CONTEXT_COLLAPSE**:将旧的对话轮次“归档”为摘要,维护一个类似git log的结构,每次新查询时重放。与常规压缩方式的区别在于保留了结构——哪一轮做了什么、结论是什么都清晰可辨,而非一坨模糊的摘要。 4. **Autocompact**:最后的兜底方案,调用一次模型将整个历史压缩成一段话。 四种机制按顺序依次执行,前一种若能够解决,就不会触发后面的。因此大多数情况下,autocompact根本无需运行。 读过这段代码后,我有一个感悟:做Agent的上下文管理不能只有一种策略。工具的中间输出可能几轮后就失效了,但用户描述的需求背景可能整个会话都需要保留。不同信息的“保质期”不同,相应的处理方式也应有所区别。 --- ### 流式工具并行:模型还未说完话,工具就已经开始干活 常见的Agent实现方式是:等模型说完 → 检查是否有工具调用 → 执行 → 结果返回 → 进入下一轮。中间有一段明显的等待时间。 Claude Code不这样等待。 ```typescript // StreamingToolExecutor.ts export class StreamingToolExecutor { // 模型流式吐出一个 tool_use block,立刻开始执行 addTool(block: ToolUseBlock, message: AssistantMessage): void { ... } // 并发安全的工具可以同时跑,写操作独占 // 结果按接收顺序排队,保证输出确定性 async *getRemainingResults(): AsyncGenerator { ... } } ``` 模型还在流式输出后面的内容时,前面的工具就已经在并行执行了。每个工具有一个`isConcurrencySafe`标记:读文件、grep这类只读操作可以并行运行,写文件、bash这类则需独占。结果按接收顺序缓冲,不会乱序。 用过Claude Code的用户应该能感受到,它的工具执行响应速度较快,原因之一就在于此。工具执行的延迟被隐藏在了模型推理的时间里,用户几乎无法察觉。 --- ### 遇到输出上限也绝不认输 ```typescript const MAX_OUTPUT_TOKENS_RECOVERY_LIMIT = 3 ``` 当模型输出触发了max_output_tokens上限时,循环不会报错;而是“扣留”错误消息,悄悄重试,最多3次,且对用户完全无感。 这段代码上方有一段注释,模仿中世纪巫师的口吻写道:“好好记住这些规则,年轻的巫师。不然你就等着花一整天调试和薅头发吧。”——负责维护这一块的开发者显然被坑过很多次。 --- ### 工具系统:40多个工具,零继承 做过Agent框架的人可能习惯写一个BaseTool基类然后继承。Claude Code完全没有继承,40多个工具全是纯函数式的`buildTool()`工厂函数: ```typescript type ToolDef = { name: string description: string inputSchema: ZodSchema // Zod v4 做校验 + 自动生成 JSON Schema call(input: T, ctx: ToolUseContext): AsyncGenerator<...> isReadOnly(): boolean getPermissions(): ToolPermission[] renderToolUse?(input: T): ReactNode // 直接渲染到终端 getToolUseSummary?(input, result): string // 压缩上下文时的摘要 } ``` 每个工具完全自包含:schema、权限、执行逻辑、UI渲染、压缩摘要,全部集中在一个文件里。没有全局注册表,每个session动态组装工具池,静态工具、MCP工具、Agent定义的工具混在一起使用。 其中最复杂的是BashTool,单个文件1143行。它做的远不止`exec(command)`: - 自动解析命令分类为search/read/write,用于权限匹配 - macOS上走sandbox-exec沙箱,Linux走seccomp - 超过15秒的阻塞命令自动转为后台运行 - 大输出存储到磁盘,仅给模型一个文件路径引用 - 内置sed命令解析器,检测到`sed -i`时UI从“Bash”变为文件编辑样式 - 复合命令(如`ls && git push`)会被拆分逐段判定安全性 一个BashTool的复杂度就超过了众多小型Agent框架的全部。 --- ### Feature Flag:见过最干净的功能门控 **编译时:代码物理消失** ```typescript import { feature } from 'bun:bundle' const voiceModule = feature('VOICE_MODE') ? require('./voice/index.js') : null ``` `feature()`是Bun的编译时宏。构建时被替换为true或false,false的分支直接被删除。不是“运行时不执行”,而是从二进制文件中物理消失,连字符串字面量都不剩。 为什么?因为安全研究员会反编译你的二进制去找隐藏功能。运行时flag再怎么关,字符串仍然留在那里。编译时DCE才是真正意义上的“不存在”。 讽刺的是,他们在二进制层面做了这么多防护,最后被一个忘记删除的.map文件全部端掉了。 搜索到了二十多个编译时flag,每一个都对应一个未发布的功能:VOICE_MODE、BRIDGE_MODE、DAEMON、KAIROS、COORDINATOR_MODE、PROACTIVE、ABLATION_BASELINE、CONTEXT_COLLAPSE、CHICAGO_MCP…… **运行时:GrowthBook A/B测试** ```typescript const enabled = checkStatsigFeatureGate_CACHED_MAY_BE_STALE('tengu_streaming_tool_execution2') ``` 用于灰度发布和紧急kill switch。所有gate名称都以`tengu_`开头——tengu(天狗)是Claude Code项目的内部代号。从磁盘缓存读取,接受脏读,不阻塞启动。 --- ### 消融实验:用科学方法做产品 这个发现很有意思。有一个flag叫做**ABLATION_BASELINE**,启用后会一次性关闭思考模式、上下文压缩、自动记忆、后台任务: ```typescript if (feature('ABLATION_BASELINE') && process.env.CLAUDE_CODE_ABLATION_BASELINE) { for (const k of [ 'CLAUDE_CODE_DISABLE_THINKING', 'DISABLE_COMPACT', 'DISABLE_AUTO_COMPACT', 'CLAUDE_CODE_DISABLE_AUTO_MEMORY', 'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS', ]) { process.env[k] ??= '1'; } } ``` 从事ML研究的人都熟悉消融实验:逐个关闭组件看对最终效果的影响。但将这种方法论应用到产品工程中,在工业代码里还是第一次见到。这意味着Anthropic每上线一个新功能(thinking、compact、memory等),都可以跑一组对照实验来量化其价值。不是“感觉有用就上”,而是“数据证明有用才上”。 --- ### 隐藏功能:源码里尚未发布的东西 编译时flag门控的那些功能,虽然在公开版二进制中看不到,但源码全部暴露了出来。 **Voice Mode(代号Amber Quartz)** `src/voice/`目录证实了语音模式的存在: - 只支持Claude.ai OAuth认证(API key、Bedrock、Vertex都不行) - 走专门的voice_stream端点 - 有紧急kill switch:tengu_amber_quartz_disabled - 从注释来看,该功能已经开发完成,只是尚未公开 **Bridge Mode:将你的电脑变为Claude的远程终端** `src/bridge/`包含31个文件,实现了一套完整的远程控制系统。运行`claude remote-control`之后,你的本地环境就变成一个可以被claude.ai远程操控的“桥接环境”。最多支持32个并发会话,采用JWT认证加可信设备机制,企业管理员可以通过策略禁用。这应该是为了让claude.ai网页版能够直接操作你本地的开发环境,不再需要手动复制粘贴代码。 **Buddy:终端里的电子宠物** 这绝对是整个源码中最出乎意料的发现。Claude Code内置了一套完整的虚拟宠物系统,而且没有使用feature flag进行门控,已经存在于每个用户的二进制中: ```typescript // 18 种宠物 export const SPECIES = [duck, goose, blob, cat, dragon, octopus, owl, penguin, turtle, snail, ghost, axolotl, capybara, cactus, robot, rabbit, mushroom, chonk] as const // 5 级稀有度 export const RARITY_WEIGHTS = { common: 60, uncommon: 25, rare: 10, epic: 4, legendary: 1, } // RPG 式属性 export const STAT_NAMES = ['DEBUGGING', 'PATIENCE', 'CHAOS', 'WISDOM', 'SNARK'] as const ``` 18种宠物,5级稀有度(传说概率1%),1%闪光变体。还有帽子系统(皇冠、礼帽、螺旋桨帽、光环、巫师帽、豆豆帽、头顶小鸭子)和不同的眼睛样式。宠物属性使用Mulberry32伪随机数生成器从用户ID确定性计算,每个用户绑定一只,无法刷取。 在一个51万行的严肃工程项目中发现一套完整的抽卡养宠系统,确实让人意外。 **宠物名字里藏了一个秘密** 比宠物本身更有意思的是它物种名的编码方式: ```typescript const c = String.fromCharCode export const duck = c(0x64,0x75,0x63,0x6b) as 'duck' export const goose = c(0x67,0x6f,0x6f,0x73,0x65) as 'goose' export const capybara = c(0x63,0x61,0x70,0x79,0x62,0x61,0x72,0x61) as 'capybara' ``` 18个物种名全部使用hex编码,没有一个用明文。注释写着:“One species name collides with a model-codename canary in excluded-strings.txt.”也就是说,其中一个宠物名恰好是Anthropic某个未公开模型的内部代号。构建系统会grep二进制产物中是否存在黑名单里的字符串,因此必须使用hex编码绕过检测。 到底是哪一个?这需要结合另一泄露信息来看。 --- ### 模型代号:两次泄露拼出完整拼图 3月28日,也就是这次npm泄露的三天前,Anthropic还发生了另一件事:CMS数据库权限未关闭,被Fortune记者翻出了近3000份内部文件。其中提到一个从未公开的模型叫做**Claude Mythos**,内部代号**Capybara**(水豚),定位在Opus之上的全新层级。 而在Claude Code源码的prompts.ts中,找到了大量`@[MODEL LAUNCH]`注释(给新模型发布准备的TODO checklist),里面反复出现了这个名字: ```typescript // @[MODEL LAUNCH]: Update comment writing for Capybara // — remove or soften once the model stops over-commenting by default // @[MODEL LAUNCH]: False-claims mitigation for Capybara v8 // (29-30% FC rate vs v4's 16.7%) ``` 这些TODO尚未完成,说明Capybara还没公开发布。但是main.tsx中已经有`capybara-fast`、`capybara-v2-fast[1m]`这些模型别名,表明Anthropic内部员工已经日常使用。 拼到一起就很清楚了:**Capybara正是比Opus更强的下一代旗舰Mythos的内部代号**。Opus 4.6在代码里叫`claude-opus-4-6`,没有动物名。宠物系统里撞车的就是这只水豚。 顺带泄露了一个内部数据:Capybara v8的虚假声明率达到29-30%,比上一版v4的16.7%翻了近一倍。Anthropic没有回退版本,而是在prompt层加入指令做修补,由内部员工先当小白鼠验证效果。 源码中还出现了另一个模型代号: ```typescript // @[MODEL LAUNCH]: Remove this section when we launch numbat. ``` **Numbat**(袋食蚁兽),又一个待发布的模型。它与Capybara之间的关系目前尚不清楚。 此外,Claude Code项目本身的代号是**Tengu**(天狗)。 --- ### Skill系统与多Agent协调 简单提两个设计,其思路值得借鉴。 **Skills就是Markdown文件**。`.claude/skills/`目录下放置.md文件,YAML frontmatter中描述工具、触发条件、允许的工具、使用的模型。Claude Code读取文件时,如果发现目录下有skills,则自动加载,无需显式注册。约定优于配置,很有Rails风格。 **多Agent协调器**意外地简洁。Coordinator模式下,主Agent只有三个工具:生成worker、给worker发消息、停止worker。Worker无法获取TeamCreate和SendMessage,防止套娃。后端支持tmux pane、in-process、remote三种方式。 --- ### 几个容易被忽略的工程细节 **隐私保护写进了类型名**:埋点数据的类型名叫`AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS`。通过类型名本身提醒开发者“你确认过这不是代码或文件路径了吗”。简单,但有效。 **投机执行**:AppState中有`speculationState`,追踪每一轮的结束方式(bash / 文件编辑 / 正常结束 / 权限拒绝),用来预判下一步操作并提前执行。这解释了为什么Claude Code有时候“想”完就瞬间开始干活。 **冷启动优化**:`--version`路径做到了零import,直接读取编译时内联的版本号,一个模块都不加载就退出。其他子命令走独立的import()路径。只有最终进入主循环时才加载完整的React应用。一个800KB的React app,不用的功能就不加载,启动时间自然会很快。 --- ### 泄露原因 npm发布时忘记删除.map文件,map里引用了R2上的源码zip,而那个URL没有访问控制。事情就是这么简单。 因此,给所有发布npm包的人提个醒: 1. `package.json`的`files`字段应采用白名单制,只包含你想发布的内容 2. CI中加入一步检查发布产物中是否有.map文件 3. 源码归档URL必须设置鉴权,不要裸挂在CDN上 4. 构建产物与源码的访问控制应独立管理 他们在二进制中做了那么多防泄漏设计(编译时DCE、物种名hex编码、excluded-strings黑名单),最后却因一个忘记删除的.map文件全部被端掉。安全这件事,100个环节做对99个,漏掉一个就等于没做。 --- ### 写在最后 读完51万行代码,最大的感受不是某个具体技术有多厉害,而是这个团队在用做研究的方法做工程。消融实验基础设施、双层feature flag、四种粒度的上下文管理、流式工具并行——每一个都不是拍脑袋加的,背后大概率有数据支撑。这种“每个功能都有量化验证”的工程文化,比任何单点技术都更值得学习。 当然,宠物系统除外。那个纯粹是因为好玩。 源码还在继续阅读中,后续可能会撰写一篇深入某个模块的分析(BashTool 1143行的沙箱和命令安全机制,或者Coordinator模式的多Agent编排细节)。 本文基于公开泄露的源码进行技术分析,Claude Code所有代码版权归Anthropic所有。
来源:https://juejin.cn/post/7623258895395110966
上一篇九成程序员还在让AI补代码 一成已指挥AI军团 下一篇OpenClaw私有知识库关联深度使用教程
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
CapCut AI Linux服务器部署教程:从环境配置到后台运行全程
AI教程 · 2026-07-08

CapCut AI Linux服务器部署教程:从环境配置到后台运行全程

CapCutAI在Linux服务器上更适合做“自动化辅助剪辑”部署,需先确认官方能力边界,再配置系统、浏览器运行环境、素材目录、任务脚本与systemd后台服务,重点关注账号安全、资源占用、版权合规和故障排查。

CapCut AI Mac安装教程:Apple Silicon和Intel配置步骤
AI教程 · 2026-07-08

CapCut AI Mac安装教程:Apple Silicon和Intel配置步骤

CapCutAI在macOS上适合短视频剪辑、字幕生成、智能抠像和素材包装。安装前需确认芯片类型、系统版本、存储空间与权限设置,AppleSilicon和Intel机型在下载、授权、性能优化上略有差异。

Veo插件安装全流程:浏览器编辑器扩展市场配置
AI教程 · 2026-07-08

Veo插件安装全流程:浏览器编辑器扩展市场配置

Veo相关插件安装应先确认官方来源与适配环境,再按浏览器、编辑器或扩展市场流程完成安装、授权和测试,重点关注权限、素材合规、版本兼容与账号安全。

Veo API Key 获取与配置教程:账号注册及国内网络设置
AI教程 · 2026-07-08

Veo API Key 获取与配置教程:账号注册及国内网络设置

围绕VeoAPIKey配置流程,梳理账号注册、项目创建、密钥获取、环境变量设置、国内网络连通性检查、常见报错处理与安全管理建议,适合首次接入AI视频能力的开发者和团队参考。

Veo macOS安装教程:苹果芯片与英特尔配置步骤整理
AI教程 · 2026-07-08

Veo macOS安装教程:苹果芯片与英特尔配置步骤整理

Veo在macOS上通常通过网页端或API环境使用,并非传统本地安装软件。AppleSilicon与Intel机型需先确认系统、浏览器、运行环境与权限配置,再按需接入开发工具。