CMU 11-768 第 1 講:agent 是跑在迴圈裡的模型,難的是讓它真的做得好
11-768 第 1 講先把 agent 拆到最小:工具定義和工具呼叫都只是 token,harness 負責解析、執行、把結果塞回 context,ReAct 迴圈一跑就是 agent。接著 Neubig 列出好 agent 要的六種能力,每一種都能從訓練或 harness 兩條路補,並主張 agent 是由 harness、沙盒、推論、訓練、監控五塊組成的系統,不只是一個模型。
11-768 第 1 講先把 agent 拆到最小:工具定義和工具呼叫都只是 token,harness 負責解析、執行、把結果塞回 context,ReAct 迴圈一跑就是 agent。接著 Neubig 列出好 agent 要的六種能力,每一種都能從訓練或 harness 兩條路補,並主張 agent 是由 harness、沙盒、推論、訓練、監控五塊組成的系統,不只是一個模型。
ThreadManager 持有 Arc<ThreadManagerState> 統管所有 thread,spawn_thread() 統一處理新建/恢復/分叉/子代理四種啟動路徑;ForkSnapshot 定義 TruncateBeforeNthUserMessage/Interrupted 兩種語義;AgentControl 透過 Weak<ThreadManagerState> 避免循環引用;agent_graph_store 追蹤 ThreadSpawnEdgeStatus::Open/Closed。
TurnContext 在 turn 初始化時捕獲所有設定(模型、審批、token budget),後續 step 透過 StepContext 讀取快照;StepActivation 驗證設定變更不違反 legacy 安全約束;ContextManager 用 Arc<Vec> + 版本號實現 Copy-on-Write 歷史共享;壓縮觸發條件為 token_remaining < threshold,支援 remote v1/v2、local、model fallback 四條路徑。
omp 的 runLoopBody 用雙層 while:內層跑 model call → tool call 的核心節奏;外層在 agent 本想停下時,排空 queued steering / follow-up / asides,決定要不要再跑一輪。這設計解決了「使用者在 model 跑時打字」與「背景任務悄悄塞訊息」的交付時機問題。
omp 用 StablePrefix 凍結 system prompt + tool specs,用 AppendOnlyLog 讓 messages 只增不改,配合 digest-based 的 longestStablePrefix 算法,在 prune/shake/steering 重寫歷史時,只重送 divergence point 之後的尾巴。這讓 Anthropic/DeepSeek 的 prompt cache 命中率最大化,解決了舊版每輪強制 ~40k token re-prefill 的問題(issue #3406)。
omp 的審批解析器 resolveApproval 按「工具宣告 → 使用者覆寫 → 模式門檻」三層決策。未宣告 approval、或格式錯誤的工具,預設降級為 exec(fail-closed)。三層分工:工具自己宣告 tier + 可選 policy/override/reason;使用者用 tools.approval.<tool> 覆寫;模式(always-ask/write/yolo)決定自動通過哪些 tier。關鍵鐵律:tool-side deny 與 user-side deny 永遠不可被模式跨越;yolo 中 override: true 不會強迫 prompt,但 policy: deny 仍生效。
omp 不只有一種 compaction:context-full 走 LLM 摘要、可疊代、失敗對半重切預算;snapcompact 不呼叫 LLM,把歷史壓成 PNG 讓 vision model 讀,解決無 API key / 低延遲 / 視覺模型便宜場景;branch summary 在 `/tree` 切分支時摘要被離開的段落;shake 純機械式把 tool-result 大段文字換成 placeholder,給 summary 太重、prune 不夠的緊急手動場景。四種策略分工明確,由 session maintenance 自動編排或使用者手動觸發。
OMP 的 Agent stream 不只是把 token 往終端機吐:它把 agent、turn、message、tool execution 分成不同層級的事件。理解這個事件契約,才能在 UI 顯示增量文字、工具進度與錯誤,同時不把暫存中的 partial message 誤當成已提交的對話。
pi-agent-core 的心臟:agentLoop() → runLoop() 雙層 while(true)。Inner loop 處理 tool calls + steering messages,Outer loop 處理 follow-up + prepareNextTurn(compaction、model switch)。Enter = steering(當前工具跑完插入)、Alt+Enter = follow-up(agent 判定結束插入)。streamAssistantResponse() 如何處理 partial message 更新、tool call 解析、parallel/sequential 執行、before/after hooks。
本系列 17 篇帶你從 CLI 使用者角度切入,逐層深入 pi-mono 的 Agent Loop、Session Tree、Tool System、Extension System、TUI 架構、Remote Session、Telemetry、Compaction、Release 流程等核心機制。適合想自架 Agent、研究 Agent 架構、或想貢獻 pi 的開發者。
我在寫自己的 Python coding agent「looplane」,這個系列把 pi、oh-my-pi、opencode、codex、claude-code 五個成熟專案的原始碼逐題對照,也對照 Looplane 現在已經落地的 TUI、外部 CLI runtime、local gateway、usage/OTel/session 工具與 Cloudflare 切片。每篇固定走「設計問題→五家做法→looplane 選擇→學術依據→改善路線」五段,證據一律給到 file#symbol 層級。
pi 的 loop 是雙層 while 加 EventStream;claude-code 明講 stop_reason 不可靠、改以串流中收到的 tool_use block 當唯一續跑訊號;codex 把 turn 做成可取消的 SessionTask 再靠 rollout crate 錄 JSONL;looplane 選了「manifest 先落盤、JSONL 跟上」的寫入順序,讓 Ctrl-C 之後能做驗證式續跑而非重跑。這篇全部附 file#symbol 級證據。
OpenAI 詳解 Codex 的 agent loop 設計:prompt 如何建構、multi-turn 對話如何管理、prompt caching 如何避免成本爆炸,以及 context window 自動壓縮的實作。
Agent loop 是每個 session 序列化的執行。最值得學的是它處理並行的方式:每個被接受的回合會記下 activeWriterRunId 宣告,之後每次逐字稿寫入都要附上 expectedWriterRunId,在交易裡比對——被取代的回合因此無法提交過期資料。