給 Agent 開發者的 # Harness + Loop Engineering
2026/6/26
ihower @ 生成式 AI 開發者年會
![w:280](harness-qrcode.jpg)
1 / 111
1. 封面
哈囉大家好,我是 ihower。今天來跟大家分享 Harness 跟 Loop Engineering。 今天這場其實是我上個月在生成式 AI 開發者年會做的演講 感謝 主辦人 James 的邀請,來到這裡再次跟大家分享。

## 我是誰
**張文鈿**,網路暱稱 *ihower* - 2002 年起從事 Web 軟體開發 - 2005 年 個人部落格 <https://ihower.tw> - 2018 年 自行開業「愛好資訊科技」<https://aihao.tw> - 2023 年 開始經營 **AI Engineer 電子報** - 開源貢獻: [OpenAI Agents SDK](https://github.com/openai/openai-agents-python/pulls?q=is%3Apr+author%3Aihower+) - 我的課程「大語言模型 LLM 應用開發工作坊」<https://aihao.tw/llm>
![w:320](photo3.jpg)
2 / 111
2. 我是誰
簡單自我介紹一下,我是 ihower,從 2002 年就開始做 Web 的軟體開發,這有我的部落格。然後 18 年自己開一人公司。從 23 年開始經營 AI 的電子報,去年也有開始貢獻 OpenAI Agents SDK,也有開設一些課程。

## Agenda
1. Recap: 什麼是 Deep Agent
2. **什麼是 Harness Engineering** 🎯
3. **時機 ①: 工具執行內**
4. **時機 ②: request 之間注入**
5. **時機 ③: 單輪結束(stop hook)**
6. **時機 ④: 外層 Loop**
7. 進階: 自我改進的 Harness
8. 收尾: 會過期的 Harness
9. 番外: 自建 Agent 的框架選型
![h:430](blog-list.jpg)
📚 搭配有 9 篇的 blog 系列《給 Agent 開發者的駕馭工程》長篇文章 👉 blog.aihao.tw
3 / 111
3. Agenda
這是今天的 agenda,有分了 9 個 part,我每個 part 其實都先已經有寫一篇部落格,都已經發表在我部落格上。因為我準備的時候其實是先寫好部落格,然後再把部落格轉成我的投影片。但因為內容比較多,所以我演講的主要 focus 會是在 2、3、4、5、6,會是今天的主要重點。那我的風格可能還是會比較像上課一點。

## 👥 預期聽眾 多數談 Harness Engineering 是在講 Claude Code、Codex 來做軟體開發流程。 本場不是這個角度,而是站在「**自行開發 AI Agent**」的切入點。你要做的可能是 Text-to-SQL Agent、知識庫 RAG Agent,場景各式各樣,用途不一定是軟體開發。
Harness Engineering 可以適用於開發任何場景的 AI Agent
4 / 111
4. 預期聽眾
我準備的 Harness 的內容,主要預期的對象是你要自行開發 Agents。因為網路上大部分講 Harness Engineering 蠻多是在講說如何運用 Claude Code 或是用 Codex 來做軟體開發。那我的部分稍微有點不太一樣,我是認為說 Harness Engineering 是可以適用在開發任何場景的 AI Agent,你自行開發的 AI Agent 上面都可以使用這個原則跟概念。

PART 1 # Recap:
什麼是 Deep Agent
5 / 111
5. Part 1 標題頁
第一個 part 我們稍微 recap 一下什麼是 Agent。

## 複習 Agent 1.0 迴圈 ![w:980 Agent 迴圈: Input → LLM 挑選工具 → Tools → 執行得到 Tool Result → 觀察結果回到 LLM,呼叫工具 N 次後輸出 Output](agent-loop.jpg)
呼叫工具 N 次、每次都把結果讀回來,直到沒有工具要呼叫才輸出
6 / 111
6. 複習 Agent 1.0 迴圈
快速複習一下 Agent 1.0 的迴圈: 用戶的 query 進來,大模型判斷說他要使用哪個工具,所以會有一個 loop 是他根據工具的結果去判斷說是不是要再去挑下一個工具。中間可能會有很多個迴圈是他不斷地去執行工具,最後 Agent 判斷說他要輸出最後答案了,就會得到最後 output。 所以這個是一個 Agent 最基本的 loop,我們的術語會跟大家說這就叫做一個 one turn,一個 turn、一輪。使用連續呼叫很多工具之後得到一個 final 輸出,這個叫做一輪。

## Agent 2.0 (Deep Agent) 的六項能力 這些能力讓 Agent 應付更大更複雜的任務,技術上都是用到 **Function Calling** 來實現的 | 能力 | 做什麼 | |---|---| | **Plan & Todos** | 拆解大任務,依序執行 | | **Filesystem & Bash** | 操作檔案、執行程式(搭配 sandbox) | | **Sub-Agent** | 把耗 token 的任務分給子代理人,隔離 context | | **Memory** | 跨 session 記得使用者與專案的長期資訊 | | **Skills** | 按需動態載入的技能 prompt | | **更多工具** | MCP、Browser、Computer Use |
代表產品: Claude CodeCodexGemini CLI、LangChain Deep Agents
7 / 111
7. Agent 2.0 (Deep Agent) 的六項能力
從去年開始我們進到所謂的 2.0 Deep Agent,開始有一些內建的新的能力,可以讓 Agent 可以去應付更大更複雜的任務。看起來很多,但其實都是用到 Function Calling 的技術來做實現的。

## Deep Agent 內建能力 ①: Plan & Todos
### 🎯 它解決什麼問題 - 只靠 in-context 規劃,思路容易被中間步驟干擾、遺失 - 改用工具維護外部 todo list,**不會忘記**沒做完的事
### 🔧 技術上怎麼辦到 透過 Function Calling 提供工具: - `TaskCreate` 建立任務項目 - `TaskGet` 取得任務詳情 - `TaskUpdate` 更新任務狀態 - `TaskList` 列出所有任務
8 / 111
8. Deep Agent 內建能力 ①: Plan & Todos
比如說包括了 Plan 跟 Todo 的能力,其實就是透過提供 Todo 的工具,讓Agent 可以去管理他自己的 Todo List。

## Deep Agent 內建能力 ②: Filesystem & Bash
### 🎯 它解決什麼問題 - **Filesystem** 讀寫改檔,**Bash** 執行任意 shell 指令 - 讓 Agent 真的**動手做事**:編譯、跑測試、git、裝套件
### 🔧 技術上怎麼辦到 透過 Function Calling 提供工具: - `Read`/`Edit`/`Write` 讀寫檔案 - `Bash` 執行 CLI 指令 - `Glob`/`Grep` 搜尋檔案
9 / 111
9. Deep Agent 內建能力 ②: Filesystem & Bash
以及 Filesystem 或 Bash 的能力,就是提供 Agent 讀寫檔案以及執行 Bash 指令的工具,也是用 Function Calling 來實現的。

## Deep Agent 內建能力 ③: Sub-Agent
### 🎯 它解決什麼問題 - 主 agent 派子代理去研究、查找、驗證 - 子 agent 是**獨立 context** 跑,只回精簡摘要(**context 隔離**) - 可**平行化**:多個子 agent 同時工作
### 🔧 技術上怎麼辦到 透過 Function Calling 提供工具: - 一個叫做 `Agent` 的工具 - 工具內就是**呼叫另一個 Agent** 執行,把子 agent 輸出回傳給主 agent
10 / 111
10. Deep Agent 內建能力 ③: Sub-Agent
Sub-Agent 就是委派 Sub-Agent 去做事情。技術上怎麼辦到呢?也是 Function Calling,就是有一個工具,那個工具裡面就是建立新一個 Agent 去執行。

## Deep Agent 內建能力 ④: Memory
### 🎯 它解決什麼問題 - 把**重要資訊存起來**,下次再開 agent,**它還記得** - 例:Claude Code 的 `CLAUDE.md`、Codex 的 `AGENTS.md`、長期 memory 儲存
### 🔧 技術上怎麼辦到 - Agent 一啟動就**預設載入** `AGENTS.md` - 使用者可以自己要求**更新** `AGENTS.md` - 可自行設計記憶行為:記什麼、存在哪些目錄檔案、什麼時候回憶哪些內容
11 / 111
11. Deep Agent 內建能力 ④: Memory
我們也會談到 Deep Agent 有 Memory 的能力,技術上怎麼做到呢?其實就是有一個預設的 System Prompt 給大模型,通常如果你用 Claude Code 的話,或是用 Codex 可能就是有一個 AGENTS.md 預設一開始會載入。蠻多的 Memory 的設計基本上就去設計說有哪些檔案什麼時候觸發載入,分別要存哪些記憶。

## Deep Agent 內建能力 ⑤: Skills
### 🎯 它解決什麼問題 - 為特定任務打包的 **prompt +工具配置+程式碼** - **不全部塞進 context**,用到才載入;寫 markdown 就能新增 - 例:翻譯 skill、寫部落格 skill、處理 PDF skill
### 🔧 技術上怎麼辦到 - 預設 system prompt 只載入 **skills 列表** - 使用者需要某個 skill 時,Agent 才用讀檔工具**載入完整 skill 內容**
12 / 111
12. Deep Agent 內建能力 ⑤: Skills
那 Skill 就是我們在 System Prompt 有 Skill 的列表,然後按需載入,當用戶需要的時候,我們就會用讀檔工具把 Skill 的完整版載出來。

## Deep Agent 內建能力 ⑥: 更多工具
### 🎯 它解決什麼問題 - **MCP**: 接外部 Slack、Gmail、Notion、自建 API… - **Browser**: 瀏覽網頁、填表單、點按鈕,能上網做事或用網頁驗證自己的產出 - **Computer Use**: 直接操作桌面 GUI(看螢幕、移動滑鼠、敲鍵盤)
### 🔧 技術上怎麼辦到 - Browser 與 Computer Use 需要**多模態模型**:讓 AI 看截圖判斷下一步該點哪裡 - MCP 標準化工具協議
13 / 111
13. Deep Agent 內建能力 ⑥: 更多工具
你會發現其實這些技術全部都是用 Function Calling 提供工具來達成的。更多的工具包括用 MCP、Browser、Computer Use 等等,也是用 Function Calling 對 Agent 來說這樣實現。

## 但有能力 ≠ 把事情做好
### ✓ 能力給了你能不能做 能讀檔、跑指令、開子代理、記憶、用工具。
### ? 但是做得對不對 · 做完了沒 這一步的產出對嗎?整個任務做完了沒?怎麼穩定地做好、做完?
14 / 111
14. 但有能力 ≠ 把事情做好
上述講了那麼多讓 Agent 有能力了,但是事情有沒有做好呢?做得對不對呢?是我們還是打上問號的。

PART 2 # 什麼是
Harness Engineering
15 / 111
15. Part 2 標題頁
所以就進到了今天重點的主題是 Harness Engineering。

## 「做完了」誰說了算?
- Agent 自信地宣稱完成,但東西是壞的 - 測試沒跑、需求沒做完,它說「已全部完成 ✅」 - 你指出問題,它道歉,然後再犯
### 這不是個案 Anthropic 整理長時間執行 agent 的失敗模式,**第一名就是「過早宣告完成」**。
16 / 111
16. 「做完了」誰說了算?
做完了是誰說了算?就是 Agent 可能會自信的宣稱完成,但其實東西沒有做完。你指出問題,他道歉又再犯。這不是個案,在 Anthropic 分析的報告裡面算是第一名的失敗模式,就是過早宣告完成。

## 什麼是 Harness? ➡️ Agent = Model + Harness
這是網路上常見的定義 **模型以外的一切**(system prompt、工具、編排、hooks)都算 harness。
### 小小吐槽 🤷 這定義有點偷懶 > 就像說「整體 = 核心 + 其他」 這個其他到底是什麼,我們需要**更可以操作的技術拆解**!
定義出自: The Anatomy of an Agent Harness(Viv Trivedy)
17 / 111
17. 什麼是 Harness?→ Agent = Model + Harness
什麼是 Harness 呢?網路上一個常見的定義是叫做 Agent 等於 Model 加 Harness,就是模型以外的一切我們都把它歸在 Harness 駕馭的工程裡面。 那我個人對這個定義有點小小的吐槽,我覺得有點偷懶,就很像說整體等於核心加其他,那這個其他是什麼?這個定義沒有講。所以今天我就希望能夠帶大家仔細的拆解一下這個「其他」到底是什麼東西。

## 首先,harness 不只是技術功能列表
### ❌ 不是這個 Skills、Sub-Agent、Hooks、Filesystem、worktree 這些都只是**手段**,不是 Harness Engineering 的思維核心。
### ✅ 真正的主軸 是如何讓 agent 在**執行過程**能被**約束、檢查、動態修正**
18 / 111
18. 首先,Harness 不只是技術功能列表
首先 Harness 我認為它不是技術的功能列表,它不是說用了 Skill、用了 Sub-Agent、用了 Hook、用了 System Prompt 等等,我覺得這些技術都是手段,不是這個思維的核心。 我們想要的核心是如何能夠讓 Agent 在執行的過程中能夠被約束、檢查跟動態修正。

## 回顧 Prompt、Context、Harness 三層 常被講成一條「演進」之路,但其實技術累加的都會用上,只是各自凸顯一個新的工程焦點: | | 核心問題 | 技術功能 | |---|---|---| | **Prompt Engineering** | 怎麼讓模型**這一次**答得更好 | system prompt、few-shot、evals | | **Context Engineering** | 在 context window 限制下**選擇**該放的資訊 | RAG、memory、compaction、tool offload | | **Harness Engineering** | 怎麼在**執行過程**中約束、檢查、動態修正 | skills、filesystem、hooks |

