01 Claude Code的Agent Loop核心循环
这么理解,你每次打开终端,都是一个QueryEngine实例,每次对话都会调用query方法,而在query方法中会while true循环调用工具来解决你的问题,即queryLoop方法,这个方法是一个生成器,从而在对话过程中实现那种问你 “是否继续/在本次会话内允许/...”queryLoop用于每次对话后多次循环调用工具,实际的agent loop是在queryLoop中的。由于我的目的更多
参考文献:
第 4 章:查询引擎 - 深入理解 Claude Code 源码
Agentic Loop:AI 自主循环的核心机制 - Claude Code Architecture
由于我的目的更多是了解agent的实现思路,所以文章中会具体描述做了哪些事,为什么要这样做。同时辅以少量源码。
什么是Agent Loop(代理循环)?
首先说一下,什么是Agent Loop(代理循环)?
当用户输入一条消息时,Claude Code 执行以下流程:
用户输入 → 上下文组装 → 模型决策 → 工具执行 → 结果注入 → 继续/停止
这个循环不断重复,直到模型决定不再调用工具——返回纯文本响应为止。这就是 Agent Loop(代理循环)的本质。

Agent Loop核心循环实现的双层架构
为什么要分两层?因为会话管理和查询执行的关注点完全不同。
系统分为两层QueryEngine与query():
QueryEngine 关心的是"用户说了什么、花了多少钱、这轮结果是否成功";
query() 关心的是"消息是否需要压缩、API 返回了什么、工具执行是否成功、是否需要恢复"。双层分离使得每层的代码都更聚焦、更容易测试。
在query方法中再调用queryLoop方法,在queryLoop方法中通过while ture 循环调用工具,实现react范式
这块QueryEngine是用于管理一整个会话,从你开始对话到关闭命令行窗口。queryLoop用于每次对话后多次循环调用工具,实际的agent loop是在queryLoop中的。

| 维度 | QueryEngine | query() |
|---|---|---|
| 作用域 | 对话全生命周期 | 单次查询循环 |
| 状态 | 持久化(mutableMessages, usage) | 循环内(State 对象每次迭代重新赋值) |
| 预算追踪 | USD/轮次检查,结构化输出重试 | Task Budget 跨压缩结转,Token 预算续写 |
| 恢复策略 | 权限拒绝、孤儿权限 | PTL 排水/压缩、max_output_tokens 升级/重试 |
再说其中的预算追踪与恢复策略:
来源:https://ccb.agent-aura.top/docs/context/token-budget
|
概念 |
核心问题 |
类比 |
|---|---|---|
|
预算追踪 |
“还能不能继续跑?” |
钱包还剩多少钱 |
|
恢复策略 |
“跑炸了怎么办?” |
车坏了怎么修 |
具体含义拆解
-
USD / 轮次检查
每一轮调用模型前,预估这次会花多少钱,超了就直接拒绝或降级。
-
Token 预算
限制输入 + 输出的总 token 数,避免无限生成。
-
跨压缩结转
对话太长 → 压缩历史 → 将压缩前消耗的 token 数量结转并传递给 API → 确保服务器能正确计算剩余预算的机制

-
结构化输出重试
JSON / 函数调用格式错了 → 在预算内允许重试几次。
👉 本质:这是“财务 + 资源控制器”。
-
权限拒绝 / 孤儿权限
-
用户没权限 → 返回“无权访问”
-
权限中途失效 → 用安全兜底,不泄露数据
-
-
PTL 排水 / 压缩
-
PTL(Prompt Token Length)太长
-
把旧对话总结、裁剪、丢弃不重要部分
-
-
max_output_tokens 升级 / 重试
-
输出被截断(没说完)
-
自动提高输出上限,再试一次
-
👉 本质:这是“容错 + 自愈机制”。
再具体说一下queryLoop的实现:
queryLoop 签名是 async function*——异步生成器。选这个而不是回调/事件的原因:
- 背压控制:消费端不处理完,生产端不继续,天然防止事件堆积
- 线性控制流:所有循环分支用普通
continue/break表达,不需要状态机
这块其实就是yield这种,通过把一个函数变成「生成器(generator)」,多次产出值,每次 yield 都“暂停”,从而在控制台输出内容。
这么理解,你每次打开终端,都是一个QueryEngine实例,每次对话都会调用query方法,而在query方法中会while true循环调用工具来解决你的问题,即queryLoop方法,这个方法是一个生成器,从而在对话过程中实现那种问你 “是否继续/在本次会话内允许/...”
再深入说一下queryLoop方法中的循环:
有两种结束方式,一是超过循环次数,另一种是大模型说做完了。
此外,每次循环只调用一次大模型,然后每次循环都会根据上次的问题再进行解决,类似于如下这种:
既然是while,存在continue也是很正常的情况,有如下几种情况:
当然,在流式调用和上下文预处理上也有很多工作与细节,具体可以看
更多推荐



所有评论(0)