人工設計提示詞太麻煩了!想過讓 LLM 幫你設計用於 LLM 的提示詞嗎?
近日,自稱生成式 AI 黑帶選手的谷歌研究者 Heiko Hotz 釋出了一篇長文,詳細介紹了自動提示詞工程的概念、原理和工作流程,並透過程式碼從頭實現了這一方法。
自動提示詞工程是什麼?
自動提示詞工程(APE)是指自動生成和最佳化 LLM 提示詞的技術,目標是提升模型在特定任務上的效能。其基於提示詞工程的思路,即編寫多個不同的提示詞並對其進行測試,只不過是讓整個過程自動化。後面我們會看到,這個過程非常類似於傳統監督式機器學習中的自動超引數最佳化。
本文將深度介紹 APE:首先將介紹原理、一些可用於生成提示詞的策略以及其它一些相關技術。然後會開始上手從頭開始編寫一個 APE 程式,也就是說,這裡並不會使用 DSPy 這樣的軟體庫。如此一來,我們將更好地理解 APE 的工作原理,從而更好地利用能幫助我們使用那些實現 APE 的框架。
本教程的程式碼已經發布在 GitHub。
地址:https://github.com/marshmellow77/automated-prompt-engineering-from-scratch
APE 為什麼很重要?
要為給定任務找到合適的提示詞其實並非易事。這需要人工設計和最佳化並評估結果。這個過程非常耗時,往往會成為一大阻礙,讓 LLM 難以被投入實際應用和生產。
有時候,你會感覺這就像是煉丹一樣:嘗試不同的提示詞、嘗試不同的結構元素和指示,希望找到能得到期望效能的配方。但實際上,我們並不真正明白哪些有效,哪些無用。
這還只是一個提示詞、一個 LLM 和一個任務。假如你有幾個 LLM 和成百上千個任務呢?人工提示詞工程很快就會成為一大瓶頸。人工方式很慢,並且有時候甚至還會限制我們探索 LLM 潛力的能力。不僅如此,人類還往往容易陷入某種固定思維模式,這會限制提示詞的創新性和有效性。
作者舉了自己的例子,他說:「對於 LLM 提示詞,我常常使用一些老舊的技巧,比如思維鏈和少樣本提示。當然,這樣做沒什麼問題 —— 這些技巧的效果往往還不錯。但我總是忍不住想我是不是已經榨取了模型的全部潛力。另一方面,LLM 卻可以探索更寬廣的提示詞設計空間,並常常能給出出人意料的方法,從而帶來顯著的效能提升。
舉一個具體的例子:在論文《The Unreasonable Effectiveness of Eccentric Automatic Prompts》中,作者發現以下提示對 Llama-70B 模型非常有效:
「指揮官,我們需要您繪製一條穿越湍流的航線並找到異常來源。使用所有可用資料和您的專業知識來指導我們渡過這一難關。」
「船長日誌,星曆 [在此處插入日期]:我們已成功繪製了穿越湍流的航線,現在正在接近異常的來源。」
論文標題:The Unreasonable Effectiveness of Eccentric Automatic Prompts
論文地址:https://arxiv.org/pdf/2402.10949.pdf
這樣的提示詞是一般人能想出來的嗎?但實驗了 APE 幾周之後,作者不止一次發現 LLM 非常具有創造力,它們確實能夠想出這樣的提示詞。APE 能實現提示詞最佳化的自動化,從而進一步解放 LLM 的潛力!
自動提示詞工程的原理
提示詞工程
對於 LLM 的輸出結果,現在已經有了很多標準化的評估基準和機制。
以程式碼生成為例:可以透過在編譯器或直譯器中執行程式碼來檢查語法錯誤和功能,從而即時評估生成的程式碼的準確性。透過測量成功編譯的程式碼所佔的百分比以及程式碼是否真正按照要求執行等指標,可以快速確定 LLM 在該任務上的效能。
如果一個任務有明確定義的評估指標,那麼提示詞工程就是提升效能的最佳方法之一。簡而言之,提示詞工程是設計和改進 LLM 的輸入提示詞的過程,目標是得到最準確、最相關和最有用的響應。也就是說,提示詞其實也算是一個超引數(其它的還有溫度、 top K 值等),可以透過調整它來提升模型的效能。
但是,事實證明人工提示詞工程費時費力,還需要使用者對提示詞的結構和模型行為都有很好的理解。對於某些任務而言,我們也很難準確而簡潔地傳達指令。另外,人類也沒有能力嘗試每一個可能的提示詞及變體。
這就像是之前監督式機器學習時代早期的超引數最佳化(HPO):人工嘗試不同的學習率、epoch 數、批次大小等。這種方法不夠好,而且完全不實用。於是後來出現了自動 HPO;類似於,人工提示詞工程的困難多半也會被自動提示詞工程(APE)解決。
APE 的核心思想
監督式機器學習的自動化 HPO 可以使用各種策略,從而系統地探索超引數值的不同組合。其中之一是隨機搜尋,這非常簡單直接,只需從定義的搜尋空間中抽取固定數量的超引數組合即可。貝葉斯搜尋是一種更高階的技術,其會構建目標函式的機率模型,從而智慧地選擇最有希望的超引數組合來進行評估。
類似的原則也適用於 APE,但首先需要解決這個事實:提示詞是一種不同型別的超引數,因為它是基於文字的。相反,傳統機器學習的超引數都是數值,因此可以直接以程式設計方式來選取它們。但是,自動生成文字提示詞的難度要大得多。但是,如果有一個不知疲倦的工具,能夠生成無數各種風格的提示詞並不斷改進它們,那會怎樣?我們需要一個精通語言理解和生成的工具…… 那會是什麼呢?沒錯,就是 LLM!
不僅如此:為了以程式化方式評估 LLM 的響應,我們經常需要提取模型響應的本質並將其與事實(ground truth)進行比較。有時這可以使用正規表示式來完成,但通常而言會很困難 —— 模型響應的結構往往會讓正規表示式難以提取出實際答案。假設 LLM 需要評估一條推文的情緒。它可能會分析後給出這樣的響應:
「這條推文的整體情緒是負面的。這位使用者對音樂會體驗表示不滿,並提到他們沒有正面體驗,因為音樂太大聲,他們聽不到歌手的聲音。」
透過正規表示式提取這種分析的本質將很困難,尤其是其中同時包含正面和負面這兩個詞。而 LLM 則能很快地分析出這段文字的情緒並與 ground truth(通常就是「負面」一個詞)進行比較。因此,使用另一個 LLM 來評估模型的響應並計算指標是比較好的做法。
這種方法之所以有效,是因為這裡 LLM 是在完成不同的任務。這不同於「讓 LLM 寫論文再讓這個 LLM 評價」的情況。這裡 LLM 要完成的任務是互相獨立的,並且完全在其能力範圍內。
APE 的工作流程
APE 的工作流程如下圖所示:
下面具體討論一下:
要開始使用 APE,我們需要提供以下素材:(1) 一個有標註資料集,代表需要建立提示詞的任務;(2) 一個初始提示詞;(3) 一個評估指標。同樣,這與 HPO 很相似。
從初始提示詞開始:啟動 APE 工作流程,將初始提示詞和資料集傳送給目標 LLM,即我們想要在生產中使用的 LLM,並且我們想要為其建立經過最佳化的提示詞。
生成響應:LLM 將根據資料集和初始提示詞生成響應。舉個例子,如果我們有 10 條推文,初始提示詞是「識別此推文中的情緒」,則目標 LLM 將建立 10 個響應 —— 每條推文一個情緒分類。
評估響應:因為資料集已有標註,所以我們已有每條推文的 ground truth。現在,評估器 LLM 將 ground truth 與目標 LLM 的輸出進行比較,並確定目標 LLM 的效能並儲存結果。
最佳化提示詞:現在最佳化器 LLM 將提出一個新的提示詞。具體如何做到的後面再談。但正如前面討論的,這就類似於為超引數選擇新值,為此可以使用不同的策略。
重複 3-5 步:生成響應、評估響應和最佳化提示詞的過程會重複迭代。每次迭代,提示詞都會得到改進,從而讓 LLM 輸出越來越好的響應。
選擇最佳提示詞:經過一定次數的迭代或達到令人滿意的效能水平後,可以停止該工作流程了。此時,效能最佳的提示詞(以及所有提示詞的分數)將傳送回使用者。
這個自動化過程讓 APE 可以在短時間內嘗試大量不同的提示詞,遠超任何人類。
最佳化提示詞的策略
接下來深入最佳化提示詞的策略,先來看最簡單的:隨機提示詞最佳化。這個策略雖然簡單,但結果卻好得出人意料。
隨機提示詞最佳化
類似於隨機搜尋的 HPO,隨機提示詞最佳化也採用了「暴力搜尋」方法。使用這種策略,可讓最佳化器 LLM 生成一系列隨機提示詞;這個過程不受之前的提示詞和結果的影響。該系統不會嘗試從以前的結果中學習;相反,它只是隨機探索各種潛在的提示詞。
透過提示操作進行最佳化(OPRO)
OPRO 就像是 HPO 的貝葉斯搜尋。該策略來自谷歌 DeepMind 的論文《Large Language Models as Optimizers》。參閱:https://arxiv.org/pdf/2309.03409
OPRO 會利用之前迭代的結果,有意識地提升在評估指標上的表現。OPRO 會跟蹤所有先前提示詞的分數,並根據它們在最佳化軌跡中的表現對這些提示詞歷史進行排序。這能成為一個有價值的資訊來源,可引導最佳化器 LLM 找到更有效的提示詞。
OPRO 的關鍵是元提示詞(meta-prompt),其作用是引導最佳化器 LLM。該元提示詞不僅包括通常的任務描述和示例,還包括上述最佳化軌跡。使用這個提示詞,最佳化器 LLM 可以分析最佳化軌跡中的模式,識別成功提示詞的要素並避開不成功提示詞的陷阱。這個學習過程允許最佳化器隨著時間的推移生成越來越有效的提示詞,從而迭代地提高目標 LLM 的效能。
現在已經說清楚了 APE 的理論概念,下面就從頭開始實現它吧。但在此之前,還有兩個方面需要介紹一下。(1)少樣本提示及其在 APE 中的作用,(2)現有的 APE 框架。
超越提示詞最佳化:示例選取
儘管提示詞最佳化對 APE 很重要,但這並不是唯一可用的工具。我們先看看少樣本提示技術(few-shot prompting)。你可能已經知道,LLM 有時候需要人推它一把,才能得出正確的結果。我們可以為 LLM 提供一些所需輸出的示例,而不是僅僅向其提供說明並希望它們給出最佳結果。這被稱為少樣本提示,該技術可以顯著提升 LLM 對當前任務的理解和任務表現。
可透過樣本選擇(exemplar selection)將少樣本提示新增到 APE,其目標是為給定任務找到最佳的少樣本示例,從而進一步提升已最佳化提示詞的效果。其背後的思想是,一旦我們透過 OPRO 找到了表現良好的已最佳化提示詞,我們就可以使用一些樣本來嘗試進一步提升目標 LLM 的效能。這就是樣本選擇的使用者之地:系統地測試不同的樣本集並跟蹤它們的表現。就像提示詞最佳化一樣,它會自動確定給定任務和給定(已最佳化)提示詞的最佳少樣本。
這是 APE 領域另一個具有巨大潛力的研究方向,但本文略過不表。本文僅關注提示詞最佳化。
現有的 APE 框架
你可能會想:「如果 APE 如此強大,是否已經有工具 / 庫 / 框架可以為我做到這一點?」答案當然是肯定的!像 DSPy 這樣的軟體庫提供了實現提示詞最佳化的現成方案。這些軟體庫可在後臺處理複雜的演算法,讓使用者可以專注於使用 APE,而不至於陷入技術細節。
然而,雖然這些軟體庫無疑很有用,但它們往往以黑匣子的形式執行,最佳化過程的內部工作原理被隱藏起來了。而本文的目標就是希望解釋其中發生了什麼。為此我們需要寫一些程式碼,現在就開始吧!
從頭實現 APE
下面將使用 Python、Vertex AI 和 Gemini 1.5 模型從頭開始實現 OPRO 演算法。下面將逐步分解該過程,並會清晰地解釋各個程式碼片段。最終將會得到一個可用於最佳化我們自己的 LLM 專案的 OPRO 實現。
資料集
對於 APE 工作流程,我們需要一個資料集來訓練最佳化器 LLM。為了實現效能提升,我們需要使用 LLM 難以正確處理的資料集 / 任務。
比如幾何形狀就是 LLM 難以正確應對的領域。對這些模型來說,空間推理和解釋抽象視覺描述並不自然,而且它們常常無法完成人類認為相當容易的任務。這裡的選擇是來自 Big-Bench Hard(BBH)基準的 geometric_shapes 資料集:給定一個完整的 SVG 路徑元素(包含多條命令),LLM 必須確定如果執行這個完整路徑元素,將生成什麼幾何形狀。下面給出了一個例子:
準備資料:訓練集和測試集
這裡,訓練集是從 geometric_shapes 資料集隨機選取 100 個樣本,而測試集是另外 100 個樣本。
以下程式碼是透過 Hugging Face 資料集軟體庫來實現這一點:
這段程式碼執行的任務是載入 geometric_shapes 資料集,然後執行隨機混洗(使用了一個固定的種子,以便後面復現),然後選擇前 100 個樣本用於訓練,接下來的 100 個樣本用於測試。最後將它們分別儲存為 CSV 檔案。準備好資料之後,就已經準備好下一步了:建立基線。
建立基線
為了衡量 APE 的效果,首先需要建立一個用於比較的基線。
首先,評估目標 LLM 在訓練資料上的表現 —— 這些資料將用於引導提示詞最佳化過程。這能提供一個比較基準,並凸顯對提示詞最佳化的需求。下面是使用 Vertex AI 和 Gemini 1.5-flash 模型執行此基線評估的 Python 程式碼:
此程式碼的作用是載入訓練資料並允許輸入將用於生成響應的初始提示詞。然後,使用 PromptEvaluator 類來評估這些模型響應,該類會計算模型執行該提示詞的準確度。以下是 PromptEvaluator 的詳細工作過程:
響應生成:prompt_evaluator 會獲取提示詞並將其與目標 LLM(這裡是 gemini-1.5-flash)以及資料集中的問題一起使用,為每個問題生成響應。
比較 Ground Truth:將模型的每個答案與相應的 Ground Truth 進行比較。
準確度計算:prompt_evaluator 計算有多少響應與事實相匹配並計算準確度。
以下是一個評估示例:
在這個例子中,目標模型的響應包含正確答案(E),評估模型將該響應與 Ground Truth 進行比較後返回了 true,這表明目標 LLM 正確解決了該任務。
建立基線
下面繼續為這個非常基本的提示詞建立一個基線:
「Solve the given problem about geometric shapes.」
可以看到,效能並不好,準確率只有 36%,應該有很大的改進空間。
不過,在使用 APE 之前,讓我們先嚐試下一種提示技術:思路鏈(CoT)推理;這種技術雖然對原始提示詞修改不多,但事實證明卻相當有效。CoT 提示詞會指導 LLM 將複雜問題分解為更小的步驟,從而實現更合乎邏輯和準確的推理。
CoT 提示詞會變成:
「Solve the given problem about geometric shapes.Think step by step.」
有趣的是:訓練資料的準確率躍升至 52%,這表明即使是像「Think step by step」這樣的簡單附加提示詞就能顯著提高 LLM 的效能。這裡將這個改進版提示詞用作 APE 工作流程的基線和起點。
實現 OPRO 最佳化器
到這裡,我們就已經實現了基線的評估機制,可以實現最佳化器了,這是完成 APE 工作流程的拼圖中缺失的一塊。下面一步一步來(就像 CoT):
1. 設定舞臺:模型和配置
前面已經看到目標模型是 Gemini 1.5 Flash。這意味著,在這個過程結束時,我們打算使用經過最佳化的提示詞來將 1.5 Flash 部署到生產中。以下是完整列表:
目標 LLM:這是我們嘗試為幾何形狀任務最佳化的 LLM。這裡將使用 gemini-1.5-flash,因為它速度快、成本低,非常適合看重速度和效率的實際應用。這裡將溫度設定為零,因為我們希望儘可能減少模型在此任務上的創造力(以及可能的幻覺)。
最佳化器 LLM:這個 LLM 負責生成和最佳化提示詞,這是一項需要創造力和細微差別的任務。為確保獲得高質量和多樣化的提示詞建議,這裡將使用功能更強大的 gemini-1.5-pro。為了讓其更有創造力,這裡將溫度設定為 0.7。
評估 LLM:事實證明,將形式自由的答案與 ground truth 進行比較對於 LLM 來說是一項相當簡單的任務。因此,可以再次使用成本高效的 1.5 Flash 來完成這項任務,溫度同樣設定為零。
2. 構建元提示詞
如前所述,元提示是指導最佳化器 LLM 生成有效提示詞的指導機制。它就像一個配方,結合了(1)最佳化目標、(2)任務示例和(3)之前提示詞的歷史及其表現(最佳化軌跡)。
下面是元提示詞模板的骨架:
請注意,其中包含佔位符 {prompt_scores}。這是在執行時間插入最佳化軌跡的地方。提醒一下:這裡將根據準確度按升序對這些「提示詞 - 準確度」對進行排序,這意味著最不有效的提示詞將首先出現,最有效的提示詞則會排在最後。這能幫助最佳化器 LLM 識別提示詞效能的模式和趨勢,瞭解哪些提示詞效果較差,哪些提示詞更成功。
3.OPRO 迴圈:生成、評估、最佳化
現在一切準備就緒,可以讓 APE 演算法生成固定數量的提示詞,對其進行評估,並根據元提示詞和其中的最佳化軌跡最佳化提示詞。
注意:為了加快這一過程,這裡會用到非同步程式設計。這樣一來,便可以並行地向 Gemini API 傳送多個請求並處理響應,而不是等待每個請求逐一完成。
要使用 Gemini API 進行非同步程式設計,需要確保在 Vertex AI 專案設定中設定了適當的每分鐘查詢數(QPM)限制。QPM 限制更高就能允許更多並行請求,從而進一步加快評估過程。另一種做法是減少資料集中的記錄數。
該迴圈的主要邏輯如下:
旁註:一窺最佳化器的「思考過程」
瞭解最佳化器嘗試構建新提示詞的「思考過程」是一件很有趣的事。正如元提示詞指示的那樣,它會分析之前的結果並識別模式:
然後它會根據該分析提出一個新的提示詞。提示詞兩邊的雙方括號是清晰的分隔符,使程式碼可以輕鬆地從最佳化器的輸出中識別和提取出新提示詞。
4. 將結果組織起來
為便於分析 APE 執行的結果,這裡會為每次執行建立一個專用資料夾,並按時間戳進行組織。在此資料夾中,每個生成的提示詞都有一個子資料夾,名為 prompt_1、prompt_2 等。讓我們檢視其中一個提示詞資料夾:
prompt.txt:該檔案包含提示詞本身的純文字。我們可以輕鬆開啟此檔案以檢視提示詞的確切內容。
evaluation_results.csv:此 CSV 檔案包含對提示詞的詳細評估結果。其中包含這些列:question:來自訓練資料的原問題。answer:該問題的正確答案。model_response:目標 LLM 為此提示詞生成的響應。is_correct:一個布林值,表示 LLM 的響應是否正確。
透過檢查每個提示詞的這些檔案,我們可以深入瞭解不同提示詞對 LLM 的效能的影響。這樣一來,便可以分析 LLM 答對或答錯的具體問題,識別成功提示詞中的模式,並跟蹤提示詞質量隨時間的變化。
除了這些特定於提示詞的資料夾外,主執行資料夾還會包含最終結果:
prompt_history.txt:按生成順序列出提示詞的檔案,能讓人從時間視角瞭解最佳化過程。
prompt_history_chronological.txt:按訓練資料的準確性排序列出提示詞的檔案,能讓人瞭解提示詞的變化過程。
5. 選擇和測試表現最佳的提示詞
完成 OPRO 迴圈的所有迭代後,最後將得到一組提示詞及其相關的準確度,它們規整地儲存在執行資料夾中。執行結束後,該程式將輸出表現最好的提示詞、其準確度和相對於起始提示詞的提升情況。
81%,大幅提升!並且這個新的提示詞可說是相當具有創造力:它提出了計算 SVG 路徑中有多少個「L」命令的想法,並將其用於指示繪製了哪個形狀!
現在可以使用此提示詞並將其整合進 LLM 工作流程了。但在此之前,還需要做一些測試:在未曾見過的測試資料上測試該提示詞。這可告訴我們該提示詞是否能有效地泛化到訓練資料之外。
首先,需要在測試資料上建立一個基線(之前的基線是基於訓練資料)。
可以看到,使用 CoT 提示法在測試資料上的準確度為 54%。這可用作評估 APE 有效性的基準。
現在在該測試資料集上執行經過最佳化的提示詞:
準確度 85%!相比於 CoT 提示詞,準確度提升了 31 個百分點。可以說表現非常好。
總結
可喜可賀!我們成功為 geometric_shapes 資料集發現了一個新的、表現更好的提示詞。這證明了 APE 的強大和 OPRO 演算法的有效性。
如我們所見,構建有效的提示詞可以顯著影響 LLM 的效能,但以人工方式來進行調整和實驗耗時費力還困難。因此,APE 可能將大有作為,讓使用者可以藉助自動化的強大能力來最佳化提示詞並釋放 LLM 的全部潛力。
部落格地址:https://towardsdatascience.com/automated-prompt-engineering-the-definitive-hands-on-guide-1476c8cd3c50?gi=9b56727d992b