為什么說JSON不一定是LLM結(jié)構(gòu)化輸出的最佳選擇? 原創(chuàng)
編者按: 在使用大語言模型時,如何在保證輸出質(zhì)量的同時降低成本?在眾多數(shù)據(jù)輸出格式中,究竟應該如何選擇?
我們今天為大家?guī)淼奈恼轮?,作者通過實際測試給出建議:在某些場景下,相比廣泛使用的 JSON 格式,不妨考慮一下其他數(shù)據(jù)格式,做一些測試,挑選出既能控制成本又能保證穩(wěn)定性和速度的最佳選項。
文章通過對比 TSV、CSV、Columnar JSON、YAML、TOML 和 JSON 六種格式,從 token 使用量、響應時間和實用性三個維度進行了深入分析。作者指出,沒有一種格式能在所有場景下都表現(xiàn)最佳。文章詳細分析了每種格式的優(yōu)劣勢,并提供了一個實用的投資回報率計算方法,幫助讀者評估是否值得將現(xiàn)有系統(tǒng)從 JSON 轉(zhuǎn)換為其他格式。
作者 | David Gilbertson
編譯 | 岳揚
當要求大語言模型(LLM)輸出結(jié)構(gòu)化數(shù)據(jù)時,所采用的格式會對結(jié)果產(chǎn)生比較大的影響。本文對比了六種不同的格式,評估考察了它們的處理速度、tokens 消耗以及各自的限制。
01 簡要說明
JSON 雖然是多數(shù)人的首選,但它對 tokens 的消耗極大。處理相同數(shù)據(jù)時,它可能需要其他格式兩倍的 tokens。
需要注意的是,沒有一種格式能在所有情況下都表現(xiàn)最佳,以下是一個決策指南:
(如果你好奇為何沒有提及 XML,那是因為我有個個人目標:50 年不碰 XML —— 只剩下 4 年就能達成了!)
我將在下文中詳細解釋這些格式選擇,并探討每種格式的局限性。但在此之前,先讓我們對比一下它們的 token 使用情況和速度。
02 token 使用情況
探究 JSON 之外的其他選項,主要目的是為了減少所需的 tokens 數(shù)量,這樣做可以降低運營成本并縮短響應時間。
為了對這些格式進行有效比較,我們將基于它們表示特定數(shù)據(jù)集所需的 token 數(shù)量來進行評估。
2.1 比較框架
本次比較我將使用一段文本作為輸入,該文本包含了關(guān)于歐盟每個國家的一段信息。
我將要求 LLM 將這段普通文本轉(zhuǎn)換成結(jié)構(gòu)化數(shù)據(jù),其中每個國家都是一條記錄,每條記錄包含國家名稱、領(lǐng)導人姓名、領(lǐng)導人出生日期、領(lǐng)導人性別、人口數(shù)量和領(lǐng)土面積等鍵/值對。
我將針對每種結(jié)構(gòu)化輸出格式執(zhí)行這一操作,并檢查六種格式的輸出結(jié)果是否相同。
感興趣的朋友,可以在這個 gist[1] 中查看完整的代碼。對于不太感興趣的朋友,這里展示了我如何為每種格式定義 name、可選的 hint 以及 parser(這里將所有數(shù)據(jù)解析成 Pandas DataFrame):
LLM(本次測試使用的是 gpt-4o-mini)能夠以不同格式準確返回相同的數(shù)據(jù)。當然,如果數(shù)據(jù)更復雜,或者使用的 LLM 不夠強大,結(jié)果可能就不會這么精確了。
2.2 比較結(jié)果
下表展示了使用不同格式表示數(shù)據(jù)所需的 tokens 數(shù)量。
JSON 所需的 tokens 數(shù)量是 TSV 的兩倍。這個差異不容小覷。設(shè)想一下,如果你在某個 API 的價格頁面上看到,選擇 JSON 格式的數(shù)據(jù)需要支付 1 美元,而 TSV 格式只需 0.5 美元,YAML 格式則是 0.8 美元。
當然,這些結(jié)果僅針對我們的示例數(shù)據(jù)。展示本圖表的目的并非要讓你認為 JSON 在所有情況下都會大量消耗 tokens,而是讓你相信值得用其他格式測試自己的數(shù)據(jù)。
接下來,我們來看看這些格式的響應時間。
盡管 JSON “只”需要兩倍于 TSV 的 tokens ,但其響應時間通常比 TSV 慢四倍。我原本以為 token 數(shù)量與響應時間之間的關(guān)系是近似線性的 —— 接近O(n),因此如此夸張的響應時間出乎我的意料,我建議我們可以將這種現(xiàn)象的時間復雜度設(shè)為O(my)。
將數(shù)據(jù)結(jié)構(gòu)化輸出的響應時間還是蠻重要的,所以趕緊測試吧。
03 局限性與考慮因素
如果這些格式都同樣可靠和靈活,那么結(jié)論就會很簡單:使用 TSV。但事實并非如此,所以讓我們對每一種格式進行更深入的了解。
3.1 TSV
在表示表格數(shù)據(jù)時,TSV 和 CSV 格式頗為相似,區(qū)別在于 TSV 使用制表符分隔每一行的數(shù)據(jù),而 CSV 則采用逗號。如果數(shù)據(jù)中本身就包含逗號或制表符,那么這些值就需要用雙引號括起來,這時兩種格式的 tokens 使用差異才會顯現(xiàn)。
由于制表符在數(shù)據(jù)中出現(xiàn)的頻率低于逗號,因此 TSV 在大多數(shù)情況下使用的分隔符數(shù)量會少于 CSV。
在解析數(shù)據(jù)時,TSV 與 CSV 相比 JSON,在純 Python 環(huán)境下解析起來略顯復雜。雖然可以利用 Python 內(nèi)置的 csv 模塊進行解析,但使用 Pandas 庫會更加便捷。在其他編程語言中,解析這兩種格式要么需要編寫更多代碼,要么得依賴第三方庫。
如果數(shù)據(jù)中不含換行符,TSV 可以輕松地逐行解析。因此,若想從 LLM 流式傳輸響應數(shù)據(jù)并實時處理每一行數(shù)據(jù),TSV(以及 CSV)都是不錯的選擇。雖然 TOML、YAML 和 JSON 也能實現(xiàn)類似功能,但處理起來會更加繁瑣。 另外,本文尚未測試的 NDJSON 也是一個值得考慮的選項。
3.2 CSV
如前文所述,CSV 格式的挑戰(zhàn)在于逗號在數(shù)據(jù)中較為常見,這可能會導致兩種情況:要么是需要更多的 tokens 來處理這些逗號,要么是 LLM 在處理時未能正確進行轉(zhuǎn)義,從而產(chǎn)生錯誤的數(shù)據(jù)。因此,如果你的數(shù)據(jù)可能包含逗號,最好避免使用 CSV,或者設(shè)計一個詳盡的提示詞,并實施有效的評估流程,以便準確衡量其可靠性。
對于 TSV 和 CSV 兩種格式,你需要用那些可能包含特殊字符(如逗號、制表符、換行符和雙引號)的數(shù)據(jù)來測試你的系統(tǒng)配置。這樣,你才能確保系統(tǒng)能夠正確處理這些特殊情況。
3.3 Columnar JSON
Columnar JSON 并不是一個常見的技術(shù)術(shù)語;我之所以將它納入這次比較,是因為我很好奇它的 tokens 使用效率如何。
可能有些人還不清楚 Columnar JSON 是什么樣的,下面就是前文提到的國家數(shù)據(jù)所對應的 Columnar JSON 格式:
在所有格式中,Columnar JSON 的直觀性最差。但是,由于其結(jié)構(gòu)特點,每個字段名只會出現(xiàn)一次,而不是每條記錄都重復,這樣就能節(jié)省 tokens。
我注意到,有時 LLM 能夠理解“Columnar JSON”的含義,但有時候需要一些額外的提示詞,例如:“應以列名作為鍵名,對應的列內(nèi)容以列表的形式組織呈現(xiàn)”。
要解析 columnar JSON,你可以這樣將其傳遞給 Pandas 處理:
與 CSV 和 TSV 不同,columnar JSON 支持嵌套的數(shù)據(jù)結(jié)構(gòu),因此它非常適合表示那些某些字段具有復雜結(jié)構(gòu)的記錄列表。
這三種格式——TSV、CSV、columnar JSON——僅適用于表示表格數(shù)據(jù),即以記錄列表為核心的結(jié)構(gòu)。它們都不適合用來表示像配置文件這樣的單一 top-level object(譯者注:指在結(jié)構(gòu)化數(shù)據(jù)格式(如 JSON/YAML/TOML)中,最外層定義的單一根對象,通常作為整個數(shù)據(jù)結(jié)構(gòu)的入口點。)。而接下來的三種格式(YAML、TOML、JSON)則更為靈活多變。
3.4 YAML
YAML 能夠返回一個 top-level list(譯者注:指在結(jié)構(gòu)化數(shù)據(jù)格式中,最外層直接定義為列表結(jié)構(gòu)而非對象。),但我注意到,某些 LLM 更傾向于生成一個 top-level object。因此,在給出提示詞時,我們需要明確指出,以確保 LLM 按照統(tǒng)一的格式返回數(shù)據(jù)。
我還遇到了一個問題,即 LLM 在返回字符串值時,格式可能會不一致。在某些情況下,這可能無關(guān)緊要,但 YAML 有五種不同的方式來表示字符串,而其中只有一種能夠正確解析轉(zhuǎn)義序列(例如\t, \u03B1)。因此,如果你的數(shù)據(jù)中包含轉(zhuǎn)義序列,那么最好明確要求 LLM 使用雙引號來定義字符串。
YAML 相較于 JSON,存在更多的“陷阱”和注意事項。建議你深入了解這些潛在的問題,而不是盲目地期待 LLM 能夠自動正確地格式化 YAML。
為了解析 YAML,你需要安裝一個第三方庫。我個人使用的是pyyaml,這是一個無依賴的庫。
3.5 TOML
TOML 是在此場景中唯一不支持 top-level list 的格式,因為它的設(shè)計初衷是作為一種配置文件格式。因此,若想用 TOML 來表示記錄列表,就必須將這些記錄包含在一個 top-level object 內(nèi),并告訴 LLM 你想在這個對象中調(diào)用什么鍵。
TOML 在使用上通常會比 YAML 需要更多的 token,因為 TOML 要求所有的字符串值都必須用引號括起來。
在解析方面,如果你的 Python 版本是 3.11 或以上,那么內(nèi)置的 TOML 解析器[2]就可以直接使用。如果不是,那就需要安裝 tomlkit 或類似的庫來處理。
TOML 的普及度不及 YAML,你可能會擔心 LLM 在處理 TOML 格式時是否會遇到難題。但在我所使用的頂級 LLM 中,并沒有發(fā)現(xiàn)明顯的格式處理問題。我認為,TOML 相較于 YAML 的簡潔性在一定程度上彌補了這一普及度差距。而且,YAML 有多種方式可以表達相同的數(shù)據(jù),這可能會降低 LLM 的確定性,使得兩種格式的可靠性相差無幾。
根據(jù)我的個人經(jīng)驗,TOML 和 YAML 都可能出現(xiàn)錯誤,但這些錯誤通??梢酝ㄟ^更精確的提示詞來解決。
關(guān)于 YAML 中的字符串和轉(zhuǎn)義序列的問題,TOML 也同樣存在。
總體而言,TOML 和 YAML 非常相似,TOML 需要更多的 token,不支持 top-level lists,但對于使用 Python 3.11 或以上版本的用戶來說,不需要額外的解析庫。
3.6 JSON
關(guān)于 JSON,其實沒什么特別需要強調(diào)的。它之所以能成為默認格式,是因為它用途廣泛、易于解析,而且出錯率低。只是它包含了大量的引號、逗號、冒號和換行符,這些都增加了 token 的數(shù)量,這一點稍顯遺憾。
值得注意的是,如果你想要使用 LLM 服務商提供的“結(jié)構(gòu)化數(shù)據(jù)模式”,或者使用像 Guardrails[3]、Outlines[4] 這樣的結(jié)構(gòu)化工具,JSON 往往是唯一的選擇。但我認為這種情況會隨著時間的推移而有所改變。隨著越來越多的基于 LLM 的應用投入實際使用,開發(fā)者會開始關(guān)注如何減少 token 使用等優(yōu)化措施,LLM 服務商也會通過支持更多結(jié)構(gòu)化數(shù)據(jù)格式來滿足這一需求。
理想的情況是,LLM 服務商能夠調(diào)整模型,使其能夠可靠地處理多種格式的數(shù)據(jù),并在結(jié)構(gòu)化數(shù)據(jù)模式中提供這些格式作為可選項。
這里有一個注意事項:對于有關(guān) LLM 在輸出特定格式時的可靠性方面的舊建議,我們應該保持謹慎。正如 OpenAI 在 2024 年 8 月的一篇博客文章中所提到的[5],GPT-4 的早期版本在處理復雜的 JSON 測試時的正確率僅為 35%,而較新版本的 GPT-4 正確率則高達 85%。這在 GPT-4 系列中是一個巨大的飛躍。
這一點對于使用某些特殊功能或軟件包的人來說尤為重要,這些功能或軟件包可能會基于一年或更久之前的假設(shè)或證據(jù)來強制輸出結(jié)構(gòu)化數(shù)據(jù)。你可能并不需要這些功能或軟件包,它們可能會迫使你使用 JSON,而實際上你可以選擇更經(jīng)濟、更快捷的格式。
04 實際應用
在理論層面這些格式各有優(yōu)勢,但假設(shè)你已經(jīng)有了一套使用 JSON 的結(jié)構(gòu)化數(shù)據(jù)處理系統(tǒng),并且運行得很順暢。你知道 TSV 格式也能適用于你的數(shù)據(jù),那么是否有必要進行格式轉(zhuǎn)換呢?
如果你關(guān)注的是速度——因為人們需要等待 LLM 生成 token,那么你需要評估等待時間的價值,這部分在這里不展開討論。
但如果你只是在后臺運行一個進程,這個問題就簡單多了。舉例來說,我們可以設(shè)定以下假設(shè)條件:
- 你的時間成本是每天 1000 美元
- 將現(xiàn)有系統(tǒng)從 JSON 轉(zhuǎn)換為 TSV 需要半天時間
- 輸出 token 的費用是每百萬 0.60 美元
- 使用 TSV 可以減少 50% 的 token 使用量
- 你希望一年內(nèi)收回投資
我們可以用一個小 Python 腳本來計算這些數(shù)值:
根據(jù)計算,如果你現(xiàn)在每天生成大約 4,566,210 個 JSON token,一年后就能實現(xiàn)收支平衡。
當然,你應該根據(jù)自己的實際情況來調(diào)整這些數(shù)值,但以下基準數(shù)據(jù)可供你參考。如果你每天只生成幾千個結(jié)構(gòu)化數(shù)據(jù)的 token(并且不介意速度),那么盲目調(diào)整數(shù)據(jù)格式的性價比極低。但如果你每天需要處理數(shù)千萬個 token,那么探索其他格式絕對是一個劃算的決定。
05 總結(jié)
選擇默認的 JSON 格式確實很有吸引力,因為它靈活、穩(wěn)定且解析起來簡單。但相對而言,它的處理速度較慢,成本也更高。因此,不妨考慮一下其他數(shù)據(jù)格式,做一些測試,挑選出既能控制成本又能保證穩(wěn)定性和速度的最佳選項。
Thanks for reading!
Hope you have enjoyed and learned new things from this blog!
About the author
David Gilbertson
I like machine learning stuff.
END
本期互動內(nèi)容 ??
?你在實際項目中最常用哪種數(shù)據(jù)格式?遇到過哪些意想不到的問題?歡迎分享經(jīng)驗??
??文中鏈接??
[1]??https://gist.github.com/davidgilbertson/fcabb55478b4a4e1537a706f808b8b09??
[2]??https://docs.python.org/3/library/tomllib.html??
[3]??https://github.com/guardrails-ai/guardrails??
[4]??https://github.com/dottxt-ai/outlines??
[5]??https://openai.com/index/introducing-structured-outputs-in-the-api/??
原文鏈接:
???https://david-gilbertson.medium.com/llm-output-formats-why-json-costs-more-than-tsv-ebaf590bd541??
