第一次使用 Claude Code 重构整个模块时,我有一种几乎神秘的体验。我描述了自己的需求,然后就去喝了一杯咖啡,等我回来时,眼前是一份包含14个文件更改的pull request,测试代码已更新,还有一条合格的提交消息。“这简直是魔法”,我当时想。
但这并不是魔法。这只不过是一个 while 循环。
最近,OpenAI 的 Michael Bolin 发布了一篇文章,揭秘了 Codex CLI 的内部运作方式。事实证明,那些所谓的AI 编程代理背后的秘密并不是某种革命性的算法,也不是神秘的神经网络。它实际上是一个调用 LLM 的循环,执行工具操作,然后一直重复,直到没有剩余的任务。
接下来,我们深入解析。
状态机:5个阶段和一个循环
每一个编程代理 —— 不管是 Codex、Claude Code、还是 Cursor —— 都遵循着同样的基本模式。Michael Bolin 将其描述为一个包含5个阶段的循环:
flowchart TD
A["1. 提示组装\n(构建 Prompt)"] --> B["2. 推断\n(发送到 LLM)"]
B --> C{工具调用?}
C -->|是| D["3. 工具调用\n(执行工具)"]
D --> E["4. 工具响应\n(将结果返回 LLM)"]
E --> B
C -->|否| F["5. 助手回复消息\n(最终响应)"]
F -->|新输入| A
style A fill:#2d3748,stroke:#4a9eed,color:#fff
style B fill:#2d3748,stroke:#4a9eed,color:#fff
style C fill:#4a3728,stroke:#ed9a4a,color:#fff
style D fill:#2d3748,stroke:#4a9eed,color:#fff
style E fill:#2d3748,stroke:#4a9eed,color:#fff
style F fill:#283d28,stroke:#4aed5c,color:#fff
通俗点说:
- 提示组装 (Prompt Assembly):构建一个巨大提示,包含代理需要知道的一切——你的消息,系统指令,可用工具,已读取的文件,和整个会话历史。
- 推断 (Inference):将提示转化为 token,然后发送到模型。模型返回一个事件流:包括推理过程、工具调用或响应文本。
- 工具调用 (Tool Invocation):如果模型请求执行某个工具(如读取文件、运行命令、写代码),则执行。如果执行失败,错误会反馈到模型。
- 工具响应环 (Tool Response Loop):工具的输出会作为额外的上下文返回给模型。然后重复步骤2到4,直到模型不再调用工具。
- 助手消息 (Assistant Message):当模型决定完成任务后,它会生成最终的消息,结束循环。
仅此而已。没有知识图谱,没有符号规划器,也没有复杂的架构。它只是一个内含 LLM 的 while 循环。
一个优秀代理和一个糟糕代理的区别并不在于循环的架构——架构是相同的——而在于每个阶段的细节处理。
阶段一:提示组装的艺术
第一阶段才是真正的“灵魂”所在。在 LLM 看到你的代码之前,代理需要构建一个包含以下元素的提示:
flowchart LR
subgraph Prompt["提示组装"]
direction TB
SP["系统提示\n(性格、规则)"]
Tools["可用工具\n(Read, Write, Bash, MCP...)"]
Ctx["已读取的\n文件或图片"]
Inst["CLAUDE.md / AGENTS.md\n(代码库指令)"]
Env["环境信息\n(OS, shell, git 状态)"]
Hist["会话历史"]
User["用户信息"]
end
SP --> Final["完整提示"]
Tools --> Final
Ctx --> Final
Inst --> Final
Env --> Final
Hist --> Final
User --> Final
style Final fill:#283d28,stroke:#4aed5c,color:#fff
这里可以看到一个关键的设计决策:顺序很重要。提示的构建遵循从稳定到变化的顺序。首先是系统提示(几乎从不改变),然后是工具(很少改变),接着是文件和历史(随着每次交互增长),最后才是你的最新消息。
为什么要这样排序?因为提示缓存(prompt caching)。缓存是基于前缀的精确匹配工作的。如果把稳定内容放在最前面,可以最大限度地提升每次迭代中从缓存读取的 token 数量。如果在前面改变了什么,就会使整个提示失效。在这篇有关提示缓存的文章中,我详细讨论过这个问题。这里的关键点是:提示顺序的设计不仅关乎美观,更关乎成本。
还有 CLAUDE.md 和 AGENTS.md 文件的作用。这就像你离开家前给水管工写的留言:“总阀门在水槽下,别碰蓝色的管子。”代理在启动之初就会读取这些内容,并把它们注入每个提示中。这是给代理提供上下文的一种机制,避免每次都要重复。