模型選好了。剩下的工作看起來很單純:把它的缺點補起來。
Day 27 我寫過,乙的兩個缺點都是 prompt 能修的——它不敢說「事實不足」,而且最難那題答非所問。
所以我做了一件最自然的事:把指令寫得更嚴格。
而這一篇要講的是,那次嘗試的結果:它變糟了,而且糟得很有啟發性。
第一版,老實說寫得很樸素。就是把事實列出來、把問題講清楚、要求分成四段回答、並且告訴它可以說「事實不足」。
沒有什麼技巧,就是把話講明白。
第二版,我加上了一整套規則:
這三條,每一條都是針對已知問題來的。特別是第三條——昨天甲才剛拿兩個無關的事實當理由,所以我直接把它寫成禁令。
我當時的期待很單純:講得越清楚,它照做的機率越高。
那個信念不是憑空來的。Day 24 那次,我把問題問得更明確之後,思考量真的從 2445 降到 1046。明確是有效的,我驗證過。
所以我理所當然地以為:再明確一點,會再好一點。
同樣的六條事實、同樣三條干擾項,換上第二版的嚴格指令之後——
乙把三條干擾項全部用上了。
第一版的時候它乾乾淨淨,一條都沒碰。加了「禁止使用不相關的事實」這條規則之後,它三條全中。
而且它還下了一個錯誤的結論:「不可以測試」——一個第一版沒有犯的錯。
我加了一條規則去禁止某件事,而那件事的發生率從零變成百分之百。
想通這件事花了我一點時間,但答案其實不複雜。
我寫的是:「每一條引用的事實都要標上編號」 加上 「不要使用不相關的事實」。
我的本意是:
「如果你標不出來(因為找不到相關的事實),那就不要寫那一段。」
而它讀到的是另一件事:
「每一段都要有編號。所以我得找到事實來標。」
看到差別了嗎?
我以為我在設一個門檻。而它理解成一個必填欄位。
於是它開始做一件很荒謬的事——清點清單,然後把手上的事實分配到各個標題底下。哪一段沒有對應的事實?那就從剩下的裡面找一個看起來最接近的塞進去。
那三條干擾項,就是這樣被用掉的。它們不是被誤認為相關,它們是被徵召去填格子的。
而最能說明問題的,是它寫出來的一種東西:為了滿足「每段都要標編號」這個要求,它在某一段寫出了類似 「無 [事實 4]」 這樣的句子。
那句話沒有任何意義。它不是一個答案,它是一個為了滿足格式而存在的填充物。
這是這篇最重要的一句話,我想把它單獨拉出來:
當兩條規則互相衝突的時候,一個四十億參數的模型會服從格式,而不是語意。
我給的兩條規則,在邏輯上是相容的——「要標編號」和「不要用無關的事實」,一個懂語意的讀者會知道,當兩者衝突時應該讓第二條勝出,也就是「寧可那一段空著」。
但那個判斷需要理解規則背後的意圖。
而它做的是更表層、也更安全的事:滿足看得見的那一條。
格式是看得見的——有沒有標編號,一眼就知道。而「這條事實跟這個問題相不相關」,是一個需要理解的判斷。
當它只能滿足一個的時候,它選了它做得到的那一個。
上面那些還算是技術上的發現。接下來這段是我的問題。
Day 17 我寫下的架構原則是這個:
真正的推理在建置期做完。查詢時,模型只負責組裝語言,不負責產生結論。
而我的第二版做了什麼?
我把三個判斷,全部丟回了查詢的當下。
我一邊寫著「查詢時不要推理」,一邊寫了一份要求它當場做三次判斷的指令。
而 Day 27 我才剛講過:乙最難那題答不出來,是因為我要它當場推理,而正確的做法是把那一步搬到建置期。
我診斷對了,然後在下一步做了完全相反的事。
我想了一下為什麼會這樣,結論有點反直覺:
「把 prompt 寫得更嚴格」這個動作,本身就是一種把工作往查詢期推的行為。
因為每一條規則,都是一件它必須在回答的當下判斷的事。
規則越多,它當場要做的判斷越多。而我加規則的動機,通常正好是「它上次某個地方判斷錯了」——
於是我為了修正一個判斷錯誤,加了一條需要更多判斷的規則。
這是一個會自己加速的循環。而它的終點,是一份長到不可能被完整遵守的指令。
真正該做的方向是反的:
不是「告訴它要判斷得更好」,是「讓它不需要判斷」。
相關性的判斷,不該在回答的當下發生。它應該在資料被撈出來之前就處理掉——如果送進去的六條事實裡有三條無關,那問題不在指令,在檢索。
如果問題在檢索,那就有一個很直接的實驗可以做:
同樣的嚴格指令,但我只餵給它相關的那幾條事實。
如果結果變好,那就證明了一件事——它不是不會做,是被淹沒了。
明天那篇是這個系列的技術結論,而它的結果讓我把前面很多天的想法又調整了一次。