今天寫完第 3 期的程式碼導讀(出題 agent 與閉環),三期的筆記到齊了。
跟昨天一樣,重讀翻出了東西。但今天最值得記的那件事,性質跟昨天不同——
昨天是「發現當時沒想清楚」,今天是發現自己寫下了一句從來沒有驗證過的話。
寫到出題 agent 的降級機制時,我很自然地打了這麼一句:
這是三個 agent 裡唯一一個「模型掛掉仍能運作」的。
聽起來很順,因為出題的降級確實做得最完整:呼叫失敗、空內容、解析失敗、
模型挑了清單外的題號——四種情況全都退回「粗篩的第一名」,學生照樣換得到題。
打完之後我回去對了一下另外兩個 agent。錯了。
評測 agent 在有執行器的時候,模型掛掉一樣能動:
try:
explanation = explainer(problem=problem, code=code, results=results)
except Exception:
# 判定已經成立了。解讀只是錦上添花,它壞掉不該把事實一起拖下水。
explanation = ""
判定是子行程跑出來的,模型只負責那句「為什麼」。它掛掉只是少一句話。
而這行程式碼是我自己在 Day 22 寫的,註解也是我寫的。 隔了五天,
我在另一個檔案裡寫下了跟它矛盾的一句話。
因為「哪些 agent 撐得住模型掛掉」這個問題,我從來沒有被迫回答過。
寫程式的時候,我一次只面對一個 agent:寫出題的降級時想的是出題,
寫評測的容錯時想的是評測。每一段都是對的。
但「三個加起來是什麼樣子」這句話,沒有任何一段程式碼需要我講出來。
導讀筆記需要。它的格式逼我寫「為什麼這樣寫」,而寫到某個程度就會需要
橫著比較——而橫著比較的結論,是程式碼裡不存在的知識。
最後改成一張表:
| agent | 模型掛掉還能不能動 | 靠什麼 |
|---|---|---|
| 評測 | 能(有執行器時) | 子行程跑出來的事實,explanation 空掉而已 |
| 出題 | 能 | 粗篩的第一名 |
| 導師 | 不能 | 引導本來就是模型的工作,沒有東西可以退回 |
然後才看出這張表其實在講一件更一般的事:
能算出來的部分要留在自己手上,模型只負責算不出來的那一段。
算得出來的部分越大,模型掛掉時剩下的功能越多。
這條原則在三個 agent 裡各出現過一次,我卻是今天才看見它。
評測把「過不過」交給執行器、出題把「排序」交給 shortlist()、
而導師什麼都交出去了——所以它最脆弱。
這不是我設計出來的,是寫筆記時才浮現的。
昨天發現設計文件寫「全過 → 直接出下一題」,實作是「全過 → 記下來 → 導師說一句」。
今天又一次。設計文件的第 3 期寫的是生成題目:
set_problem: { title, description, tests: [str], targets: [...] }
實作是從題庫挑。理由寫在 agents/setter.py 的模組 docstring 裡,
而且是個好理由——錯誤會傳染:
生成的測資錯了
→ 評測照著錯的測資判定(而且是「實際執行」,看起來非常確定)
→ summary 把錯的結果寫成一句話
→ 導師引用那句話去引導學生
→ 學生對著一份正確的程式碼,被要求找出不存在的錯
學生沒有任何辦法發現是題目錯了,因為系統的每一層都在說同一件事。
判斷沒問題。問題是我又一次沒回頭改文件。兩天兩次,這就不是意外了,是習慣缺口。
targets(這題練到你的哪些弱點)與 pick_reason(為什麼挑這題)這兩個欄位,
系統內部沒有任何邏輯讀它們。
沒有分支靠它們決定、沒有計算用到它們。刪掉的話,挑題結果一模一樣。
它們存在的唯一理由是 app.py 那兩行:
st.caption(f"🎯 這題針對你的:{labels}")
st.caption(saved["pick_reason"])
寫筆記時我對這件事的說法是:
一個看不見的閉環,在使用者眼裡等於不存在。
這也是為什麼 reason 值得花一次 API 呼叫去問模型。粗篩算得出 targets,
但算不出一句人話。「因為你在迴圈上錯了 5 次,這題會練到迴圈邊界」——
這句話比一行 🎯 迴圈 更能讓人相信系統真的在看著自己。
設計文件第一天就誠實寫著:「以本專案的規模,框架在技術上賺不到成本,
採用它的理由是學習框架本身。」
跑完三期,這句話仍然成立,但可以講得更精確了。真正賺到兩件:
沒賺到的是動態路由——route() 讀的是 UI 給的 intent,不是模型的決定。
這個系統的流程由按鈕決定,不由 agent 決定。
那才是 LangGraph 真正的主場,而這個專案沒有用到。
知道自己沒用到什麼,跟知道自己用到了什麼一樣重要。不然很容易把
「我用了 LangGraph」講成「我需要 LangGraph」。
程式碼沒動,測試維持 327 支全綠。三期的導讀筆記到齊:docs/notes/phase-{1,2,3}-code-walkthrough.md。