当“AI 程序员”被扒了底裤:Claude Code 源码泄露事件全解析,以及我们如何本地跑起来玩玩
过去一周,开发者社区被一条消息刷屏:Anthropic 旗下编程智能体 Claude Code 的部分实现细节与源码逻辑疑似通过 npm 包、source map 与调试接口被逆向暴露。无论最终官方如何定性,这件事都像一面镜子,照出了当前 AI 编程助手赛道的三个真问题:闭源模型公司的工程化边界在哪里、智能体(Agent)架构的“秘密”到底值多少钱、以及开发者能否从泄露线索中复刻一个可玩的本地版本。本文不炒作八卦,而是从技术视角拆解这次事件的来龙去脉,并给出一套“合规、可玩、可部署”的本地实验方案。
一、事件回顾:泄露的到底是什么
根据社区逆向分析者的整理,此次流出的内容大致分为三类:
-
客户端侧打包产物中的 source map 与未混淆字符串
Claude Code 以 CLI 与 IDE 插件形态分发,其 Node 侧产物包含大量可读的 prompt 模板、工具调用描述、系统提示词片段。source map 的存在使得部分 TypeScript 源码结构可被还原。 -
工具调用协议与 Agent 循环逻辑
包括文件读写、Bash 执行、代码检索(grep/glob)、任务分解(Todo 列表)等工具的 schema 定义,以及“模型输出 → 解析工具调用 → 执行 → 回填结果 → 继续推理”的主循环伪代码。 -
上下文管理与压缩策略
涉及对话历史裁剪、文件片段注入顺序、token 预算分配等工程细节。这部分是商业产品真正的“护城河”之一,也是社区讨论最激烈的部分。
需要强调:泄露的是工程实现线索,不是模型权重。Claude 模型本身仍在 Anthropic 的推理服务后面,所谓“源码泄露”并不等于“模型被开源”。这一点在传播中经常被混淆。
二、为什么这件事值得开发者认真对待
1. Agent 产品的竞争力正在从“模型”转向“脚手架”
过去两年,大家默认“模型强则产品强”。但 Claude Code、Cursor、Cline 等产品的实践表明:同一个模型,配上不同的工具集、上下文策略、失败重试机制,实际编码成功率可以差出数倍。泄露事件恰好把这个“脚手架层”暴露在阳光下——它证明系统提示词与工具编排本身就是核心资产,而不是可有可无的胶水代码。
2. 闭源分发的“可逆向性”是行业通病
只要产品以 JS/TS 形态分发到本地,source map、字符串常量、工具描述就几乎必然可被提取。这不是 Anthropic 一家的问题,而是所有“本地 CLI + 云端模型”架构的共同软肋。合理的做法是:默认假设客户端产物会被阅读,把真正的秘密留在服务端(如工具执行沙箱、权限校验、计费与审计)。
3. 对开发者的直接价值:一份高质量的 Agent 设计参考
抛开法律与道德争议,泄露出的结构对想自建编程 Agent 的团队极有参考价值。它回答了几个工程界长期争论的问题:
- 系统提示词应该多长?如何组织成“角色 + 工具说明 + 行为约束 + 输出格式”四段式;
- 工具返回结果如何截断?大文件读取如何做行号窗口与摘要;
- 多轮任务中如何维护 Todo 状态,避免模型“忘记做到哪了”;
- 何时触发上下文压缩,压缩时保留哪些“锚点信息”。
这些细节在论文里看不到,在产品文档里也不会写。
三、技术拆解:一个编程 Agent 的最小可行架构
结合泄露线索与公开资料,一个 Claude Code 类产品的核心循环可以抽象为如下伪代码(示意,非泄露原文):
while not task_done:
context = build_context(system_prompt, history, repo_snapshot, todo_state)
response = llm.chat(context, tools=TOOL_SCHEMAS)
for call in response.tool_calls:
result = execute_tool(call.name, call.args) # 带权限校验与超时
history.append(tool_result(call.id, truncate(result)))
if needs_compaction(history):
history = compact(history, keep=["task_goal", "todo", "key_files"])
关键设计点有四个:
(1)工具 schema 即契约
每个工具(Read、Write、Edit、Bash、Grep、Glob、Todo)都有严格的 JSON Schema。模型只能通过这些“窄接口”操作文件系统,从而把不可控的自然语言输出转化为可审计的结构化动作。
(2)权限与沙箱是一等公民
Bash 执行必须限定工作目录、设置超时、拦截危险命令(如 rm -rf /、curl | sh)。泄露材料中反复出现的“确认提示”机制说明:产品化 Agent 的第一原则是默认不信任模型。
(3)上下文是有预算的稀缺资源
文件内容不会整份塞入,而是按相关性做片段检索与行号窗口;历史对话超过阈值后做摘要压缩,但保留任务目标与 Todo。这是“长任务不崩”的关键。
(4)Todo 状态外置
把任务清单存在 Agent 循环之外的结构化状态里,每轮注入,避免模型在多轮中丢失进度。这个思路简单,但效果显著。
四、动手:搭一个“致敬版”本地编程助手
下面给出一套完全合规、可本地运行的实验方案。我们不复制任何泄露代码,只用公开的模型 API 与开源工具,复刻上述架构的核心思想。请务必只在你自己拥有权限的代码库中运行,并为 Bash 工具设置白名单。
4.1 技术选型
- 运行时:Node.js 20+ 或 Python 3.11+(本文用 Python 示意,便于阅读)
- 模型:任意支持 function calling 的 API(OpenAI 兼容接口、本地 Ollama 均可)
- 工具层:标准库
subprocess、pathlib、ripgrep - 交互:CLI 即可,先不追求 IDE 插件
4.2 目录结构
mini-agent/
├── agent.py # 主循环
├── tools.py # 工具实现与 schema
├── prompts.py # 系统提示词
├── sandbox.py # 路径与命令校验
└── workspace/ # 被操作的代码目录(隔离)
4.3 核心代码骨架
tools.py 中定义四个最小工具:
TOOL_SCHEMAS = [
{"name": "read_file", "description": "读取文件指定行范围",
"parameters": {"type": "object",
"properties": {"path": {"type": "string"},
"start": {"type": "integer"},
"end": {"type": "integer"}},
"required": ["path"]}},
{"name": "write_file", "description": "写入或覆盖文件",
"parameters": {"type": "object",
"properties": {"path": {"type": "string"},
"content": {"type": "string"}},
"required": ["path", "content"]}},
{"name": "run_bash", "description": "在沙箱目录执行只读或构建命令",
"parameters": {"type": "object",
"properties": {"cmd": {"type": "string"}},
"required": ["cmd"]}},
{"name": "search_code", "description": "正则检索代码",
"parameters": {"type": "object",
"properties": {"pattern": {"type": "string"}},
"required": ["pattern"]}},
]
sandbox.py 是最容易被忽视、却最重要的部分:
import os, subprocess
from pathlib import Path
ROOT = Path("./workspace").resolve()
ALLOW_PREFIX = ("ls", "cat", "grep", "rg", "python", "pytest", "npm", "node")
def safe_path(p: str) -> Path:
target = (ROOT / p).resolve()
if not str(target).startswith(str(ROOT)):
raise PermissionError("路径越界")
return target
def safe_bash(cmd: str, timeout=20) -> str:
if not cmd.strip().startswith(ALLOW_PREFIX):
return "[拒绝] 命令不在白名单"
try:
out = subprocess.run(cmd, shell=True, cwd=ROOT, timeout=timeout,
capture_output=True, text=True)
return (out.stdout + out.stderr)[:4000] # 截断,保护上下文
except subprocess.TimeoutExpired:
return "[超时]"
agent.py 的主循环与第三节伪代码一致,重点是两处工程细节:工具结果截断与历史压缩。前者防止单次大输出撑爆上下文,后者在历史超过 N 轮时调用模型做摘要,但把“任务目标 + Todo + 最近 3 轮”原样保留。
4.4 系统提示词的写法
参考泄露