提示工程是有效利用大語言模型(LLM)的關鍵。良好的提示設計能引導模型生成更精確、更符合預期的結果。本文除了探討提示結構設計外,也深入研究如何利用程式碼片段強化提示效果,並解析 XML、YAML 和 JSON 等結構化檔案在提示工程中的應用。此外,文章也將探討如何根據不同的檔案型別和應用場景,選擇合適的程式碼片段格式化策略,以及如何組合提示元素以獲得最佳效能。最後,文章將分析如何最佳化 LLM 輸出,包括控制輸出長度、使用停止序列和串流模式等技巧,以提升效率並降低成本。
分析報告範例
目錄
分析
結論
附錄
本報告旨在分析市場趨勢。
分析
市場趨勢顯示…
程式碼解析範例
# 定義一個函式來分析市場趨勢
def analyze_market_trend(data):
# 對資料進行處理和分析
trend = process_data(data)
return trend
# 呼叫函式並輸出結果
trend = analyze_market_trend(market_data)
print(trend)
內容解密:
analyze_market_trend函式:此函式負責分析市場趨勢,接受資料作為輸入,並傳回分析結果。process_data函式:在此範例中未定義,但它負責對輸入資料進行處理和分析,以得出市場趨勢。market_data變數:代表輸入的市場資料,用於函式呼叫。print(trend):將分析得到的市場趨勢輸出到控制檯。
透過上述範例,可以看到如何利用程式碼來支援分析報告的撰寫,以及如何使用Markdown格式來組織報告內容。這種結合技術內容和清晰結構的方法,可以有效地提高生成內容的品質和相關性。
結構化檔案在大語言模型中的應用
結構化檔案遵循特定的格式規範,這使得大語言模型(LLM)能夠對輸出的形式做出強有力的假設,從而簡化解析過程,包括解析複雜的輸出內容。
結構化檔案的優勢
以 Anthropic 的 Artifacts 提示為例,Artifacts 是使用者與助手共同協作的自包含檔案,例如 Python 指令碼、小型 React 應用程式、Plantuml 圖表和可縮放向量圖形(SVG)圖表。這些 Artifacts 在 UI 中以文字形式呈現在對話視窗右側的面板中,並且在 React、Plantuml 和 SVG 的情況下,它們會被渲染成功能性或視覺化的原型。
Artifacts 提示範例
<examples>
<example>
<user_query>Can you help me create a Python script to calculate the factorial of a number?</user_query>
<assistant_response>
Sure! Here's a Python script that calculates the factorial of a number:
<antThinking>Creating a Python script to calculate factorials meets the criteria for a good Artifact. Therefore, I'm creating a new Artifact.</antThinking>
<antArtifact identifier="factorial-script" type="application/vnd.ant.code" language="python" title="Simple Python factorial script">
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
</antArtifact>
</assistant_response>
</example>
</examples>
程式碼解析
上述範例展示瞭如何使用 XML 結構來定義 Artifacts。在 <assistant_response> 中,首先是助手的回應,接著是一個 <antThinking> 區塊,讓助手可以「思考」是否應該使用 Artifact 或只是進行正常的對話。如果決定使用 Artifact,則文字中會包含一個 <antArtifact> 區塊,其中包含 Artifact 的文字。
XML 結構的特點
XML 檔案由一系列開啟和關閉的標籤組成,標籤可以具有屬性和內容,並且可以包含子標籤。選擇 XML 的好處在於,如果個別元素相對較短,並且在多行時,縮排並不重要。但是,需要注意 XML 中的五個轉義序列:" ("), ' (’), < (<), > (>), 和 & (&)。
其他結構化檔案格式
除了 XML 之外,YAML 和 JSON 也是常見的結構化檔案格式。YAML 使用縮排來追蹤層次結構,這在需要精確縮排的情況下很有用,例如程式碼或格式化文字。JSON(或其變體 JSON Lines)曾經因為需要大量轉義而被認為不適合使用,但是 OpenAI 對其模型的 JSON 生成能力進行了大量改進,因此對於 OpenAI 而言,JSON 仍然是一個合理的選擇。
結構化檔案的應用
結構化檔案可以以多種不同的格式呈現。使用 XML、YAML 或 JSON 等常見格式,可以使 LLM 更容易解析和生成內容。在實際應用中,可以根據具體需求選擇適合的結構化檔案格式,以實作更高效的內容生成和解析。
結構化檔案的未來發展
隨著 LLM 的不斷發展,結構化檔案的應用也將變得更加廣泛。未來,我們可以期待看到更多創新的結構化檔案格式和應用場景,以滿足不同領域的需求。
格式化程式碼片段的藝術
格式化程式碼片段的方式取決於你的檔案型別。在對話形式的建議中,你可以將片段資訊格式化為來回的對話回合。例如,假設你的應用程式檢索到以下天氣預報資料:
weather = {
"description": "sunny",
"temperature": 75
}
這些資訊可以被包裝成使用者詢問澄清問題,而助理則回答如下:
使用者:天氣怎麼樣?
助理:將會是 {{ weather["description"] }},氣溫為 {{ weather["temperature"] }} 度。
程式碼解密:
這段程式碼展示瞭如何將天氣資料格式化為自然語言對話。weather 字典包含了天氣描述和溫度,透過範本引擎將這些值插入到自然語言回應中。這種方法的優點是能夠以自然的方式呈現資料,使其更易於理解。
在分析報告中,通常需要以自然語言陳述你的知識。API呼叫的結果需要你瞭解API傳回的內容,然後你可以將字串格式化成句子。通常,將個別API呼叫的結果作為獨立章節包含進來是非常有用的,就像這樣:
天氣預報
{{ weather[“description”] }},氣溫為 {{ weather[“temperature”] }} 度。
程式碼解密:
這裡的天氣預報被格式化為報告的一部分,直接將 weather 字典中的值插入到報告中。這種方法使得報告內容能夠根據實際資料動態生成,保持資訊的即時性和準確性。
最後,如果你使用的是結構化檔案,你的生活通常會比較輕鬆:只需將記憶體中代表你知識的物件的所有相關欄位序列化即可:
<weather>
<description>sunny</description>
<temperature>75</temperature>
</weather>
程式碼解密:
這段XML程式碼展示瞭如何將天氣資料序列化為結構化的格式。每個元素(如 <description> 和 <temperature>)對應於 weather 字典中的一個鍵值對。這種格式化的優點是能夠清晰地組織資料,便於進一步處理或解析。
無論使用何種檔案型別,一種有用的傳達背景脈絡的方式是明確地標註旁白(例如,“順便一提,”)。例如,在GitHub Copilot的程式碼補全中,我們發現可以在原始碼檔案形式的檔案範本中使用來自其他檔案的程式碼,並透過註解明確指出某些參照片段是為了比較:
// <考慮來自 ../skill.go 的片段>
// type Skill interface {
// Execute(data []byte) (refs, error)
// }
// </結束片段>
程式碼解密:
這段註解展示瞭如何在程式碼中參照其他檔案的內容,並明確標示出這是一個用於比較的片段。這種做法能夠為模型提供額外的上下文,幫助它更好地理解目前的任務。
在格式化程式碼片段時,需要考慮以下幾點:
- 模組化:片段應該能夠輕易地插入或從提示中移除。理想情況下,檔案應該像列表(對話的回合)或樹狀結構(具有層次結構的報告;結構化檔案),這樣片段就可以作為列表中的專案或樹的葉節點來處理。
- 自然性:片段應該感覺像是檔案中有機的一部分,並以這種方式進行格式化。如果讓LLM完成原始碼,任何自然語言資訊都應該格式化為註解,而不是直接放在程式碼行之間。
- 簡潔性:如果可以用更少的token傳達相關的上下文,那就太好了!
- 惰性:你希望只計算一次片段的token長度,因此一個片段的分詞不應該影響前一個或下一個片段的分詞。
更多關於惰性的討論
惰性取決於你的分詞器,它可能會使用不同的token來對組合字串A + B進行分詞,而不是對每個字串單獨進行分詞。這很容易增加或減少對組合字串進行分詞所需的token數量。
格式化少樣本範例
在格式化少樣本範例時,你通常有選擇。可以明確地將它們標示為範例,如下所示: 在以下情況下,當我遇到像“誰是美國第一任總統?”這樣的問題時,我會給出像“喬治·華盛頓”這樣的答案。
或者,你可以直接將範例整合到檔案中,作為之前任務的解決方案。這種方法需要仔細的表述,但可以非常有效。它允許模型更自然地利用少樣本範例,並創造出更流暢的提示。
彈性片段
當你將內容轉換為片段時,每個資訊通常對應一個單獨的片段。然而,有時一條內容可以被分割成多個片段,或以不同的形式表示。
例如,考慮一個文學分析任務,詢問關於Alex Garland的小說《海灘》中某個特定場景的重要性。如果你詢問ChatGPT關於這個場景,它很可能不熟悉這個特定的場景,任何給出的答案都可能是模糊的、錯誤的,或者兩者皆是。為了改善回應,你需要在提示中包含來自書中的相關上下文。你記得如何從第5章中檢索相關的書段,假設你識別出兩個關鍵時刻。
你可以以不同的方式將這些段落製作成片段,如圖6-5所示。理想情況下,你會包含整個章節以提供完整的上下文。這是一種方法,但在有限的提示空間和有限的模型注意力下,你可能需要稍微收緊上下文。但這留給你不同的可能性:
- 新增兩個沒有上下文的片段。
- 新增兩個帶有一些上下文的片段。
- 新增一個結合了上下文的單一片段,將各部分連結起來。
程式碼解密:
這裡討論瞭如何根據不同的需求和限制,將文學分析中的關鍵段落製作成不同的片段,以提供給模型適當的上下文。每種方法都有其優缺點,需要根據具體情況進行選擇。
提示元素組合的最佳實踐
在組合提示元素時,需要考慮多種因素以確保最終的提示具有最大價值。以下是一些關鍵的最佳實踐:
彈性提示元素的應用
當面臨多種不同的上下文內容時,可以採用兩種主要方法:
- 彈性提示元素:根據可用空間選擇不同版本的提示元素,從最簡短到最完整。例如,可以準備多個版本的章節內容,從完整的章節到只包含關鍵片段的簡短版本。
- 多重提示元素:建立多個提示元素,每個元素包含不同程度的上下文內容。然後,根據需求選擇最合適的元素。
提示元素之間的關係
在組合提示元素時,需要考慮三種主要的關係:
位置與順序:元素的順序應該保持邏輯一致性,如按照原始檔案的順序或時間順序。
@startuml skinparam backgroundColor #FEFEFE skinparam componentStyle rectangle
title LLM 提示工程最佳實務架構
package “提示結構設計” { component [系統提示] as system component [使用者提示] as user component [上下文資訊] as context component [範例 (Few-shot)] as example }
package “結構化格式” { component [XML 標籤] as xml component [YAML 結構] as yaml component [JSON 格式] as json component [Markdown] as md }
package “輸出最佳化” { component [長度控制] as length component [停止序列] as stop component [串流模式] as stream component [溫度調整] as temp }
package “程式碼整合” { component [程式碼片段] as code component [語法高亮] as syntax component [解析器] as parser }
system –> user : 角色定義 user –> context : 任務描述 context –> example : 參考範例
xml –> parser : 結構化 yaml –> parser json –> parser
length –> stream : 效率 stop –> stream temp –> stream : 生成品質
code –> syntax : 格式化 syntax –> md : 嵌入
note right of system 提示元素:
- 角色設定
- 任務說明
- 輸出格式 end note
note right of xml 格式選擇:
- XML: 層級結構
- JSON: API 整合
- YAML: 可讀性 end note
@enduml
此圖示展示了保持元素順序的重要性。
2. **重要性**:根據元素的內容和相關性評估其重要性。通常,重要的元素應該優先被包含在提示中。
##### 重要性評估方法
- 使用數字評分或離散的優先順序別來評估元素的重要性。
- 將元素分為不同的層級,以決定哪些元素必須被包含。
3. **依賴關係**:某些元素之間可能存在依賴或不相容的關係。例如,一個元素可能需要另一個元素的存在,或者兩個元素不能同時被包含。
```python
# 示例程式碼:檢查依賴關係
def check_dependency(element1, element2):
if element1.requires == element2:
return True
return False
# 使用範例
element_a = {"requires": "element_b"}
element_b = "element_b"
print(check_dependency(element_a, element_b)) # 輸出:True
內容解密:
check_dependency函式用於檢查兩個元素之間的依賴關係。element_a需要element_b,因此當element_b存在時,函式傳回True。
組合提示的最佳化
組合提示的過程可以視為一個最佳化問題,需要在滿足依賴關係和長度限制的條件下,選擇最有價值的元素組合。
解決依賴結構:確保所選的元素組合滿足所有的依賴關係和不相容限制。
# 示例程式碼:解決依賴結構 def resolve_dependencies(elements): resolved_elements = [] for element in elements: if check_dependency(element, resolved_elements): resolved_elements.append(element) return resolved_elements內容解密:
resolve_dependencies函式遍歷所有元素,檢查其依賴關係,並將滿足依賴條件的元素新增到結果列表中。- 該函式確保最終的提示組合滿足所有的依賴限制。
控制提示長度:確保最終的提示長度不超過設定的限制,通常是上下文視窗大小減去模型回應所需的 tokens 數量。
組裝提示的藝術:從資訊收集到精確回應
前言
在前一章中,我們成功地將所有上下文資訊濃縮成一個連貫的提示。現在,是時候讓大語言模型(LLM)發揮作用,並確保一切順利進行。本章將重點介紹如何確保獲得有意義且準確的回應。
理想回應的剖析
在本文中,我們將探討回應的呈現方式,無論是傳統的完成還是聊天回應。更重要的是,我們將討論如何使它們看起來清晰有效,同時避免不必要的延遲或混淆的細節。
回應格式的重要性
如同第6章中對提示的處理一樣,我們將逐一分析LLM回應的組成部分(參見圖7-1)。一個理想的回應應該是清晰、簡潔且與上下文高度相關。
完成格式與停止時機
為了確保LLM的回應符合預期,我們需要了解如何控制完成格式以及何時停止生成內容。使用所謂的"logprob技巧"可以幫助我們更好地解釋和控制回應的生成。
Logprob技巧的應用
“logprob技巧"允許開發者透過分析單詞或詞元的對數機率來最佳化回應的生成。這種方法可以幫助我們更好地理解模型的信心度,並據此調整生成策略。
選擇合適的模型
在獲得理想回應之前,我們需要選擇合適的LLM。是選擇專業的商業服務、開源替代方案,還是自定義的微調模型?本章將幫助您做出明智的選擇。
商業服務 vs. 開源替代方案
商業服務通常提供更穩定和最佳化的效能,但可能缺乏靈活性。開源替代方案則提供了更多的自定義選項,但可能需要更多的技術投入和維護。
自定義微調模型的優勢
透過對預訓練模型進行微調,可以使其更好地適應特定領域或任務。這種方法可以顯著提高模型的表現,但需要足夠的資料和計算資源。
隨著LLM的不斷發展,未來我們可以期待更先進的功能和更最佳化的效能。透過不斷地學習和實踐,我們可以充分發揮LLM的潛力,創造出更多令人驚豔的應用。
最佳化大語言模型(LLM)輸出:剖析理想的完成內容
在與大語言模型(LLM)互動時,如何獲得理想且精確的輸出結果是關鍵。本章節將探討LLM輸出的結構組成,特別是「前言」(preamble)的不同型別及其對輸出的影響,並提供相關技術來控制輸出的長度和內容。
前言的型別及其影響
LLM生成的文字通常由前言和主要內容組成。前言是生成文字的初始部分,它為主要內容奠定基礎。根據前言的特性,可以將其分為三種型別:結構樣板(Structural boilerplate)、推理(Reasoning)和冗餘內容(Fluff)。
結構樣板
結構樣板是指在提示(prompt)結束後到完成內容開始前的文字。在使用LLM時,盡可能在提示中包含確定性的樣板內容,可以提高效率並確保模型遵循所需的格式,從而使過程更快、更便宜。
推理
隨著模型的進步,特別是在2023年末,像ChatGPT這樣的模型開始在回應中包含對問題的解釋,以澄清理解並突出潛在的誤解。這種方法有助於模型透過關注提示的關鍵方面來做出更好的推斷。鏈式思考(Chain-of-thought)提示技術可以幫助模型將問題分解為可管理的部分,通常這些詳細過程會出現在前言中而不是主要答案中。對於需要深入推理的任務,較長的前言是有益的。
冗餘內容
經過RLHF(Reinforcement Learning from Human Feedback)訓練的模型往往會產生冗長和禮貌的回應,這對於需要簡潔輸出的程式化應用來說可能是一個問題。為了管理這種情況,可以透過提供包含少數示例的指令或重新格式化提示,將主要答案與額外的評論分開。然而,這種方法可能會增加成本。
識別輸出的開始和結束
要從LLM的回應中提取主要答案,必須能夠識別答案的開始和結束。許多檔案結構使這變得相對容易,如Markdown檔案、YAML檔案、JSON檔案和程式碼列表等。透過精心設計的提示,可以改進對開始和結束的識別方法。例如,在YAML檔案中,如果知道下一個關鍵字是什麼,可以透過查詢較低縮排級別後跟該關鍵字來確定結束。
結束標記和串流處理
控制LLM答案的長度對於減少成本和提高效率至關重要。有兩種主要方法可以實作這一目標:
- 停止序列(Stop sequences):許多模型允許提供停止序列列表,當模型生成到這些序列時,將停止生成答案,從而避免額外的成本。
- 串流模式(Streaming):一些模型支援串流模式,可以逐個或以小批次傳送生成的Token。透過識別結束標記,可以避免等待不必要的Token生成,甚至可以取消生成以節省計算資源。