並沒有「XXX 已死」這回事,後者是基於前者的發展之上,而非取而代之。

19 / 111
19. 回顧 Prompt、Context、Harness 三層
回想這兩三年的發展,從 Prompt、Context 到 Harness,常常被講成一個演進之路,但是我認為這其實是不太對的。技術其實是累加的都會用上,新的名詞發明出來,你可以說它是取代,但你也可以換一個思維去想說它其實是在凸顯一個新的工程焦點。 所以從最早的 Prompt Engineering,我們希望讓模型可以一次回答的更好;到 Context Engineering 我們在 Context Window 的限制下去選擇要放的資訊;進到 Harness Engineering,講的是如何在執行過程中做動態的修正。 所以我認為其實沒有什麼「XXX 已死」這回事,每次看到網路文章看到說 Prompt Engineering 已死,我就翻白眼。因為我覺得所有技術都是累加在前面的,而不是取而代之。

## Harness 核心策略: 先 generate,再 verify 核心策略就是: **驗證 (verification)**,廣義的說就是 **回饋(feedback)**
### 常見失敗 agent 輸出答案 → agent 覺得「看起來沒問題」→ 就停了。
### 解法: generate → verify → fix 模型有自我修正的能力,但我們需要讓 Agent 順利觸發進入「輸出 → 回饋驗證 → 修正」這個流程。
那工程上怎麼確保 verify「真的會發生」?
20 / 111
20. Harness 核心策略:先 generate,再 verify
Harness Engineering 的核心策略到底是什麼呢?其實就是驗證。 首先 generate 輸出,然後我們再驗證。核心策略廣義的說其實是 Feedback,就是Agent 輸出之後一定要拿到一個 Feedback,讓 Agent 接下來能夠繼續的去輸出得更好。 常見的失敗就是 Agent 覺得他沒問題他就繼續就停了。但模型本身其實有自我修正的能力的,我們要做的事情就是讓 Agent 能夠順利觸發進入到這個輸出、回饋驗證跟修正的流程。 剛提到模型有自我修正的能力是說: 你主動要模型去找有什麼問題它還是能找得出來的,但是 Harness Engineering 想要積極 push 這件事情,讓 agent 能夠自動順利的進入這個自我修正流程。

## 兩個軸把 harness 拆解 Thoughtworks 用兩個軸拆解 harness 作法: **方向**×**型態**: | | 運算式 Computational(確定性、程式工具)| 推論式 Inferential(LLM 生成)| |---|---|---| | **前饋 Feedforward**
引導器 Guides(行動前引導)| 用程式工具產生的 code metadata 與約束:LSP、Codemod/ast-grep、架構規則(ArchUnit 等)| **system prompt**、AGENTS.md、Skills、bootstrap instructions、how-to 文件 | | **回饋 Feedback**
感測器 Sensors(行動後修正)| 測試、linter、type checker、靜態分析(eslint、semgrep)、pre-commit hook | **LLM as Judge**、AI code review、Review Skills |
原文是針對 coding agent 場景,但此框架被我延伸到非 coding agent 上
參考:Birgitta Böckeler(Thoughtworks)Harness engineering for coding agent users
21 / 111
21. 兩個軸把 Harness 拆解
Thoughtworks 有一篇蠻不錯的文章,就是他用兩個軸來去拆解 Harness 的做法,他拆成方向跟型態。所謂的方向就是分成前饋跟後饋(又叫回饋),前饋指的就是在輸出之前,回饋指的就是輸出之後。 然後他又分成兩種型態,一個是運算式,一個是推論式。運算式就是用程式產生出來的東西,推論式指的是用 AI 生出來的東西。 表格右上角,大家可能比較熟悉的 System Prompt、AGENTS.md,其實這種都算是前饋,我們在輸出之前就把 System Prompt 寫好了。System Prompt 通常是怎麼來的?通常也是我們用 AI 生出來的。 而表格左上角那一邊的前饋指的是用一些程式工具產生出來的。 表格左下角是運算式的回饋,例如 AI 寫完 code 之後,我們會跑一些測試、跑一些 linter、type check 等等,那這些是用程式檢查之後得到的回饋。 那右下角就是 LLM as a Judge,就是我們用另外一個模型去看剛才的輸出,然後給他一些 feedback,可能是 AI code review 等等。 那這篇文章其實是針對 Coding Agent 的場景,但是我接下來是會把它延伸到非 Coding Agent 上面。

## 好的 Harness 做兩件事
### 🧭 Guides 前饋 **提高「一次做對」的機率** 文件、skills、範例、架構約束。 軟性引導,做不做最後還是要看 agent
### 📡 Sensors 回饋 **輸出之後,感測提供回饋,引導 Agent 自我修正** 測試、linter、judge、AI review。 用程式自動觸發,不靠 Agent 自覺。
好的 harness 同時做兩件事: 提高「一次做對」的機率,並在出錯時能自我修正。
22 / 111
22. 好的 Harness 做兩件事
剛才那個架構帶我們了解兩件事情:一個是前饋,提高一次做對的機率,前饋指的是一開始的 System Prompt、一開始的 Skills 等等。 另一個是回饋,就是輸出之後我們要提供一些回饋,給它引導 Agent 去做自我修正。好的 harness 同時會有前饋跟後饋。

## 前饋 Guides 你的 system/developer prompt,要把「什麼是好的結果」以及「驗證流程」寫清楚。 例如 AGENTS.md/CLAUDE.md 都會要求 Agent 要去做驗證
### Claude Code > 「**非常重要**:完成任務時你**必須**執行 lint 和 typecheck(npm run lint、ruff…),確保程式碼正確。」
### Codex > 「如果 AGENTS.md 裡有可程式化的檢查,你**必須**全部執行並盡力驗證通過。即使只是改文件也一樣。」
23 / 111
23. 前饋 Guides
前饋的部分就是 System Prompt。以 Claude Code 或者是 Codex 來說, 就是 CLAUDE.md 跟 AGENTS.md 他們都有塞類似這樣的句子: 你必須要檢查這些、執行這些東西、確保程式碼正確,其實就是要求 agent 去做這些事情,來收集到回饋。

## 前饋的限制 前饋終究是**軟性、機率性**的引導 你在 AGENTS.md 寫十遍「一定要驗證」,模型還是有可能跳過 😢
24 / 111
24. 前饋的限制
但前饋的限制就是它畢竟是軟性的、機率性的引導。所以你在 AGENTS.md 寫十遍一定要驗證,還是有可能會被跳過。

## 回饋 Sensors: 把 verify 變成自動執行 前饋是軟性引導;回饋則用程式**自動執行**,不靠模型自覺 這可以插在 Agent lifecycle 的不同位置,來給 Agent 回饋。 本場將深入講解回饋的四個時機點
**① 工具執行內**(Part 3) **② request 之間注入**(Part 4)
**③ 單輪結束 · Stop hook**(Part 5) **④ 外層 Loop**(Part 6)
25 / 111
25. 回饋 Sensors:把 verify 變成自動執行
所以我們要多做的事情就是做回饋,把 verify 變成自動執行的,不靠模型自覺。接下來的一大重點就是說那這個回饋到底要放在整個 Agent 的 lifecycle 的哪幾個地方。我分析出來就是有四個時機點是可以做的。

## 當然,前饋和回饋缺一不可
### 若只有回饋、沒有前饋 agent 寫 code → 測試失敗 → 改 → 再失敗,跑好幾輪還是超時。 通常不是回饋不夠,是 agent 從頭就不知道「好的執行過程跟結果」該有的樣子。
### 若只有前饋、沒有回饋 Agent 可能跳過驗證流程,可能沒有確實做好驗證。不知道做的對不對、不確定做完了沒
Agent 需要前饋一開始走對方向,也需要回饋負責把關修正。兩者缺一不可。
26 / 111
26. 前饋和回饋缺一不可
前饋跟後饋當然是缺一不可。因為你如果只有回饋沒有前饋,那模型會一直 try and error,最後就試到超時了。那如果只有前饋沒有後饋,那就是 Agent 可能會跳過驗證的流程。所以兩者是缺一不可的。

Harness Engineering:
讓 Agent 依目標持續、正確地動作的工程。

本場將重點講「回饋訊號」:要有東西能判斷做得好不好、做得對不對、做完了沒

27 / 111
27. Harness Engineering 定義
定義總結一下,Harness Engineering 的策略目標就是讓 Agent 能夠依照我們的目標持續執行正確的動作。

## 回饋的四個時機點 把 agent 的迴圈由內而外拆解,回饋有四個時機點: | 時機 | 多久觸發一次 | 成本 | 修正粒度 | 對應的 hook | |---|---|---|---|---| | **① 工具執行內** | 每次 tool call | 毫秒,最便宜 | 單一動作 | Pre/PostToolUse | | **② request 之間注入** | 使用者或程式想注入時 | 趨近零 | 當前這一輪的方向 | 無專屬 hook | | **③ 單輪結束** | 每一輪 | 秒級 | 整輪的產出 | Stop hook | | **④ 外層 Loop** | 每個 session | 分鐘到小時 | 整個任務 | 排程/外迴圈 |
28 / 111
28. 回饋的四個時機點
接下來我們來看今天的一大重點,回饋的四個時機點,我跟大家拆解。四個時機點:一個是工具執行內、一個是 request 之間、一個是單輪結束(也就是我一開始講的 Agent 的那一輪),然後第四個是外層的 loop。

## 回饋的四個時機 ①②③④ ④ 外層 Loop · 每個 session · 分鐘~小時 · 修正整個任務 ③ 一輪 Turn · 秒級 使用者輸入 模型 request 1 🔧 tool calls 模型 request 2 🔧 tool calls 模型 輸出答案 ② request 之間注入 (人 steer 或程式) ① 工具執行內 · 修正單一動作 Stop hook 沒過 → 同份 context 再跑一輪 一輪 (Turn) = 多次「模型 request → tool calls」反覆,直到模型輸出答案 ④ 通過後這個 session 收掉,換上全新 context 再跑一圈
29 / 111
29. 回饋的四個時機 ①②③④ 圖解
這裡有一個看起來比較複雜的圖表,我們還是先解釋一下。中間那一排是模型的 request 1,從左邊看中間的左邊,一開始會發出第一個 request,之後 AI 會回覆說你要呼叫哪些工具,其實在那個工具內就是一個回饋的時機點。 接著我們執行完工具之後會回覆給 AI,這時候就是 request 2。在回給 request 2 前面又有一個時機點,我這邊定義叫做 request 之間。如果你有用 Codex 或 Claude Code 的話,他有一個功能叫做 steering,就是這個時機點,叫做引導。拿到結果之後這裡也可以插一個回饋。 接著 AI 拿到收到 request 了之後,他可能會再決定呼叫下一次的工具,所以右邊還有第二次的 tool call,這是舉例。那最後接著他決定要輸出最後答案了,那這時候就有一個新的時機點。這第三個時機點我們可以用一些機制,去強迫 agent 再跑一輪,例如 Codex 的 Goal 或是 Claude Code 的 Goal 的功能,這個等會會詳細解釋。 那第四個時機點就是全新的一個 session,我把它定義在外層的 loop。

PART 3 · 時機 ① # 在工具執行內
30 / 111
30. Part 3 標題頁
(時機 ① 在工具執行內)

## Tool Call 裡面 工具呼叫內,有三個可以設計的地方:
### 執行前: 驗證輸入 確定性檢查參數與內容, 擋掉危險或無效的呼叫
### 執行後: 檢查結果 對結果做品質檢查, 必要時就地修復或重試
### 工具回傳值+夾帶指引 tool response 不只回資料,**還夾帶指示與 metadata**,引導 Agent 的下一步
31 / 111
31. Tool Call 裡面
我們來看在工具執行內裡面可以做怎樣的回饋。在 Tool Call 裡面,單一的 Tool Call 裡面我們可以有三個可以設計的地方: 我們可以在執行工具前做驗證輸入、執行工具後做檢查結果做品質的檢查,然後另外我們可以設計它的工具的回傳值,是可以夾帶指引的。

## 工具輸出不只是 function output,
是你寫給 Agent 的回饋

寫程式習慣把回傳值當「資料」: 查到什麼回什麼,出錯就回傳 error code

但對 Agent 來說,tool response 也是一個對話訊息:
你可以在裡面夾帶指示、更多資訊 metadata,
甚至告訴 Agent 下一步怎麼做。
32 / 111
32. 工具輸出不只是 function output,是你寫給 Agent 的回饋
這裡有個很重要的概念,就是說工具輸出不只是 function 的 output,是你寫給 Agent 的回饋。 因為對工程師來說我們蠻習慣就是那個 function 其實就是回傳資料,查到什麼就回傳什麼,如果有錯誤就回傳 error code。但其實對 Agent 來說,這個 tool 的 response 其實也是一個對話訊息,所以我們是可以在裡面夾帶指示的,甚至也可以夾帶更多的資訊的 metadata,來告訴跟暗示 Agent 下一步可以怎麼做。

## 案例: Text-to-SQL Agent
### 場景 使用者用自然語言問財務數據, Agent 基於 DB schema 產生 SQL 用 `execute_sql(sql_query)` 工具查詢。
### LLM 生成 SQL 的風險 - **幻覺**不存在的表格和欄位 - 生成查詢以外的危險語法 - 忘記**分頁**,回傳爆量資料 - SQL dialect 語法不同
我們會在 system prompt 插入 table schema 說明有哪些 tables/columns,以及各種 SQL 限制,這是前饋要先寫好。
33 / 111
33. 案例:Text-to-SQL Agent
我們來具體的舉個例子,比如說做一個 Text-to-SQL 的 Agent。使用者可以用自然語言去問你的財務數據,所以我們的 Agent 會根據 DB schema 產生 SQL,然後 SQL 再去查資料庫。這樣的一個 Agent 最重要的工具就是叫做 execute SQL,我們會定義一個 function 叫做 execute SQL,它的參數就是 SQL query,所以大模型的任務就去產生那個 SQL。 這裏的前饋的部分是什麼?就是我們會在 System Prompt 裡面插入 table schema 的描述跟定義,以及各種 SQL 的限制。

