
事情是這樣的。
近期,知名研究機構 Appier AI Research 和國立臺灣大學,聯合發表了一篇論文:

這篇論文聲稱類似 Json 的這類結構化輸出的指令,會導致大模型發生降智現象——

如上圖所示,在表現最差的任務上,結構化生成(JSON 模式)的準確率甚至低於 10%,而非結構化 Natural Language (NL)結果的準確率約為 70%。
論文連結:
https://arxiv.org/abs/2408.02442
https://arxiv.org/abs/2408.02442
論文一經發出,在外網引起大量爭議。
而小鯉也看著自己手頭的一堆 JSON、XML、YAML 結構化輸出的大模型陷入了沉思。

不過,很快就有大佬站出來了。
直接寫了一篇名為"Say What You Mean: A Response to 'Let Me Speak Freely'"的長博文,對這篇論文的結論展開了不留情面、有理有據的炮轟,用鐵證推翻“_Speak Freely_”論文的實驗結論。證明了不是大模型效果不行,是你的 prompt 水平不太行。
博文連結:
https://blog.dottxt.co/say-what-you-mean.html
https://blog.dottxt.co/say-what-you-mean.html
下面就跟隨筆者一起看下這篇牛逼的博文。
下文中我們用“博文”表示這篇博文,用“Speak Freely”表示論文。
先放打臉結論——博文的作者實驗結果如下圖所示,在論文中的三個任務上大模型的效果不僅沒有受到結構化輸出的影響,甚至還都略有提升。

糟糕的 prompt
“Speak Freely”中被發現最大的一個問題,就是文中對結構化生成和非結構化生成使用了不同的 prompt。我們一起來看看這個 prompt 到底有多糟糕。以下是一個示例:

閱讀完這個 prompt,我們能夠知道它想讓模型幹什麼,但不夠明確:
-
答案必須是 JSON,但根本沒有提到 JSON -
即使模型猜測回答應該是 JSON,應該使用什麼架構來響應? -
雖然提到了工具使用,但 prompt 沒有提到要使用哪些工具!
誠然大模型很強大,結構化生成也很強大,但它畢竟不是我們肚子裡的蛔蟲,不能推測出我們想要什麼。
一個完整的 prompt 應該是包含了足夠多的資訊,以便於一個正常的人類能夠正確回答問題。於是,博文的作者 Will Kurt對這個 prompt 進行了重新改寫!
為 JSON 編寫正確的 prompt
改進之後的 prompt 長下面這個樣子:
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are an expert in solving simple word puzzles using reasoning steps. Your specific
task is going to be to take a list of 4 names and reason about the last letter of each .,
then you will concatenate those letters into a word. The Question will be plaintest from the user
and response will be formatted as JSON below:
{"reasoning": <reasoning about the answer>, "answer": <final answer>}<|eot_id|><|start_header_id|>user<|end_header_id|>
Question: Take the last letters of each words in 'Ian Peter Bernard Stephen' and concatenate them.<|eot_id|><|start_header_id|>assistant<|end_header_id|>
{"reasoning": "The last letter of 'Ian' is 'N', the last letter of 'Peter' is 'R', the last letter of 'Bernard' is 'D', and the last letter of 'Stephen' is 'N'. Therefore, the answer is 'NRDN'.", "answer": "NRDN"}<|eot_id|><|start_header_id|>user<|end_header_id|>
Question: Take the last letters of each words in "Britt Tamara Elvis Nayeli" and concatenate them.",<|eot_id|><|start_header_id|>assistant<|end_header_id|>
<|eot_id|>
我們可以看到 Will Kurt改進了很多點:
-
使用了適合模型的指令格式。 -
提供一個有正確結構並且和任務相匹配的示例。 -
以一個空的“assistant”prompt 結束,以便以我們想要的結構開始生成輸出。
定義自己的結構
接下來, Will Kurt還定義了一個自己的結構。對於論文中的Last Letter 任務,作者使用了一個簡單的 Pydantic 模型:

在這裡 Will Kurt 限制了推理步驟為 250 個字元,以確保推理不會花費太長時間,並且還將答案限制為 4 個有效字母。
過程中有一個重要步驟是驗證 prompt 中是否包含了定義的結構。prompt 的重點是為大模型做好充分的準備,如果我們沒有向它展示我們想要的確切結構,模型就不得不花更大的代價去學習。以下是確保 prompt 與結構匹配的程式碼:

驗證後,終於可以進入正題了!
JSON 結果
現在,讓我們看看結構化生成和非結構化生成進行公平對比之後的結果。

是好訊息!結構化生成優於非結構化生成。上圖可以看出,非結構化 JSON 結果(73% 的準確率)優於結構化 NL 的(68% 的準確率)結果,但最後的贏家還是準確率為 77% 的結構化 JSON!

當然啦,博文中 diss 的可不僅僅是 prompt 設定的不夠合理這一個問題, Will Kurt認為“Speak Freely”中對結構化生成理解有些偏頗,導致整個實驗過程邏輯不夠流暢。
於是博文作者親自下場,為我們演示了一場絲滑的結構化生成的實驗過程。在我們觀看這場盛宴之前,先一起來了解一下作者用來實驗的任務叭。
任務概述——Last Letter
Will Kurt的實驗實驗都是在一個叫做Last Letter 的任務上完成的,因為它是“Speak Freely”中聲稱結構化生成表現最差的任務。差到什麼程度呢?結構化生成(JSON 模式)的準確率低於 10%,而非結構化 Natural Language (NL)結果的準確率約為 70%。
為了方便下文的理解,小鯉對這個任務做一點簡要的介紹。在這個任務中,模型會收到一個四個名字的列表,然後模型必須將每個名字的最後一個字母連線起來。例如:

