01:Agent Loop:Claude Code 的运行时主循环
01Agent LoopClaude Code 的运行时主循环上一篇先把 Claude Code 放回工程系统里看。它更像一个能进入仓库、观察环境、调用工具、处理风险、验证结果的 coding agent。沿着这个角度往下拆第一条主线就是 Agent Loop。工具、上下文、提示词、计划、权限、恢复、多 agent后面都会单独讲。但这些模块最后都要挂到同一条运行链路上用户给出一个目标以后Claude Code 如何一轮一轮地观察、判断、行动、接收反馈直到任务完成、阻塞或需要用户决策这篇先把范围收窄到主循环本身工具系统、提示词、上下文管理和权限细节只看它们在主循环里的位置。后面第 02 篇会专门讲工具第 03 篇讲提示词第 05 篇讲上下文第 07 篇讲权限第 09 篇讲失败恢复。这篇文章要拆的主线这一篇回答的问题是Claude Code 如何把模型、工具、上下文、权限和验证组织进一个可持续推进的运行时主循环普通的大模型问答通常是一次请求响应。用户提出问题模型根据已有输入给出答案。这个过程可以很强但它主要发生在文本里。Coding agent 面对的是另一种任务。用户通常希望它在真实仓库里完成一件事“帮我修一下这个构建错误。”“根据现有风格加一个页面。”“看看这个接口为什么返回 500。”“把这段逻辑重构一下别破坏测试。”这些任务一开始只有目标现场信息还很少。入口文件、错误根因、项目约定、验证方式都要在运行过程中逐步找出来。模型需要先看现场再决定下一步。所以 Agent Loop 的意义是让模型进入一个持续更新的工程现场。每一轮都拿到新的信息每一轮都更新任务状态每一轮都判断下一步是继续、停止还是询问用户。用一句话概括Agent Loop 是 coding agent 把模糊用户目标推进成可验证工程结果的运行时主循环。为什么主循环要管理状态和反馈“模型调用工具然后继续问模型”可以解释一个演示版本。真实 coding agent 需要处理的问题要多得多工具可能成功也可能失败。命令输出可能很长需要裁剪和摘要后再回到上下文。用户可能拒绝某个权限请求。修改文件以后验证可能失败。一轮搜索可能返回空结果这个空结果本身也会改变下一步策略。任务变长以后agent 需要记住已经做过什么还差什么。所以主循环的重点在于维护状态、保留证据、控制风险、判断出口。有资料把 Claude Code 的主循环描述成一个围绕queryLoop展开的运行时结构每一轮都像一次状态转移可以在不同阶段产出事件、等待工具结果、处理权限和继续推进[1][2]。这类源码细节在这一篇点到即可。这里真正值得吸收的是工程思路主循环要能暂停、恢复、记录、分支和收束。这也是 Claude Code 和简单工具调用 demo 的差别。demo 证明模型能调用工具就够了生产级 coding agent 还要在工具失败、上下文变长、权限受限、用户插入新要求时继续保持任务方向。主循环的工程形态任务状态机更合适的理解方式是把 Agent Loop 看成一个任务状态机。状态机这个词听起来有点硬但放到 coding agent 里很直观系统每一刻都处在某种任务状态里然后根据新的观察结果进入下一个状态。比如用户刚提出目标系统处在“需要理解任务”的状态。搜索找到了相关文件系统进入“需要阅读证据”的状态。已经定位修改点系统进入“准备行动”的状态。写文件前发现风险系统进入“需要权限判断”的状态。测试失败系统进入“根据失败输出继续排查”的状态。验证通过系统进入“可以总结”的状态。主循环真正做的事就是不断完成这种状态转移。这也解释了为什么很多看起来分散的机制都要接进 Agent Loop工具系统提供外部观察和行动能力第 02 篇展开。上下文管理决定哪些信息进入下一轮第 05 篇展开。计划和任务状态帮助长任务保持方向第 06 篇展开。权限系统决定哪些动作可以执行第 07 篇展开。可观测系统记录每轮发生了什么第 08 篇展开。失败恢复决定卡住以后怎么换路第 09 篇展开。也有资料把 Claude Code 的价值概括为多个模块挂到同一条运行链路上工具、上下文、hook、subagent 围绕主循环协同工作[4]。在 01 这里先只保留一个总判断Agent Loop 是所有运行时能力的总线。一轮循环如何推进任务把一轮主循环拆开看大致会经历这些步骤。接收目标。系统先把用户的话变成当前任务目标。这里可以先得到一个可推进版本这次是解释、调试、修改、重构还是高风险操作。组装上下文。系统把当前目标、已有对话、项目规则、相关文件片段、工具说明和任务状态放进本轮输入。提示词、记忆、上下文和任务状态的细节会在第 03、04、05、06 篇分别展开。模型决策。模型基于当前状态判断下一步需要搜索、读文件、编辑、运行命令、验证还是问用户。工具请求。如果下一步需要接触仓库就会转成工具调用。工具是 agent 接触真实环境的手。工具系统后面第 02 篇单独讲。权限判断。读文件、写文件、运行命令、访问外部系统的风险不同。主循环需要在工具执行前接入权限判断。这里先标注位置第 07 篇再展开。工具执行。工具真正去读文件、搜索代码、修改文件或运行命令。执行结果会改变系统能看到的事实。观察结果更新。工具结果会回到任务状态里。成功输出、错误信息、diff、测试结果、权限拒绝都会影响下一轮。进入下一轮判断。系统判断现在该继续、停止还是询问用户。这个过程可以画成一条闭环用户目标 - 当前任务状态 - 本轮上下文 - 模型决策 - 工具请求 - 权限判断 - 工具执行 - 观察结果 - 更新任务状态 - 停止 / 继续 / 询问用户这个闭环里最重要的是最后两步工具结果会从工具层回到任务状态成为下一轮输入。如果读文件成功下一轮就基于文件内容继续判断。如果测试失败下一轮就基于失败输出继续定位。如果权限被拒绝下一轮就要换一个低风险策略或者向用户解释为什么需要这一步。如果搜索返回空结果下一轮也要调整关键词、换入口或说明当前线索不足。所以 Agent Loop 更像模型决策和环境反馈之间的循环协议。任务状态主循环真正维护的东西普通聊天里流动的是文本。上一轮说了什么下一轮接着说。Coding agent 里流动的是任务状态。文本仍然存在但它要被组织成更稳定的结构否则任务一长就容易丢线索。一个主循环至少要维护这些状态状态它回答的问题目标用户这次到底要完成什么上下文当前已经掌握哪些项目事实计划接下来准备怎么推进工具结果刚才的搜索、读取、编辑、命令返回了什么改动仓库里已经发生了哪些变化证据有哪些信息证明任务接近完成或证明还没完成风险下一步是否可能越界是否需要确认阻塞点当前为什么卡住下一轮理由为什么要继续、停止或询问用户这里的“下一轮理由”很关键。一个可靠的 agent 每次继续都应该有原因因为搜索发现了相关文件。因为错误输出暴露了新的调用点。因为验证失败给了可追踪的线索。因为权限拒绝后需要换成只读观察。因为目标已经满足可以停止。因为缺少业务判断需要问用户。缺少这个理由时主循环就容易变成“多试几次”。多试几次有时能碰巧成功稳定性很弱。Claude Code 这类工具最值得学的地方也在这里它把模型的临场判断放进一个受控的任务状态里让长任务沿着状态推进。失败反馈下一轮判断的重要输入很多系统把失败当成终点命令报错任务失败测试报错任务失败权限被拒绝任务失败。对 coding agent 来说失败经常是最有价值的观察结果。测试失败告诉它哪里没满足预期。构建报错告诉它语法、依赖或路径哪里有问题。搜索无结果告诉它当前关键词可能错了。权限拒绝告诉它当前动作风险太高或者用户更希望换一种路径。命令缺失告诉它项目的验证方式需要重新判断。资料里也反复提到Claude Code 的主循环周围有很多工程守卫权限拒绝要进入后续判断失败和压缩问题要有降级路径工具输出过大还要进入上下文处理链路[2][3]。这一篇先看这些守卫对主循环的意义失败是下一轮状态的一部分。这句话非常重要。如果构建失败agent 先提取失败里的有效信号哪个文件、哪一行、哪个模块、哪个命令、哪个依赖。然后决定下一轮是读文件、搜索调用方、修改代码还是说明当前环境缺失。当然失败也需要预算。连续几轮都缺少新信息时主循环要停下来。好的恢复会判断“继续这样试的收益已经很低”。这部分会在第 09 篇展开。循环控制器什么时候继续、停止或询问用户Agent Loop 最容易被忽略的能力是停止。很多人谈 agent 时会强调“它能自动执行多少步”。对真实工程任务来说一个可靠的 agent 还必须知道什么时候停、什么时候问、什么时候说明当前卡点。主循环每一轮结束时至少有三类出口。继续。还有明确的新线索继续执行有收益。比如测试失败给出了新的文件路径或者搜索结果指向了关键模块。停止。目标已经满足验证证据足够或者继续执行收益很低。停止时要总结做了什么、改了什么、验证了什么。询问用户。当前问题需要用户做业务判断。比如有两个业务方案或者下一步动作风险较高或者权限不足。这三个出口可以整理成一张表控制选择触发条件输出继续有新证据下一步清楚风险可控进入下一轮观察或行动停止完成条件满足验证足够总结结果和验证情况询问用户需要业务判断、权限确认或风险确认给出清楚的问题和选项阻塞停止多轮缺少新进展或环境缺失说明卡点和已尝试路径这里的关键是“控制选择要有理由”。一个成熟的 agent 最终给用户的应该是一份当前状态改了什么。为什么这么改。用什么验证过。哪些验证还缺失。还剩什么风险。这让用户能接管也让后续恢复有依据。案例解析博客构建失败如何被逐步收敛用一个常见任务看得更清楚用户说“博客页面构建失败了帮我修一下”。普通问答可能会回答请检查依赖是否安装、语法是否正确、路径是否存在。这个回答方向合理但任务还停在建议层。coding agent 的主循环更像一串事件。事件 1接收目标 用户目标被识别为修复博客页面构建失败。 当前完成条件暂定为构建命令通过且改动范围集中。 事件 2观察项目 读取 package.json确认构建命令。 运行构建命令拿到具体错误输出。 事件 3更新状态 错误指向某个 Markdown 文件的 frontmatter。 任务状态里新增相关文件、错误信息和可能修改点。 事件 4行动前判断 修改 Markdown 属于低到中风险写入。 如果文件已经有用户改动需要先确认如果当前没有冲突可以继续最小修改。 事件 5执行修改 只修改出错字段改动范围保持集中。 事件 6验证 重新运行构建。 如果仍然失败把新的错误输出放回状态进入下一轮。 如果构建通过检查本轮改动范围。 事件 7停止 总结错误原因、修改内容、验证命令和结果。这条轨迹里最重要的是状态如何变化。第一次构建失败把模糊目标变成了具体线索。第二次构建通过是停止条件的一部分。中间每一步都在回答同一个问题当前状态是否足够支持下一步对我写 Agent 的启发先设计运行时契约如果要自己写一个 coding agent第一版可以先放慢工具少一点提示词短一点主循环清楚一点。更应该先设计运行时契约。所谓运行时契约就是主循环里哪些东西必须被结构化保存哪些动作必须有记录什么时候可以继续什么时候必须停。我会先设计五个对象。对象作用任务状态保存目标、上下文、计划、改动、证据和阻塞点工具结果统一描述工具是否成功、返回了什么、是否改变环境下一轮理由记录为什么继续、停止或询问用户停止条件定义什么叫完成、阻塞、越界或预算耗尽失败预算限制同类失败重复出现的次数这个版本很朴素但它已经比“用户目标进来模型直接回答”稳定很多。它至少能保证四件事任务有状态减少模型在长上下文里硬记。工具有反馈模型能基于真实环境继续判断。失败有去处报错以后还能转成下一轮输入。循环有出口执行过程能自然收束。如果继续往后做再逐步接上工具系统、上下文压缩、权限裁决、任务计划和可观测日志。这些模块都是主循环变长以后需要的支撑结构。下一篇工具系统如何让主循环真正行动这一篇先把 Agent Loop 当作 Claude Code 的运行时主线来理解。这条主线的结论是Claude Code 会把用户目标、项目环境、工具结果、权限判断和验证反馈组织进一个持续循环让任务逐渐收敛。主循环本身负责组织过程。真正让 agent 能读仓库、改代码、跑测试、拿到反馈的是工具系统。所以下一篇继续追的问题是一个 coding agent 的最小工具集是什么工具结果又是怎么回到下一轮判断里的参考资料Claude Code 源码分析[1] 《驾驭工程从 Claude Code 源码到 AI 编码最佳实践》本文主要参考它关于主循环、状态重建、错误恢复和工程化拆解方式的分析。[2] What Claude Code’s Leaked Source Actually Teaches Us About Building AI Agents - Kubesimplify本文主要参考它关于主循环是状态机、工具结果回流、权限降级和成本工程的分析。[3] What the Claude Code Source Leak Reveals - Blake Crosley本文主要参考它关于权限守卫、失败检测、缓存风险和工程边界的分析。[4] Diving into Claude Code’s Source Code Leak - Engineer’s Codex本文主要参考它关于主循环与工具、上下文、hook、subagent 等模块挂接关系的分析。