## 在工具內: 把 SQL 解析成語法樹(AST),做確定性的檢查和改寫 ```python import sqlglot from sqlglot import exp tree = sqlglot.parse_one(sql_query, dialect="postgres") # 1. 只允許 SELECT(擋下來) if not isinstance(tree, exp.Select): return "只允許 SELECT 查詢" # 2. 資料表白名單(擋下來) for table in tree.find_all(exp.Table): if table.name not in ALLOWED_TABLES: return f"資料表 {table.name} 不在允許範圍,可用:{ALLOWED_TABLES}" # 3. 沒 LIMIT 就補安全上限(補強) if tree.args.get("limit") is None: tree = tree.limit(200) safe_sql = tree.sql(dialect="postgres") # 確保輸出 postgres 語法 ```
34 / 111
34. 在工具內:把 SQL 解析成語法樹(AST),做確定性的檢查和改寫
這裡我更關注後饋怎麼做。雖然前饋你會寫如何產生 SQL ,但是模型產生 SQL 的問題是,它可能會幻覺不存在的表格或欄位,或是生成查詢以外的危險語法(通常我們是希望它只有查詢),或者是它忘記要分頁等等,或者不同資料庫的 SQL 語法不一樣,大模型可能很熟悉 SQLite 或 PostgreSQL,但是其實它可能不熟悉一些比較冷門的資料庫的語法,所以可能會很容易生錯的。 所以我們可以在工具內把大模型產生的 SQL 語法解析成語法樹,做確定性的檢查跟改寫。它可以檢查說只能允許 SELECT,只能允許我白名單的資料表跟白名單的欄位,然後它可以自動幫你修改這個 SQL 加上 LIMIT。因為我們不希望 `SELECT *` 全部,一次撈出幾萬筆的資料是不行的,所以我們會加上一個 LIMIT 限制,要求它一定要做分頁。 這裡還可以做用戶的權限檢查,在這邊補上它一定會有的某些條件,就是有些事情就是不需要靠大模型生的,我們可以用確定性的語法補上我們需要的限制條件。最後我們再輸出轉成合法的我們需要的資料庫的語法。

## 工具回饋的設計 驗證沒過時,tool response 的品質決定 Agent 自我修正的能力
### ❌ 爛 error ```text ERROR: column "revenue_growth" does not exist ``` Agent 只能瞎猜重試,越改越歪。
### ✅ 好 error ```text 欄位 revenue_growth 不存在。 financial_metrics table 可用欄位有: revenue, revenue_yoy, gross_margin… 和 revenue_growth 最相似的欄位有 revenue_yoy, revenue_qoq ``` 下一步直接被導正。
每個失敗訊息都是引導模型再次做對的好機會
35 / 111
35. 工具回饋的設計
執行工具有錯誤的時候,我們也必須設計它錯誤的訊息。比如說有一個欄位不存在,左邊是不好的訊息,就是直接告訴它這個欄位不存在。那右邊我可以設計更好的錯誤訊息說這個欄位不存在,但是你查的這個 table 還有這些欄位,然後我還可以用相似性的搜尋跟它提示說跟這個最相似的欄位還有 ABC 可以選。 所以 Agent 透過這個錯誤訊息就可以更好的去引導它,下一次再做對的機會。

## 連「成功」都可以回傳更多狀態資訊
### ❌ 陽春的成功 flag `{"success": true}` 或 `{"count": 0}` - 查詢成功但 0 筆,是真的沒有結果,還是查詢不正確? - 是改了幾筆,也看不出來
### ✅ 回傳更多狀態資訊 把規模與範圍寫清楚: - 影響幾筆、動了哪些欄位或區塊 - 有沒有碰到不該碰的 更多資訊,Agent 才有依據判斷「這次結果合不合理」,是否要修正
錯誤要設計,成功也要設計。一個陽春的成功 flag,也可能是「假完成」的訊號
36 / 111
36. 連「成功」都可以回傳更多狀態資訊
甚至成功也可以設計。找不到零筆,但找不到零筆是真的沒有結果,還是查詢不正確?改了幾筆也不知道。所以其實就算沒有發生錯誤,我們也可以回傳更多的狀態資訊,總共影響了幾筆、動了哪些欄位等等,提供更多的資訊,那 Agent 才有能力去判斷說這次的結果合不合理、是否需要修正。 所以錯誤要設計,成功也可以設計。一個陽春的成功 flag 也可能是一個假完成的訊號。

## 工具回傳的引導訊息 各種純運算式(Computational)的檢查,回傳的是對應的固定訊息: ```python def collect_feedback(output, source): # 純運算式檢查:規則直接判定,不靠 LLM,沒過就回寫死的固定訊息 msgs = [] if count_words(output) > 500: msgs.append("摘要超過 500 字,請縮短") if missing_required_terms(output): msgs.append("漏掉必留的專有名詞,請補回") if cosine_similarity(output, source) < 0.8: msgs.append("與原文語意偏離,請貼近來源重寫") return msgs ```
### 運算式檢查(固定訊息) 回**事先寫死**的固定字串:又快又穩又可重現。
### 語意 judge(當場生成) 若沒辦法用純運算式的檢查,也可用 LLM 當 judge,附上回饋的 **reasoning** 理由。
37 / 111
37. 工具回傳的引導訊息
那這些工具回傳的引導訊息,剛才都是純運算式的檢查,所以它回傳的東西其實都是我們預先寫好的固定訊息。假設你有一個檢查是檢查字數一定要小於 500 字,假設超過 500 字的時候我們就有個回傳說「摘要超過 500 字請縮短」。所以你回傳的不是一個 error code,是一段引導 Agent 的訊息。這是左下角運算式的檢查,它是一個固定的訊息。 我們待會也會講到可以做成語意的,因為有些事情可能沒有辦法用完全的運算式來做的話,我們可以在工具裡面再塞一個大模型的 prompt 去做語意的回饋,比如說檢查品質好不好,然後在那個 prompt 裡面也會要求輸出一些分析的理由,在工具內用那個 prompt 得到結果之後再回傳。所以這是語意的 judge。

## 設計回傳值的另一個重點: 需要有意識地控制 context window 注意控制別塞滿 context。context 過了某個門檻,模型會變笨(context rot) 別忘了 [Context Engineering](https://ihower.tw/blog/12817-context-engineering) 的整套策略,各種縮減 context 的技術:
### Context Offloading **硬性工具輸出上限**、**頭尾保留** (切頭切尾)、**卸載到檔案** (只留預覽 + 路徑,有需要 Agent 再打開看)
### 檢索技術 關鍵字、向量檢索、reranker 等,只挑選相關的 context
### Sub-Agent 龐大的中間過程交給 sub-agent 在獨立 context 跑,只回傳結論
38 / 111
38. 設計回傳值的另一個重點:需要有意識地控制 context window
另外工具內設計工具另外一個重點就是我們必須要非常有意識的去控制 context window,因為 context 如果太長的話模型就會變笨。這一塊其實是我們 Context Engineering 蠻大一部分都在講這個策略。 如果去看 Context Engineering 是有很多縮減 context 的技術,比如說 Coding Agent 最喜歡用的 Context Offloading 的技術,就是所有工具的輸出一定都要硬性限制輸出的上限,我記得 Claude Code 好像是兩萬五千個字元,他們讀檔進來的時候都會只保留頭尾,把中間卡掉。然後如果搜尋的東西他一定會先存到檔案,然後 Coding Agent 再去用搜尋的方式、grep 的方式搜出來,避免一次把大量的東西塞到工具的輸出裡面。 然後 Context Engineering 還有很大部分在講檢索的技術,關鍵字檢索、向量檢索的 branch,重點就是說只挑出需要的資訊回傳。 然後第三個 Context Engineering 會做的是 Sub-Agent,就是讓 Sub-Agent 去處理龐大的中間過程,最後只回傳結論。那這些都是有意識的去控制 context window。

## 案例: 知識庫 RAG Agent 知識庫問答 Agent 會配一個 `search_knowledge(query)` 工具 (關鍵字搜尋+向量搜尋 等) 工具不只回傳搜尋結果,我們還可以回傳以下資訊,回饋給 Agent 更多資訊:
### 1️⃣ 標註來源與分數 回傳時標上來源和相關度分數,讓 Agent 有依據判斷哪些該引用、哪些該丟
### 2️⃣ 同源就 load 整頁 好幾個 chunk 都來自同一份文件 → 暗示整份相關。**可以指示 Agent 直接把整頁讀回來**,比散落片段好用
### 3️⃣ 看見 top-k 以外的資訊 回傳不只 top-k 搜尋結果,還夾帶整個資料集的統計
39 / 111
39. 案例:知識庫 RAG Agent
我們看第二個案例是 RAG,如果你做一個知識庫問答的 Agent,那你就會配工具叫做搜尋,搜尋的工具通常比如說這邊叫做 search knowledge,會有一個參數是 query,就是大模型產生一個查詢的字串。那在這工具裡面可能是關鍵字搜尋或向量搜尋。 那這邊我想要帶給各位就是這樣的搜尋工具,其實我們設計的時候不只可以回傳搜尋結果,我們還可以回傳更多東西。 第一個是我們可以回傳標註它的來源跟相關性的分數。 第二個是我們可以暗示它,就是如果你搜尋了好幾個 chunk 其實都來自同一份文件,你可以額外加一個指示說請 Agent 把整份文件讀出來就好。一份文件拆成十個 chunk,結果我們搜出來有六個 chunk 都出自這份文件,最好的理解方式是不是請 Agent 把整份文件都讀完,而不是只有讀那六個 chunk。 那第三個可以做的事情是我們可以在回傳 top-k 之外再夾帶整個資料集的統計數據。

