扩展-AI Loop:在Calude code中的实现

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 在每轮结束后可以用命令直接验证,知道自己是否做完。

好目标的三个标准

  1. 可执行验证:有命令可以跑,跑出来有明确的 pass/fail
  2. 有边界:明确哪些文件、哪些范围,不是整个项目
  3. 原子化:一个目标只描述一件事,别把"修 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:需要人来判断质量的设计类任务、涉及外部系统权限的操作、会影响生产环境的变更。