这是「Claude Code 第一性原理拆解」的第 1 篇。
我想先不谈功能表,而是先回答一个更底层的问题:一个编程智能体到底在解决什么,以及为什么 Claude Code 会长成今天这样。
摘要
这一篇我主要想讲清 4 件事:
- Claude Code 真正在解决的,不是“聊天更聪明”,而是“让模型在真实工程环境里持续行动”。
- 主循环、工具运行时、权限、上下文压缩,不是功能堆砌,而是问题自然外溢出来的架构层。
- 如果站在大模型应用开发工程师的视角,读 Claude Code 最重要的不是追功能,而是建立问题意识。
- 这套问题意识,会直接影响我以后怎么设计自己的 Agent 系统。
你会得到什么
读完这一篇,最少应该能回答这几个问题:
- 为什么我会把 Claude Code 看成 Agent Runtime,而不是编程版聊天工具。
- 为什么一旦模型开始行动,系统复杂性就会迅速上升。
- 为什么我读源码时要先抓主问题,而不是先扫目录。
我现在看 Claude Code,不会先去看它支持多少命令、多少模式、多少工具。我会先问一个更底层的问题:
如果不看产品文案,只看工程现实,Claude Code 到底在解决什么问题?
因为一旦这个问题没想清楚,后面很容易陷入一种很表层的阅读方式:
- 看到
FileReadTool,觉得“哦,就是读文件” - 看到
BashTool,觉得“哦,就是跑命令” - 看到
AgentTool,觉得“哦,就是多开几个智能体”
这样读,最后很难得到自己的方法论。最多只是知道“这个仓库很大、功能很多”。
但我现在越来越确信,Claude Code 的价值不在“功能多”,而在它很认真地解决了一类特定系统问题:
如何让一个模型在真实工程环境里持续、可控、可恢复地行动。
如果只用一句更工程化的话来说,就是:
Claude Code 不是聊天机器人加几个工具,而是一个面向编程场景的 Agent Runtime。
这篇文章,我就只做一件事:把这个判断从第一性原理讲明白。
一、先从第一性原理问:一个“编程智能体”到底要干嘛
如果我把“编程智能体”这四个字拆开来看,其实它至少要同时满足四个条件:
1. 它不是纯生成系统
也就是说,它不能只是:
- 听用户说一句话
- 返回一段文字
如果只是这样,那它本质上还是一个聊天系统,只不过主题是编程。
2. 它必须理解环境
编程不是在真空里进行的。
它总要面对:
- 当前仓库
- 当前文件树
- 当前分支或工作区
- 当前已有代码和配置
- 当前用户真正想解决的问题
所以一个编程智能体,第一性原理上一定不是“单轮问答机”,而是“带环境的系统”。
3. 它必须能行动
只会说“你可以改一下这个函数”没有用。
真正的编程智能体必须能:
- 读文件
- 搜代码
- 修改文件
- 跑测试
- 看错误输出
- 必要时继续再行动
这意味着它必须把“语言理解”转成“具体动作”。
4. 它必须对动作后果负责
这是最关键的一点。
一旦它能改文件、跑命令、调用外部系统,它就不再是纯信息系统,而是一个带副作用的系统。
而一旦系统有副作用,就会立刻出现这些问题:
- 动作有没有权限
- 多个动作能不能并发
- 失败以后怎么恢复
- 长会话如何维持上下文
- 用户如何知道它做了什么
所以如果从第一性原理看,编程智能体天然会长出四层结构:
- 环境理解
- 行动执行
- 状态维持
- 风险约束
Claude Code 的整个架构,其实都是这四件事往外长的结果。
二、我为什么说“先别看功能,先看问题”
因为我觉得工程阅读里最常见的误区,就是被功能表带跑。
比如看到 Claude Code 这种项目,最常见的感想是:
- 它支持编辑文件
- 它支持终端命令
- 它支持子智能体
- 它支持 MCP
这些当然都是真的,但这不是最重要的信息。
更重要的是:
为什么一个认真做的编程智能体,最后几乎一定会长出这些东西?
我会倒着推一遍。
如果它要持续做任务
它就不能把每次模型调用都当成独立结束点。
于是一定需要主循环。
如果它要调用工具
它就不能把工具当成普通函数,而要统一管理:
- schema
- 执行
- 错误
- 回填消息
于是一定需要Tool Runtime。
如果它能改真实环境
它就不能只靠 prompt 自觉,而要在运行时做决策。
于是一定需要权限系统。
如果它会话会很长
它就不能无限堆消息,而要做:
- 压缩
- 记忆
- 信息分层
于是一定需要上下文工程。
如果任务太复杂
它就不能把所有事情都压在一个执行体上。
于是会自然长出子任务 / 多 Agent / 隔离执行。
也就是说,从问题出发,Claude Code 的架构其实非常“必然”。
三、Claude Code 的主问题,不是“怎么问模型”,而是“怎么约束复杂性”
这是我读这个项目以后最大的感受之一。
很多人做大模型应用,前两个月最容易关注的是:
- prompt 够不够强
- 模型够不够好
- tool description 写得准不准
这些都重要,但只要系统开始进入“能持续行动”的阶段,问题重心就会迅速移动。
真正困难的东西变成:
- 会不会把状态搞乱
- 会不会执行危险操作
- 会不会在第 10 轮以后忘掉真正任务
- 会不会在工具失败后陷入死循环
- 会不会让一个小任务无限膨胀成大系统复杂性
所以我现在更愿意把 Claude Code 看成“复杂性约束系统”。
它不是在炫耀模型多聪明,而是在努力回答:
当模型开始行动以后,系统怎样还能保持清楚、稳定、可控。
四、源码主线:我会先看哪几条
如果我只保留最少的源码主线,我会锁定这几条:
1. 入口和主控
src/entrypoints/cli.tsxsrc/main.tsxsrc/QueryEngine.tssrc/query.ts
我看这组文件,不是为了背命令参数,而是为了理解:
- 请求如何进入系统
- 会话如何开始
- 回合如何推进
2. 工具层
src/Tool.tssrc/tools.tssrc/services/tools/toolOrchestration.tssrc/services/tools/toolExecution.ts
我看这组文件,是为了理解:
- 模型说“我要执行工具”以后,系统到底怎么把这件事做实
3. 权限与约束
src/utils/permissions/permissions.ts
我看这个文件,是为了回答:
- 模型有行动冲动,但谁来裁决可不可以行动
4. 上下文与长期状态
src/services/compact/compact.tssrc/services/SessionMemory/sessionMemory.ts
我看这组文件,是为了理解:
- 为什么 Agent 的长期会话绝不是“把聊天记录一直往后拼”
5. 子任务与多 Agent
src/tools/AgentTool/AgentTool.tsxsrc/tasks/LocalAgentTask/LocalAgentTask.tsx
我看这组,是为了回答:
- 任务复杂以后,系统怎么拆,怎么追踪,怎么回填
五、用一张架构图把 Claude Code 压到最简
如果不用产品语言,只用系统语言,我会把 Claude Code 压成下面这张图:
flowchart TD
U[用户输入] --> S[会话状态]
S --> Q[主循环 Query Loop]
Q --> P[系统提示与上下文构造]
Q --> M[模型推理]
M --> T{是否发起工具动作}
T -->|否| R[生成最终回复]
T -->|是| X[Tool Runtime]
X --> G[权限与风险裁决]
G --> E[执行工具]
E --> S
Q --> C[上下文压缩与记忆]
E --> A[子任务 / 子 Agent]
A --> S
我特别喜欢这张图,因为它说明了一个很重要的事实:
Claude Code 的骨架不是“聊天框 + 工具栏”,而是:
- 一个回合循环
- 一组受控动作
- 一套状态回流机制
这和很多人脑海里对 AI 助手的想象非常不一样。
六、我会怎么把这套思路转成 Python 伪代码
我每次读这种 TypeScript 项目,都会主动把它压回 Python 风格伪代码,因为这样最容易看清主语义。
我心里的 Claude Code 最小骨架,大概长这样:
class CodingAgentRuntime:
def __init__(self, tools, permissions, memory):
self.tools = tools
self.permissions = permissions
self.memory = memory
self.messages = []
def handle_user_turn(self, user_input):
self.messages.append(user_message(user_input))
while True:
prompt = self.build_system_prompt()
assistant = self.call_model(prompt, self.messages)
self.messages.append(assistant)
tool_calls = assistant.extract_tool_calls()
if not tool_calls:
return assistant
tool_results = []
for call in self.partition_and_run_tools(tool_calls):
if not self.permissions.allow(call):
tool_results.append(permission_denied(call))
continue
result = self.tools.execute(call)
tool_results.append(result)
self.messages.extend(tool_results)
if self.should_compact():
self.messages = self.compact(self.messages)
if self.should_update_memory():
self.memory.update(self.messages)
这段伪代码不求贴近每个实现细节,但它足够让我看清:
- 为什么它是循环
- 为什么它一定会有工具层
- 为什么它一定会有权限层
- 为什么它一定会有 compact / memory
七、这件事和“大模型应用开发”到底有什么关系
这个问题我很在意,因为我不是为了“研究某个产品”才读这个项目。
我读它,是为了反过来校准我自己对大模型开发的理解。
如果我只做过最简单的应用,我对系统的理解可能停在:
- prompt
- 模型
- 检索
- API 封装
但 Claude Code 会逼我承认:
真正一旦走到“智能体”阶段,工程重点会整体迁移到这些问题上:
- Runtime 怎么设计
- 工具怎么托管
- 状态怎么回流
- 权限怎么治理
- 长上下文怎么管理
- 复杂任务怎么拆解
这其实就是一种认知升级。
八、我的个人判断:Claude Code 最值得学的不是实现,而是问题意识
我不觉得所有团队都要复制 Claude Code 的体量。
很多团队根本不需要那么大的系统。
但我觉得所有认真做 Agent 的团队,都应该学它的一件事:
不要把问题想得太轻。
一旦模型开始读写环境,它面对的就不再只是“生成质量”问题,而是:
- 系统一致性问题
- 风险边界问题
- 长期状态问题
- 调度问题
如果这些问题在脑子里不存在,再优雅的框架都会被你用成临时脚手架。
九、这一篇我最后想留下的结论
如果我只能留一句话给以后写 Agent 的自己,我会写:
Claude Code 最值得学习的地方,不是它能做多少事,而是它非常诚实地面对了“模型一旦开始行动,系统就必须承担哪些复杂性”这个问题。
而这也是我认为,大模型应用开发从“会接 API”走向“会做系统”时,最关键的一道坎。