/~learn/s/06a631e1
> 2026 年 3 月 31 日,Anthropic 在发布 Claude Code v2.1.88 时,因 .npmignore 遗漏了 source map 文件,导致 51.2 万行 TypeScript 源码、1906 个源文件、完整内部架构设计被公之于众。这不是安全入侵,而是一次发布配置失误——但它意外地成为 2026 年 AI 工程领域最有价值的公开课。
>
> 本文从工程实践角度,逐层拆解 Claude Code 的核心架构、设计模式、关键实现,提炼出可供学习、借鉴、复用的工程方法论。
---
| 指标 | 数值 |
| ------ | ------ |
| TypeScript 源文件 | 1,906 个 |
| 代码总行数 | 512,847 行 |
| 内置工具数 | 66+ |
| 压缩流水线级数 | 5 级 |
| 权限防御层数 | 7 层 |
| 预估研发成本 | $50M-$100M USD |
| 预估工时 | 150-200 人年 |
| 模块 | 文件数 | 代码行数 | 占比 |
| ------ | -------- | --------- | ------ |
| 工具系统 | 312 | 89,450 | 17.4% |
| CLI 交互层 | 287 | 82,340 | 16.1% |
| 查询引擎 | 276 | 78,120 | 15.2% |
| 记忆系统 | 245 | 71,230 | 13.9% |
| 会话管理 | 198 | 67,890 | 13.2% |
| 沙盒环境 | 198 | 52,340 | 10.2% |
| 认证授权 | 156 | 34,560 | 6.7% |
| 工具函数 | 234 | 36,917 | 7.2% |
---
Claude Code 采用严格的分层架构,每一层有明确的职责边界:
┌─────────────────────────────────────────┐
│ CLI 交互层 │
│ (Ink 渲染器 / Yoga Flexbox 布局) │
├─────────────────────────────────────────┤
│ Agent 编排层 │
│ (主 Agent → 子 Agent 调度 / 任务分发) │
├─────────────────────────────────────────┤
│ 会话管理层 │
│ (QueryEngine / 消息规范化 / 压缩) │
├─────────────────────────────────────────┤
│ 上下文工程层 │
│ (5级压缩流水线 / 提示词缓存 / 记忆系统) │
├─────────────────────────────────────────┤
│ 工具执行层 │
│ (66+工具 / 流式并行 / MCP协议 / 沙箱) │
├─────────────────────────────────────────┤
│ 安全与权限层 │
│ (7层纵深防御 / AST分析 / 竞速确认) │
├─────────────────────────────────────────┤
│ API 通信层 │
│ (Anthropic API / 流式 SSE) │
└─────────────────────────────────────────┘
设计原则:
Tool<TParams, TResult>
| 工具 | 架构模式 | 工具调用 | 上下文管理 | 完整任务闭环 |
| ------ | --------- | --------- | ----------- | ------------ |
| Claude Code | 分层 Agent 架构 | 66+ 工具链 | 智能压缩 + 缓存 | ✅ 全自动 |
| GitHub Copilot | IDE 插件模式 | 无独立工具 | 仅当前文件 | ❌ |
| Cursor | IDE 集成 + Agent | 部分工具 | 项目级上下文 | 部分 |
| ChatGPT | Web 对话 | 无系统工具 | 纯对话历史 | ❌ |
---
这是整个 Claude Code 的"心脏"——模型如何决定"什么时候该继续、什么时候该停"。
QueryEngine(会话生命周期管理)
└── query()(单次查询循环)
├── 消息规范化 + 压缩
├── API 流式调用
├── 工具执行
└── 继续 / 终止判断
| 维度 | QueryEngine | query() |
| ------ | ------------- | ---------- |
| 作用域 | 对话全生命周期 | 单次查询循环 |
| 状态 | 持久化(mutableMessages、usage) | 循环内(State 对象每次迭代重新赋值) |
| 预算追踪 | USD/轮次检查 | Task Budget 跨压缩结转 |
submitMessage() 八阶段生命周期阶段 1: 设置阶段 — 清除技能发现、包装 canUseTool、初始化模型配置
阶段 2: 孤儿权限处理 — 处理上次会话崩溃后遗留的权限授权
阶段 3: 用户输入处理 — 解析斜杠命令、处理附件、持久化消息
阶段 4: 系统初始化消息 — 工具/命令注册信息注入
阶段 5: 本地命令检查 — /clear 等不需要调用 API 的命令直接处理
阶段 6: 主查询循环 — for await (const msg of query(params))
阶段 7: 预算检查 — USD 成本 + 结构化输出重试次数
阶段 8: 结果提取 — yield 最终结果消息
工程启示:把用户输入 → API 调用 → 工具执行 → 结果返回这条链路拆解为 8 个明确的阶段,每个阶段有单一职责。这种"纵向切分"让每个阶段的错误处理和状态恢复可以独立设计。
Claude Code 的核心性能优化之一:不等模型输出完毕就开始执行工具。
串行执行:
[=========API=========][tool1][tool2][tool3]
流式并行:
[=========API=========]
[tool1] ← 利用流式窗口(5-30s)
[tool2] ← 覆盖 ~1s 工具延迟
[tool3]
[====结果即时可用====]
StreamingToolExecutor 的核心设计:
queued → executing → completed → yielded 四状态concurrent-safe,可并行执行工程启示:利用模型流式输出的 5-30 秒窗口,把约 1 秒的工具 I/O 延迟完全"藏起来"。用户感知的是"模型还在想,但文件已经在读了"。
当 Agent Loop 遇到故障时,不是直接报错退出,而是根据故障类型尝试恢复:
| 继续原因 | 触发条件 | 处理方式 |
| --------- | --------- | --------- |
next_turn | 模型调用了工具 | 正常继续 |
collapse_drain_retry | Token 超限 + Collapse 有暂存 | 提交折叠,释放 Token |
reactive_compact_retry | Token 超限 + Collapse 不够 | 强制全量摘要压缩 |
max_output_tokens_escalate | 输出 Token 不够 | 升级到 64K |
max_output_tokens_recovery | 升级不可用 | 注入续写提示,最多 3 次 |
stop_hook_blocking | Stop Hook 阻止终止 | 继续执行 |
token_budget_continuation | Token 预算续写 | 继续生成 |
工程启示:容错不是"try-catch 一包了之",而是为每一种已知故障模式设计专门的恢复路径。可恢复的错误用户根本看不到——只有所有恢复尝试都失败时,错误才暴露给用户。
---
这是 Claude Code 最被低估、也是最有技术含量的系统。
系统提示词中有一个哨兵字符串 __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__:
工程启示:将提示词分为"全局不变的"和"因人而异的"两部分,前者可以在服务端缓存复用,显著降低推理成本(cache read token 便宜 90%)。
| 层级 | 机制 | 作用 |
| ------ | ------ | ------ |
| Level 1 | Tool Result 预算裁剪 | 大结果持久化到磁盘,零成本 |
| Level 2 | History Snip | 剪裁历史冗余,释放最多 Token |
| Level 3 | Microcompact | 清理旧工具结果,两条路径(缓存冷/热) |
| Level 4 | Context Collapse | 投影式只读视图,不修改原始消息 |
| Level 5 | Autocompact | fork 子 Agent 生成摘要,最后手段 |
设计哲学:渐进式压缩——先轻后重。每一级都可能释放足够空间让后续级别不需要执行。
压缩后系统自动恢复最近编辑的 5 个文件内容,防止模型忘记刚刚在做什么——这是一个非常细节但关键的设计。
9 段式结构化提取:
关键原则:AI 可以遗忘,但绝不能篡改用户的意图。用户说的每一句话都是不可压缩的原始上下文。
---
最小实现:JSON Schema 数组 + switch/case 分发(326 行)
生产版本:Tool<TParams, TResult> 泛型接口,30+ 方法/属性
interface Tool<TParams, TResult> {
name: string;
description: string;
parameters: ParameterSchema;
execute: (params: TParams) => Promise<TResult>;
// 安全元数据
isReadOnly(): boolean; // 是否跳过权限检查
isConcurrencySafe(): boolean; // 是否可并行执行
needsPermission(): boolean; // 是否需用户确认
}
核心原则:新工具默认不可并发、非只读——必须显式声明安全性。
partitionToolCalls() 将一批工具调用分区:
concurrent-safe 工具合并为一批并行执行
工程启示:工具系统的复杂度不在于"有多少个工具",而在于"工具之间如何协调"。并发安全标记、输出截断策略、延迟加载——这些看似边缘的设计,才是生产级系统与 Demo 的分水岭。
---
| 防线 | 机制 | 说明 |
| ------ | ------ | ------ |
| Layer 1 | 工作区信任确认 | 不信任则禁用所有自定义 Hook |
| Layer 2 | 权限模式 | default / plan / acceptEdits / bypass / dontAsk |
| Layer 3 | 权限规则匹配 | allow / deny / ask 列表,支持通配符 |
| Layer 4 | Bash 多层安全 | tree-sitter AST 解析 + 23 项静态检查 |
| Layer 5 | 工具级安全 | validateInput / checkPermissions |
| Layer 6 | 沙箱与隔离 | Sandbox 进程隔离 + Git Worktree 文件隔离 |
| Layer 7 | 用户确认 | 交互式对话框 + ML 分类器竞速 + 200ms 防误触 |
用 tree-sitter 真正的语法解析器替代正则匹配,解析结果三选一:
simple:成功提取干净的 argv[],正常权限匹配too-complex:无法静态分析 → 直接要求用户确认parse-unavailable:WASM 未加载 → 回退 legacy 路径
覆盖命令注入、环境变量泄露(LD_PRELOAD)、特殊字符攻击、IFS 注入、Unicode 空白混淆、控制字符终端注入、jq 系统函数、/proc/environ 泄露等。各自独立,任一触发即拒绝。
用户确认和自动化检查(Hook + ML 分类器)同时进行:
createResolveOnce 守卫确保只有第一个决定生效工程启示:安全设计的核心哲学是"Fail-Closed"——不理解的结构一律不信任。多层防御中每一层都是独立的判决点,不依赖上一层的结果。
---
| 模式 | 适用场景 | 通信方式 | 特点 |
| ------ | --------- | --------- | ------ |
| 子 Agent | 独立子任务 | fork-return | 最简单,父等待结果 |
| 协调器 | 复杂多步任务 | 派生 + 综合 | 协调器只编排不执行 |
| Swarm | 并行协作 | 命名信箱 | Agent 间对等通信 |
| 类型 | 工具集 | 模型 | 用途 |
| ------ | ------- | ------ | ------ |
general-purpose | 全部 | 默认子 Agent 模型 | 通用任务 |
Explore | 排除写操作 | Haiku(快) | 代码库探索 |
Plan | 同 Explore | 继承父级 | 设计实施方案 |
核心原则:默认隔离,显式共享。
// 子 Agent 创建时的隔离策略
{
readFileState: clone(), // 克隆副本,防止缓存污染
abortController: newChild(), // 父中断 → 子中断(单向传播)
setAppState: noop(), // 子 Agent 状态变更不传播到父级 UI
setAppStateForTasks: shared(), // 始终共享,防止僵尸进程
queryTracking: { chainId: new, depth: depth + 1 } // 防止无限递归
}
子 Agent 在独立 Worktree 中工作,防止多个 Agent 同时修改同一文件。完成后无变更自动清理,有变更返回路径由用户决定。
所有 fork 子级共享同一缓存前缀(cache read token 便宜 90%):
tool_result 统一为 Fork started — processing in background工程启示:子 Agent 不是"开个新线程",而是完整嵌套一套 Agent Loop。隔离策略的设计(文件状态克隆、中断传播、UI 状态隔离)直接决定了多 Agent 系统的稳定性天花板。
---
| 类型 | 内容 | 持久化 |
| ------ | ------ | -------- |
| 用户偏好 | 编码风格、工具偏好、交互习惯 | 长期 |
| 行为反馈 | 用户对之前输出的反应 | 中期 |
| 项目信息 | 技术栈、架构决策、团队规范 | 中期 |
| 外部资源 | 文档链接、API 参考 | 短期 |
代码相关的事实,实时读取,不存入记忆。原因:
触发条件:距上次整理超过 24 小时、且新会话累计超过 5 个 → 系统在后台自动整理记忆。
工程启示:记忆系统的价值不在于存了多少,而在于存对了什么。"不记代码,只记人"这六个字背后,是对 AI 认知局限的清醒认识——知道 AI 不该做什么,比知道 AI 能做什么更重要。
---
Layer 1: 身份定义 — "You are Claude Code, an AI programming assistant"
Layer 2: 能力边界 — 你可以做什么,不可以做什么
Layer 3: 行为规则 — 铁律、铁律、铁律
Layer 4: 工具描述 — 每个工具的用途和参数
Layer 5: 安全约束 — 权限模型、禁止操作
Layer 6: 输出规范 — 格式、风格、语言
Layer 7: 元指令 — 关于如何理解指令的指令
系统提示词中显式列出常见错误模式并告知模型"不要这样做":
当你脑海中浮现以下想法时:
- "这个问题太简单了,不需要做设计..."
- "我先写完代码,一会再补测试..."
- "我已经手动验证过了,应该没问题了..."
→ 这些想法是错误的。立即停止,回退到规范流程。
这是借鉴了我们文档库中 01-上下文密度衰减 中提到的问题——"反模式接种"是用明确的否定指令对抗模型的投机倾向,比正面指令更有效。
对每个操作标注其"爆炸半径"(如果出错,影响范围有多大):
模型在做决策时需要感知每个操作的"代价",从而在高风险操作上更谨慎。
---
❌ 整文件重写的问题:
- Token 消耗巨大(整个文件内容作为输出)
- 容易引入意外修改(模型"顺手"改了不相干的代码)
- 无法精确追踪变更(diff 不干净)
✅ Search-and-Replace 的优势:
- 只传输变更部分,Token 消耗最小
- 精确匹配 + 唯一性约束,防止误修改
- 变更可追踪、可审计
// SearchReplace 的核心约束
interface EditRequest {
old_string: string; // 必须在文件中唯一匹配
new_string: string; // 替换后的内容
}
// 如果 old_string 匹配到多处,操作失败
// 如果 old_string 匹配不到,操作也失败
在发送 Edit 请求前,系统会先执行一次 Read 确认文件当前内容——不是靠模型的"记忆",而是靠实际的 Read 操作。这个设计防止了模型"以为文件内容是 A,实际上文件已经被修改成 B"的幻觉问题。
---
不是等模型全部想完再显示,而是每生成一个 token 就立刻渲染到终端。从 API 调用(SSE 流)到终端渲染(Ink + React),整条链路都是流式的。
模型说"我要读某个文件"的时候,这个文件已经在读了。系统在模型还在输出工具调用参数的同时就开始解析和执行——用户看不到等待。
---
源码中有一段逻辑:当系统检测到操作者是 Anthropic 内部员工、且正在操作公开 GitHub 仓库时,会自动抹除所有 AI 生成代码的痕迹。system prompt 里明确要求模型"不要暴露你的身份"——且这个模式没有强制关闭的开关。
工程启示:AI 工具在开源社区中的透明度不是一个技术问题,而是一个信任基础设施问题。
src/buddy/ 目录下藏着一套从未发布的虚拟宠物系统:18 种物种、6 种眼睛样式、完整的稀有度体系(普通到传说)、五维属性(调试能力、耐心、混沌值、智慧、毒舌)。开发者用 String.fromCharCode() 做了混淆,防止公司内部的防泄露扫描器发现——这是工程师文化的真实切片。
KAIROS 是整个代码库里出现频率最高的 feature flag(154 次),其核心能力包括:
claude assistant [sessionId] 入口,可被恢复、持续运行KAIROS_GITHUB_WEBHOOKS,可订阅 GitHub 的外部信号KAIROS 的本质不是终端编程工具,而是一个常驻后台、自主运行、随时响应的 AI 操作系统。
底层遥测系统记录用户是否对 Claude 爆过粗口,以及连续输入 continue 的频率——后者被明确标注为"烦躁行为指标"。这是产品洞察的极致形态:直接把用户的情绪反应量化成可优化的信号。
---
要从零实现一个功能完整的 Coding Agent,真正需要的是这 7 个组件:
| # | 组件 | 作用 | 复杂度 |
| --- | ------ | ------ | -------- |
| 1 | Prompt Orchestration | 运行时组装系统提示词 | 低 |
| 2 | Tool Registry | 发现、分发、验证工具调用 | 中 |
| 3 | Agent Loop | 核心循环:调模型 → 执行工具 → 继续/停止 | 高 |
| 4 | File Operations | 读文件、搜索、列目录 | 低 |
| 5 | Shell Execution | 运行命令 | 中 |
| 6 | Edit Strategy | search-and-replace 编辑策略 | 中 |
| 7 | CLI UX | 流式输出、进度展示 | 中 |
核心洞察:
---
# 每一个新工具必须显式声明自己的安全属性
class ToolBase:
is_readonly: bool = False # 默认非只读
is_concurrency_safe: bool = False # 默认不可并发
needs_permission: bool = True # 默认需要确认
class ReadTool(ToolBase):
is_readonly = True
is_concurrency_safe = True
needs_permission = False
class BashTool(ToolBase):
# 全部使用默认值——最保守的安全策略
pass
COMPRESSION_TEMPLATE = """
## 核心请求
{core_request}
## 关键概念
{key_concepts}
## 文件和代码变更
{files_and_code}
## 错误和修复
{errors_and_fixes}
## 解决过程
{resolution_process}
## 用户消息(完整保留)
{all_user_messages}
## 待办任务
{todo_tasks}
## 当前工作状态
{current_work}
## 下一步行动
{next_steps}
"""
class AgentLoop:
CONTINUE_REASONS = {
"next_turn": lambda self: self.model_called_tools(),
"token_limit_retry": lambda self: self.try_compress_and_retry(),
"max_output_escalate": lambda self: self.escalate_output_limit(),
"recovery_retry": lambda self: self.inject_continuation_prompt(),
}
async def run(self, user_input: str):
while True:
response = await self.call_model()
if response.is_complete():
return response
reason = response.stop_reason
handler = self.CONTINUE_REASONS.get(reason)
if handler and handler(self):
continue
if self.recovery_attempts >= self.max_recovery:
raise AgentLoopExhausted(reason)
self.recovery_attempts += 1
class PermissionPipeline:
async def check(self, action: str, resource: str) -> PermissionResult:
# Layer 1: 历史规则缓存命中
cached = await self.rule_cache.get(action, resource)
if cached:
return cached
# Layer 2: 低风险操作自动放行
if self.is_low_risk(action):
return PermissionResult.ALLOW
# Layer 3: 只读工具白名单
if self.is_readonly_whitelisted(action, resource):
return PermissionResult.ALLOW
# Layer 4: ML 分类器 + 用户交互竞速
return await self.race_classifier_with_user(action, resource)
class MemorySystem:
CODE_RELATED_PATTERNS = [
r"def \w+\(.*\):",
r"class \w+",
r"import \w+",
r"from \w+ import",
]
PREFERENCE_PATTERNS = [
r"(?:我|用户)(?:喜欢|偏好|习惯|希望|要求)",
r"(?:不要|别|禁止|避免)",
]
def should_store(self, content: str) -> bool:
# 代码相关内容不存入记忆
for pattern in self.CODE_RELATED_PATTERNS:
if re.search(pattern, content):
return False
# 偏好相关内容存入记忆
for pattern in self.PREFERENCE_PATTERNS:
if re.search(pattern, content):
return True
return False
---
Claude Code 好用 = 60% 模型能力 + 40% Harness 工程
Harness 工程包含:工具设计、安全机制、记忆系统、上下文管理、多 Agent 协作。模型会越来越强、差距会越来越小;但那套让模型变得"可靠、可预测、可信任"的工程体系,才是真正把产品和玩具区分开来的东西。
---