## 工具回傳除了 top-k,還夾帶統計與指示 ```xml 回傳的 2 筆全是 Done。facets 顯示另有 5 筆 Open 沒進 top-k,請改用 search(query, status="Open") 追查進行中的問題。 ```
### `` 揭露隱藏資料 告訴 Agent:符合的不只你看到這 2 筆,還有 5 筆 Open 沒進 top-k </div>
### `` 額外的指示 直接在工具輸出裡告訴 Agent 下一步該怎麼搜 </div> </div> </div> </div>
40 / 111
</div>
40. 工具回傳除了 top-k,還夾帶統計與指示
我們下面舉個例子。上面是我設計的工具回傳值,假設它搜出來兩筆,這可能是一個專案管理系統,搜出來兩筆是已經完成的 Done 的資料。那我下面其實還有一個欄位是告訴它總共 Done 的有六筆、總共 Open 的有五筆。 所以我不只告訴它我搜出來的那兩筆,我還告訴它統計的資訊。我下面還有一個額外的資料告訴它說,你搜出來的兩筆都是 Done,但是還有五筆是 Open 的,你可以修改你的搜尋條件再搜。 重點就是說我們可以除了回傳搜尋結果之外,我們還可以夾帶指示以及夾帶統計的資訊,幫助 Agent 去理解全貌跟決定他的下一步行為。
</div> ---
## 語意 judge: 把回饋交給另一個模型 呼叫另一個模型做 review,把回饋當 tool response 帶回來。從主迴圈看,這仍是一次普通的 tool call。 ```python @function_tool async def consult_model(question, files, model): """遇到難題、想確認方向、或要 review 產出時呼叫, 交給另一個模型給獨立回饋。""" ... ``` 例如: RAG Agent 生成答案後,用另一個模型檢查有沒有幻覺。
41 / 111
41. 語意 judge:把回饋交給另一個模型
語意的 judge 就是在工具裡面我們呼叫另外一個模型來做 review。比較常見的例子可能是 RAG 的 Agent 生成答案之後,我們用另外一個模型檢查他有沒有幻覺。
---
## 案例: Claude Code + Codex plugin 這種做法在 coding agent 上也蠻常見
`/codex:review`: Claude 把本地 git 改動交給 **Codex(GPT)** 做 code review,並說明「只做 review、不准順手改」。一個寫 code、一個分析審查。
這是人工觸發,也可以寫進前饋規則,說明「在流程中何時、遇到哪類情況就呼叫」
42 / 111
42. 案例:Claude Code + Codex Plugin
這個案例其實在 Claude Code 裡面有一個 plugin 叫做 Codex plugin,就是你可以在 Claude Code 裡面裝這個 plugin,然後叫 Codex 幫你 code review,其實也是叫另外一個模型來做 review。
---
## 工具層 Harness 的設計原則
### 1️⃣ 能確定性檢查最好 例如 SQL 語法驗證用 SQLGlot,又快又穩
### 2️⃣ 語意判斷才用 LLM Judge 細緻品質好不好沒有確定性 assert 可寫, 使用 LLM judge 補規則型檢查的不足
### 3️⃣ 回饋最好可行動 錯誤訊息要附「該怎麼辦」,不是只丟一個程式 error code。
### 4️⃣ 延遲預算內完成 工具層回饋在 tool call 內發生,要注意 latency,別拖慢整個迴圈。
43 / 111
43. 工具層 Harness 的設計原則
總結一下工具層的 Harness 設計原則: 1. 能確定性檢查當然是最好,因為速度比較快,又快又穩。 2. 然後如果真的需要語意判斷的時候,我們才會在裡面再塞一個 LLM 的 judge。 3. 第三個是回饋最好是可行動的,就是工具的回傳除了回傳的資料之外,還可以告訴 Agent 下一步怎麼做。 4. 然後第四點就是設計工具的時候要考慮到 latency,畢竟是工具這一層的話,我們不希望裡面會花太多的時間在單一的 tool call,不然整個 latency 會很長。
---
PART 4 · 時機 ② # 兩次 model request 之間,
把訊息注入執行中的 agent
44 / 111
44. Part 4 標題頁
(時機 ② 兩次 model request 之間,把訊息注入執行中的 Agent)
---
## 這個時機在哪:兩次 model request 之間 一輪 (Turn) 不是「一問一答」,而是「模型 request → tool calls → 模型 request → …」反覆,直到輸出答案。注入就發生在這個迴圈內部、**還沒輸出答案前**: 一輪 Turn (agent 還在進行中) ↓ 在這裡注入訊息 (人 steer 或程式) 模型 request 1 🔧 tool calls 模型 request 2 🔧 tool calls 模型 輸出答案 (還沒到) 注入發生在每個「tool calls → 下一個 model request」之間 (圖中標記處) agent 還沒到「輸出答案」這一步,就把新訊息插進這一輪
不是等 agent 執行完才注入(那是時機③單輪結束),而是在它還在迴圈中間、還沒輸出答案時就插進去。來源可以是人 (steer),也可以是程式。
45 / 111
45. 這個時機在哪:兩次 model request 之間
接著我們來看第二個時機點,就是在 agent 一輪之內,兩個 model request 之間,可以把訊息注入這個執行中的 Agent。這時機點在哪裡?所謂的一輪,其實內部是連續的工具呼叫,而在工具呼叫之間,我們有一個時機點可以插入訊息給 AI。 注意到這個時候 AI 還沒有回傳給你最後的答案,他還在執行過程,是要我們主動插進來訊息。
---
## 同一個注入點,兩種用途 Agent 還在反覆呼叫工具、還沒輸出答案時,就把新訊息插進去,馬上影響它接下來的動作
### 🧑 用途一: 人中途 steer 使用者就主動輸入一段話介入,叫做 **steering** 轉向/引導。 在 **Codex、Claude Code** 這類互動式 coding agent 最常見,是內建功能。
### ⚙️ 用途二: 程式注入 例如背景工具程式跑完送回結果、外部事件 (webhook、告警) 要讓 agent 知道。 目前**較少框架實作**,少數像 **Pydantic AI** 做成通用機制。
46 / 111
46. 同一個注入點,兩種用途
這比較常見的現在有兩個用途。第一個是人中途去插進去的,最常見的是你在 Claude Code 或者是在 Codex 裡面,如果 AI 還在輸出,你開始打字,他就會加入一個 queue 的排程。但是 Codex 他不會馬上插入,他後面有一個小小的字叫做「引導」,所以你點了引導之後他才會用這個 steering 插進去,不然的話他那個只加入排程,他會等到全部最後輸出完之後才放進去。 那第二個用途是程式的注入,就是如果我們做一個跑背景的 job、背景的工具的時候,我們可以用這個方式在背景 job 工具執行完之後盡快的把工具結果插進來。
---
## 只能在 requests 之間: 這是 API 後端的限制 已經發出 tool calls 但還沒拿到結果,這時若添加 user message 回傳,API 會錯誤
### ❌ 不合法 assistant 發了 tool calls → 還沒等到所有工具結果 → 直接加 user message 回傳。下一個 request 送出就 400。
### ✅ 合法 assistant 發了 tool calls → **每個 call 的結果都補齊** → 再加 user message → 下一個 request。
OpenAI、Anthropic 模型發出的每一個 tool call 都必須先補上對應結果,中間不能插別的訊息。所以必須等當前 tool 全部執行完、湊成 API 合法狀態,才能在下一個 model request 之前注入你的訊息。
47 / 111
47. 只能在 requests 之間:這是 API 後端的限制
這裡有一個小小的注意,就是說它只能在 request 之間。AI 叫我們執行工具 ABC,我們一定要回傳工具的結果 ABC 才能夠插這個東西,你不能說工具執行沒有結果你就插入這個訊息,API 會跟你報錯。所以這是 API 後端的限制,OpenAI、Claude 都是這樣子的。
---
## 用途一: 人中途 steer 最常見的用途是人主動介入。steering 和 interrupt 都是 **Codex、Claude Code** 的內建功能。這跟 human-in-the-loop 不一樣:
### 🛑 Human-in-the-loop 你**刻意設計一個等待點**,讓 agent 跑到那裡停下來問你 (最典型: 執行某工具前先請使用者確認)。 是 **agent 停下來問你**。
### 🧭 Steering agent **沒有等待點、也不打算停**,是你在它還在執行時主動輸入 (通常因為「需求變了」)。 是**你主動介入**。
48 / 111
48. 用途一:人中途 steer
剛剛有提到一個用途是人中途插進去,那這個跟 human-in-the-loop 是不一樣的。通常我們講 human-in-the-loop 是我們刻意設計一個等待點,讓人類來回答,比如說你在工具裡面設一個等待點,有一個 UI 等用戶輸入才下一步,這個叫 human-in-the-loop。跟我現在做的 steering 是不一樣的,現在這個是 Agent 沒有等你的,他也沒有打算停的,是你要主動介入的。
---
## 當用戶中途輸入訊息時,還可以細分兩種: steering 與 interrupt
### 🧭 不中斷: steering 訊息先排進佇列,等當前 tool calls 結果到齊、正要發下一個 model request 前才注入。 agent 沒中斷,只是下一步多了你的訊息,**已建立的 context 全部保留**。
### 🛑 強制中斷: interrupt 取消正在執行的工具,沒答完的 tool call 硬塞 `tool_result`,內容是固定字串 `aborted` ,維持對話 API 合法。
49 / 111
49. 當用戶中途輸入訊息時,還可以細分兩種:steering 與 interrupt
那細分的話其實還有可以分兩種:不中斷的是 steering,他會等到這一批工具執行完拿到結果之後才插入。另外一種是真的強制中斷的,連工具我都不想要執行我就想要插進來,這種比較少見。 而且我剛才不是說工具沒有執行完不能插入嗎?那要怎麼辦?如果你真的要強制中斷的話,我們得塞一個假的工具回傳值叫做 aborted(放棄),你得在 API 的訊息裡面跟他說這個工具的執行結果是放棄的。塞了放棄之後你才能塞用戶的訊息進來,這是強制中斷。
---
## 用途二: 程式注入 用途常見有:
### 🔧 背景工具結果 長時間工具在背景跑完,把結果送回 agent。
### 📡 外部事件 webhook、錯誤告警、聊天平台訊息主動送進來。
有提供這個注入點的框架不多: OpenAI Agents SDK、Google ADK 都沒有。少數例外是 Pydantic AI v1.101.0(2026 年 5 月)的 enqueue,兩種模式: asap(盡快插入,就是這篇的時機點)與 when_idle(整輪結束後才插入)。
50 / 111
50. 用途二:程式注入
程式注入另外一個用途,假設你有一個背景的工具結果想要插進來,或是外部事件等等想要盡快插進來的話,他要怎麼做呢? 首先如果你想要做一個背景工具的話,你第一次 call 工具的時候,因為我們想要把它丟到背景去跑,所以第一次的 call 工具它的回傳值會是說這個東西已經被丟到背景去跑了,然後工具執行就結束了。
---
## 背景工具結果怎麼送回 agent 它分兩步:
### 第一步: 當工具被呼叫時 tool call 後不等跑完,馬上回 `tool_result`,內容是固定的:
Tool 'X' is running in background (task N). You will receive the result automatically when it completes.
### 第二步: 當背景任務完成時 只能用 user message 插入:
Background tool 'X' (task N) completed. Result: …
注意不能用 `tool_result` 訊息了,因為 API 的 tool call 跟 tool result 是一對一配對的。
51 / 111
51. 背景工具結果怎麼送回 Agent
那第二步是當我的背景 job 跑完的時候,我要插進來的時候,這時候你已經不能用工具的回傳值,不能放在 tool result 的 message,因為工具的執行跟工具的結果那個訊息是一對一配對的。所以工具執行完的時候你不能再用 tool result,我們只能用這個時機點,用 user message 插進來,把工具的結果用 user message 的形式插進來,這是蠻特別的。
---
PART 5 · 時機 ③ # 單輪結束的
Goal 與 Outcomes
52 / 111
52. Part 5 標題頁
(時機 ③ 單輪結束的 Goal 與 Outcomes)
---
## 單輪結束的時機 ③ Agent 連續呼叫工具後,最後輸出文字答案時 ④ 外層 Loop · 每個 session · 分鐘~小時 · 修正整個任務 ③ 一輪 Turn · 秒級 使用者輸入 模型 request 1 🔧 tool calls 模型 request 2 🔧 tool calls 模型 輸出答案 ② request 之間注入 (人 steer 或程式) ① 工具執行內 · 修正單一動作 Stop hook 沒過 → 同份 context 再跑一輪 一輪 (Turn) = 多次「模型 request → tool calls」反覆,直到模型輸出答案 ④ 通過後這個 session 收掉,換上全新 context 再跑一圈
53 / 111
53. 單輪結束的時機 ③ 圖解
我們看一下每輪結束的時機點。這個時機點會在於每一輪 AI 他想要呼叫的工具都呼叫完之後,他要輸出完最後的答案、文字答案之後的這個時機點,也就是第三個時機點。
---
## 設計 Goal 可驗證的停止條件,強迫模型自動再一輪
給 Agent 一個目標: - 希望的**最終狀態**是什麼 - 用什麼**證據**驗證 - 有哪些**限制**要遵守 讓 Agent 持續修正,直到通過為止。 這是 Codex 和 Claude Code 的內建功能。
### 核心精神 > 不能因為「模型**覺得**大概做完了」 > 就算數。 完成與否,要對著**停止條件**驗證, 沒過就繼續做。
54 / 111
54. 設計 Goal 可驗證的停止條件,強迫模型自動再一輪
這個功能在最近在 Codex 跟 Claude Code 都是一個新的內建功能,它叫做 Goal,就是你可以用一個斜線 Goal,然後去設定它一個可以驗證的停止條件。如果它沒有滿足那個條件的話,它就會強迫模型再跑一輪。 所以我們會給 Agent 一個目標,描述我們希望的最終狀態、用什麼證據去驗證、有哪些限制需要遵守,然後讓 Agent 強迫去跑讓它直到這個條件通過為止。
---
## Goal 合約模板 好的 Goal 不一定是更長的 prompt,而是一份**精簡的契約**: ```text /goal ← 期望的最終狀態 verified by ← 用什麼證據驗證 while preserving . ← 同時要保住什麼 Use <allowed inputs, tools, boundaries>. ← 允許的工具與邊界 Between iterations, . If blocked or no valid paths remain, . ```
範例:「將 p95 latency 降到 120ms 以下,用壓力測試做驗證,並保持測試套件都要通過」
🤖 **讓 AI 幫你寫**:任務夠清楚時,直接 `Help me turn this into a strong /goal: <任務描述>` </div> </div> </div>
55 / 111
</div>
55. Goal 合約模板
好的合約模板大概講這樣子,它算是一份精簡的契約,這出自 OpenAI 的 Cookbook。如果不會寫的話,其實現在都叫 AI 寫,你就跟他說請幫我把我的任務描述轉成一個 strong Goal,它就幫你轉成上面的形式。
</div> ---
## 不適合用 Goal 的時候
### ❌ 完成條件模糊 - 「把這個變得**更好**」 - 「**重構**這段程式碼」 沒有可靠的完成條件,
### ✅ 先定義,再開工 - 預期的**最終狀態** - 驗證用的**測試** - 要保住的**限制** 定義不出來?那問題不在工具, 在你還不知道自己要什麼。
56 / 111
56. 不適合用 Goal 的時候
這邊是不適合用 Goal 的時候,就是條件模糊的時候比較不適合,如果你能夠清楚地定義的時候會比較適合。
---
## 使用者的角色轉變: turn → round
藏在 Goal 背後的,是交付物的轉變: - 你交付的不再是一句 **prompt**,而是一份「**目標 + 邊界**」的契約 - 然後讓 Agent 持續去跑: **prompt → 判斷完成沒 → 再 prompt** 讓 agent 繼續做 - 思考單位,從「一次對話 **turn**」換成「一輪工作 **round/loop**」
### 那這迴圈怎麼判斷「做完了沒」? 有各種不同實作,讓我幫你分析。
57 / 111
57. 使用者的角色轉變:turn → round
所以我們使用 Goal 的時候會有一個角色的轉變,變成說我們設計每個 turn 變成每個 run,你交付的不再只是一個 prompt,而是一份目標跟邊界的一個契約。因為我們會讓 Agent 持續去跑然後讓他得到最後的結果。所以思考單位變成從單一的 turn 變成一輪的工作的感覺。
---
## 深入研究三種產品實作,沿著「驗證的 Judge 有多獨立」來看
### Codex 的 Goal 由**主模型自我審計**,自己呼叫 `update_goal` 宣告
### Claude Code 的 Gooal 每輪結束,交給獨立的 **Haiku** 小模型裁決
### Claude Managed Agents 的 Outcome 由獨立的 grader agent 拿 rubric 評分標準,去檢查產出物做驗收
58 / 111
58. 深入研究三種產品實作
那關鍵就是他到底怎麼判斷東西做完了沒。所以這裡有三種不同的實作。我深入研究了三種不同的產品實作:Codex 的 Goal、Claude Code 的 Goal,以及第三個是 Claude Managed Agents 裡面有一個 Outcome 的功能。 這三種其實都看起來好像一樣,但其實實作上蠻不一樣的,我帶大家來解析一下。
---
## 實作一: Codex /goal,沒有裁判的自我審計 Codex 沒有第二個模型在做判定,是自我審計
### Agent loop 像是確定性狀態機 - 當判斷完成時,主模型呼叫 `update_goal(complete)`更新狀態 - 如果狀態還是 Active,就重新注入同一份 continuation.md prompt 強迫 Agent 繼續跑下一輪
### 判定者就是主模型自己 - 完成 = 模型呼叫 `update_goal(complete)` - Agent 帶著完整的對話紀錄和推理脈絡繼續下一輪
59 / 111
59. 實作一:Codex /goal,沒有裁判的自我審計
第一個是 Codex Goal,它其實是沒有第二個模型在做判定的,它其實是自我審計的。這個 Agent loop 它其實有點像是一個確定性的狀態機,它有一個工具叫做 update_goal,就是模型認為它已經完成的時候就會呼叫這個工具 update_goal 把狀態改成完成。 所以當它判斷狀態是完成的時候它就脫離回圈回傳最後的答案。如果它判斷還沒有完成的時候,它會強迫注入一個叫做 continuation 的 prompt,就是如果它沒有完成它會強迫注入一個叫它繼續做事的 prompt。 這個繼續做事的 prompt 裡面: 會去要求說請再去找更多的證據來去證明我的目標已經完成了,請你再去找證據、請你再去做事情讓它下一輪能夠做完。所以如果它判定它沒有做完的時候,它其實是強迫硬塞一個 user message 就是 continuation prompt 塞進來讓它再跑下一輪。 在 Codex 裡面這個判定者就是主模型它自己,它判定的材料是 Agent 自己的完整的對話紀錄跟推理脈絡。
---
## Codex /goal:自我審計迴圈 update_goal(complete) ✅ 注入 continuation.md 每輪同一份合約 prompt 主 agent 跑一輪 推理 + 工具呼叫 自我審計 達成目標? 否: 沒呼叫 update_goal → thread idle 且 goal.status = Active → 再注入 判定者就是主 agent 自己, 全程沒有第二個模型
60 / 111
60. Codex /goal:自我審計迴圈圖
大概的流程就是從中間開始主 Agent 跑一輪之後,它會自我審計,如果它沒有達成目標的話它會再注入這個 continuation prompt 強迫它再跑下一輪,直到它最後更新它的狀態就出去了。這是 Codex。
---
## Codex 怎麼防「過早宣告完成」 判定權在主模型手上,Codex 用 prompt 要求以「當前 worktree 與外部狀態」去自查
### Tool description update_goal 的 description 寫好寫滿: > Set status to `complete` **only when the objective has actually been achieved** and no required work remains.
### 每輪注入的 Continuation prompt 要求模型逐項找證據: > "treat completion as **unproven** and verify it against the actual current state" > "The audit must **prove** completion, not merely fail to find obvious remaining work" 每輪注入的 prompt 都一樣 (只有 Budget 數字不同)
61 / 111
61. Codex 怎麼防「過早宣告完成」
那它怎麼防範它過早宣告完成呢?一個是透過它的 continuation prompt,一個是它的 tool description 也會寫好寫滿,就是說你必須要在目標完成的時候才能夠呼叫這個工具。
---
## 別只看名字,要看實作
### 流傳的誤解 有些技術文章寫: Codex 的 Goal「用一個獨立小模型每回合評分」
### 翻原始碼跟文件才知道 沒有第二個 model、沒有額外的 grader
harness 的實作細節,不能靠幻覺想像那是怎麼做的
62 / 111
62. 別只看名字,要看實作
所以這個就是不能只看名字要看實作。有些坊間的技術文章可能會寫說 Codex Goal 用一個獨立的小模型每回合評分,看到獨立的小模型這邊文章我就會打算跳過了,因為它根本沒有在看技術的實作。很多 Harness 的技術細節就是不能靠幻覺想像是怎麼做的,還是要看一下它的文件,最好能看到它的 source code。
---
## 實作二: Claude Code 的 Goal,獨立 Haiku 讀刪減 transcript Claude Code 把判定交給**另一個模型**。當主迴圈(Opus)輸出答案時,harness 不交還控制權,而是發一個 request 把整段對話交給一個獨立小模型來審計 (類似 fork): ```text Based on the conversation transcript above, has the following stopping condition been satisfied? Answer based on transcript evidence only. ```
⚠️ 注意: 這只會看對話紀錄,審計是不會呼叫工具打開檔案、實際檢查 artifact 產出物
</div> </div>
63 / 111
</div>
63. 實作二:Claude Code 的 Goal,獨立 Haiku 讀刪減 transcript
那第二個我們來看 Claude Code,也滿有趣的。它的判定是交給另外一個模型,通常我們主模型可能是一個 Opus。所以當它輸出答案的時候,整個 harness 還不會交還控制權,而是它會發另外一個 request,把整段對話交給一個獨立的小模型來做審計,有點像類似 fork 的概念。最後它覺得要判定要不要輸出最後答案的時候,它會 fork 出來,然後用一個小的 Haiku 模型來去判定。 那中間那一塊就是它判定的 prompt,就是說: 請基於這個對話的 transcript 然後以及我的停止條件,來去判斷說是不是有足夠的證據可以結束。
</div> ---
## Claude Code /goal 的三個細節
### 獨立的小模型 預設 **Haiku**,用另一份 system prompt
### transcript 是重組副本 保留對話紀錄、工具呼叫紀錄,**移除** thinking、移除整包 claudeMd 環境、tool metadata 等
### structured output 回覆 `{ok, reason, impossible}`,包括回饋理由,以及是否不可能辦到(此時應該放行,避免無窮迴圈卡死)。
### 判「是」 目標完成,把最後答案輸出給你
### 判「否」 擋下,把 Haiku 寫的 `reason` 注入主 agent,強迫跑下一輪
64 / 111
64. Claude Code /goal 的三個細節
特別要注意的是它只會看對話紀錄的,這個審計是不會打開工具、不會用工具去打開檔案再去查東西的,它只會看傳進來的 transcript 對話紀錄而已。 所以精確來說是判定交給另外一個模型、另外一個 prompt、發一個 request 去檢查。不是另外一個 Agent 去檢查,不一樣。另外一個 Agent 的意思是說那個 Agent 有工具可以去查,不是,它只是一個 request 去查而已。 它查的東西是 transcript,是一個重組的副本,它有保留原先的整個對話串、工具的呼叫紀錄,但是裡面是沒有 thinking 推理脈絡的。就是原來的主 Agent 裡面的 thinking 區塊是被剝離掉的,跟剛才 Codex 不一樣。剛才 Codex 是自我審計的時候整個對話紀錄是包含 thinking 的,這個是 thinking 被剝除的。它也移除掉整個 Claude Code 的環境,就是它不能執行工具的,所以它不會有工具的列表等等。 那它最後的回傳值會回傳是不是 OK、以及原因,以及還有一個蠻有趣的是 impossible, 是不是這個目標不可能辦到。因為有可能這個目標不可能辦到嘛,那它就會無窮迴圈了,所以它也蠻有趣的設計一個 impossible 的判斷,如果 impossible 的話它就脫離迴圈了。
---
## Claude Code /goal:Haiku 裁判流程 主 agent 跑一輪 (Opus) 自認達成, 要結束 Stop hook 攔下結束 複製刪減版 transcript (剝除 thinking) 獨立 Haiku 裁判 另一個模型, 只讀 transcript ok: true ok: false 目標完成, 交還控制 ✅ goal 達成 reason 注入回主 thread 針對性診斷 → 主 agent 繼續下一輪
65 / 111
65. Claude Code /goal:Haiku 裁判流程圖
這是它的裁判的流程,從左上角主 Agent 進來,輸出答案的時候進到 stop hook 攔下來,然後用獨立的 Haiku 去判斷。如果判斷失敗的話就是它會再把那個 reason 注入進來,然後強迫它跑下一輪。
---
## 判「沒完成」之後,兩家差在哪 | | Codex /goal | Claude Code /goal | |---|---|---| | **回饋形式** | 重播同一份 continuation.md,只有 budget 數字在動 | Haiku 寫的針對性診斷,指出 transcript 缺了什麼 | | **下一步依據** | 環境證據(測試失敗、compile error等)+自己保留的 reasoning | 外部裁判指出缺口 | | **成本代價** | 每輪多累積一份 prompt,但會有 prompt cache | 每輪多一次 Haiku call,主 thread 只增加一小段 reason | | **失效模式** | 模型有盲點時無外部視角打破,可能連錯好幾輪 | Haiku 誤判:會被自信的收尾語言騙過 |
66 / 111
66. 判「沒完成」之後,兩家差在哪
所以這是這兩家的差別,它們在回饋的形式、下一步的依據跟成本代價跟失效模式都有所不同。
---
## 實作三: Claude Managed Agents 的 Outcome
第三種最為獨立,獨立 Agent 拿著 rubric 操作 artifact 做檢查: - Grader 在**全新 context window**:只拿 rubric 與產出物,**看不到主 agent 的推理與敘事** - 不只「看」:而是有工具操作,可以像真實使用者**實際操作** artifact 產出物,開檔、點 UI、打 API、查 DB 等 - Rubric **逐條可評分**;沒過就帶著**逐條缺失**進下一輪 - `max_iterations` 預設 3、最多 20
### Rubric 評分條件 範例 ```markdown # Outcome: 研究報告完成 - [ ] 涵蓋 7 項必查數據,各附來源 - [ ] 每個引用 [n] 連到有效 URL, 且原文逐字支持該主張 - [ ] 財務數字出自 10-K / 10-Q 正式文件 ```
67 / 111
67. 實作三:Claude Managed Agents 的 Outcome
接下來看實作三。這三種實作,我是根據獨立性來區分的,而這個是最獨立的。 這個是真的有一個獨立的 Agent,拿著我的 rubric 的評分條件去做操作的。所以它是一個全新的 grader Agent,拿著全新的 context window,它只看它的評分標準跟最後的產出物。它完全不看 transcript,完全不看主 Agent 的對話紀錄,什麼都不看,它只檢查最後的產出物而已。它是一個獨立的 Agent,有工具可以去操作的,可以打開檔案去看、實際去跑跑看、開瀏覽器等等,就看你怎麼設計。所以這是最為獨立的。
---
## Outcome:獨立 grader 操作 artifact 主 agent (generator) artifact (檔案 / app) 獨立 grader agent 全新 context + rubric 產出 拿 rubric 操作 點 UI / 打 API / 查 DB satisfied needs_revision 交付 ✅ 逐條缺失回饋 主 agent 再改一輪 裁判完全獨立: 不看 transcript, 直接對成品逐條驗收
68 / 111
68. Outcome:獨立 grader 操作 artifact 圖
所以這是獨立的流程圖,主 Agent 產出來一個 artifact,然後右邊獨立的 grader 再去評分它。
---
## 相比自評,獨立驗收是最準確的
### Agent 會自我吹捧 要 agent 評自己做的東西,它傾向**自信地稱讚**,哪怕在人眼中品質明顯普通。 而且 context 裡的錯誤推理會**不斷累積**,前面說服了自己「方向對」,後面就一路錯下去。
### 問題在於「誰來批判」 同一個 agent 較難對自己的產出下得了手,換一個全新 context 獨立評審,比較容易做出準確的 Judge。
「調出一個挑剔的獨立 evaluator,比教會 agent 自我批判容易得多。」
69 / 111
69. 相比自評,獨立驗收是最準確的
相比自評的話如果我們要看準確性,獨立的當然是最準確的。因為我們都怕 Agent 會自我吹捧,所以問題就在擔心說是誰來批判。 如果是自己評自己就比較容易自我吹捧,如果是獨立評的話就是比較容易做出準確的 judge。就是對工程師來說,調出一個挑剔的獨立的 judge 是比讓它自我批判容易的。
---
## 學界研究表示: 越獨立、越會動手,判定越可信
### 自我評審 - **純自我修正**: 缺乏外部回饋時容易失敗 - **只讀文字的 judge**: 偵測假性完成(false success)能力有限,容易被「自信的收尾語言」帶著走
### 獨立評審 - **環境/執行回饋**: 看測試與執行結果,不看語言宣稱 - **rubric 分解**: 把驗收拆成逐條標準 - **Agent-as-a-Judge**: 能讀檔、跑指令的裁判,可靠度接近人類
越往獨立、越會實際操作的那端,判定越可信。
70 / 111
70. 學界研究表示
學界研究也表示有蠻多 paper,就是自我評審的問題以及獨立評審的好處等等。
---
## 三種實作的總比較 | | Codex 的 Goal | Claude Code 的 Goal | Claude Managed Agents Outcomes | |---|---|---|---| | **誰來判定** | **主模型自我審計** | 獨立的 Haiku | 全新 context 的 grader agent | | **harness 角色** | 不判斷,閒置時重播合約 prompt | 每輪結束送 transcript 裁決 | 自動配置 grader 評估迴圈 | | **看什麼證據** | 自己 context 裡的一切(含 reasoning) | **刪減版 transcript** | **只看 artifact,實際操作驗收** | | **怎麼宣告完成** | 主模型呼叫 `update_goal` | yes/no +診斷 reason | rubric 逐條 pass/fail | | **沒完成時的回饋** | 沒有診斷,只重播同一份模板 | 一段針對性診斷,指出缺什麼 | 逐條列出缺失,最具體 |
獨立性: Codex Goal < Claude Code goal < Managed Agents Outcomes
71 / 111
71. 三種實作的總比較
所以這是三種實作的總比較。關鍵就是 Codex 它是自我審計,然後 Claude Code 中間那個是雖然是獨立的,但是它是讀刪減版的 transcript,右邊那個是完全獨立的 grader。所以獨立性來說是右邊大於中間大於 Codex。
---
## 但是對工程師來說,一切都有 tradeoff: 成本和獨立性的代價 獨立性換來可靠度,但要付出代價。差別不只是「單次評估多少錢」,也要看「錯誤多久才被發現」 | | 獨立性/可靠度 | 單次評估成本 | 錯誤多久被發現 | |---|---|---|---| | **Codex 自我審計** | 低:主模型自評 | 趨近零:只查狀態 | 靠模型自己就先發現 | | **Claude Code Haiku** | 中:獨立小模型讀 transcript | 小:約 1-2 秒 | 每 turn 一次 | | **Outcome grader** | 高:獨立 agent 操作 artifact | 高:數十倍、約 8 分鐘 | 整個 iteration 做完才抓到 |
越獨立越可靠,但需要用到更多 tokens 來分析,錯誤也是在整個流程中越晚被發現,導致總成本較貴也較慢
72 / 111
72. 成本和獨立性的代價
但這樣講起來好像 Codex 是最差的,看來獨立性好像很好。但是對工程來說一切都是有 tradeoff 的。你的獨立性帶來就是成本的代價,你獨立性可以有很好的可靠度,但是你要換來代價。代價是什麼?token 成本以及 latency,越獨立它的 latency 就越慢,以及花費的 token 數就越多。 所以當然我們評估的不只是單次評估多少錢,也要看錯誤多久會被發現。你越獨立的話其實整個錯誤會在整個迴圈的越尾端才會被發現。你如果越自我審計的話,Codex 其實就會自己可以比較早發現錯誤。所以這跟成本有關係。
---
## OpenAI Codex goal 為什麼不用獨立裁判?
### 有兩層可以裁判: - **harness 層**: 用獨立裁判,就像 Claude 作法 - **模型層**: 要靠模型本身的驗證、自我審計能力行不行
### 我個人推測 - 我推測 OpenAI 有特別加強 update_goal 的 post-training 模型訓練,強化模型自我審計的能力 - **比較節省執行 tokens 的總成本**
兩家方向不同: OpenAI 偏向加強模型訓練 goal、把自評 prompt 寫好。Claude 則用 harness 層的獨立裁判來做。
73 / 111
73. OpenAI Codex Goal 為什麼不用獨立裁判?
這邊是我自己的一些推論,就是 Codex 的 Goal 為什麼不用獨立裁判呢?因為裁判其實有兩層,我們可以在 harness 層用獨立裁判,或者是完全的靠模型來做自我審計。 我個人的推測是 OpenAI 有特別加強它的 update_goal 的 post-training 模型訓練,一定有針對這件事情加強它自我審計的能力它才能夠表現得這麼好。它帶來的好處就是能夠比較節省 token 的總成本。這是我個人的推論。
---
## 如果是自行開發 agent,該怎麼選
### 自我審計(Codex 式) 調教難度較高。高度依賴模型的自律,一般模型容易過早宣告完成。 適合: 重視 Latency 和成本的中短任務。
### Transcript 裁判(Claude Code 式) 折衷做法。小模型判 transcript,好實作、好評估(輸入輸出都是文字)。 適合:中程任務,在 transcript 中就能看到可信的證明。
### 獨立 verify(Outcome 式) 效果最好,但成本最高、latency 是最大弱點。每次驗收要把 artifact 跑起來操作。 適合:長時間、以交付物為終點,價值高到值得花評估開銷。
74 / 111
74. 如果是自行開發 Agent,該怎麼選
所以對我們開發者來說,這幾種實作有什麼經驗的教訓呢?該怎麼選呢? 首先,自我審計的那種方式我認為調教難度是比較高的,因為它高度依賴模型的自律,我們又不是 OpenAI 可以訓練自己的模型,所以如果你自己做自己的專案然後要用自我審計的話,難度還是比較高的,它可能比較適合重視 latency 跟成本的中短任務。 claude code 的做法是我比較推薦的,就是算是折中的做法,用一個獨立的小模型去判它的 transcript,比較好實作也比較好評估。 完全獨立 verify 這種是完全獨立的,效果最好但是成本也最高,latency 會非常的慢。
---
## 綜合案例: 使用者訪談 Agent,結合兩家的做法
需求: 按訪綱逐題訪問用戶 挑戰: 但什麼時候該換下一題?這題問夠了沒? 模型會偏向「覺得差不多了就想往下走」,跟第二篇的**過早宣告完成**是同一個問題,只是這裏是「這**一題**問完了沒」。
### 我的做法 - 借 **Claude Code** 的 transcript judge 把關「這題問夠了沒」 - 借 **Codex** 每輪重新注入 prompt 的做法,讓訪談持續往前
75 / 111
75. 綜合案例:使用者訪談 Agent,結合兩家的做法
所以這邊有一個綜合的案例是我自己實作的,就是我在做一個使用者訪談的 Agent。需求就是它會按照訪綱逐題去訪問用戶,例如問說: 你覺得這網站你最常用的情境是什麼,第二個問題可能是你覺得這個品牌對你的印象是什麼,最後會有一個訪綱。 所以你如果設計 Agent 去做訪問用戶的話,這個挑戰就是什麼時候會換下一題、這一題問夠了沒。因為我們不希望一問一答然後就跳下一題,如果被訪問的人回答得太模糊的時候我們希望 AI 能夠追問。但問題是這個追問到底追問幾次或者是追問到什麼樣的程度才可以換下一題,以及我還有時間控制,整個訪問要 15 分鐘要做完,我要分配到 5 題裡面。所以這裡面需要一些 AI 的判斷。
---
## 借 Claude Code 的做法: 提供換題工具,裡面做 transcript judge agent 想跳下一題時,呼叫 `switch_next_question_workflow` 工具,裡面是一個獨立 Judge 審核: ```python @function_tool async def switch_next_question_workflow(reason: str, user_requested_next: bool) -> str: """當你判斷目前這題已取得足夠答案、或使用者要求跳題時呼叫。""" # 真正的判定在 server 端,工具只是把請求轉過去 ... ```
prompt 寫說:「回傳 Y/已切換才代表進到下一題」、「回傳 N 你 MUST 繼續聚焦同一題,換問法追問」
76 / 111
76. 借 Claude Code 的做法:提供換題工具,裡面做 transcript judge
我的做法是我借鑑了這兩個實作的兩個招數。第一個是我借鑑了 Claude Code 的做法,就是我提供一個換題的工具,在裡面我會做 Transcript Judge。就是每次 Agent 判斷他收集到足夠的資訊要換下一題的時候,我會要他去 call 這個工具叫做 switch_next_question。 在這個工具裡面我會用一個獨立的 prompt 去檢查 transcript 是否滿足條件可以跳到下一題。回答 yes 的話他才會換到下一題,如果回傳 no 的話我的指示會跟他說請你繼續聚焦在這一題,換個問法繼續問。
---
## Judge 看什麼: 每題有不同的 rubric,根據逐字稿判斷 不同題目有不同的完成標準(rubric),用小模型根據逐字稿來判斷:
```python QUESTION_WORKFLOW = [ { "title": "最近一次使用情境", "completion_criteria": "需含最近一次使用的具體情境," "至少提到使用的功能與當時任務。" }, { "title": "替代方案", "completion_criteria": "需提到至少一個替代方案," "最好指出最常用者與原因。" }, # …其餘題目 ] ```
```text You are a user interview quality reviewer. Use only the transcript below. Do not infer facts that are not in the transcript. Current question: {question} Completion criteria: {completion_criteria} Transcript: {transcript} Return exactly one character: Y if complete. N if not. ```
77 / 111
77. Judge 看什麼:每題有不同的 rubric
所以這個 judge 看什麼?當然不同題就會有不同的 rubric。我們會去看訪談稿判斷不同題目會有不同的檢查標準,我們就會用不同的 prompt。
---
## 沒過時的回傳值: 還是要可行動 Judge 回 N 時,工具不是只回一個 false,而是回一段**可行動的指令**,順便附上這是第幾次被退: ```text N: 仍停留在第 1 題「最近一次使用情境」。這是第一次追問。 請換一種問法追問目前這題,不要切換題目。 ```
78 / 111
78. 沒過時的回傳值:還是要可行動
如果 Judge 沒有通過,我會提示他要繼續追問,而且我還會提示他這是第幾次被退。我有設計說如果被退了三四次的話就算了,就放棄就跳下一題吧,不然他可能會卡無窮迴圈。
---
## 借 Codex 的做法: time_control 每輪注入動態狀態 每輪推動 agent 往對的方向走: 「現在過幾分鐘了、第幾題了」的狀態也傳給 Agent ```text 已過 7 分鐘 / 共 15 分鐘 第 2 / 5 題: 題目.... ```
每輪動態注入當下狀態,提醒目前在哪一題,以及用這個訊號調節奏:時間充裕就從容追問,時間不夠了就加速減少追問。
79 / 111
79. 借 Codex 的做法:time_control 每輪注入動態狀態
另外一個是借鑑了 Codex 的做法,每一輪動態注入訊息。我在每一輪都會注入一個 time_control 的訊息,動態的狀態告訴他說現在時間過了多久、總共現在時間已過了七分鐘、總共有十五分鐘、現在在第幾題。我會提示 Agent 說如果時間充裕的話就可以追問,如果時間快到了那就要趕快跳下一題了。所以透過這個動態注入的狀態,我們可以讓 Agent 感知到目前時間的情況。
---
## 訪談 Agent:time_control 推進度,Judge 把關 time_control: 每輪注入動態狀態 (時間 / 題號) Codex 式 · 前饋: 給模型它自己算不出的當下狀態 訪談 agent 跑一輪 逐題問答 · 判斷這題問夠了沒 獨立 Judge · 只讀 transcript + 該題 rubric Claude Code 式 · 回饋: 把關「這題能不能換」 進到下一題 ✅ harness 推進到下一題 留在本題, 換問法追問 回傳可行動指令 + 第幾次被退 影響何時換題 想換題: 呼叫 switch 工具 Y: 切換 N: 留本題 下一輪 退 3 次 / 使用者喊跳 → 強制放行 time_control 推進度, Judge 把關: 一前一後讓限時訪談問得深又跑得完
80 / 111
80. 訪談 Agent 流程圖:time_control 推進度,Judge 把關
所以這是整個流程圖。我借鑑了這兩種實作的方式。
---
PART 6 · 時機 ④ # 外層 Outer Loop
81 / 111
81. Part 6 標題頁
(時機 ④ 外層 Outer Loop)
---
## Agent 輸出一輪完整答案之後 ④ 外層 Harness ④ 外層 Loop · 每個 session · 分鐘~小時 · 修正整個任務 ③ 一輪 Turn · 秒級 使用者輸入 模型 request 1 🔧 tool calls 模型 request 2 🔧 tool calls 模型 輸出答案 ② request 之間注入 (人 steer 或程式) ① 工具執行內 · 修正單一動作 Stop hook 沒過 → 同份 context 再跑一輪 一輪 (Turn) = 多次「模型 request → tool calls」反覆,直到模型輸出答案 ④ 通過後這個 session 收掉,換上全新 context 再跑一圈
82 / 111
82. Agent 輸出一輪完整答案之後 ④ 外層 Harness 圖解
接下來是 Outer Loop 最外層了,也就是剛才的時機點 3 結束、目標也達成了,接著最外層的迴圈就是展開一個新的 session、展開一個全新的 context window。
---
## 為什麼需要外層迴圈?
### 三種情況 - **① 單一 context 能力有限**: 大任務得拆段,每段用乾淨 context 重新開始、表現不受前一段影響(塞滿、失敗推理污染、Goal 跨不過 session) - **② 是另一個不相關的新任務**: 本來就該各自開乾淨 context,並管理多條平行的 agent - **③ 要由外部事件自動觸發**: webhook、新郵件、排程、CI 失敗一來就啟動
### 共同的解法 需要一個在單輪 agent 之外的工程迴圈,也就是 **外層 harness** 它決定何時觸發、每件事開獨立 agent、多條 agent 怎麼協調。 進度不靠 context 記憶,會寫到檔案系統共享。
83 / 111
83. 為什麼需要外層迴圈?
為什麼需要這個外層迴圈呢?主要是因為單一的 context 能力有限,以及我們會展開一個全新的任務,或者是我們有一個外部的事件去觸發 Agent 做事。所以會有這種需求。 那共通的解法當然就是在整個每一輪的 Agent 之外,我們還會有一個外層的 harness 去控制它什麼時候去觸發 Agent 開始做事情,每件事是不是開一個獨立的 Agent 等等。然後這個外圈的觸發通常也蠻靠 filesystem 檔案系統的,因為我們會開新的 context window,所以那個進度跟狀態要怎麼維持,通常就會用到 filesystem,我們會把狀態放到 filesystem 上。
---
## 思路: 設計提示 Agent 的迴圈
這一層最近在社群很熱門: - 龍蝦爸 Peter Steinberger:「你不該再去提示 agent,你該**設計提示 agent 的迴圈**」講了好幾個月 - Claude 的 Boris Cherny、Andrej Karpathy 大神也講過類似的話 - 最近出現 **loop engineering** 新詞
### 具體來說 其實就是強調 Outer loop (Outer harness) 這一層,讓我們看具體實作案例,拆解給你看
參考: Peter Steinberger: You should be designing loops that prompt your agents.
84 / 111
84. 思路:設計提示 Agent 的迴圈
這整個就是最近在社群上很熱門的 Loop Engineering 這個新詞。包括龍蝦爸爸有提到說你不應該再去提示 Agent,你應該設計提示 Agent 的迴圈等等。那這些其實都是在強調 Outer Loop 就是 Outer Harness 的這一層。
---
## 外層 Loop 的三種實作案例
### 🔁 Ralph **bash 蠻力重跑** 每圈全新 context,同一份 prompt 反覆送進去直到做完
### 🎼 OpenAI Symphony **看板協調器** 專案管理工具當控制平面,每張開啟的 ticket 配一個 agent
### ⏰ 自動排程 **定時觸發** 時間到就跑一輪;依 context 是否沿用,再分「獨立」與「heartbeat」兩種
85 / 111
85. 外層 Loop 的三種實作案例
我們來看看具體的案例。我這邊跟大家介紹三種:第一個是 Ralph 的暴力重跑、第二個是跟大家介紹一下 OpenAI Symphony、第三個是自動排程。讓我們分別來看一下。
---
## Ralph:最笨也最有名的 Loop ```bash while :; do cat PROMPT.md | claude-code done ``` - 一個 bash 無窮迴圈,每圈把同一份 prompt 再送進去一次 - **每一圈都是全新的 context**:每圈歸零,只從固定幾份檔案重新讀起 - **完成才跳出**:當 AI 認為所有任務都完成,輸出 `COMPLETE` 代表完成,就脫離無窮迴圈
出處: ghuntley.com/ralph(2025 就有了)
86 / 111
86. Ralph:最笨也最有名的 Loop
第一個是最笨也是最有名的 Loop: Ralph,就是你直接用一個 bash 的 while loop,然後讓它不斷的去讀這個 prompt 然後塞到我們的 Agent 就好。看起來很笨很簡單,暴力跑,每次都是重新的全新的 context window。
---
## 跨圈記憶: 進度全靠外部狀態 Ralph 拆成三個檔案:
### 📜 git history 完成的工作就是 commit, 新 agent 開圈先看歷史
### 📝 progress.txt 每圈追加學到的事: 陷阱、模式、決策
### ☑️ prd.json 任務清單與 `passes` 狀態: 每圈挑最高優先且未完成的
**ralph 的每一圈**: 讀 prd.json/progress.txt → 挑最高優先尚未完成的 story → 只實作這一個 → 跑 typecheck 和測試 → 過了 commit 標記完成 → learning 追加進 progress.txt → 下一圈。
87 / 111
87. 跨圈記憶:進度全靠外部狀態
那它什麼時候會完成呢?我們在這個 prompt 裡面會跟它說如果你認為全部任務都已經完成的話,你就輸入一個特殊的字串 COMPLETE,它就會跳出去,就這樣子很簡單。 那它是怎麼判斷目前有哪些任務以及做到哪裡、哪些算完成呢?它是靠外部的狀態,就是有三種檔案來去判斷。第一個它看 git history,第二個是它有一個叫做 progress.txt 它會去記錄學到的事情,然後還有一個列表是 prd.json 是任務清單跟目前的執行狀態。 所以這些都是外部的檔案,每次開新的 context window 就讀這些東西,判斷它要做什麼事情然後做,然後再跑,直到它認為全部都做完的時候就輸出一個特殊的字串再脫離這個迴圈。是蠻簡單的。
---
## Ralph:一圈的樣子 每圈結束 → context 整個丟掉, 開全新一圈 prompt.md 每圈用同一份 全新 context 的 agent 乾淨的 context, 跑一圈 挑一個 story 做 過 typecheck/測試才 commit 檔案狀態 (跨圈不丟) git history · progress.txt · prd.json ① 開圈先讀 ② commit、 記下學到的
88 / 111
88. Ralph:一圈的樣子圖
其實這是它一圈的樣子,重點就是它是一個全新的 context window、一個新的 Agent 在重跑,然後拿現在的外部狀態判斷。
---
## Claude Code 的 ralph-wiggum Plugin: 別只看名字,要看內部實作 名字叫 Ralph,但讀完 code,它的機制跟原版不同:
### 原版 Ralph bash 外迴圈,**每圈整個重來**:全新 context、靠檔案傳遞進度。是「**換新 context**」的設計。
### ralph-wiggum plugin 用 **Stop hook** 在**同一個 session** 內攔住結束,進行完成判定。
「同一條 thread 延續」+「完成與否主模型自己決定」= 其實是 Codex /goal 作法,而不是原版 Ralph。
89 / 111
89. Claude Code 的 ralph-wiggum Plugin:別只看名字,要看內部實作
社群上也有一個 plugin 叫做 Claude Code Ralph 的 plugin,名字叫做一樣,但是如果看它的實作的話其實跟原版的不一樣。原版是每圈重來有新的 context window,但是這個 plugin 其實是用 stop hook 在同一個 session 內攔住結果來做判定的。所以如果看 source code 的話這個東西應該更像是 Codex 的 Goal 的那種自我審計的做法。 所以名字長一樣但是做法其實是不一樣的。我覺得對工程師來說,外行人會說一樣的名詞,但是工程師自己要知道裡面的實作是不一樣的。
---
## 對 Ralph 的批評
- **無狀態重跑**: prompt 每圈不變,progress.txt 只是軟性筆記、缺結構化記憶 - **暴力跑,收斂困難**: 弱模型的權宜之計,靠大量 token 硬做、可能把關不足 - **執行成本**: 可能卡住一直耗 token
心得: 驗證 (goal) 應該在內層 harness 就要做好,而不能只靠外層一直重跑。只依靠外層既耗 token,也很難對大範圍做好驗證。
90 / 111
90. 對 Ralph 的批評
像龍蝦爸爸 Peter 對這一招的批評滿多的,因為它每一圈都無狀態的重跑,然後那個 progress.txt 是軟性的筆記、比較缺乏結構化的記憶。它更像是一種弱模型的權宜之計,靠大量的 token 去硬做,可能把關不足,也有可能卡住一直耗 token。 所以我的心得是認為驗證這件事情其實在內層的 harness 時機就應該要做好,不能全部靠外圈的 harness 一直重跑。不然你其實很難在大範圍的外圈裡面做好驗證,就會浪費很多 token。
---
## OpenAI Symphony: 把專案管理系統變成 Agent 控制系統 OpenAI 開源的 harness 外層系統(以Spec形式): 以任務為中心,將 Linear 當做控制平面,每張開啟的 ticket 都有一個 agent 在自己工作區跑(有新 ticket 就派工)
### 專案看板就是狀態機 - ticket 狀態驅動:進 Todo 派 agent、進 Rework 帶 review 重做、進終態收掉 - 任務 DAG:沒被 block 的就開 agents 平行跑 - agent 自己開 ticket、交付 **proof of work** 成果(CI、review、示範影片等)
### 人管理的是「工作」,不是 code - 有些 ticket 純調查分析,從頭到尾不碰 codebase - Agent 的目標不只是「寫完 code」,而是要「說服人類把這段程式碼合併」
91 / 111
91. OpenAI Symphony:把專案管理系統變成 Agent 控制系統
那接下來我們看第二個案例。第二個 Outer Harness 的案例是 OpenAI 有開源一個 Harness 的外層系統叫做 Symphony。它是把專案的管理系統變成一個 Agent 的控制系統。它用的專案管理叫做 Linear,就是那個專案看板。大家一定用過專案管理工具,裡面可能會有 Kanban 的看板,就是 Todo 有這些、正在進行有這些、完成有這些。 所以它把這個系統跟 Agent 是連動的,每開一張票就會有個 Agent 去做那張票的事情。就是用整個專案看板來當作狀態機去控制 Agent。Agent 如果碰到問題它就自己開 ticket,如果人去開一個 ticket 就會有個 Agent 去做事,做完事情之後它就會把做事的結果更新到那張票上面。所以人就會變成是管理工作而不是管理 code。
---
## Symphony:看板就是狀態機 🎼 Symphony: 看板當控制平面, 每張開啟的 ticket 都配一個 agent 在自己的 workspace 跑 Todo In Progress Review Done TICKET-12 待派工 TICKET-13 待派工 TICKET-9 🤖 agent A 實作中 TICKET-10 🤖 agent B 實作中 TICKET-7 PR + 證明影片, 等人審 TICKET-3 ✓ merged ticket 狀態由左往右流動 = 狀態機; 沒被 block 的各配一個 agent 平行跑
92 / 111
92. Symphony:看板就是狀態機圖
這是它大概的圖解流程,裡面就是專案管理的狀態,每張票你開下去它就會有個 Agent 去做事了。就是等於是 Agent 變成一個控制的平面。 額外一提就是它開源的這個不是開源程式碼,它開源的是 spec,滿有趣的。它不是程式碼給你,它是一個自然語言的 spec 的文字給你的。
---
## 自動排程(cron): 最輕量、最通用的觸發
設定觸發條件,條件一到就自動把一段 prompt 丟出去跑一輪。 Claude Code、Codex 都已**內建**(`/loop`、Routines、Automations),設定就能用,是最容易上手的。
### 觸發的節奏 - **定時**: cron 排程,時間到就跑 - **動態**: 讓 agent 自己決定下次何時跑 - **事件**: webhook、新郵件、CI 失敗才觸發
例如 ```text /loop 5m 檢查 deploy 狀態,失敗就修 ← 固定間隔 /loop 盯著 CI,紅了就處理 ← 動態間隔:模型自己決定 ```
93 / 111
93. 自動排程(cron)
那第三種 Outer Harness 的案例就是自動排程,也算是最輕量跟最通用的觸發方式。就是我們設定觸發條件,時間一到它自動就會把我們的 prompt 丟進去開始跑。那在 Claude Code 跟 Codex 裡面都有內建這個功能,包括 Loop、Routine、Automation 等等,這些都是這些 Coding Agent 內建的功能。
---
## 設計重點: 要不要沿用 context ?
### 每次獨立 context 每次開**全新的 agent**。乾淨 context、進度靠外部狀態。 例如 Codex 的 standalone automation 模式 、Claude Code 的 Routines 功能
### 沿用 context: Heartbeat 把 prompt 打到**同一個長駐 session**。記憶連續、反應快,但 context 會持續變大。 例如 Codex 的 thread automation 模式、Claude Code 的 in-session `/loop`功能
94 / 111
94. 設計重點:要不要沿用 context?
我剛才雖然講說 Outer Harness 只開一個全新的 context window,也就是左邊的情況: 每次觸發都開一個全新的 context window 來做。但也有另外一種做法是沿用同一個 context,那個做法叫做 Heartbeat,其實是龍蝦開始發明這個名詞然後大家就開始用了。 當我們說 Heartbeat 排程的時候指的是沿用同一個 context window。以 Codex 來說就是你左上角可以去標籤把某一個對話串標上去,然後你在設定 Automation 的時候可以跟它說我是要再沿用同一個 context window。 因為很多時候你的排程任務可能是需要之前的記憶的,你想要那個記憶一直用下去,這時候你就會用 Heartbeat 的方式。所以這是兩種排程觸發,你要去決定到底你的 context 是要沿用還是開新的。
---
## 兩種觸發:獨立 context vs heartbeat cron 觸發 時間到就跑 開新的 回同一條 每次獨立 context (cron + headless / 雲端排程) t1 全新 run 乾淨的 context t2 全新 run 乾淨的 context t3 全新 run 乾淨的 context 各自了結, 結果送出後 context 就丟掉; 進度靠外部狀態傳遞 Heartbeat: 沿用 context (/loop · thread automation) t1 t2 t3 同一條 session 一直活著 context 每次都更長 →
95 / 111
95. 兩種觸發:獨立 context vs heartbeat 圖
(圖解兩種模式)
---
## Loop 和 Goal 可以一起用 | | 管什麼 | 回答的問題 | |---|---|---| | **外層 Loop** | scheduling 排程 | **什麼時候**跑、多久跑一次 | | **Goal** | termination 終止 | 做到**什麼程度**才能停 |
### 作法一 排程內的 Agent 就直接用上 Goal 把事情做完
### 作法二 在排程內,把工作丟到某個 queue 就結束。另外有真正做事帶 goal 的 Agent 去執行
96 / 111
96. Loop 和 Goal 可以一起用
然後剛才這個 Loop——外層的 Loop 跟 Goal 是可以一起用的,這是分開的兩件事情。你可以排程的任務裡面是有 Goal 的,你可以把這兩個結合在一起。 那這有兩種做法:一個是你排程裡面的那個 Agent 就直接帶著 Goal 把事情做完;另外做法是你在排程裡面把這工作丟到某個 queue,然後你有另外一個 Agent 去從那個 queue 裡面拉出來做事。右下角的做法會是比較工程上比較 scale 的做法。 所以你這兩個東西加起來其實就會變成很多現在 Loop Engineering 的範例,就是自動的排程加上排程裡面帶有一個目標任務。
---
## 案例: 龍蝦爸爸的 Loop 自動維護 Repo Steinberger 開源的 maintainer-orchestrator skill 每隔 5 分鐘醒來執行
### 🕰️ Cron + Orchestrator 協調分配任務 - orchestrator 本身只當**控制平面**:定時檢查、派工、監控、需要時問人決策 - 每 5 分鐘 **heartbeat** 醒來讀各 worker 現況 - 實作全部下放給平行跑的 **worker thread**;worker **不准再往下委派**
### 🗂️ 先過一道 triage 分類 github-project-triage 把進來的 queue 分三類: - **Autonomous**:可重現、有界、可驗證 → 直接派工 - **Needs owner**:產品決策、安全、缺權限 - **Defer/close**:過期、重複 → 附證據處置
出處:@steipete(2026/6),skills 開源於 agent-scripts
97 / 111
97. 案例:龍蝦爸爸的 Loop 自動維護 Repo
看個案例,龍蝦爸爸就有開源他的那個自動維護 Repository 的 Skill。就是他設定每五分鐘會起來執行,他會先有一個 Skill 裡面會去拉出來有哪些事情發生了,那接著他有另外一個 Skill 去分類說這個事件屬於哪一類。就是自動的排程去幫他維護他的專案。
---
## 外層 Loop 核心三個問題
### 1️⃣ 怎麼被觸發 固定 cron、動態間隔,還是事件(webhook、新郵件、CI 失敗、看板多一張 ticket)?
### 2️⃣ 醒來看什麼 要讀哪些 context 之外的狀態,才知道進度到哪、有沒有新工作? 例如 Ralph 讀 git/progress.txt、Symphony 讀專案看板等等
### 3️⃣ 結果送去哪 開 PR、寄一封簡報、丟進 triage 收件匣,還是安靜歸檔?
98 / 111
98. 外層 Loop 核心三個問題
所以回歸到外層 Loop 核心就三個問題:怎麼被觸發、Agent 醒來之後要看什麼東西、做完事結果要送去哪裡。就這樣。
---
![w:860 loopcraft: 由內到外五層巢狀迴圈,從 token 到開放探索](loopcraft.png)
出自 Shawn "swyx" Wang 電子報,其中 loop engineering 最想強調的是第 ④ 層 MetaLoop(生迴圈的迴圈)
99 / 111
99. Loopcraft 圖
所以這個 Loop 一層疊一層。在 Shawn "swyx" 的電子報裡面他就畫一個蠻有趣的圖。有趣的是我覺得第一層也蠻有趣的,第一層叫做 Token 的 Loop,在大模型裡面 Token 也是不斷的預測下一個 Token,那個其實也是一個 Loop,他把它放在第一個 Loop。第二個 Loop 就是 Agent 的那個 Turn,第三個 Loop 是 Goal 的那個 Turn,那第四個是 Outer Harness 的那一個 Loop。第五個是他打了問號,就是我們也許下個月有新發明出來一個東西。
---
PART 7 · 進階 # 自我改進的
Harness
100 / 111
100. Part 7 標題頁
(進階:自我改進的 Harness)
---
## 把「改 harness」這件事交給 agent
**連 harness 本身,都讓 agent 自己改。** 讓 agent 根據自己跑出來的 trace 與 eval,回頭改自己的 harness,包括 system prompt, skills 甚至 code 。
自我改進不是讓 agent 想改什麼就改什麼 需要在 eval、trace、版本控制、regression test 的限制下,提出可驗證的變更。 不然,「自我改進」和「把 harness 改壞」就分不出來了。
### 📡 方法一: 讀 Production Traces
### 🔧 方法二: 用 Agent 當優化器改 code
### 📚 方法三: Self-Improving 改 Skills
💡 詳見 blog.aihao.tw 文章: 自我改進 Harness, Meta-Harness 與爬坡
101 / 111
101. 把「改 Harness」這件事交給 Agent
那接下來是 Part 7、8、9,其實今天的重點最重要的東西就是剛才的那幾個時機點。那整個系列裡面 7、8、9 還是可以跟大家快速的分享一下。 進階的部分是做自我改進的 Harness,最近發現一個新的名字叫做 RSI: Recursive Self-Improvement,遞迴自我改進。其實就是在做這個自我改進的 Harness,就是我們把改 Harness 這件事情也交給 Agent。我們剛才講了那麼多就是寫 Harness 就是人去寫,那有沒有辦法讓 AI 幫我們自己去寫 Harness?就讓連 Harness 本身也讓 Agent 自己改。 可以改的東西可以改 Prompt,這最簡單的,改 Skill,那最重要再進一步就是我們連 Harness 的 code 也讓 Agent 來幫我們改。 這三種方法詳細在我的文章裡面會介紹到: 第一個是我們可以讀 Production 的 Trace,如果你上了 Production 的話我們根據用戶的實際的 Trace 從這裡面發掘出一些 insight,做錯誤的分析找到可以去改進的東西,然後再改我們的 code。 第二個方法就是用 Agent 當作優化器去改 code,如果我們有一個先做了一個 Evaluator 評估器的話,我們就可以讓 Agent 像爬坡一樣去改進我們的程式。那這個如果你有看 Karpathy 的話它叫做 Auto Research 就是這條思路。 然後第三個方法就是用 Agent 去幫我們改 Skill,也有蠻多文章是在講如何用 Self-Improvement 的方式去改 Skill。 關鍵是自我改進不是 Agent 想改什麼就改什麼,我們還是希望能夠有一些評估的機制,不然自我改進跟把 Harness 改壞你可能就分不出來了。
---
PART 8 · 收尾 # 會過期的 Harness

