今天沒寫程式。寫的是 docs/notes/phase-2-code-walkthrough.md——
第 2 期(評測 agent)的程式碼導讀。
第 1 期做完的時候我寫過一份,格式是固定的:
做了什麼 → 在哪一行 → 為什麼這樣寫 → 不這樣寫會怎樣。
最後那段是重點。API 名稱查文件就有,取捨的理由查不到。
本來以為這是一天的整理工作。結果重讀自己的程式碼,翻出三件當時沒想清楚的事。
第 1 期的筆記留了一個待辦:
messages要不要加Annotated[list, add](reducer)?
第 2 期tutor會變成 fan-in 匯合點,到時候「多個來源同時更新同一個欄位
要怎麼合併」才是真問題,reducer 的選擇要在那時一起決定。
現在 fan-in 真的出現了——tutor 有三個上游(START、grade、solved)。
按照當時的計畫,今天該回答這個問題。
答案是:仍然不要加。
因為那三條路徑不會同時到達 tutor。它們是互斥的分支,不是並行的分叉——
一次互動只會走其中一條。而 reducer 解決的是「多個 node 在同一步各自回傳同一個欄位」,
那件事在這裡根本沒發生。
我當時把「多個上游」和「並行寫入」當成同一件事了。 圖上長得很像:
好幾條線指向同一個框。但一個是路徑的匯合,一個是資料的競爭。
差點就為了一個不存在的競爭狀況付出抽象的代價——而且會付兩次:tutor_node 要改成只回傳新訊息,之後發現不對再改回來。
設計文件的第 3 期寫著:
"submit" ─▶ grade ──┬─ 未全過 ───▶ tutor
└─ 全部通過 ─▶ set_problem ─▶ END
全部通過就直接出下一題。實作卻是:
"submit" ─▶ grade ──┬─ 未全過 ───▶ tutor
└─ 全部通過 ─▶ solved ─▶ tutor
記下已解,然後題目留在原地,交給導師講一句肯定。
我當時是有理由才改的,理由也寫在註解裡:一換題,那份「你過了」的判定就會被蓋掉,
學生什麼都沒看到;而且通過之後學生需要聽到一句肯定,不是只看到一塊綠色。
但我沒有回去更新設計文件,也沒在任何地方記下「這裡與文件不同」。
今天照著文件畫流程圖,畫到一半才發現圖跟程式碼對不上。
導讀筆記最後寫成這樣:
設計文件與實作不一致時,改的是文件還是實作? 這裡選擇改實作、並把理由寫進註解。
判準是:文件寫的是「怎麼做」,而做下去之後發現它違反了更上層的「為什麼」
(學生要看得到自己的成果)。上層的理由贏。
判斷本身我現在仍然認為是對的。錯的是沒有把這個分歧記在文件那一側——
註解只有讀到那段程式碼的人看得到,而看設計文件的人會被誤導。
筆記最後照慣例附了「想動手驗證的話」:
pytest tests\test_graph.py -k visiting
寫完順手跑了一次:
75 deselected
一支都沒選到。 因為 visiting 只出現在 helper 函式 _visiting_graph 的名字裡,
而 -k 比對的是測試函式的名字。改成能用的版本之後才真的選到 14 支。
這件事小,但性質不小:文件裡的指令是可執行的東西,它也會壞。
而壞掉的文件比沒有文件糟——照著做不會動的時候,讀的人會懷疑自己,不會懷疑文件。
同樣的理由,筆記裡每一個 graph.py:158 這種行號我都回去對了一次。
對的方法是寫個小腳本,把文件裡所有 檔名:行號 抓出來、印出那一行:
graph.py:128 | "user_message": "", # 消化掉,否則下一輪會重送同一句
tests/test_graph.py:578 | def test_intent_persists_in_the_checkpoint_and_must_be_resent():
抓出九個錯的。原因很單純:我這幾天在 tests/test_graph.py 中間插了新測試,
後面所有測試的行號都往下推了。而我引用的是插入之前的記憶。
行號會過期,這是導讀筆記這種東西的固有成本。所以第 1 期那份開頭就寫著
「對應 commit 0ff4597,行號以該 commit 為準」——今天這份也一樣,釘在 5b49a19。
釘住版本,行號就從「會爛的東西」變成「某個時間點的事實」。
寫給三個月後的自己。三個月後我會記得 add_conditional_edges 怎麼用
(查文件就有),但不會記得:
route() 裡未知的 intent 是當場拋例外,而不是走預設路徑not out.parsed_ok 而不是 not out.all_passed
source 的預設值是「推測」而不是「執行」這些都是當時想過、選了一邊、而另一邊看起來也很合理的決定。
不寫下來的話,三個月後的我會看著它們想「這裡幹嘛寫這麼囉唆」,然後改掉。
所以每一節的最後一段都是「不這樣寫會怎樣」。那一段才是筆記的本體,
前面的「做了什麼」只是讓你找得到位置。
下一份是第 3 期(出題 agent、閉環讀黑板)。程式碼沒動,測試維持 327 支全綠。