Claude Code 中大多数操作都是"一问一答"的模式。但面对多步骤的复杂任务时——比如"把所有测试跑通"或"调查这个 bug 的根因"——Claude Code 会进入 Agentic Loop 模式。/loop 就是手动触发这个模式的入口。
单次对话 vs Agentic Loop
单次对话模式是标准的 Request-Response 模式。每次用户输入触发一次 API 请求,模型生成响应后控制权交回用户:
用户输入 → API 请求 → 模型响应 → 等待用户下一次输入Agentic Loop 模式则是模型自主驱动的连续执行模式。模型在完成一个工具调用后,分析工具的执行结果,决定下一步动作,持续循环直到任务完成或触发终止条件:
用户输入
│
▼
API 请求 → 模型响应(tool_use)
│
▼
本地执行工具 → tool_result
│
▼
API 请求 → 模型响应(tool_use 或 end_turn)
│ │
└──────────────┘
(持续循环直到 end_turn)Tool Use 的多轮调用
/loop 的底层实现建立在 Anthropic 的 Tool Use API 之上。每一轮循环都是一次独立的 HTTP 请求,携带截至当前的完整对话历史(包含所有前序工具调用和结果)。
以"帮我跑测试并修复失败的用例"为例:
第一轮:决定运行测试
{
"stop_reason": "tool_use",
"content": [
{
"type": "text",
"text": "我先运行测试套件,看看哪些用例失败了。"
},
{
"type": "tool_use",
"id": "toolu_01",
"name": "run_in_terminal",
"input": { "command": "pnpm test" }
}
]
}第二轮:携带测试结果,决定读取文件
Claude Code 客户端在本地执行 pnpm test,将输出封装为 tool_result,追加到 messages 数组,发起第二次请求:
[
{ "role": "user", "content": "帮我跑测试并修复失败的用例" },
{
"role": "assistant",
"content": [
{ "type": "text", "text": "我先运行测试套件..." },
{ "type": "tool_use", "id": "toolu_01", "name": "run_in_terminal",
"input": { "command": "pnpm test" } }
]
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": "FAIL src/utils/math.test.ts\n ✕ add() should handle negative numbers\n ✕ divide() should throw on zero\n\nTests: 2 failed, 18 passed"
}
]
}
]模型收到结果后决定读取失败的测试文件:
{
"stop_reason": "tool_use",
"content": [
{
"type": "text",
"text": "有两个用例失败,我来查看测试文件和对应的实现。"
},
{
"type": "tool_use",
"id": "toolu_02",
"name": "read_file",
"input": { "filePath": "src/utils/math.test.ts", "startLine": 1, "endLine": 60 }
}
]
}这个过程会持续——读取源文件、修改代码、再次运行测试——直到所有测试通过,模型返回 stop_reason: "end_turn",循环终止。
messages 数组的增长
Agentic Loop 过程中,messages 数组随每轮循环线性增长。每完成一个工具调用,就追加两条消息:
assistant消息:包含模型的思考文本 +tool_use对象user消息:包含tool_result对象
初始: [user_input] ~50 tokens
第1轮后: [..., assistant(tool_use), user(tool_result)] ~300 tokens
第2轮后: [..., assistant(tool_use), user(tool_result)] ~800 tokens
第3轮后: [..., assistant(tool_use), user(tool_result)] ~1500 tokens
...对于一个涉及大量文件读取和命令执行的复杂任务,经过十几轮循环后,context window 的消耗可能相当可观。这也是为什么 loop 模式下更需要 /compact 命令——参见深入理解 Claude Code /compact 命令的底层实现。
循环终止条件
Loop 不会无限运行,有以下几种终止条件:
模型主动结束(end_turn)
模型判断任务完成时,将 stop_reason 设为 end_turn,不再生成新的 tool_use:
while (true) {
const response = await anthropic.messages.create({ messages })
messages.push({ role: 'assistant', content: response.content })
if (response.stop_reason === 'end_turn') {
break
}
const toolResults = await executeTools(response.content)
messages.push({ role: 'user', content: toolResults })
}最大轮次限制
为防止失控循环,Claude Code 设有最大轮次上限(默认约 10 轮,可通过配置调整)。超过上限后强制终止并提示用户:
const MAX_ITERATIONS = 10
let iteration = 0
while (iteration < MAX_ITERATIONS) {
// ...
iteration++
}
if (iteration >= MAX_ITERATIONS) {
console.warn('Loop reached maximum iterations. Stopping.')
}Context Window 逼近上限
当 usage.input_tokens 超过模型 context window 的 95% 时,Claude Code 会提前终止 loop:
const CONTEXT_LIMIT_RATIO = 0.95
if (response.usage.input_tokens / MODEL_CONTEXT_WINDOW > CONTEXT_LIMIT_RATIO) {
console.warn('Context window nearly full. Loop terminated early.')
break
}工具执行失败
若某个工具调用返回了错误(如命令执行超时、文件不存在),Claude Code 默认将错误信息作为 tool_result 传回模型,由模型决定是重试、绕过还是放弃。但对于不可恢复的错误(如权限拒绝),会直接终止 loop。
并行工具调用
Anthropic API 支持在单次响应中返回多个 tool_use 对象,Claude Code 会并行执行它们,然后将所有结果一起打包为 tool_result 列表返回:
// 模型一次性请求读取两个文件
{
"stop_reason": "tool_use",
"content": [
{
"type": "tool_use",
"id": "toolu_03",
"name": "read_file",
"input": { "filePath": "src/utils/math.ts" }
},
{
"type": "tool_use",
"id": "toolu_04",
"name": "read_file",
"input": { "filePath": "src/utils/math.test.ts" }
}
]
}客户端并行执行两次文件读取,将两个结果一起返回:
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_03", "content": "..." },
{ "type": "tool_result", "tool_use_id": "toolu_04", "content": "..." }
]
}并行工具调用可以显著减少总轮次。
/loop 与自动模式的区别
Claude Code 中有两种方式进入 Agentic Loop:
手动 /loop:用户明确触发,Claude Code 在每次需要执行写操作(修改文件、执行命令)前会暂停并请求用户确认。适合需要审查每一步操作的场景。
自动模式(-p / --print):通过命令行标志直接进入完全自动的 loop,不在中途请求确认,直到任务完成或触发终止条件:
claude -p "修复所有 ESLint 错误,不要改动任何业务逻辑"两者的底层 API 调用逻辑完全相同,区别仅在于客户端是否在写操作前插入人工确认步骤。
Loop Engineering
Agentic Loop 能否稳定完成任务,很大程度上取决于如何设计这个 loop——这就是 Loop Engineering 关注的问题。它本质上是 Prompt Engineering 在 Agentic 场景下的延伸。
任务指令的颗粒度
Loop 的第一个输入是任务描述。指令太宽泛,模型会在 loop 过程中不断"发散",消耗大量 context;指令太细,又失去了 loop 的意义。
一个好的 loop 任务指令应该满足:目标明确(有可判断的完成条件)、范围受限(明确哪些文件或模块在范围内)、失败可接受(当工具调用失败时模型能决定继续还是放弃)。
# 差:目标模糊,loop 可能永远不知道什么时候算"完成"
claude -p "优化这个项目的代码质量"
# 好:目标明确,有可验证的完成条件
claude -p "运行 pnpm test,修复所有失败的测试用例,直到全部通过。
只修改 src/utils/ 目录下的文件,不要修改测试文件本身。"工具定义的边界
Loop Engineering 的另一个核心是工具的设计。工具太多,模型可能在不必要的工具调用间"漂移";工具太少,模型可能因缺少必要能力而陷入死循环。
一个常见技巧是为特定任务提供专用工具而不是通用工具:
// 通用工具:模型需要自己构造正确的命令
{ name: "run_in_terminal", input: { command: "pnpm test --reporter=verbose" } }
// 专用工具:工具内部封装了正确的调用方式,模型只需声明意图
{ name: "run_tests", input: { filter: "src/utils/math.test.ts" } }专用工具减少了模型在工具调用参数上犯错的概率,使 loop 更稳定。
显式的终止信号
依赖模型自己判断"任务完成"有时不够可靠。一个实践是在任务描述中嵌入显式的终止信号——一个可被客户端检测的输出模式:
claude -p "运行测试,修复所有失败项。完成后,在最后一行输出 DONE: <通过数>/<总数>"客户端检测到 DONE: 前缀后立即终止 loop,而不依赖 stop_reason: end_turn。这在自动化流水线中尤其有用。
的共同点是:不把模糊性留给 AI,在给 AI 任务之前先把结构想清楚。
总结
/loop 的本质是将标准的 Request-Response 对话改造成由模型自主驱动的工具调用循环。每一轮循环都是一次独立的 HTTP 请求,messages 数组是贯穿整个 loop 的状态容器。模型通过分析历史工具结果来决定下一步,所有上下文都在客户端维护,以 messages 数组的形式随每次请求携带。