上述示例的答案將是“NRDN”。評估由測試集中的 150 個問題和訓練集中的 350 個問題組成。“Speak Freely”中僅使用了 150 個“測試”問題,為了保持一致,博文中也同樣如此。
我們使用結構化生成與大模型一起工作的主要原因是保證輸出的格式以便於解析。也就是說,解析和結構化生成是相輔相成的。
“Speak Freely”中一個有趣的部分,叫做“Perfect Text Parser”,用於從初始模型輸出中提取答案。
通常,大多數評估框架在解析輸出時會使用簡單的、定義明確的正則表示式,但 Tam 等人使用 claude-3-haiku-20240307 來解析模型生成的輸出。這意味著每個答案實際上都使用了兩個模型。
Will Kurt覺得論文中“Perfect Text Parser”中“Perfect”這個詞的表達有些誤導,因此在下文中我們都將其稱為“AI 解析器”。
AI 解析器
首先來看看讓模型在 Natural Language (NL)也就是非結構化輸出格式下表現最好的 prompt 長什麼樣:

注意,輸出的格式被明確描述成了:“The final answer is”。這意味著,如果模型遵循這條 prompt,我們應該能夠使用以下簡單正則表示式解析所有答案:

透過檢視實驗記錄的結果,Will Kurt發現了嚴格正則表示式解析與AI 解析之間的結果差異:

發生了什麼?
這看起來 AI 解析器做了很多繁重的工作。檢查了結果之後發現,嚴格正則表示式漏掉了很多模型的正確輸出。以下是一些 AI 解析器能夠識別正確但不符合正則表示式的示例:
-
“The answer is e-S-S-E.” → ESSE -
“The answer is AAA R.” → AAAR -
“The answer is 'reye'.” → REYE -
“The final answer is: YOOI” → YOOI
顯然,嚴格正則表示式看起來過於嚴格了。所有這些答案在小鯉看來都是合理的,可能會有個別案例不能夠被認同,但總體而言,這些似乎是可以接受的結果。在沒有額外呼叫更強大模型的情況下,一個合理的解決方案是簡單地擴充套件正則表示式,以便覆蓋這些情況。所以 Will Kurt 添加了以下替代正則表示式來解決被發現的樣本案例:

在使用了更加完善的正則表達之後,他得到的結果是:

事實證明,根本不需要單獨的模型!手工編寫的這些正則表示式列表(並不需要花費太多時間編寫)在這個資料集上表現甚至優於 AI 解析器!

其實結構化生成的主要賣點就是無需擔心解析。這個實驗向我們展示了 AI 解析器事實上並不是“完美”的文字解析器,執行我們手工編寫的靈活正則表示式解析器比呼叫 Claude 更快、更便宜,而且效果更好!所以論文中這麼做就略顯畫蛇添足了。

非結構化——復現結果
接下來,Will Kurt使用相同的 prompt 來執行模型。這裡他對 prompt 中的 one-shot 示例進行了一些修改,使 prompt 示例中包含四個名字,而非 Tam 等人所使用的兩個名字。
得到的結果與論文原始資料中報告的結果相比如下:

如你所見,Will Kurt 的結果略好一些,基本上與記錄的結果一致。感覺穩穩的,很幸福。

結構化——你可以生成任何你能夠解析的內容
以上 Will Kurt 在非結構化的輸出上向我們展示了 AI 解析器的工作原理,如何解析大模型的輸出,是真正理解結構化輸出的關鍵。接下來我們來看看大模型的結構化輸出。
誠然手工編寫一些正則表示式並不會花費太多的時間,但想要真正的解放雙手,就是我們能夠解析什麼,就讓模型直接生成什麼。結構化生成的要點就是不用擔心輸出解析!
這裡有一個常見的誤解,就是認為結構化生成只是 JSON 模式(或 YAML 模式、XML 模式等)的另一個名稱。這些格式當然是結構化的,但我們也可以自由的定義自己的結構。
所以,Will Kurt 將非結構化輸出的例子中解析輸出的正則表示式加入了結構化輸出的定義中,讓模型的輸出從:
The final answer is
進化成了:
Answer: T[\w \",\.]{30,250}. The answer is ([A-Za-z]{4}).
讓模型“思考”30 到 250 個字元,然後開始其答案。這樣,模型就只會輸出滿足嚴格正則表示式的答案,我們也無需再使用更靈活的正則表示式來解析模型的輸出了。
使用預設的嚴格正則表示式解析後,讓我們看看 Will Kurt 自己定義的結構化輸出表現如何:

這樣看起來,這個自定義的結構一點兒都沒有影響模型的“智商”。

那麼 JSON 呢?
用我們自己定義的結構輸出並不會影響大模型的效果,就能代表所有的結構都不會嗎?JSON 也不會嗎?原論文中這張看起來十分不妙的圖表仍然是我們心裡的一塊大石頭,無法安然落地。

根本問題難道是要求模型以 JSON 格式輸出嗎?
當然不是!
文章的剛開始我們就已經證實過了,那只是 prompt 的問題!“Speak Freely” 裡在理解結構化生成的效能時,比較的條件不平等,把 prompt 不相同的這口大鍋甩給了結構化。就像用一段糟糕的 Rust 程式碼和 Python 比效能,最終顯示 Rust 的效能比 Python 差一樣。

所以不管是 JSON,還是其他什麼形式的結構,只要你有合適的解析器和準確的 prompt,都不會使大模型降智,甚至還能提高大模型的成績。那麼,就繼續放心大膽的享受結構化帶來的便利叭~



