Claude Code 源码学习

什么是 Claude Code

Anthropic 官方的编程 Agent,能直接在终端里读代码、改文件、跑命令、管 Git。

和 ChatBot / Copilot 的区别:

  • ChatBot:你问一句答一句,一次性问答
  • Copilot:写代码时给补全建议,一次性预测
  • Agent:给它一个目标,它自己决定先读哪个文件、跑什么命令、改哪行代码,循环几十轮直到完成

核心循环:感知 → 决策 → 行动,每一步都由大模型自主决策,不走预定义流程图。

四层分层架构

层级 职责 设计原则
引擎层 思考和调度 不含业务逻辑,只做协调、分发、决策
工具层 40+ 工具的全部能力 统一规范,类型系统强制三个安全属性
服务层 共享基础设施 大模型 API 调用、上下文压缩、MCP 协议
安全与治理层 安全网覆盖全层 权限系统、Hook 系统、Bash 安全模块

引擎层的关键设计:新增能力只需新增工具,引擎层完全不用改

工具层的安全属性由类型系统强制要求:只读/可写、是否破坏性、能否并行执行——漏了任何一个编译不过。每一把刀都有刀鞘,从出厂就配好了安全机制

Agent 工作模式:Tool-Use Loop

Claude Code 没有用 ReAct,而是用了更简洁的 Tool-Use Loop

ReAct 的问题

ReAct 是 2022 年提出的 Agent 范式,每轮拆成 Thought → Action → Observation 三步。问题:

  1. Token 浪费:每轮输出显式 Thought,50 轮下来好几万 Token
  2. 应用层复杂:需要从文本中解析 Thought/Action,格式不标准就崩
  3. 为弱模型设计:Claude Opus 级别的模型推理能力足够强,不需要显式引导

Tool-Use Loop 的设计

核心就是一个 while(true) 循环:

  • 模型通过 Extended Thinking 在内部完成推理(不占上下文空间)
  • 直接返回 tool_use(执行工具,继续循环)或 end_turn(结束对话)
  • 没有 Thought 步骤,没有文本解析,只有 if/else

核心哲学:信任模型的推理能力,保持应用层框架尽可能简单

Plan Mode

先规划再执行的两阶段工作流:

  1. 模型自主判断或用户手动触发(Shift+Tab)
  2. 进入后权限降为只读,只能用 Read/Grep/Glob 探索,不能改代码
  3. 每 5 轮对话塞一张”小纸条”提醒模型还在 Plan Mode
  4. 用户审批后恢复读写权限,按计划执行

精髓是**”工具即能力”**——不需要切换框架,只是把写入工具从可用列表中移除,用工具的有无来定义行为边界。

System Prompt 的构造

System Prompt 不是静态文件,而是动态组装的十几个 Section。

核心内容

角色定义:定位为 interactive agent 而非 assistant,暗示模型应主动行动。第一条安全红线:”不能乱编 URL”。

行为准则

  • 修改前先阅读:不要对没读过的代码提修改建议
  • 少即是多:修 bug 不需要顺手重构,三行相似代码比过早抽象更好
  • 先诊断再换方案:失败了先看报错信息,不要盲目重试也不要草率放弃

操作安全用两个维度判断风险:可逆性 × 影响范围

  • 改本地代码(可逆+局部)→ 直接放行
  • git push(不可逆+影响他人)→ 必须确认

Git 安全协议

  • 绝不修改 git config
  • 绝不 force push 到 main/master
  • commit 失败后不能 --amend(hook 失败意味着 commit 没发生,amend 会改错上一个 commit)

输出风格:工具调用间文字不超过 25 词,最终回复不超过 100 词,先给答案再给推理。

三级缓存体系

System Prompt 中间有一条分割线 __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__

  • 分割线之上:角色定义、行为准则等——所有用户完全一样
  • 分割线之下:环境信息、CLAUDE.md、记忆指令——每个用户不同

为什么要分?Claude API 的 Prompt Cache 机制:前缀相同的请求复用计算结果,**费用降低 90%**。分割线之上全球用户共享同一份缓存。

