第一部|最小閉環 · 第 1 章
從 LLM 到 Agent
拆開 LLM、Agent 與 coding agent,親手建立不可再刪的 model → tool → result 閉環。
LLM 能產生下一段文字;Agent 則把文字模型放進一個可以觀察世界、採取行動、接收結果並繼續判斷的閉環。這一章只留下不可再刪的部分。
LLM 不是 Agent
一次 LLM 呼叫可以抽象成
output = model(messages)。模型不會記得上一次呼叫,也不會真的讀檔、執行測試或修改系統。它只根據本次輸入預測輸出。所謂「記憶」,其實是 host
在下一次呼叫時,把先前的訊息再次送入。
LLM
- 輸入訊息,輸出文字或 tool call
- 單次呼叫無狀態
- 不直接產生外部副作用
Agent
- 保存 transcript
- 執行模型選擇的 tool
- 把結果送回模型,直到得到 final answer
不可再刪的閉環
async function runAgentLoop(userText: string) {
messages.push({ role: "user", content: userText });
for (;;) {
const answer = await callModel(messages, toolDefinitions);
messages.push(answer);
if (!answer.toolCalls.length) return answer.text;
for (const call of answer.toolCalls) {
const result = await tools[call.name].execute(call.arguments);
messages.push({ role: "tool", toolCallId: call.id, content: result });
}
}
}
這段程式不理解「修 bug」或「查營收」。它只負責機械性的控制:呼叫模型、執行能力、保存結果、決定是否繼續。領域能力在 tools;決策能力在 model;連續性在 messages。
Coding Agent 多了什麼
給 Agent 四個能力,就得到最小 coding agent:
read:取得原始碼與檔案。write:建立或完整覆寫檔案。edit:精準修改既有內容。bash:搜尋、編譯、測試與執行命令。
真正困難的不是把 loop 寫出來,而是讓它在錯誤、取消、context 增長、程式 crash 與不確定外部 effect 下,仍保持 transcript 合法且能安全恢復。後面七章都在補上這些可靠性。
第一性原則的責任分配
| 責任 | 由誰負責 | 不該負責什麼 |
|---|---|---|
| 選擇下一步 | Model | 直接取得 host credential |
| 控制迴圈 | Agent runtime | 理解每個領域的業務規則 |
| 產生副作用 | Tool adapter | 自行改變授權範圍 |
| 持續與恢復 | Session | 猜測未記錄的 effect 是否成功 |
| 介面與部署 | CLI / trusted host | 把 deployment security 假裝成 agent 功能 |
動手驗證
tiny-ts --plugin read "讀取 README.md,說明 agent loop"
tiny-ts --plugin edit "讀取 README.md"
# 第二個命令缺少 read 能力,Agent 應明確說明缺少能力,不能捏造結果。
這個對照揭示一個重要觀念:Agent 的能力不是 prompt 宣稱出來的,而是本次 request 實際提供的 tool definitions。
這個迴圈假設 messages 這個陣列永遠活著——它只存在 process 的記憶體裡,process
一死,這個陣列就跟著消失。下一章先處理它裡面裝的東西合不合法,再往後幾章處理它會不會突然消失。