大模型能写代码, 靠的是一个简单循环
我读 Gemini CLI 源码, 起因很具体: 去年我在公司内部做了一个 Code Agent 产品, 给它设计循环机制的时候, 我想知道一个已经跑在大量开发者终端上的开源实现是怎么做的, 于是把 Gemini CLI 的核心目录翻了一遍。
翻完的结论出乎意料: 最核心的东西非常小——就是一个循环。模型说话, 发起工具调用, 拿到工具结果, 再说话。其余的一切, 审批、上下文压缩、循环检测、预算控制、模型降级, 全是围着这个循环做的外围工程。我后来自己搭产品, 也是先把这个循环立起来, 再逐个补护栏。连"下一句话该谁说"这种问题, 也只是循环里的一个判定点: 模型说完而没发起工具调用时, 一个轻量模型会被叫来判一次"该继续还是该交还用户", 判"继续"就自动接一轮。
这个结论在源码里有多简单, 可以用三个细节说明。Turn 类把一次模型调用包装成事件流, 事件类型在源码里就是一个枚举——从文本流、工具调用请求到循环检测、会话轮数到顶, 覆盖了循环可能遇到的每一类情形。client.ts 里写死一个 MAX_TURNS = 100, 给这个递归加硬上限。next-speaker-checker 的判定提示里只有三条规则: 上一条回复说了接下来要做什么, 模型接着说; 以向用户的提问结尾, 交还用户; 除此之外, 交还用户。一个让大模型自主干活的系统, 它的决策点就是这几行。
flowchart TB
A[用户请求] --> B[模型说话<br/>可能发起工具调用]
B --> C{发起了<br/>工具调用?}
C -->|是| D[调度器执行工具<br/>结果写回历史]
D --> B
C -->|否| E[Next Speaker 判定<br/>轻量模型决策]
E -->|模型继续| B
E -->|交还用户| F[控制权回到输入框]Anthropic 在《Building effective agents》里把这个事实写得很直白: agent 通常就是"大模型在循环里依据环境反馈使用工具"。那接下来的三个问题就值得认真回答了: 这套机制从哪来? 为什么它偏偏在写代码这件事上威力这么大? 现在的 coding agent 是不是都在这么跑?
机制从哪来: 不是 LLM 时代的新发明
这个循环最深的一层根, 比 LLM 早得多。强化学习的教科书(比如 Sutton 与 Barto 的《Reinforcement Learning: An Introduction》)把"agent 与环境的交互"作为整个学科的形式化核心: agent 观察环境状态, 采取动作, 环境返回新的状态与奖励, 循环往复。经典 AI 教材里 agent 的定义也是同一句话: 能感知环境并作用于环境的东西。所以这个循环本身不是谁"发明"的——它的形式在控制论和强化学习里早就写清楚了。2022 年之后发生的事情, 是把循环里做决策的部分换成了语言模型。
换完决策部分之后, 第一个环节是 ReAct(2022-10): 把推理轨迹和动作交织在同一个循环里, 模型先想一步、再动一步、观察结果、再想。它解决的是纯推理的两个老毛病——幻觉漂移和不可追溯: 有了动作和环境观察夹在中间, 推理链条被环境反馈持续校准。在 ALFWorld 和 WebShop 两个交互任务上, ReAct 比当时的模仿学习和强化学习方法分别高出 34% 和 10% 的绝对成功率, 而它只用了极少的示例。
第二个环节是 Toolformer(2023-02): 它用自监督的方式让模型自己学会"什么时候该调 API、传什么参数、怎么把结果用进后续预测"。在这之前, “调工具"是脚本的事——脚本解析模型的文本输出, 模型不参与决策; 在这之后, 调工具的判断权回到了模型手里。这个思路后来成为各家模型 API 的标准能力(函数调用), “发起工具"从解析文本变成了一次结构化的接口调用。
第三块拼图是代码场景的落地, 而它有一个明确的起点: 2023 年 10 月 SWE-bench 发布, 用 2294 个真实 GitHub issue 给了所有 agent 一个统一的基准。当时的答案是残酷的——最强的 Claude 2 只能解决 1.96%。七个月后 SWE-agent 用 12.5% 刷新纪录, 而它的核心主张不是更强的模型, 是 ACI(agent-computer interface): 给模型的搜索、编辑、浏览命令要专门为模型设计, 编辑命令带 linter 护栏, 文件视图做窗口化。接口设计得好坏, 直接决定同一颗大脑能考出多少分。
2024 年这条线开始收敛成共识。OpenHands(2024-07, 后中 ICLR 2025)把"像人类开发者一样干活——写代码、用命令行、浏览网页"做成开源平台, 证明这个循环可以作为通用底座搭建一整套平台; Anthropic 在 2024 年底把经验写成方法论: 先用最简单的增强 LLM, 需要时再上 agent, 并把"花在优化工具上的时间超过优化 prompt"写成了一带实践者的共同体会。
flowchart TB
A["控制论与强化学习<br/>感知-行动循环<br/>Sutton 与 Barto 的形式化"] --> B["2021.12 WebGPT<br/>模型操作文本浏览器检索"]
B --> C["2022.10 ReAct<br/>推理与动作交织<br/>解决幻觉漂移"]
C --> D["2023.02 Toolformer<br/>调工具的判断权交给模型"]
D --> E["2023.10 SWE-bench<br/>2294 个真实 issue<br/>Claude 2 仅 1.96%"]
E --> F["2024.05 SWE-agent<br/>ACI 接口决定成败<br/>12.5%"]
F --> G["2024 OpenHands 与<br/>产品级 harness<br/>循环成为通用底座"]为什么偏偏在代码里威力这么大
把三个证据摆在一起, 答案是反馈的性质。
第一, 代码环境能提供廉价且确定的验证结果。编译器和测试套件不输出模糊判断: 通过就是通过, 失败会给出具体报错和位置。Anthropic 的总结是: 代码方案可以通过自动化测试验证, agent 拿测试结果当反馈迭代。这意味着循环里的"观察"一步信号极强, 模型可以在一个会话里完成多轮自我修正, 而不用人插手。
Anthropic 还给过两个更具体的接口设计细节: 他们的 agent 用相对路径会出错, 于是把工具改成强制绝对路径, 之后模型在这个点上没有再犯过错; 他们把这类设计原则叫 poka-yoke(防呆)——让工具的参数定义本身就难以用错。这些提升与模型能力无关, 全是工程决策。
第二, 连权重都不用更新。Reflexion(2023)证明: agent 把失败经历写成语言反思、存进记忆、再进下一轮, 就把 HumanEval 的 pass@1 从 GPT-4 的 80% 推到 91%。循环加语言反馈本身就能产生"学习"的效果——这是这个模式便宜又好用的直接证据。
第三, 数字轨迹说明提升来自循环工程而非模型换代。SWE-bench 发布时 1.96%, SWE-agent 七个月后 12.5%, 靠的是接口重设计; 2024 年之后 OpenHands、Claude Code、Gemini CLI 这类产品把同样的循环装上护栏(审批、压缩、循环检测、预算), 让它能扛住真实工作负载。同一个循环结构, 配更好的模型、更好的接口、更完备的护栏, 分数一路往上走。
现在的 coding agent 都在这么跑吗
我的答案分两层。
主流的自主 agent, 是的。OpenHands 的论文对这个底座有更完整的描述: agent 在沙箱环境里执行代码, 支持多个 agent 协作, 接入了 15 个基准测试(SWE-bench、WebArena 都在其中), 以 MIT 协议开源, 收到 188 位贡献者的 2100 多次提交。它被 ICLR 2025 接收, 说明学术界也把"LLM 加工具循环"当成软件工程研究的标准范式。Claude Code、Gemini CLI、SWE-agent、OpenHands 这四家的公开实现或论文, 核心都是同一个循环: 模型驱动的工具调用加环境反馈。它们的差异不在循环, 在循环外面——工具面怎么设计、权限怎么守、上下文怎么管、失控怎么拦。这正是我读 Gemini CLI 源码的最大感受: 目录里几十个模块, 没有一个在改循环本身, 全部在给循环装护栏。我自己做产品的过程给了同一个结论的另一个样本: 先把模型、工具面、循环立起来, 第一版就能跑通一个完整的编码任务; 之后的版本迭代, 精力几乎全部花在护栏上——权限、上下文、中断恢复, 循环本身一行没改。
但也有收窄的变体。aider 是一个好例子: 它不开放自由工具调用, 而是让模型按固定格式输出 SEARCH/REPLACE 编辑块, 程序解析并应用这些块, 再自动提交 git、跑测试。循环被收窄成"对话 → 改文件 → 测试"三步, 模型没有"决定下一步"的自由度, 换来的是编辑行为的可控性。这类设计说明同一个循环结构可以按需收放: 要自主性就放开工具面, 要可控性就收窄成工作流。
收尾
所以对开头那三个问题, 我的答案是: 这套循环不是新发明, 它是感知-行动的老结构, 2022 年之后把决策部分换成了语言模型, 由 ReAct、Toolformer 一路铺到代码场景; 它在代码里威力大, 是因为编译器和测试给它提供了便宜、确定的验证结果; 主流自主 coding agent 都在这么跑, 而产品的竞争已经不在循环本身, 在接口(ACI)和护栏上。
这段读源码加自研的经历给我的最大收获是: 不要试图发明新的循环, 把工程精力投到接口和护栏上。
我接下来会盯两件事: 一是 agent 与环境接口的标准化(MCP 这类协议能不能把 ACI 从各家私有设计变成公共设施); 二是循环的"停止判定"能不能更可靠——什么时候该继续、什么时候该交还给人, 这个判定的误判率直接决定 agent 的手感。