# 给 Claude Code 一个任务，它的内部发生了什么？

> 作者：晨旭｜发布：2026-04-20｜系列：动手落地AI
> 来源：https://chenxu.xin/writing/claude-code-query-loop

面对几十万行源码，不逐行讲，只切进最核心的 query_loop：Claude Code 的两层分工架构，以及一次请求在 while(True) 状态机里经历的四个阶段。

---

最近在学习拆解 Claude Code 的底层源码。面对几十万行的代码，一开始确实会有一种无从下手的感觉。但再复杂的系统，也一定有它的主心骨。

这篇文章，不是把整个项目讲一遍，而是切入它最核心的部分：`query_loop`。把这个的逻辑理解清楚了，其他外围的支撑基建也就顺理成章了。

一共会分为以下两部分：

- Claude Code 的两层分工架构
- 深入 query_loop：一次请求到底经历了什么？

## Claude Code 的两层分工架构

在之前的文章[拆穿 tools=tools：从工具调用到 Deep Research 架构](/writing/tools-to-deep-research)中提到过工具调用的本质。其实在 Claude Code 的整体架构设计中，这种分工合作的理念体现得更加淋漓尽致。

Claude Code 项目的本质，是一个工作流驱动的 AI Agent 系统。可以把它拆解为一个极简公式：

> Claude Code = LLM + Harness

除了模型，其他部分都是 Harness。那这个 Harness 具体都包含了些什么呢？



下面这张架构图把它划分为了内外两层：Runtime（内层运行时）和 Supporting Systems（外层控制层）。

### 1、Runtime（运行时主循环）

这是系统的核心，也是整个 Agent 动起来的引擎。它本质上就是 `query_loop`，是真正干活的车间流水线。在这个循环里，包含了：

- `messages` / `transcript` 的状态流转
- 模型调用与流式事件消费（Model Streaming）
- `tool_use` 与 `tool_result` 的工具执行与结果回写
- 回合的推进（Turn）以及退出条件判断（`stop_reason`）
- 为了保障循环不崩溃的容错机制（如 retry、max_turns 和触发式的 compact）

可以把它想象成一个项目经理，不断地在客户（User）、大脑（LLM）和跑腿小弟（Tools）之间来回搬运信息，直到项目节点（`stop_reason`）达标为止。

### 2、Supporting Systems（支撑系统）

如果说上面的 Runtime 是工作流水线，那这一层就是保障车间运转的基建与后勤库。模型不能在真空中运转，它需要手脚，也需要备忘录和安全员。这个外层的支撑系统由四个维度装配而成：

**入口与装配**：比如 `main.py`、`REPL` 交互界面和 `QueryEngine`。它负责解析用户的输入并准备初始环境，可以把它理解为系统的「任务发布大厅」。

**能力系统**：包含了 `tools`、`AgentTool` 抽象层以及 `MCP` 协议。它们负责把「读写文件」「搜索网络」等复杂动作，封装成模型看得懂、调得动的 API。

**约束扩展**：包含了 `permissions`（权限校验）、`hooks`（生命周期钩子）以及 `prompt sections`（局部提示词）。它们是系统的「安全护栏」，防止模型失控或越权执行危险代码。

**持久化上下文**：包括 `memory`（记忆提取）、`session`（会话持久化）、`compact`（上下文压缩）以及 `prompt builder`。它们构成了 Agent 的「长短期记忆库」，决定了系统能记住什么、该忘记什么。

总结一下：代码（Runtime）搭建了骨架，决定了流程怎么跑；模型（LLM）只是在特定节点被唤醒做决策；Prompt 负责设定每个阶段的行为边界；而工具（Tools）和记忆（Memory）则是被随时调用的客体。

## 深入 query_loop：一次请求到底经历了什么？

建立起全局的认知后，下面就来看看系统中最核心的部分：`query_loop`。

这个 `query_loop` 本质是一个 `while(True)` 的状态机循环，每次迭代主要经历四个核心阶段。比如以一个真实场景为例：用户输入「帮我看看 README.md 里写了什么」。



通过这段流程，我们可以看到整个过程的数据流转：

