前言

最近在 X 和部落格上,常常看到 「Loop Engineering(迴圈工程)」 這個詞。
像是 「我已經不再對 Claude 下指令了,我的工作是寫迴圈」 之類,帶點幽默感的說法正在流傳:point_up_tone1:

一開始我還想著:「又來一個新的『XX 工程』嗎……」
上下文工程 的書還在賣,harness 工程 也才剛看到不久:sweat_smile:

不過,這次有點不一樣。以往那些是在教你 「怎麼做好」,而迴圈工程說的是 「從你親自動手的位置上,乾脆退開」

233516EA-C742-4D48-B626-43CCB459D142_4_5005_c.jpeg

本文將依序介紹:

  • 迴圈工程到底是什麼
  • 迴圈是由什麼構成的
  • 以門檻最低的 Claude Code 動手組出第一個迴圈(入門實作)
  • 如果要自己開發:用 Mastra 跑迴圈
  • 持續運轉的 代價

先快速掌握整體輪廓,深入的實作會放到後篇:relaxed:

內容以 2026/06 當下資訊為準。工具名稱、指令與支援版本很容易變動,最新資訊請以各官方文件為準:point_up_tone1:

迴圈工程是什麼

一句話說,就是把「發號施令的人」換成一套機制

最常被引用的定義來自 Google Chrome 團隊的 Addy Osmani:

Loop engineering is replacing yourself as the person who prompts the agent. You design the system that does it instead.

大致翻成:「把你自己從『對代理下提示詞的人』的位置上移開,改為設計一套替你做這件事的系統。」

重點不是「怎麼把 prompt 寫得更好」,也不是「怎麼整理 context」,而是 把你這個人從那個位置上移開

以前是工程師也要親自下場做事;接下來則是成為 設計工作流程的人。這就是角色的轉移。

如果把自己想成 團隊主管,就很容易理解。對成員事事微管理,團隊跑不起來;但如果 全丟出去不管,也跑不起來:frowning2: 好的主管要做的是,把目標、審查機制、交接流程設計好,讓自己不用逐一插手也能運作

2389B0BC-8B8F-4F92-879C-AE4AD545328E.png

使用 AI 代理也是同樣道理,這就是迴圈工程:point_up_tone1:

這個詞是在 2026 年 6 月幾乎同時出現並定型的:

  • Peter Steinberger(OpenClaw 作者)發文說:不要直接對 coding agent 下指令,而是要設計「讓 agent 接收指令的迴圈」
  • Boris Cherny(Anthropic、Claude Code 負責人)也表示:「我已經不再對 Claude 下指令了;我的工作是寫迴圈」
  • Addy Osmani 把這些內容整理成文章,正式命名為 Loop Engineering

這三個人講的其實是同一件事:
你所設計的對象,已經從「代理的一次行為」,升級成「讓代理持續運轉的整個系統」

逐層堆疊的 4 層:Prompt → Context → Harness → Loop

迴圈工程和這兩年常聽到的各種「XX 工程」之間,其實不是互相取代,而是一層層堆上去

每往上一層,負責的範圍就更大。

層級 管理重點 核心問題
Prompt engineering 單次指令 要對模型說什麼
Context engineering 這一刻視窗裡放什麼 要搜尋什麼、摘要什麼、丟掉什麼
Harness engineering 單次執行的「裝備」 允許哪些工具、以什麼算完成
Loop engineering 在 harness 之上自動循環 怎麼讓它自己反覆跑

我會覺得,迴圈就是比 harness 再高一層
下層的 harness 是負責裝備 AI 代理的「一次執行」,上層的 loop 則是負責「讓它自動反覆執行」:point_up_tone1:

迴圈是由什麼構成的

迴圈的 5 個動作

所謂迴圈,不是「同一段程式一直空轉」的那種繞圈圈。
它每一輪都確實在做具體工作,拆開來就是 5 個動作

動作 要做的事
發現(discovery) 自己找出這一輪該做什麼
交接(handoff) 將任務隔離後交給負責工作的代理
驗證(verification) 由另一個代理檢查「這樣可以嗎」
持久化(persistence) 把狀態寫到對話外部(例如檔案)
排程(scheduling) 透過 timer 等方式,讓它即使放著也能持續運作