三级缓存:全局缓存(跨组织)→ 组织缓存(跨会话)→ 会话缓存(单次会话内)。

记忆系统

每次启动都是新会话,但用户偏好、项目背景需要跨会话保持。没有用向量数据库。

四类型分类

user      // 用户画像:角色、偏好、知识水平
feedback  // 行为反馈:该做什么、不该做什么(记录 Why + How to apply)
project   // 项目动态:截止日期、协作信息(相对日期转绝对日期)
reference // 外部指针:去哪找什么信息

只有这四种,不能随便加。无约束的记忆会膨胀成垃圾堆,限定类型逼 Agent 做分类决策。

排除清单

不记什么同样重要:

  • 代码模式、文件结构(通过 grep/git 就能获取)
  • Git 历史和最近改动(git log 才是权威来源)
  • 调试方案(修复已经在代码里了)
  • CLAUDE.md 已有的内容

核心原则:可以从当前代码推导出来的信息,一律不存。记忆是”死的”,代码是”活的”,存了反而会产生”权威的错误”。

存储:索引 + 独立文件

每条记忆存为独立 .md 文件,开头有 YAML 元信息(name/description/type)。

MEMORY.md 作为索引(不超过 200 行/25KB)始终加载到 System Prompt,但具体记忆文件按需加载

召回:Sonnet 当秘书

用廉价小模型(Sonnet)做记忆检索:

  1. 扫描所有记忆文件的前 30 行(只读元信息,不读全文)
  2. 拼成清单发给 Sonnet,让它选出最多 5 条最相关的
  3. 加载选中记忆的完整内容注入上下文

细节:

  • 陈旧度检测:超过 1 天的记忆自动附加警告,提醒模型先验证再引用
  • 并行预取:Sonnet 侧查询在用户提交消息后立刻启动,比主模型 API 调用快得多,几乎零延迟

上下文窗口管理

五步从轻到重的压缩策略,像医院分诊:先试最温和的,不行再上猛药。

层级 手段 信息损失 API 开销 触发条件
第 1 层 大结果存磁盘 几乎为零 工具结果超 50KB
第 2 层 砍掉远古消息 消息过时
第 3 层 清理老工具输出 中低 缓存过期/数量超限
第 4 层 读时投影压缩 中低 上下文达 90%
第 5 层 全量摘要 高(一次 API 调用) 上下文达 ~93%

第 1 层:单个工具结果超 50KB 时,完整内容写磁盘,消息里只留 2KB 预览。模型需要时可以重新读取。

第 2 层:Snip 直接砍掉对话开头的老消息,不做摘要,零 API 开销。会告诉第 5 层”我释放了多少 Token”,避免重复压缩。

第 3 层:时间衰减——越老的工具结果越不重要。只裁剪”可重新获取”的工具(Read/Bash/Grep),子 Agent 输出等不可重复的结果永不裁剪。

第 4 层读时投影(Read-Time Projection)——不修改原始消息,只在调用 API 时动态计算压缩视图。两级阈值:90% 主动压缩,95% 紧急压缩。如果这层够用,第 5 层就不触发。

第 5 层:全量摘要,按多维度结构化总结(用户意图、技术概念、文件片段、错误修复、待完成任务等)。压缩后还有 Post-Compact Restoration:从文件缓存中恢复最近访问的最多 5 个文件(50K Token 预算),让模型无缝继续工作。

全量摘要连续失败 3 次自动放弃(熔断器模式),防止拖垮整个 Agent。

总结

几个最值得借鉴的设计:

  1. Tool-Use Loop 替代 ReAct:信任模型内部推理,应用层只做最简单的 while 循环
  2. System Prompt 分割线:静态内容和动态内容分开,利用 Prompt Cache 省 90% 费用
  3. 记忆四类型 + 排除清单:记该记的,不记能从代码推导的
  4. 五步渐进压缩:能轻则轻,逐步加码,前三层零 API 开销
  5. 安全属性类型系统强制:工具的安全属性编译时检查,不是运行时约定