1. **用户输入**：被包装成 UserMessage 追加到 messages 列表中。
2. **Phase 1 整理**：由于大模型是失忆症患者，每次都要把整个 messages 列表发给它。所以发送前必须做 normalize，确保对话总是 user / assistant 交替的合法格式。
3. **Phase 2 决策与行动**：模型开始输出。在这里，系统并没有呆呆地等待模型把所有字打完，而是采用了流式分发。当识别到安全的读取类工具被触发时，直接让 Python 脚本这个跑腿小弟并发去执行，极大提升了响应速度。
4. **Phase 4 结果回填**：这是理解 Agent 的最关键一步。Python 脚本执行完读取 README 文件的操作后，代码会将读取到的文件文本打包成 ToolResultBlock，并**伪装成 UserMessage** 塞回 messages 列表。
5. **进入下一轮**：带着带有文件内容的完整上下文，再次进入 `query_loop`。模型这次看到上下文里有足够的信息了，决定直接总结回答，并输出 `stop_reason == "end_turn"`，循环终止。

理清了上述的流转逻辑后，再进一步想一想：当模型输出 `end_turn`，跳出这个无限循环后，它这一路的思考和动作，也就随着函数结束而消失了吗？

这个问题呼应了之前的文章[上下文不等于记忆](/writing/context-is-not-memory)中探讨过的上下文与记忆的核心差异。在 `query_loop` 里，记忆的沉淀悄然发生在了这两个关键节点：

### 1、短时上下文的「快照浓缩」

在 Phase 1，如果粗略估算 token 预算快要触顶，系统就会触发压缩算法。它不会粗暴截断旧记录，而是将旧消息总结成一条边界消息。

这就像是会议室的白板写满了，项目经理把过往讨论提炼成一张摘要便签贴在角落，然后继续开会。

这是低成本将「上下文」转化为「记忆」的第一步。

### 2、任务结束的「本地轻量归档」

当主循环彻底结束，这条包含完整链路信息的 Transcript 会被存入文件。

这里没有选择向量数据库，而是使用「本地保存 + 渐进式加载」的极简设计，完美支持了 Rewind（回退）机制：一旦用户需要撤销某步操作，底层的记忆状态机会精准回滚，不会留下任何干扰数据。

总的来看，Claude Code 内部所谓的神奇能力，拆开来看，不过是一次次严谨的状态维护、API 请求、本地代码执行、字符串的拼接，以及将每一次交互的结晶，稳稳地沉淀进本地档案中。

## 最后

从外层的 Supporting Systems 支撑基建，到内层无限流转的 `query_loop`，Claude Code 的强大源于其严密且克制的系统工程。

技术概念的浪潮总是一波接着一波，但底层的本质却始终如一。希望这篇文章，可以帮助你从底层拨开 Agent 的迷雾，在动手落地的路上走得更稳一点。

## 核心结论

- Claude Code 的本质可以压缩成一个极简公式：Claude Code = LLM + Harness。除了模型本身，其余所有部分都是 Harness——内层是 query_loop 这条运行时流水线，外层是入口装配、能力系统、约束扩展、持久化上下文四类支撑基建。（判断 · 把握较大）
  永久链接：https://chenxu.xin/writing/claude-code-query-loop#claude-code-is-llm-plus-harness
- 理解 Agent 最关键的一步在 Phase 4：Python 执行完工具后，代码会把结果打包成 ToolResultBlock，并伪装成 UserMessage 塞回 messages 列表。模型下一轮看到的「工具结果」，在数据结构上就是一条用户消息。（把握较大）
  永久链接：https://chenxu.xin/writing/claude-code-query-loop#tool-result-disguised-as-user-message
- 系统并不呆等模型把所有字打完。当流式输出中识别到安全的读取类工具被触发时，直接让 Python 并发去执行，这是响应速度的关键设计。（把握较大）
  永久链接：https://chenxu.xin/writing/claude-code-query-loop#streaming-dispatch-not-waiting
- 循环里记忆的沉淀发生在两个节点：一是 token 预算触顶时把旧消息总结成一条边界消息（低成本地把上下文转成记忆），二是主循环结束后把完整 Transcript 存入文件。（把握较大）
  永久链接：https://chenxu.xin/writing/claude-code-query-loop#memory-happens-at-two-points
- Claude Code 的归档没有选择向量数据库，而是「本地保存 + 渐进式加载」的极简设计。这个取舍换来了完整的 Rewind 能力——用户撤销某步操作时，记忆状态机可以精准回滚，不留干扰数据。（判断 · 把握中等）
  永久链接：https://chenxu.xin/writing/claude-code-query-loop#local-archive-over-vector-db

---

本文出自晨光里的AI（https://chenxu.xin），作者晨旭。
引用时请保留来源链接。文中标注「判断」「假设」的部分是作者的个人看法，不是事实。
