AI Loop:在Calude code中的实现
本文可作为第十四章 14.15 节的扩展内容
为什么 Agent 总在关键时刻停下来等你
你让 Claude Code 修一批测试,它把第一个测试文件改好了,然后停下来问:"要继续修下一个吗?"
你说"继续",它改了第二个,又停下来。
这不是 Bug,是设计------传统的 AI 编码助手默认每完成一步就等待确认。这个设计很安全,但把"自主 Agent"的承诺砍掉了一大半。你变成了一个人肉进度条,每隔几分钟点一次"继续"。
更麻烦的是,每次重启对话,Agent 都忘了上一轮做了什么,又得从零开始解释现状。一个本来应该自动完成的 20 个文件的迁移任务,你可能花了两小时在键盘前守着。
这是 2024 年前大多数 AI Agent 工具的通病:任务粒度和人工干预频率不匹配。
Claude Code 在 2025 年推出的 /loop 和 /goal 命令,直接在工具层面解决了这个问题。
Agent Loop:六步闭环模型
在介绍具体命令之前,先理解 Agent Loop 的理论模型。它是所有自主 Agent 的执行骨架:
┌─────────────────────────────────────────────────────────┐
│ Agent Loop │
│ │
│ ┌────────┐ ┌─────────┐ ┌────────┐ │
│ │ Goal │───▶│ Context │───▶│ Plan │ │
│ └────────┘ └─────────┘ └────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌────────┐ ┌─────────┐ ┌────────┐ │
│ │ Loop? │◀───│Evaluate │◀───│ Action │ │
│ └────────┘ └─────────┘ └────────┘ │
│ │ │ │
│ │ └─── 目标已达成 → 退出 │
│ └──────── 未达成 → 下一轮 │
└─────────────────────────────────────────────────────────┘
六个步骤的含义:
| 步骤 | 内容 | 关键问题 |
|---|---|---|
| Goal | 定义终态,不是步骤 | "完成"长什么样? |
| Context | 收集当前状态 | 现在离目标有多远? |
| Plan | 决定下一步操作 | 这一轮做什么? |
| Action | 执行操作 | 写文件、运行命令、调 API |
| Evaluate | 检查是否达成目标 | Goal 满足了吗? |
| Loop | 决定继续还是退出 | 未达成则回到 Context |
这个模型的关键在于 Goal 是整个闭环的锚点。传统 AI 助手没有持久的 Goal,每一步都是独立的,所以需要人来充当"记忆"和"导航"。Loop 模式把 Goal 保留在 Agent 的运行上下文中,让它自己知道什么时候该停。
/goal:定义可验证的终态
/goal 命令告诉 Claude Code 你最终要达到的状态,不是要做的事情。
错误写法(描述过程):
/goal 重构用户服务模块
这个"目标"Claude 无法验证------重构到什么程度算完成?什么叫做好的重构?Agent 无从判断,要么提前宣告完成,要么永远跑下去。
正确写法(描述可检验的终态):
/goal src/services/user/ 目录下所有 TypeScript 文件通过 ESLint 检查,
且单元测试覆盖率不低于 80%,所有测试绿灯
这个目标有三个清晰的检验点:ESLint 通过、覆盖率 ≥ 80%、测试全绿。Claude Code 在每轮结束后可以用命令直接验证,知道自己是否做完。
好目标的三个标准
- 可执行验证:有命令可以跑,跑出来有明确的 pass/fail
- 有边界:明确哪些文件、哪些范围,不是整个项目
- 原子化:一个目标只描述一件事,别把"修 bug + 写文档 + 更新测试"塞进一个 goal
bash
# 好的 goal:具体、可验证
/goal /src/api/ 下所有端点的响应结构与 openapi.yaml 中的定义完全一致,
使用 openapi-validator --strict 验证零错误
# 不好的 goal:抽象、模糊
/goal 代码质量提升,做好文档
/loop:让 Agent 持续迭代
/loop 命令改变 Claude Code 的默认行为:完成一轮后自动开始下一轮,而不是停下来等待。
基本语法
bash
# 按时间间隔循环
/loop every 5m
# 按条件退出
/loop until: all tests pass
# 两者结合(推荐)
/loop every 5m until: all tests pass
# 限制最大轮次(防止失控消耗)
/loop max: 10 until: migration complete
Loop 和反复手动运行的区别
这不只是"省了几次敲回车"。
手动重启 Claude Code 时,上下文断裂了。新对话里 Agent 不知道上一轮尝试了什么、为什么失败、哪些方向已经走不通。它会重新推理,很可能踩同一个坑。
Loop 模式下,整个执行历史保留在对话上下文中。如果上一轮某个测试因为缺少 mock 数据而失败,这一轮 Agent 知道要先补 mock,不会重复尝试同一个没用的修法。
这个区别在长任务上体现得非常明显。一个有 50 个测试要修的任务,手动重启方式可能每次修2-3个就忘了前面发生了什么,而 Loop 方式通常能连续推进直到碰到真正需要人介入的问题。
完整案例:自动修复 CI 失败
这是一个在实际工程中高频出现的场景:你推了一批代码,CI 跑红了,但你有其他事情要处理,想让 Agent 后台帮你修。
场景设定
项目有一个 GitHub Actions 流水线,包含三个 job:
lint:ESLint 检查test:Jest 单元测试(43 个用例)type-check:TypeScript 类型检查
当前状态:lint 过了,test 有 7 个失败,type-check 有 3 个错误。
第一步:设置 Goal
bash
/goal GitHub Actions 上 main 分支最新 commit 的三个 job(lint、test、type-check)
全部通过,本地运行 npm run ci 也全绿
注意这个 goal 同时包含 远端 CI 和 本地命令的验证,避免 Agent 修了本地但忘了推送或推送后又引入新问题。
第二步:给 Agent 必要的上下文
在启动 loop 前,先把关键信息告诉 Agent,省得它第一轮浪费时间探索:
目前 CI 状态:
- lint: pass
- test: 7 failures(失败详情在 CI log 里,链接:[你的 CI URL])
- type-check: 3 errors
本地运行命令:
- npm run test → 跑测试
- npm run type-check → 跑类型检查
- npm run ci → 跑全套
git push 到 main 会触发 CI。
第三步:启动 Loop
bash
/loop every 3m until: npm run ci exits with code 0
3 分钟间隔是这样算的:一轮 Agent 操作(读 log → 修代码 → 跑本地测试)大约需要 1-2 分钟,加上 CI 触发到出结果的时间约 2 分钟,间隔定 3 分钟刚好留一点余量,不会让两轮重叠。
Loop 执行过程(典型流程)
第 1 轮(第 0-3 分钟):
Agent 读取失败的测试 log →
发现 7 个测试失败分为两类:
- 3 个:mock 数据格式与新接口不匹配
- 4 个:异步函数未正确 await →
修复 mock 数据格式 →
修复 4 个 await 问题 →
本地跑 npm run test:全绿 →
本地跑 npm run ci:全绿 →
git push →
等待 CI
第 2 轮(第 3-6 分钟):
读取 CI 结果:test pass,type-check 仍有 2 个 error →
发现 type-check 的错误是第一轮改动引入的新类型问题 →
修复类型定义 →
本地 npm run ci:全绿 →
git push
第 3 轮(第 6-9 分钟):
读取 CI 结果:三个 job 全绿 →
验证本地 npm run ci 退出码为 0 →
Goal 满足,Loop 自动退出 →
输出摘要:修复了 7 个测试失败 + 2 个类型错误,共 3 轮迭代
整个过程你不需要守在键盘旁,9 分钟后回来看结果就好。
关键:Goal 的保护机制
注意 goal 里写的是"三个 job 全部通过"。如果只写"测试通过",Agent 可能修了测试但忽略了 type-check 的新错误,错误地认为 goal 已达成然后退出。
Goal 越精确,Loop 越可靠。
三个高频工程场景
场景一:文档自动补全
bash
/goal src/ 目录下所有导出函数和类都有 JSDoc 注释,
注释中的参数类型与实际函数签名一致,
使用 typedoc --strict 编译零错误
/loop until: typedoc --strict exits 0
Agent 会逐文件扫描,补缺失的注释,修错误的类型描述,直到 typedoc 不报错为止。
场景二:依赖安全审计
bash
/goal package.json 中没有 npm audit 报告的 high 或 critical 级别漏洞
/loop every 30m
这里没有 until 条件,意味着循环不会自动退出------每 30 分钟检查一次,发现新漏洞就修,作为开发阶段的持续监控 Agent 使用。记得离开前手动停止。
场景三:大规模代码迁移
从旧的设计系统迁移到新的 token:
bash
/goal src/components/ 下所有组件不包含任何 import from '../design-system/legacy',
改用 import from '../design-system/v2',
且 npm run build 编译零错误
/loop max: 20 until: migration complete
max: 20 加了一个安全阀:最多跑 20 轮,防止 Agent 陷入死循环消耗大量 token。如果 20 轮内没完成,会停下来报告当前进度,让你判断是继续还是需要人工介入。
工程陷阱:三种最常见的失控情况
陷阱一:目标描述模糊导致提前退出
症状:Agent 声称完成了,但你一看代码只改了一小部分。
根因:目标里有主观词,Agent 的判断标准和你不一样。
bash
# 有问题:Agent 可能认为"基本完成"就算满足
/goal 代码看起来比较规范,没有明显的 code smell
# 正确:所有检查点都是命令可以验证的
/goal eslint src/ --max-warnings 0 命令零输出,
jest --coverage 报告 branches ≥ 85%
陷阱二:循环间隔太短耗尽 Rate Limit
症状:运行十几分钟后 API 开始返回 429 错误,Loop 中断。
根因:每轮 Agent 消耗大量 token,加上循环频率太高,超出 API 速率限制。
规避方法:
- 间隔设置为单轮实际耗时的 1.5 倍以上
- 启动 loop 前用
/compact压缩对话历史,减少每轮的 context token 消耗 - 用
/cost命令监控实时消耗,发现异常立即暂停
bash
# 先压缩历史,再启动长时间 loop
/compact
/loop every 10m until: all migrations done
陷阱三:目标范围太宽让 Agent 越界
症状:Agent 在修 A 的时候顺手改了 B,结果 B 原来能过的测试挂了。
根因:Goal 没有明确边界,Agent 在推进过程中做了"善意的额外工作"。
bash
# 有问题:没有限定范围
/goal 所有测试通过,代码质量好
# 正确:明确文件范围和禁止区域
/goal src/services/payment/ 目录下的 7 个失败测试全部通过,
且不修改 src/services/payment/ 以外的任何文件,
其他测试的通过率不能下降
在 Goal 里加上"不修改 X 之外的文件"是一个非常有效的约束,可以把 Agent 的行动范围锁定在安全区域内。
与 AgentLoop 内核的关系
你可能记得第 14.3 节讲过 Claude Code 内部有一个 AgentLoop------那是引擎层的单轮执行机制(处理工具调用、流式输出、轮次限制)。
/loop 命令是在这个引擎之上工作的调度层 :它以固定间隔或条件触发新一轮的 AgentLoop 执行,在轮次之间维护 Goal 状态和历史上下文。
┌─────────────────────────────────────────┐
│ /loop 调度层(你配置的 Goal + 间隔) │
│ │
│ ┌─────────────────────────────────┐ │
│ │ AgentLoop 内核(单轮执行) │ │
│ │ 工具调用 → 流式输出 → 轮次控制 │ │
│ └─────────────────────────────────┘ │
│ ↕ 轮次间传递上下文 │
│ ┌─────────────────────────────────┐ │
│ │ AgentLoop 内核(下一轮执行) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
所以 /loop 并不改变 AgentLoop 的内部逻辑,而是给它套了一个自动重启 + 目标检验的外壳。
工程小结
/goal 的核心价值:把"完成的定义"从你的脑子里搬到 Agent 的运行上下文里,让 Agent 自己知道什么时候该停。目标必须可以被命令验证,不能有主观词。
/loop 的核心价值:保留跨轮上下文,避免手动重启导致的信息断裂。Agent 记得上轮失败的原因,不会重复踩坑。
两者结合的最佳实践:
bash
# 标准姿势:压缩历史 → 提供上下文 → 设定目标 → 启动循环
/compact
# [粘贴关键上下文:文件结构、CI 日志、已知约束]
/goal [可验证的终态描述,包含检验命令]
/loop every [单轮耗时的1.5倍] max: 20 until: [验证命令] exits 0
什么任务适合 Loop:迭代型(需要多次尝试)、可验证型(有命令可检查)、有明确边界型(影响范围可控)。
什么任务不适合 Loop:需要人来判断质量的设计类任务、涉及外部系统权限的操作、会影响生产环境的变更。