作者 | ken kantzer
譯者 | 平川
策劃 | 褚杏娟
本文最初發佈於 ken kantzer 的個人博客。
在過去的六個月里,我的創業公司 truss(gettruss.io)發布了多項倚重 llm 的功能,而我在 hacker news 上讀到的關於 llm 的故事現在已經和我的實際情況脫節了,所以我想在處理過 5 億多(我估計)tokens 之後,分享一些更“令人驚訝”的經驗教訓。
本文要點:
我們正在使用 openai 模型,如果你想知道我對其他模型的看法,請閱讀底部的問答部分。
在我們的用例中,gpt-4 占 85%,gpt-3.5 占 15%。
我們專門處理文本,因此不涉及 gpt-4-vision、sora、whisper 等。
我們有一個 b2b 用例——重點是匯總 / 分析 - 提取,你的情況可能有所不同。
5 億 tokens 其實並不像想象的那多,也就大概 75 萬頁文本,要正確看待。
我們發現,不要在提示中給出確切的列表或指令——如果這些東西已經是常識的話,這樣可以獲得更好的結果。gpt 並不愚蠢,你提供的細節過多,反而會讓它混亂。
這和編寫代碼不一樣,代碼必須明確。
下面是我們遇到的一個例子。
我們的一部分管道讀取了一些文本塊,並要求 gpt 根據它們與美國 50 個州或聯邦政府的相關性進行歸類。這不是什麼很難的任務——或許用 string/regex 就可以搞定,但會有許多奇怪的邊緣情況,花費的時間會更長。因此,我們首先做了(大致)這樣的嘗試:
here's a block of text. one field should be "locality_id", and it should be the id of one of the 50 states, or federal, using this list:
[{"locality: "alabama", "locality_id": 1}, {"locality: "alaska", "locality_id": 2} ... ]
這樣做有時候是可以的(我估計 98% 以上的情況都可以),但如果需要深入挖掘的話經常會失敗。
經過研究,我們注意到字段 name 始終返回州的全名——即使我們沒有明確要求它這樣做。因此,我們改為對 name 做簡單的字符串搜索來找出相應的州。從那以後,它就工作得很好了。
我認為,更好的方法應該是:
“you obviously know the 50 states, gpt, so just give me the full name of the state this pertains to, or federal if this pertains to the us government.”
就是這麼不可思議!你的提示模糊一點,gpt 概括的反而更好,反饋的質量反而更高——這是高階委託 / 思維的典型標誌。
(注 1:你可能會想 gpt 從根本上講是一個隨機模型,但它面對 m 開頭的州失敗次數最多。)
(注 2:當我們要求 gpt 從列表中選擇一個 id 時,如果我們以格式化的 json 發送,每個州一行,那麼它就不會那麼困惑了。我認為,\n 是一個比逗號更強大的分隔符。)
langchain 是過早抽象的一個典型例子。
我們一開始以為必須得用它,因為網上是這麼說的。而實際上,在 tokens 數量達到成百上千萬、生產環境具備大概 3~4 個完全不同的 llm 特性之後,我們的 openai_service 文件中仍然只有一個 40 行的函數:
def extract_json(prompt, variable_length_input, number_retries)
我們唯一使用的 api 是 chat。我們總是提取 json。我們不需要 json mode、函數調用和助手(雖然我們都做了),我們甚至沒有使用系統提示(或許我們應該)。當 gpt-4-turbo 發布的時候,我們只更新了代碼庫中的一個字符串。
這就是功能強大的通用模型的美妙之處——少即是多。
在這個函數的 40 行代碼中,大部分代碼都是用來處理普通的 500 錯誤或套接字關閉錯誤(儘管 openai api 變得越來越好,但考慮到它們的負載,出現這樣的問題也並不奇怪)。
我們內置了一些自動截斷代碼,因為我們不必擔心上下文長度限制。我們有自己的 tokens 長度估計器,如下所示:
if s.length > model_context_size * 3
# truncate it!
end
在一些極端情況下,如句號或數字過多時,上述代碼會不起作用。因此,我們還有下面這個特有的 try/catch 重試邏輯:
if response_error_code == "context_length_exceeded"
s.truncate(model_context_size * 3 / 1.3)
我們使用這種方法取得了不錯的效果,而且也有足夠的靈活性來滿足我們的需求。
我們可能認為這就是一個噱頭,但用戶對於這個特性的反響很是積極。
“return an empty output if you don’t find anything(如果沒有找到任何內容,則返回空)”——這可能是我們遇到的最容易導致 gpt 出錯的提示語。
gpt 經常會產生幻覺,提供不那麼真實的答案,而不是什麼都不返回。但這樣的問題會導致它缺乏信心,什麼都不返回的次數會比正常情況下多。
我們大部分提示都是類似下面這樣:
“here’s a block of text that’s making a statement about a company, i want you to output json that extracts these companies. if there’s nothing relevant, return a blank. here’s the text: [block of text]”
(這裡有一段文字描述了一家公司,我們希望你提取這家公司並輸出 json。如果未找到任何相關內容,則返回空。文本如下:[文本內容])
有一段時間,我們有一個 bug,就是 [文本塊] 可以為空。gpt 會出現糟糕的幻覺。順便說一下,gpt 喜歡幻想麵包店,下面這些都很棒:
sunshine bakery
golden grain bakery
bliss bakery
我們的解決方案是修復這個 bug,如果沒有文本就不發送提示。但難點在於,通過編程判斷“它是空”比較困難,其實這時需要 gpt 參與進來了。
很少有人知道:gpt-4 允許的最大輸入窗口為 128k,而輸出窗口仍然只有 4k。顯然,“上下文窗口”一詞是有迷惑性的。但問題的糟糕之處在於,我們經常要求 gpt 返回一個 json 對象的列表。想象一下,一個 json 任務的數組列表,每個任務都有一個名稱和標籤。
gpt 實在沒法返回 10 項以上。硬要讓它返回 15 項的話,或許只有 15% 的情況下可以做到。
一開始,我們以為這是因為 4k 大小的上下文窗口限制,但我們發現,10 項的時候只有 700~800 個 tokens,gpt 就停下了。
現在,你當然可以把輸出變成輸入。你給它一個提示,要求它返回一個任務,然後把提示和任務一起提供給它,再要求下一個任務,以此類推。但現在,你在和 gpt 玩電話遊戲,並且必須處理類似 langchain 這樣的事情。
我累了,我真得累了。每次我想到一個殺手級的 rag / embeddings 用例時,我都會狼狽不堪。
我認為,數據庫 /rag 事實上是為搜索而存在的,僅限於搜索,而且是像谷歌或必應那樣的真正的搜索。下面是一些原因:
缺少相關性界限。這裡有一些解決方案,比如你可以創建自己的相關性界限啟發式,但那並不可靠。在我看來,這會扼殺 rag——總是會檢索出不相關的結果,或者過於保守,錯過重要的結果。
為什麼要把向量存入一個專有數據庫里而遠離其他數據呢?除非你的規模達到了谷歌 / 必應的水平,否則是不值得丟失上下文的。
除非你做的是一個非常開放的搜索,比如整個互聯網——用戶通常不喜歡語義搜索,因為它會返回一些不相關的東西。對於大多數商業應用中的搜索,用戶都是領域專家——他們不需要你去猜測他們的意思,他們會直接告訴你!
在我看來(沒測試過),對於大多數的搜索場景,llm 更好的用法是使用正常的提示補全將用戶的搜索轉換為面搜索,甚至是更複雜的查詢(甚至是 sql)。但這根本不是 rag。
從根本上講,我們的用例都是“這裡有一個文本塊,從中提取一些東西。”
一般來說,如果你讓 gpt 給出一段文本中提到的公司名,它不會隨機給出一個公司(除非文本中沒提及任何公司——這是零假設問題!)。
如果你是一名工程師,那你肯定已經注意到了:gpt 並沒有真正地生成幻覺代碼,它不會創建變量,或者在重寫你發送給它的代碼塊過程中隨機引入錯別字。
當你要求它給你一些東西時,它確實會產生存在標準庫函數的幻覺,但我還是把那看作零假設。它不知道怎麼說“我不知道”。
但如果你的用例完全是這樣的:“這是全部的上下文信息,分析 / 總結 / 提取”,那麼它會非常可靠。最近發布的很多產品都強調了這個嚴謹的用例。
因此總的來說,輸入的數據好,gpt 就會給出好的響應。
對於一些問題,我在下面直接做了回答。
a:不。用這種轉換器 + 互聯網數據 +$xb 基礎設施的方法是不行的。
a:它百分之百有用。現在仍然是互聯網的早期階段。
a:不。從根本上講,它降低了人們進入 ml/ai 領域的門檻,而之前這是谷歌才有的能力。
a:實際上,我們並沒有做任何嚴謹的 a/b 測試,但我在日常編碼過程中測試過,感覺它們還差得比較遠。主要體現在一些比較微妙的事情上,比如感知你的意圖。
a:不需要這麼做。關於 the bitter lesson,我想過很多,模型性能的總體改進會遠超小幅優化。如果真是這樣,你所需要擔心的就只有 gpt-5 何時問世,其他的都不重要。openai 在此期間發布的其他所有東西(不包括 sora 等,那是完全不同的東西)基本上都是干擾。
a:和其他人一樣,我一直在試圖從 openai 那裡尋找相關的蛛絲馬跡。遺憾的是,我認為我們接下來只會看到漸進式的改進。我對“gpt-5 會改變一切”不抱多少希望。
這其中的根本原因是經濟方面的。我之前以為,從 gpt-3 到 gpt-3.5 可能是模型通過訓練獲得超線性改進:訓練難度提高 2 倍,而性能提升 2.2 倍。但顯然,情況並非如此。我們看到的是對數關係。事實上,為實現增量改進,token 速度是呈指數級下降而單 token 成本是呈指數級增長的。
如果是這樣的話,我們就處於某種帕累托最優曲線上,而 gpt-4 可能就是最優的:儘管與 gpt-3.5 相比,我願意為 gpt-4 支付 20 倍的價格。但老實說,從 gpt-4 到 gpt-5,我不認為我會為每個 token,而不是為 gpt-4 所使用的任務集,支付 20 倍的價格。
gpt-5 可能會打破這一局面。或者,只是 iphone 5 與 iphone 4 的差別。我並不會為此感到失落!
聲明:本文為 infoq 翻譯,未經許可禁止轉載。