Model-Harness-Fit

102 / 111
102. Part 8 標題頁
(收尾:會過期的 Harness)
---
## 模型一升級,harness 會怎樣?
### 🔗 沒有一套 harness 適用所有模型 - 同一套 harness 換個模型,效果**不一樣** - 小模型要更複雜精巧的 harness,大模型需要的 harness 可以較輕薄
### ⏳ harness 會過期 模型每次變強,某些當初**補強它的元件**就不再有用,該被移除。 每次升級時可以檢查之前的 prompt 約束、workflow 還有必要嗎?
> Terminal-Bench 2.0 排行榜排的不是「模型」,而是「**harness + 模型**」的配對。同一個模型配不同 harness,分數差好幾個百分點,差距甚至大過一個模型世代的升級。
103 / 111
103. 模型一升級,Harness 會怎樣?
Part 8 會跟大家分享一個概念是會過期的 Harness。這個副標就是 Model-Harness-Fit,指的意思是沒有一個 Harness 適用所有的模型,同一個 Harness 換不同模型效果就不一樣。 比如說現在一些新的 Coding Agent 的排行榜上面,已經不直接排模型了,而是排這個模型搭配哪一個 Harness 的排名。因為就算是同一個模型它搭不同的 Harness,它的百分比差距可能不是差幾個百分點而是差十幾個百分點。 一般來說比較小的模型它可能會比較需要精巧複雜的 Harness,比較大的模型它比較聰明,它可能需要的 Harness 就比較輕薄。所以隨著模型的智能升級變聰明,Harness 可能就會有過期的現象,就是當初我們補強它的一些元件可能就必須被移除掉、不再需要了。
---
## 設計 Harness 架構時,應考慮模型升級
### ⏳ 會過期 **各種 harness 做法與補強措施** Bitter Lesson: 能隨算力擴大的通用方法,終究勝過手工規則。很多會隨更強的模型逐步不再需要。
### ♾️ 不會過期 **定義「什麼叫做好」+ 驗證** 就算模型強到能完美自我驗證,它驗證的,仍然是一個「由你定義的目標」。定義什麼是「好」,是無論模型多強都得自己做的核心。 Harness 應該設計得**容易替換元件、更容易測量性能**: 模型一變強,你才拆得掉。
💡 詳見 blog.aihao.tw 文章: 會過期的 Harness, Model-Harness-Fit 與 Bitter Lesson
104 / 111
104. 設計 Harness 架構時,應考慮模型升級
所以我們在設計 Harness 的時候就需要考慮到模型升級的情況。那有一些是不會過期的情況,就是定義什麼叫做好,以及如何驗證是不會過期的。 所以我們 Agent 應該設計得容易去替換元件、更容易去測量它的性能,這樣模型如果之後升級變強,我們才有辦法去拆掉 Harness 裡面不需要的東西。
---
PART 9 · 動手做 # 自建 Agent 的
框架選型
105 / 111
105. Part 9 標題頁
(番外:自建 Agent 的框架選型)
---
## 該從哪個開發框架開始?
### 路線一: 從功能完整的 Deep Agent 開始 **起點高**: 一開始就有能跑的 agent,但相對不好改。 **✅ 優點**: 馬上能跑;harness 原廠針對自家模型調過。 **⚠️ 缺點**: 會帶用不到的 context/工具;可控性/可維護性受限;常綁特定供應商。
### 路線二: 從基礎構建 **起點低**: 要自己接的多,但彈性與可控性好,能一步步朝想要的設計走。 **✅ 優點**: 完全可控,貼著任務分布拿掉無關 context/工具;model 無關、好換供應商、好控成本。 **⚠️ 缺點**: 前期工程量較大。
106 / 111
106. 該從哪個開發框架開始?
那這個 Part 跟大家分享自建 Agent 的框架選型,就是該從哪個框架開始。大致上可以分兩個路線:一個是從功能完整的 Deep Agent 開始,另外一個是從基礎開始構建。 從完整的 Deep Agent 開始指的是你從 Codex SDK 開始、從 Codex App Server 開始、從 Claude Agent SDK 開始,或是 LangChain 它有一個 Deep Agent。這種是我歸類在從 Deep Agent 路線,這一種就是有完整的內建功能都有的。但缺點就是它會帶有很多用不到的功能或是 context,可控性跟維護性也會比較差因為太多內建的東西了,通常也會綁特定的供應商。 比如說 Codex 的話就是用 OpenAI,它最近有說可以換其他模型,但我個人認為因為模型訓練的時候是會針對 Harness 做特別訓練的。比如說修改工具這件事,Claude 的修改工具跟 GPT 的修改工具其實是不一樣的,所以他們在模型訓練的時候是有針對自家熟悉的工具做 post-training 的。所以你如果隨便換一套其實效果不會比較好。 路線二是從基礎構建,你會獲得更好的可控性,可以把 成本 / latency 控制得更好。
---
## 框架舉例
### 路線一: 全套 Deep Agent - [Codex SDK / app server](https://developers.openai.com/codex/sdk/))Apache 2.0 開源,可用 ChatGPT 訂閱帳號登入 - [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview)(Anthropic)核心閉源,第三方只能用 API key - [LangChain deepagents](https://github.com/langchain-ai/deepagents) MIT 開源
### 路線二: 從基礎構建(opinionated 高 → 低) - [AWS Strands Agents](https://strandsagents.com/) - [Google ADK](https://adk.dev/) - [Microsoft Agent Framework](https://github.com/microsoft/agent-framework) - [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) - [Pydantic AI](https://ai.pydantic.dev/) - [LangGraph](https://github.com/langchain-ai/langgraph)
107 / 111
107. 框架舉例
這頁是一些框架舉例。
---
## 那到底該選哪個?
### 🔹 特定情境/規模大 特定情境,或使用者多 → **從基礎構建**。貼近單一任務分布的 vertical agent 更有效率: token 成本低、延遲低,也能換供應商、精算成本。
### 🔹 自用/內部開發 要打造團隊用的 harness 與 outer loop → **從現成 deep agent**。 要的本來就是強的通用開發 agent,原廠已調好內層,先有能跑的東西、疊上 outer loop 最快。
### 🔹 想用訂閱帳號 要讓使用者帶自己的 ChatGPT 帳號 → **看 Codex SDK 或 Codex app server**。 支援訂閱帳號登入,不必 API key 計費;Claude Agent SDK 第三方只能用 API key。
💡 詳見 blog.aihao.tw 文章: 自建 Agent 的框架選型: 全套 Deep Agent 還是從基礎構建?
108 / 111
108. 那到底該選哪個?
到底該選哪個呢?這裡簡單跟大家分析。如果你是特定的情境、規模比較大的、用戶比較多的,我會建議你從基礎開始建,你才可以更有效率的去控制你的 token 跟 latency。 那如果你是團隊內要自用的,我會建議你從 Deep Agent 開始,就是團隊內部自用的這種你直接拿 Codex SDK 或是 Claude Agent SDK 來做是比較快的。 另外還可以提的就是如果你想要讓使用者帶著自己的 ChatGPT 帳號、花他自己的 token 的話,這種你可以特別考慮用 Codex 的方案,因為 OpenAI 允許這條路線。
---
CONCLUSION # 總結