我個人覺得,沒有驗證就不算迴圈
如果這一塊太鬆,那就只是個不停生成內容的裝置而已:point_up_tone1:

組迴圈的 6 個零件

接著,若要把這 5 個動作真的做起來,就需要對應的工具。
落到開發層面,Addy 把迴圈需要的東西整理成 6 個零件

零件 是什麼 對應動作
Automations 用時間表/觸發器自動啟動 排程
Worktrees 讓並行代理的工作目錄彼此隔離 交接
Skills 把知識固定在 SKILL.md 以便重用 發現
Connectors(MCP) 連接 issue tracker、DB、Slack 等外部系統 記憶 / 發現
Sub-agents 將生成角色與評估角色分開 驗證
Memory 留存在檔案中的狀態(例如 MEMORY.md 記憶

「只有檔案可見的迴圈」只能做很小的事;要能真正替你工作,得能碰到 任務票、資料庫、瀏覽器 才行。

MCP / Skills 想成迴圈用的 harness,會比較好理解:relaxed:

迴圈中最重要的,是能說「不行」的評估角色

因為寫程式的人,最容易對自己的作品心軟。

就像自己寫的文章常常看不出錯字一樣,若讓作者自己打分數,很容易把自己說服成「看起來不錯」:sweat_smile: 所以要把 寫的人(生成角色)檢查的人(評估角色) 分開,而且評估角色最好是另一套指令、甚至是另一個模型。

Claude Code 有一個 /goal,會持續跑到條件成立為止,完成判定是交給不是本人在做事的另一個模型

其實 /goal 的內部實作,就是 基於 prompt 的 Stop hook。每一輪最後由判定角色檢查條件,沒過就不結束,再跑一輪——下一章我們就會手動做出這個東西:point_up_tone1:

E60DECC7-46DD-4812-99AE-E2CD7F33D681.png

入門:用 Claude Code 組出第一個迴圈

到這裡,相信大家對迴圈的概念都已經完全理解了。接下來就實際組一個能拿來做 coding 任務的迴圈吧。
第一個迴圈,只要把「完成的定義」和「無路可逃的檢查」交給 Claude Code 就夠了

這裡我們會用 3 個檔案,做出一個把 coding 任務從「直線流程」變成「迴圈」的最小架構。

接下來會以你自己的專案來試作為前提。
預設目標是使用 React 或 Next.js、TypeScript 寫成的專案。:point_up_tone1:

Gemini_Generated_Image_ee5a2cee5a2cee5a.png

① 在 CLAUDE.md 寫入「迴圈協議」(=重新定義完成)

在專案根目錄的 CLAUDE.md 中,寫下任務應該怎麼跑。
重點是 不要讓它自己宣稱完成:point_up_tone1:

CLAUDE.md

## 迴圈協議

每個任務都要以「迴圈」而不是「直線流程」來執行:

1. 寫出修改
2. 跑檢查:測試 + linter + 型別檢查
3. 失敗了?讀取錯誤、找出原因、修正,然後回到第 2 步
4. 迴圈最多 5 次

停止條件:
- 全部檢查通過 → 回報「完成」,並附上通過的輸出作為證據
- 5 次用完 → 停下來,回報還剩下什麼沒解決
- 同一個錯誤連續出現 2 次 → 停止迴圈,並提示呼叫 @fixer

禁止:沒有檢查輸出就回報「完成」
禁止:透過刪除 assertion 或弱化測試來混過去。要修的是程式碼,不是分數板

最後那兩個「禁止」,其實是這個設定裡最有效的部分。
我曾經在沒加這個的情況下跑過,結果 Claude 在第 3 輪偷偷刪掉一行 assertion,把測試過掉了:sweat_smile:
測試是過了,但 bug 還在,而且看起來還很自然。只要把評估標準(停止條件)寫得不夠明確,迴圈就會毫不猶豫地鑽漏洞:point_up_tone1:

② 在 .claude/settings.json 放入 hook

就算在 CLAUDE.md 寫了規範,Claude 還是可能會忘記。
所以我們把 settings.json 裡的 hook 當成「硬性約束」。
每當 Claude 想停下來時,系統就強制跑檢查,並把結果塞回對話中。

.claude/settings.json

{
  "hooks": {
    "Stop": [{ "hooks": [{ "type": "command", "command": "npm test --silent 2>&1 | tail -20" }] }],
    "PostToolUse": [{ "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "npx tsc --noEmit --pretty false 2>&1 | head -10" }] }]
  }
}
  • PostToolUse:每次編輯檔案就做型別檢查,讓它邊寫邊修
  • Stop:當 Claude 想說「完成」的瞬間,跑完整測試;如果失敗,輸出會直接進入對話,強制再跑一輪

這就是前面提到的 /goal 的本體= Stop hook」 的自製版本。
Stop hook 負責扮演那個能說「不行」的評估角色,只要這一關沒過,迴圈就不能結束。
如果是 Python,就換成 pytest -q + pyright;Rust 則換成 cargo test --quiet + cargo check 即可:point_up_tone1:

.claude/agents/fixer.md(用不同的上下文打破卡關)

有些問題在同一段對話裡就是修不好。通常已經試了 4 次,context 裡充滿失敗 log,思路也被鎖死了。
這時候就把它交給 一個全新 context 的另一個代理

.claude/agents/fixer.md

---
name: fixer
description: 用於同一個測試在兩次修正嘗試後仍失敗時,打破卡關的代理
tools: Read, Edit, Grep, Glob, Bash
model: opus
---

你要修正失敗的檢查。禁止猜測。

1. 自己執行失敗的檢查,讀完整個錯誤訊息
2. 從頭到尾讀完失敗路徑上的所有檔案
3. 用一句話寫出:真正原因是什麼
4. 只修那個原因,不做順手重構
5. 重新執行檢查,並回報修正前後的輸出

禁止:刪除測試、放寬 assertion、用 try/catch 吞掉錯誤、把測試 skip 掉

它是被主對話呼叫出來的,不帶著前面 4 次失敗的記憶,從零開始診斷,所以常常一次就能過。
這就是前面 6 個零件裡的 Sub-agents(將生成角色與評估角色分離) 本身。

組起來之後

CLAUDE.md 的協議、.claude/settings.json 的 hook、.claude/agents/fixer.md 的 fixer 放好,再把實際任務丟給 Claude 就行了。

一旦組好,反覆把終端機錯誤複製貼上重試的工作就消失了
Claude 會自己跑、自己看、自己修,卡住時再叫出 fixer。

你最後只需要看一次 diff 就好:relaxed::point_up_tone1:

如果要自己開發——Mastra

前面介紹的 Claude Code,是一個不需要新框架、就能 立刻在本機試用 的入口。接下來要談的是,把迴圈嵌進你自己的服務或工具裡來開發 的做法。

Mastra 的 Goals 功能

不需要從零自己寫迴圈骨架,框架裡已經內建了對應前面 /goalGoals 功能,會持續跑到條件成立為止,並由另一個模型負責判定是否完成。
Goals 會把「持續存在的目標」綁在 thread 上,每一輪都由另一個判定角色(judge)模型評分,直到達成或達到上限為止。

src/mastra/worker.ts

import { Agent } from '@mastra/core/agent';

const worker = new Agent({
  name: 'worker',
  instructions: '把軟體任務完整做到最後',
  model: 'openai/gpt-5.5',
  memory, // 需要先接好 storage 的 memory
  goal: {
    judge: 'openai/gpt-5-mini', // 與作業角色不同的「判定角色」模型
    maxRuns: 30,                // 空轉上限(=成本上限)
    prompt: '只有在測試通過時才視為完成',
  },
});

// 為 thread 設定一個「持續存在的目標」(重新載入後也會保留)
await worker.setObjective('/health endpoint を追加してテストする', {
  threadId,
  resourceId,
});

judge(用與作業角色不同的模型來評分)和 maxRuns(空轉上限=成本上限)是兩個關鍵點。Claude Code 的 /goal 做的事情,幾乎就直接落到這兩個設定上了:point_up_tone1:

Goals 是相對新的 experimental 功能(@mastra/[email protected] 新增),官方也明確說了未來可能會變動。最新參數請以官方文件為準。若停止條件是 能直接用程式碼判斷 True/False 的確定性條件,也可以考慮使用工作流程的 .dountil()

持續運轉的代價

方便歸方便,迴圈也有 放著不管就會默默累積代價 的一面。

A loop running unattended is also a loop making mistakes unattended.(沒有人看著的迴圈,也是會沒人看著地持續犯錯的迴圈)

大致有 4 個:

陷阱 症狀 一句防範方式
漏掉驗證 成果在累積,但沒人檢查 加入獨立於作業角色之外的評估角色(也就是 Stop hook)
理解退化 程式碼越來越多,但腦中的地圖還停在舊版 定期閱讀輸出,確認自己是否還能說得清楚
放棄判斷 迴圈一跑起來,人就開始「算了啦」 可以交給系統執行,但不能把判斷也一起放掉
token 暴衝 使用量劇烈波動,帳單難以預測 上線前先設定預算與最大重試次數的上限

特別是 token 暴衝,說白了就是錢的問題。
如果一個 bug 讓它整晚空轉,早上醒來時等著你的可能不是修好的程式碼,而是 陌生的帳單:frowning2:

與其說是節省成本,不如說是 避免事故。上線前務必設定硬性上限(單次預算、每日預算、最大重試次數)。前面 CLAUDE.md 裡的「最多 5 次」、「同樣錯誤出現 2 次就立刻停止」,也正是這類上限。

最後——其實這篇文章,也是用迴圈寫出來的

前面一直在說「迴圈要怎麼做」,最後來揭曉一個小彩蛋:relaxed:

這篇文章本身,就是用這裡介紹的迴圈寫出來的。 結構正好就是前面說的 6 個零件的最小版。

  • 說明文件 PROMPT.md(要寫什麼、文體、參考來源)= 發現
  • 負責寫本文的我(生成角色) 逐節草稿 = 交接
  • 3 個評估角色子代理 = 驗證
    • 文體檢查角色(Sonnet):是否接近我過去文章的文體與結構
    • 程式碼驗證角色(Haiku):文中放的程式碼是否真的能跑
    • 出處檢查角色(Haiku):確認術語有沒有亂編、是否有幻覺
  • MEMORY.md:記錄調查筆記與判斷 = 記憶
  • 停止條件是 「3 個評估角色全部通過」,主關卡是文體檢查角色的「是否已足夠接近過去文章」

老實說,這些評估角色真的把我盯得很緊。程式碼驗證角色說「Mastra 的範例這裡要再確認」,文體檢查角色說「用語比過去文章更硬」,最後連出處檢查角色都直接指出 「這個術語在參考來源裡沒有。是不是你自己亂掰的名字?」,抓出幻覺問題,讓我改了好幾輪:sweat_smile: 這正是 CLAUDE.md 裡那句「禁止:動分數板」的反過來,輪到我自己被修理了。

而我最有感的是這一句。Addy 結尾那段話真的很有力:

Build the loop. But build it like someone who intends to stay the engineer, not just the person who presses go.

把迴圈做起來吧。但要像一個打算繼續當工程師的人那樣去做,而不是只會按下啟動鈕的人。

迴圈可以讓生成變得近乎無限便宜,但 「要往哪個方向寫、要停止哪些產出」 這種判斷,還是無法被代勞。這篇文章也是一樣,比起評估角色的接線(工程),更有影響的是 把「什麼樣的文章算好」這個標準寫進 CLAUDE.md,再交給評估角色

容器可以靠工程做出來,但裡面要放什麼樣的好壞標準,終究還是在做這件事的人心裡:point_up_tone1:

有興趣的人,不妨先不要想得太複雜,照著本文的入門做法,CLAUDE.md 裡放入「迴圈協議」和 Stop hook,然後丟一個實際任務進去試試看

你大概很快就會有種「啊,原來是這樣」的感覺:relaxed:


原文出處:https://qiita.com/Syoitu/items/97ed37e7ba9c38dc75d8


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝16   💬1   ❤️1
492
🥈
我愛JS
📝1   ❤️1
26
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登