大語言模型的提示工程-Part 2
此篇整理自OpenAI的技術文件。
策略四:給模型時間“思考”
如果我們要在腦中計算 19 乘以 26,我們腦袋無法立即知道答案,因為需要一點時間才能計算出來。同樣,LLM在嘗試立即回答而不是花時間找出答案時會犯更多推理錯誤。在給出答案之前詢問「思路鏈(chain of thought)」可以幫助模型更可靠地推理出正確答案。
戰術一:指示模型在急於下結論之前找出自己的解決方案
有時候,當我們明確指示LLM在得出結論之前從第一原理進行推理時,我們會得到更好的結果。假設我們想要一個模型來評估員工對一個商業問題的解方。解決這個問題最明顯的方法是簡單地詢問LLM,員工的解決方案是否正確。例如以下問題:
決定員工的解決方案是否正確。
問題描述:
我正在建立一個雲端架構,我需要協助解決財務問題。
- VM租賃成本 100 美元/每台/每月
- 我可以以 250 美元/每的價格長期租賃VM美元/每台/一年
- 我簽了一份維護合約,每年將花費我 10 萬美元,每台VM額外花費 10 美元
第一年營運的總成本是多少,與每台VM的函數關係。
員工的解答:設 x 為VM的規格(以一顆CPU/ 4G記憶體為單位)。
1.雲端機房成本:100x
2.VM成本:250x
3.維護成本:100,000 + 100x
總成本:100x + 250x + 100,000 + 100x = 450x + 100,000
但以上的的解法其實不正確!因為LLM的回答就只會是正確或不正確。我們可以透過提示模型先產生自己的解決方案來讓模型注意到這一點。問題提範例如下:
首先制定自己的問題解決方案。然後將你的解決方案與員工的解決方案進行比較,並評估學生的解決方案是否正確。在你自己完成問題之前,不要決定員工的解決方案是否正確。
問題描述:
我正在建立一個雲端架構,我需要協助解決財務問題。
- VM租賃成本 100 美元/每台/每月
- 我可以以 250 美元/每的價格長期租賃VM美元/每台/一年
- 我簽了一份維護合約,每年將花費我 10 萬美元,每台VM額外花費 10 美元
第一年營運的總成本是多少,與每台VM的函數關係。
員工的解答:設 x 為VM的規格(以一顆CPU/ 4G記憶體為單位)。
1.雲端機房成本:100x
2.VM成本:250x
3.維護成本:100,000 + 100x
總成本:100x + 250x + 100,000 + 100x = 450x + 100,000
模型的回答:
設 x 為VM的規格(以以一顆CPU/ 4G記憶體為單位)。
1.雲端機房成本:100x
2.VM成本:250x
3.維護成本:100,000 + 100x
總成本:100x + 250x + 100,000 + 100x = 450x + 100,000
該員工的解決方案是錯誤的。他們在維護成本計算中犯了一個錯誤,使用了 100x 而不是 10x。第一年營運的正確總成本是 360x + 100,000。
戰術二: 使用內部小劇場或一系列問題來隱藏模型的推理過程
上面的戰術呈現到,模型有時在回答特定問題之前詳細推理問題很重要。對於某些應用程式,模型用於得出最終答案的推理過程不適合呈現給人類。例如,在輔佐應用程式中,我們可能希望鼓勵員工得出自己的答案,但模型關於員工解決方案的推理過程可能會向員工揭示答案。
內部小劇場(inner monologue)是一種可以用來緩解這種情況的戰術。內部小劇場的想法是指示LLM將原本對使用者隱藏的部分輸出放入結構化格式中,以便於解析它們。然後,在向使用者呈現輸出之前,將解析輸出並且僅使部分輸出可見。例如以下問題:
請依照以下步驟回答使用者的疑問。
步驟 1 — 先找出你自己的問題解決方案。不要依賴員工的解決方案,因為它可能是不正確的。將這一步驟的所有作業用三引號 (“””) 括起來。
步驟 2 — 將你的解決方案與員工的解決方案進行比較,並評估員工的解決方案是否正確。將這一步驟的所有作業用三引號 (“””) 括起來。
步驟 3 — 如果員工犯了錯誤,請確定在不洩漏答案的情況下可以給員工什麼提示。將這一步驟的所有作業用三引號 (“””) 括起來。
步驟 4 — 如果員工犯了錯誤,請向員工提供上一步的提示(在三重引號之外)。不要寫“步驟 4 — …”,而寫“提示:”。
使用者的問題:
問題描述:XXXXXXX
員工的解決方案:XXXXXXXXX
或者,這可以透過一系列問題來實現,其中除了最後一個問題之外,所有問題的答案都對問問題的人隱藏。
首先,我們可以要求模型自己解決問題。由於這個初始問題不需要員工的解決方案,因此可以省略。這提供了額外的優勢,即模型的解決方案不會因員工嘗試的解決方案而產生偏差。
接下來,我們可以讓模型使用所有可用資訊來評估員工解決方案的正確性。問題範例如下:
問題描述:XXXXXXXXXX
將你的解決方案與員工的解決方案進行比較,並評估員工的解決方案是否正確。
問題陳述:“”“XXXXXXXXXXXX”“”
你的解決方案:“”“XXXXXXXXXXXXX”“”
學生的解決方案:“”“XXXXXXXXXXX”“”
最後,我們可以讓LLM使用自己的分析來以導師的角色進行回答。範例問題如下:
你是雲端架構師。如果員工犯了錯誤,請以不透露答案的方式向員工提供提示。如果員工沒有犯錯,只需給他們一個鼓勵性的評論。
問題陳述:“”“XXXXXXX”“”
你的解決方案:“”“XXXXXXXXXXXX”“”
員工的解決方案:“”“XXXXXXXXXXX”“”
分析:“”“XXXXXXXXXXXXXXX”“”
戰術三:詢問LLM在先前的過程中是否遺漏了任何內容
假設我們使用一個模型來列出與特定問題相關的來源的摘錄。列出每個摘錄後,模型需要確定是否應該開始編寫另一個摘錄或是否應該停止。如果來源文件很大,模型通常會過早停止並且無法列出所有相關摘錄。在這種情況下,透過使用一連串問題提示模型來尋找在先前的產出中遺漏的任何摘錄,通常可以獲得更好的效能。範例問題:
你將取得一份由三重引號分隔的文件。任務是選擇與以下問題相關的摘錄:“雲端運算歷史上發生了哪些重大的範式轉變。”
確保摘錄包含解釋它們所需的所有相關上下文 — 換句話說,不要提取缺少重要上下文的小片段。提供 JSON 格式的輸出,如下所示:
[{“摘錄”:“…”},
……
{「摘錄」:「…」}]
“””插入文件”””
模型回覆:
[{“摘錄”: “模型在此編寫摘錄”},
……
{「摘錄」:「模型在這裡寫了另一個摘錄」}]
使用者再次詢問:
還有更多相關摘錄嗎?注意不要重複摘錄。還要確保摘錄包含解釋它們所需的所有相關上下文 — 換句話說,不要提取缺少重要上下文的小片段。
策略五:運用外部工具
透過向模型提供其他工具的輸出來彌補模型的弱點。例如,文字檢索系統(有時稱為 RAG 或檢索增強生成)可以告訴模型相關文件。像 OpenAI 的代碼解釋器這樣的代碼執行引擎可以幫助模型進行數學運算並運行代碼。如果一項作業可以透過工具而不是語言模型更可靠或更有效地完成,那麼可以加入工具以充分利用兩者。
戰術一:使用基於嵌入的搜尋實現高效的知識檢索
模型可以利用外部資訊來源作為輸入的一部分。這可以幫助模型產生更明智和最新的回應。例如,如果使用者詢問有關特定雲端的問題,則將有關雲端的高品質資訊(例如廠牌、佈署模型等)添加到模型的輸入中可能會很有用。嵌入(Embeddings)可用於實現高效的知識檢索,從而可以在運作時動態地將相關資訊添加到模型問題輸入中。
文字嵌入(text embedding)是一個可以衡量文字字串之間相關性的向量。相似或相關的字串比不相關的字串更接近。這一事實以及快速向量搜尋演算法的存在意味著嵌入可以用於實現高效的知識檢索。特別地,文字語料庫(text corpus)可以被分割成區塊,並且每個區塊可以被嵌入和儲存。然後可以嵌入特定的查詢,並且可以執行向量搜尋以從語料庫中找到與查詢最相關的嵌入文字區塊(即在嵌入空間中最接近的文字區塊)。
範例實作可以在 OpenAI Cookbook 中找到。請參閱策略二-戰術一的“指示模型透過引用參考文本來回答問題”,以了解如何使用知識檢索來最大程度地減少模型編造不正確事實的可能性的範例。
戰術二: 運用執行代碼來執行更準確的計算或呼叫外部API
不能依賴LLM自行準確地執行算術或長時間計算。在需要的情況下,可以指示模型編寫和執行代碼,而不是進行自己的計算。特別是,可以指示模型將要執行的代碼放入指定的格式,例如三重反引號。產生輸出後,可以提取並運行代碼。最後,如有必要,可以將代碼執行引擎(如 Python interpreter)的輸出作為下一個查詢的模型的輸入。
你可以透過將 Python 代碼括在三個反引號中來編寫和執行,例如```代碼在這裡執行```。用它來執行計算。
使用者的問題: 求下列多項式的所有實值根:3*x**5–5*x**4–3*x**3–7*x — 10。
代碼執行的另一個很好的用例是呼叫外部 API。如果模型接受如何正確使用 API 的指導,它就可以編寫使用該 API 的代碼。透過向模型提供展示如何使用 API 的文件和(或)代碼範例,可以指導模型如何使用 API。例如:
你可以透過將 Python 代碼括在三個反引號中來編寫和執行它。另請注意,可以訪問以下模組來幫助使用者向朋友發送訊息:
```python
import message
message.write(to="Jason", message="要在下午開會嗎?")```
警告:執行LLM產生的代碼本質上並不安全,任何試圖執行此操作的應用程式都應採取預防措施。特別是,需要sandboxed code execution environment來限制不受信任的代碼可能造成的危害。
戰術三:授予模型存取特定函數的權限
Chat Completions API 允許在request中傳遞函數描述清單。這使得模型能夠根據提供的模式產生函數參數。產生的函數參數由 API 以 JSON 格式傳回,可用於執行函數呼叫。然後,可以將函數呼叫提供的輸出回饋到以下請求中的模型以關閉循環。這是使用OpenAI模型呼叫外部函數的建議方式。更多的資訊,請參閱介紹性文字生成指南中的函數呼叫部分以及 OpenAI Cookbook 中的更多函數呼叫範例。
策略六: 有系統地測試變更
如果我們可以衡量效能,那麼提高效能就會更容易。在某些情況下,對提示的修改將在幾個獨立的範例上實現更好的效能,但會導致在一組更具代表性的範例上整體效能變差。因此,為了確保變更對效能產生純粹的正面影響,可能有必要定義一個全面的測試套件(也稱為「評估」)。
戰術:參考黃金標準答案評估模型輸出
假設已知問題的正確答案應參考一組特定的已知事實。然後我們可以使用模型查詢來計算答案中包含多少必需的事實。
例如,使用以下系統訊息:
擬將會有由三引號分隔的文本,該文本應該是問題的答案。檢查答案中是否直接包含以下資訊:
- 尼爾阿姆斯壯是第一個登上月球的人。
- 尼爾阿姆斯壯首次登上月球的日期是 1969 年 7 月 21 日。
對於其中的每一點,請執行以下步驟:
1 — 重申這一點。
2 — 提供最接近這一點的答案的引文。
3 — 考慮不知道主題的閱讀引文的人是否可以直接推斷出該點。在做出決定之前解釋一下原因或原因。
4 — 如果 3 的答案是“是”,則寫“是”,否則寫“否”。
最後,計算有多少個「是」答案。將此計數提供為 {“count”: <在此處插入計數>}。
使用者第一個問題:
“””尼爾阿姆斯壯因成為第一個踏上月球的人類而聞名。這一歷史性事件發生在 1969 年 7 月 21 日,在阿波羅 11 號任務期間。”””
使用者第二個問題:
“”” 1969 年夏天,阿波羅11 號進行了一次偉大的航行,像傳奇之手一樣大膽。阿姆斯特朗邁出了一步,歷史展開了,“一小步,”他說,為了一個新世界。” “”
這種基於模型的評估有許多可能的變體。考慮以下變體,它追蹤可能的答案和黃金標準答案之間的重疊類型,並且還追蹤可能的答案是否與黃金標準答案的任何部分相矛盾。以下的系統訊息:
使用以下步驟回應使用者輸入。在繼續之前充分重申每個步驟。即「第 1 步:原因…」。
第 1 步:逐步推理所提交答案中的資訊與專家答案相比是否為:不相交、相等、子集、超集或重疊(即有交集,但不是子集/超集)。
步驟2:逐步推理提交的答案是否與專家答案的任何方面相矛盾。
步驟 3:輸出一個 JSON 對象,結構如下
:{"type_of_overlap": "disjoint" or "equal" or "subset" or "superset" or "overlapping", "contradiction": true or false}
這是一個範例輸入,其答案不合格,但與專家答案並不矛盾:
<系統訊息 — 如上的文字描述>
使用者問題:
問題:“”“尼爾·阿姆斯特朗最著名的事件是什麼以及它發生的日期?假設 UTC 時間。”“”
提交的答案:“”“他沒有在月球上行走過嗎?”“”
專家解答:“”“尼爾·阿姆斯特朗最著名的是第一個登上月球的人。這一歷史性事件發生在1969年7月21日。”“”
這是一個範例輸入,其答案與專家答案直接矛盾:
<系統訊息 — 如上的文字描述>
使用者問題:
問題:“”“尼爾·阿姆斯特朗最著名的事件是什麼以及它發生的日期?假設 UTC 時間。”“”
提交的答案:“”“1969 年 7 月 21 日,尼爾·阿姆斯特朗成為繼巴茲·奧爾德林之後第二個登上月球的人。”“”
專家解答:“”“尼爾·阿姆斯特朗最著名的是第一個登上月球的人。這一歷史性事件發生在1969年7月21日。”“”
下面是一個帶有正確答案的範例輸入,它還提供了比必要的更多的細節:
<系統訊息 — 如上的文字描述>
使用者問題:
問題:“”“尼爾·阿姆斯特朗最著名的事件是什麼以及它發生的日期?假設 UTC 時間。”“”
提交的答案:“”“世界標準時間1969 年7 月21 日大約02:56,尼爾·阿姆斯特朗成為第一個踏上月球表面的人類,標誌著人類歷史上的一項里程碑式的成就。” “”
專家解答:“”“尼爾·阿姆斯特朗最著名的是第一個登上月球的人。這一歷史性事件發生在1969年7月21日。”“”