Takeaways

109 / 111
109. 總結
(此頁講者未有對應逐字稿)
---
## 給 Agent 開發者的駕馭工程 系列九篇 1. **Part 1**|六項 Deep Agent 能力 2. **Part 2**|Harness = 在**執行迴圈**裡約束、檢查、修正;agent 要**回饋迴路**,不是完美 prompt 3. **Part 3 · 時機①**|**工具裡**閉合最小迴圈: 驗證、改寫、回傳值夾帶指示 4. **Part 4 · 時機②**|**request 之間注入**: 人 steer/interrupt,或程式注入背景工具結果 5. **Part 5 · 時機③**|**單輪結束**驗收 Goal/Outcomes;三種 judge 不同實作分析 6. **Part 6 · 時機④**|**外層 Loop** 跨 session: Ralph/Symphony/cron,**把自己移出迴圈** 7. **Part 7 · 進階**|讓 agent **自己改自己的 harness** 8. **Part 8 · 收尾**|Harness **綁模型、會過期**;不過期的是 **Eval 與 Judge** 9. **Part 9 · 番外**|框架兩條路:**全套 Deep Agent/從基礎構建**
📚 歡迎到 blog.aihao.tw 看全篇內容。
110 / 111
110. Recap
所以總結今天跟大家講了很多,花比較多時間講在不同的時機點可以去插入我們想要去駕馭 Agent 的回饋。每一篇都在我的 blog 上面還有完整的內容,歡迎大家再去看。
---
Thank You # 謝謝,請多指教 🙏
- 個人部落格 <https://ihower.tw> - Facebook [ihower](https://www.facebook.com/ihower) - Threads [@ihower](https://www.threads.net/@ihower) - Twitter [@ihower](https://twitter.com/ihower)
111 / 111
111. Thank You
那今天的演講就到這邊了,謝謝大家。