# Prompt Engineering
> 原文:[Prompt Engineering by Google](https://www.kaggle.com/whitepaper-prompt-engineering)
---
## 介紹 (Introduction)
大型語言模型 (Large Language Models, LLMs) 的輸入與輸出主要基於文字提示 (text prompt),有時也包含圖片等多模態輸入。提示是模型用來預測特定輸出的依據。雖然任何人都可以撰寫提示,但製作最有效的提示可能相當複雜。影響提示效果的因素眾多,包括:使用的模型、模型的訓練資料、模型配置、用詞選擇、風格語氣、結構以及上下文脈絡等。
因此,Prompt Engineering 是一個迭代的過程。不恰當的提示可能導致模棱兩可、不準確的回應,並阻礙模型提供有意義輸出的能力。
---
## 提示工程 (Prompt Engineering)
LLM 的基本工作原理是一個**預測引擎**。模型接收順序性的文字作為輸入,然後根據其訓練數據預測下一個最可能的詞元 (token)。這個過程會重複進行,將先前預測的詞元添加到序列末尾,以預測再下一個詞元。下一個詞元的預測是基於先前詞元與 LLM 在訓練期間所學習到的內容之間的關係。
當你撰寫提示時,你試圖引導 LLM 預測出正確的詞元序列。Prompt Engineering 是設計高品質提示的過程,用以引導 LLMs 產生準確的輸出。這個過程涉及反覆試驗以找到最佳提示、優化提示長度,並評估提示的寫作風格和結構與任務的關聯性。在自然語言處理 (Natural Language Processing, NLP) 和 LLMs 的背景下,提示是提供給模型以生成回應或預測的輸入。
這些提示可用於實現各種類型的理解和生成任務,例如文本摘要、資訊提取、問答、文本分類、語言或程式碼翻譯、程式碼生成以及程式碼文檔或推理。
---
## LLM 輸出配置 (LLM output configuration)
選擇模型後,需要調整模型的配置。大多數 LLMs 都帶有多種配置選項來控制輸出。有效的 Prompt Engineering 需要為特定任務優化這些配置。
### 輸出長度 (Output length)
一個重要的配置是設定回應中生成的詞元數量上限。生成更多詞元需要 LLM 進行更多計算,導致更高的能源消耗、可能更慢的回應時間和更高的成本。
限制 LLM 的輸出長度並不會使其在風格上更簡潔,只是在達到限制時停止預測。如果需要簡短的輸出,通常也需要透過 Prompt Engineering 來實現。
對於某些 LLM 提示技巧(如 ReAct),輸出長度限制尤其重要,因為模型可能會在產生所需回應後繼續輸出無用的詞元。
### 取樣控制 (Sampling controls)
LLMs 並非直接預測單一詞元,而是預測下一個詞元可能是什麼的**機率分佈**,詞彙表中的每個詞元都會獲得一個機率。接著,模型會對這些機率進行取樣,以確定實際產生的下一個詞元。溫度 (Temperature)、Top-K 和 Top-P 是最常見的配置設定,用於決定如何處理預測的詞元機率以選擇單一輸出詞元。
#### 溫度 (Temperature)
Temperature 控制**詞元選擇中的隨機性程度**。較低的 Temperature 適用於期望更確定性回應的提示(例如數學計算、事實問答),而較高的 Temperature 會產生更多樣化或意想不到的結果(例如創意寫作)。Temperature 為 0(稱為貪婪解碼, greedy decoding)是確定性的:總是選擇機率最高的詞元(但若有多個詞元機率相同,結果可能因 tiebreaking 機制而不同)。
接近最大值的 Temperature 傾向於產生更隨機的輸出。隨著 Temperature 越來越高,所有詞元成為下一個預測詞元的可能性趨於均等。
Gemini 的 Temperature 控制類似於機器學習中的 softmax 函數。低 Temperature 設定類似於低 softmax Temperature (T),強調單一首選詞元,具有高確定性。高 Temperature 設定類似於高 softmax Temperature,使得選定設定周圍更廣泛的詞元範圍變得可接受。這種增加的不確定性適用於不需要剛性、精確輸出的場景,例如實驗創意輸出。
#### Top-K 與 Top-P (Top-K and top-P)
Top-K 和 Top-P(也稱為核取樣, nucleus sampling)是 LLMs 中使用的兩種取樣設定,用於將預測的下一個詞元限制在具有最高預測機率的詞元範圍內。與 Temperature 類似,這些取樣設定控制生成文本的隨機性和多樣性。
* **Top-K** 取樣從模型預測分佈中選擇 K 個最可能的詞元。Top-K 值越高,模型的輸出**越具創意和多樣性**;Top-K 值越低,模型的輸出越受限制和基於事實。Top-K 為 1 等同於 greedy decoding。
* **Top-P** 取樣選擇累積機率不超過某個值 P 的最高機率詞元集合。P 的值範圍從 0(greedy decoding)到 1(LLM 詞彙表中的所有詞元)。
選擇 Top-K 還是 Top-P 的最佳方法是實驗兩者(或兩者結合),看看哪種方法能產生您想要的結果。
#### 綜合考量 (Putting it all together)
選擇 Top-K、Top-P、Temperature 以及生成詞元數量取決於具體應用和期望的結果,且這些設定會相互影響。理解您選擇的模型如何組合不同的取樣設定也很重要。
* 如果 Temperature、Top-K 和 Top-P 都可用(如在 Vertex AI Studio 中):
* 首先,只有同時滿足 Top-K 和 Top-P 標準的詞元才有資格成為下一個預測詞元。
* 然後,應用 Temperature 從通過篩選的詞元中進行取樣。
* 如果只有 Top-K 或 Top-P 可用,行為類似,但只使用該單一設定進行篩選。
* 如果 Temperature 不可用,則從滿足 Top-K 和/或 Top-P 標準的詞元中隨機選擇一個作為下一個預測詞元。
在某個取樣配置值的**極端設定**下,該設定可能會**抵消其他配置設定**或使其變得無關緊要:
* 若設定 Temperature 為 0,Top-K 和 Top-P 變得無關緊要,因為總是選擇機率最高的詞元。若設定 Temperature 極高(通常 > 1,甚至幾十),Temperature 也變得無關緊要,任何通過 Top-K/Top-P 標準的詞元都會被隨機取樣。
* 若設定 Top-K 為 1,Temperature 和 Top-P 變得無關緊要,因為只有一個詞元通過標準。若設定 Top-K 極高(如 LLM 詞彙表大小),則任何具有非零機率的詞元都會通過,等於沒有篩選。
* 若設定 Top-P 為 0(或非常小的值),大多數 LLM 實作只會考慮機率最高的詞元,使得 Temperature 和 Top-K 無關緊要。若設定 Top-P 為 1,則任何具有非零機率的詞元都會通過,等於沒有篩選。
#### 一般起點建議:
* 相對連貫且不失創意的結果:Temperature 0.2, Top-P 0.95, Top-K 30。
* 特別有創意的結果:Temperature 0.9, Top-P 0.99, Top-K 40。
* 較少創意的結果:Temperature 0.1, Top-P 0.9, Top-K 20。
* 任務總有單一正確答案(如數學問題):Temperature 0。
**注意**:給予更多自由度(更高的 Temperature、Top-K、Top-P 和輸出詞元數)可能導致 LLM 生成較不相關的文本。
#### 警告:重複迴圈錯誤 (repetition loop bug)
LLMs 可能會陷入循環,重複生成相同的(填充)詞、短語或句子結構。這通常因不當的 Temperature 和 Top-K/Top-P 設定而加劇。
* 在**低溫**下,模型**過於確定性**,若最高機率路徑回到先前生成的文本,則可能形成迴圈。
* 在**高溫**下,輸出**過於隨機**,偶然選中導致回到先前狀態的詞語機率增加。
解決此問題通常需要仔細調整 Temperature 和 Top-K/Top-P 值,以找到確定性與隨機性之間的最佳平衡。
---
## 提示技巧 (Prompting techniques)
LLMs 被調整以遵循指令,並在大量數據上進行訓練,因此它們能理解提示並生成答案。但 LLMs 並非完美;提示文本越清晰,LLM 預測下一個可能文本的效果就越好。此外,利用 LLMs 訓練方式和工作原理的特定技巧將有助於獲得相關結果。
### 通用提示 / 零樣本提示 (General prompting / zero shot)
零樣本 (Zero-shot) 提示是最簡單的類型。它只提供任務描述和一些讓 LLM 開始的文本。輸入可以是任何東西:問題、故事開頭或指令。"Zero-shot" 指的是「沒有範例」。
**範例 (表 1)**:使用 Vertex AI Studio 的 Playground 測試提示,分類電影評論。
* **目標**: 將電影評論分類為正面、中性或負面。
* **模型**: gemini-pro
* **Temperature**: 0.1 (不需要創意)
* **Top-K**: N/A (使用預設值)
* **Token Limit**: 5
* **Top-P**: 1 (使用預設值)
* **提示**:
```
Classify movie reviews as POSITIVE, NEUTRAL or NEGATIVE.
Review: "Her" is a disturbing study revealing the direction humanity is headed if AI is allowed to keep evolving, unchecked. I wish there were more movies like this masterpiece.
Sentiment:
```
* **輸出**: POSITIVE
* **說明**: 使用表格格式是記錄提示的好方法。由於需要低創意性,模型 Temperature 設為較低值。提示中的 "disturbing" 和 "masterpiece" 同時出現,增加了預測的複雜度。
記錄提示工程的工作(如此表格格式)是重要的,因為提示通常需要多次迭代。
### 單樣本與少樣本提示 (One-shot & few-shot)
當 zero-shot 效果不佳時,可以在提示中提供示範或範例,這就引出了「單樣本 (one-shot)」和「少樣本 (few-shot)」提示。
* **One-shot prompt**: 提供 **單個** 範例。模型可以模仿這個範例來完成任務。
* **Few-shot prompt**: 提供 **多個** 範例。這向模型展示了需要遵循的模式。範例越多,模型遵循該模式的可能性就越大。
所需範例數量取決於任務複雜性、範例品質、模型能力等因素。經驗法則是使用至少 3 到 5 個範例進行 few-shot 提示。但複雜任務可能需要更多範例,或者受模型輸入長度限制可能需要更少範例。
**範例 (表 2)**:將披薩訂單解析為 JSON。
* **目標**: 將披薩訂單解析為 JSON。
* **模型**: gemini-pro
* **Temperature**: 0.1
* **Top-K**: N/A
* **Token Limit**: 250 (增加以容納更長的回應)
* **Top-P**: 1
* **提示**:
```
Parse a customer's pizza order into valid JSON:
EXAMPLE:
I want a small pizza with cheese, tomato sauce, and pepperoni.
JSON Response:
{
"size": "small",
"type": "normal",
"ingredients": [["cheese", "tomato sauce", "peperoni"]]
}
EXAMPLE:
Can I get a large pizza with tomato sauce, basil and mozzarella
JSON Response:
{
"size": "large",
"type": "normal",
"ingredients": [["tomato sauce", "bazel", "mozzarella"]]
}
Now, I would like a large pizza, with the first half cheese and mozzarella. And the other tomato sauce, ham and pineapple.
JSON Response:
```
* **輸出**:
```json
{
"size": "large",
"type": "half-half",
"ingredients": [["cheese", "mozzarella"], ["tomato sauce", "ham", "pineapple"]]
}
```
* **說明**: 選擇的範例應與要執行的任務相關,多樣化、高品質且書寫良好。一個小錯誤就可能混淆模型。若要生成對各種輸入都穩健的輸出,包含邊緣案例 (edge cases) 的範例很重要。
### 系統、上下文與角色提示 (System, contextual and role prompting)
系統 (System)、上下文 (Contextual) 和角色 (Role) 提示都是用來引導 LLMs 生成文本的技巧,但各有側重:
* **系統提示 (System prompting)**: 設定語言模型的整體背景和目的。定義模型應執行的「大局」,如翻譯語言、分類評論等。
* **主要目的**:定義模型的基礎能力和總體目標。
* **上下文提示 (Contextual prompting)**: 提供與當前對話或任務相關的具體細節或背景資訊。幫助模型理解問題的細微差別並相應地調整回應。
* **主要目的**:提供即時的、特定於任務的資訊以引導回應。高度針對當前任務或輸入,是動態的。
* **角色提示 (Role prompting)**: 為語言模型分配一個特定的角色或身份以供其採納。幫助模型生成與所分配角色及其相關知識和行為一致的回應。
* **主要目的**:塑造模型的輸出風格和語氣。增加了一層特異性和個性。
這三者之間可能存在相當大的重疊。例如,為系統分配角色的提示也可能包含上下文。
區分這三種提示類型提供了一個框架,用於設計意圖清晰的提示,允許靈活組合,並更容易分析每種類型的提示如何影響模型的輸出。
#### 系統提示 (System prompting)
**範例 (表 3)**:指定輸出格式(大寫)。
* **目標**: 將電影評論分類為正面、中性或負面,僅返回大寫標籤。
* **模型**: gemini-pro
* **Temperature**: 1 (提高以增加創意,但指令清晰,模型仍遵循)
* **Top-K**: 40
* **Token Limit**: 5
* **Top-P**: 0.8
* **提示**:
```
Classify movie reviews as positive, neutral or negative. Only return the label in uppercase.
Review: "Her" is a disturbing study revealing the direction humanity is headed if AI is allowed to keep evolving, unchecked. It's so disturbing I couldn't watch it.
Sentiment:
```
* **輸出**: NEGATIVE
* **說明**: System prompts 可用於生成滿足特定要求的輸出。例如,生成與特定程式語言兼容的程式碼片段,或返回特定結構(如 JSON)。
**範例 (表 4)**:返回 JSON 格式。
* **目標**: 將電影評論分類為正面、中性或負面,返回 JSON。
* **模型**: gemini-pro
* **Temperature**: 1
* **Top-K**: 40
* **Token Limit**: 1024
* **Top-P**: 0.8
* **提示**:
```
Classify movie reviews as positive, neutral or negative. Return valid JSON:
Review: "Her" is a disturbing study revealing the direction humanity is headed if AI is allowed to keep evolving, unchecked. It's so disturbing I couldn't watch it.
Schema:
MOVIE:
{
"sentiment": String "POSITIVE" | "NEGATIVE" | "NEUTRAL",
"name": String
}
MOVIE_REVIEWS:
{
"movie_reviews": [MOVIE]
}
JSON Response:
```
* **輸出**:
```json
{
"movie_reviews": [
{
"sentiment": "NEGATIVE",
"name": "Her"
}
]
}
```
* **說明**: 返回 JSON 物件有助於提取數據,可以在應用中直接使用,支持排序(對日期時間物件有用),並強制模型創建結構、限制幻覺。System prompts 也可用於安全性和毒性控制,例如添加 "You should be respectful in your answer."。
#### 角色提示 (Role prompting)
Role prompting 涉及為 AI 模型分配特定角色。這有助於模型生成更相關和資訊豐富的輸出,因為模型可以根據被分配的角色來調整其回應。
**範例 (表 5)**:扮演旅行指南。
* **目標**: 扮演旅行指南,提供 3 個旅行建議。
* **模型**: gemini-pro
* **Temperature**: 1
* **Top-K**: 40
* **Token Limit**: 1024
* **Top-P**: 0.8
* **提示**:
```
I want you to act as a travel guide. I will write to you about my location and you will suggest 3 places to visit near me. In some cases, I will also give you the type of places I will visit.
My suggestion: "I am in Amsterdam and I want to visit only museums."
Travel Suggestions:
```
* **輸出**:
```
1. Rijksmuseum: World-renowned museum, known for Dutch masterpieces like Rembrandt's "The Night Watch."...
2. Van Gogh Museum: Immerse yourself in the captivating works of Vincent van Gogh...
3. Stedelijk Museum Amsterdam: Discover modern and contemporary art from around the world...
```
* **說明**: 如果將角色更改為地理老師,將會收到不同的回應。為 AI 模型定義角色視角,為其提供了語氣、風格和專業知識的藍圖,以提高輸出的品質、相關性和有效性。
可以指定的風格包括:對抗性 (Confrontational)、描述性 (Descriptive)、直接 (Direct)、正式 (Formal)、幽默 (Humorous)、有影響力 (Influential)、非正式 (Informal)、鼓舞人心 (Inspirational)、有說服力 (Persuasive)。
**範例 (表 6)**:包含幽默和鼓舞人心的風格。
* **提示**:
```
I want you to act as a travel guide. I will write to you about my location and you will suggest 3 places to visit near me in a humorous style.
My suggestion: "I am in Manhattan."
Travel Suggestions:
```
* **輸出**:
```
1. Behold the Empire State of Mind: Ascend to the dizzying heights of the Empire State Building... feel like King Kong... minus the giant ape-sized banana.
2. Get Artsy-Fartsy at MoMA: Unleash your inner art aficionado... make you question whether your stick-figure drawings have any artistic merit.
3. Shop 'Til You Drop on Fifth Avenue: Indulge in some retail therapy... Brace yourself for sticker shock... make your wallet cry...
```
#### 上下文提示 (Contextual prompting)
提供 contextual prompts 有助於確保 AI 互動盡可能無縫和高效。模型能更快地理解請求,並生成更準確和相關的回應。
**範例 (表 7)**:為關於復古遊戲的博客建議文章主題。
* **目標**: 為關於復古遊戲的博客建議文章。
* **模型**: gemini-pro
* **Temperature**: 1
* **Top-K**: 40
* **Token Limit**: 1024
* **Top-P**: 0.8
* **提示**:
```
Context: You are writing for a blog about retro 80's arcade video games.
Suggest 3 topics to write an article about with a few lines of description of what this article should contain.
```
* **輸出**:
```
1. **The Evolution of Arcade Cabinet Design:** ... explore the evolution from the 1970s wood and metal cabinets to the sleek, neon-lit designs of the 1980s...
2. **Blast From The Past: Iconic Arcade Games of The 80's:** ... feature a glimpse into the history, impact, and legacy of iconic games...
3. **The Rise and Retro Revival of Pixel Art:** ... delve into the evolution of pixel art as a defining visual style...
```
### 後退一步提示 (Step-back prompting)
Step-back prompting 是一種提高性能的技巧:
1. 先提示 LLM 考慮與手頭特定任務相關的 **一般性問題**
2. 將該一般性問題的答案饋送到後續針對 **特定任務** 的提示中
這種「後退一步」允許 LLM 在嘗試解決特定問題之前,激活相關的背景知識和推理過程。
通過考慮更廣泛和潛在的原則,LLMs 可以生成更準確和有見地的回應。Step-back prompting 鼓勵 LLMs 批判性思考,並以新的、創造性的方式應用其知識。它改變了執行任務的最終提示,利用了比直接提示 LLM 時會發揮作用的更多 LLM 參數中的知識。
它可以通過關注一般原則而非具體細節來幫助減輕 LLM 回應中的偏見。
**範例**:為第一人稱射擊遊戲關卡編寫故事情節。
* **傳統提示 (表 8)**:
* **提示**: `Write a one paragraph storyline for a new level of a first-person shooter video game that is challenging and engaging.`
* **輸出**: (可能隨機且通用) `The level begins with the player's squad being ambushed... fight through a maze of back alleys... uncover intel...`
* **Step-back 步驟 (表 9)**:
* **提示**: `Based on popular first-person shooter action games, what are 5 fictional key settings that contribute to a challenging and engaging level storyline in a first-person shooter video game?`
* **輸出**:
```
1. **Abandoned Military Base**: ...post-apocalyptic military complex...
2. **Cyberpunk City**: ...neon-lit, futuristic urban environment...
3. **Alien Spaceship**: ...vast alien vessel stranded on Earth...
4. **Zombie-Infested Town**: ...desolate town overrun by hordes...
5. **Underwater Research Facility**: ...deep-sea laboratory flooded...
```
* **結合上下文的提示 (表 10)**:
* **提示**:
```
Context: 5 engaging themes for a first person shooter video game:
1. **Abandoned Military Base**: ...
2. **Cyberpunk City**: ...
3. **Alien Spaceship**: ...
4. **Zombie-Infested Town**: ...
5. **Underwater Research Facility**: ...
Take one of the themes and write a one paragraph storyline for a new level of a first-person shooter video game that is challenging and engaging.
```
* **輸出**: (選擇了水下設施主題) `In the heart of a murky abyss, lies a dilapidated underwater research facility... The player, an elite marine... must navigate treacherous corridors... confront gruesome sea monstrosities...`
* **說明**: 使用 step-back prompting 技巧可以提高提示的準確性,產生的故事情節更具體、有趣。
### 思維鏈提示 (Chain of Thought, CoT)
思維鏈 (Chain of Thought, CoT) 提示是一種通過生成 **中間推理步驟** 來提高 LLMs 推理能力的技術。這有助於 LLM 生成更準確的答案,特別是對於需要推理的複雜任務。可以將其與 few-shot 提示結合使用,以在需要響應前進行推理的更複雜任務上獲得更好結果,這對於 zero-shot CoT 來說是一個挑戰。
**優點**:
* 低工作量,效果顯著。
* 適用於現成的 LLMs(無需微調)。
* 提供可解釋性(可以看到遵循的推理步驟)。
* 在不同 LLM 版本之間遷移時,似乎能提高穩健性(提示性能漂移較少)。
**缺點**:
* LLM 回應包含 CoT 推理,意味著更多的輸出詞元,導致預測成本更高、耗時更長。
**範例**:解決數學應用題。
* **未使用 CoT 的提示 (表 11)**:
* **提示**: `When I was 3 years old, my partner was 3 times my age. Now, I am 20 years old. How old is my partner?`
* **輸出**: `63 years old` (錯誤)
* **使用 Zero-shot CoT 的提示 (表 12)**:
* **提示**: `When I was 3 years old, my partner was 3 times my age. Now, I am 20 years old. How old is my partner? Let's think step by step.`
* **輸出**:
```
1. Let's assume my current age is "x" years. (這一步似乎多餘)
2. When I was 3 years old, my age was 3 years.
3. My partner's age at that time was 3 times my age, which means my partner's age was 3 * 3 = 9 years.
4. Now, I am 20 years old, which means my age has increased by 20 - 3 = 17 years since I was 3 years old.
5. Since my partner's age was 9 years when I was 3 years old, and my age has increased by 17 years, my partner's age must have also increased by 17 years.
6. Therefore, my partner's current age is 9 + 17 = 26 years.
So, my partner is 26 years old.
```
(正確)
* **使用 Single-shot CoT 的提示 (表 13)**:提供一個帶有推理步驟的範例。
* **提示**:
```
Q: When my brother was 2 years old, I was double his age. Now I am 40 years old. How old is my brother? Let's think step by step.
A: When my brother was 2 years, I was 2 * 2 = 4 years old. That's an age difference of 2 years and I am older. Now I am 40 years old, so my brother is 40 - 2 = 38 years old. The answer is 38.
Q: When I was 3 years old, my partner was 3 times my age. Now, I am 20 years old. How old is my partner? Let's think step by step.
A:
```
* **輸出**: `When I was 3 years old, my partner was 3 * 3 = 9 years old. That's an age difference of 6 years and my partner is older. Now I am 20 years old, so my partner is 20 + 6 = 26 years old. The answer is 26.`
* **適用場景**: 程式碼生成(將請求分解為步驟)、合成數據生成、任何可以通過「逐步講解」解決的任務。
### 自我一致性 (Self-consistency)
Self-consistency 旨在改進 CoT 的效果。標準 CoT 使用簡單的 'greedy decoding' 策略,限制了其有效性。Self-consistency 結合了 **取樣** 和 **多數投票** 來生成多樣化的推理路徑並選擇最一致的答案。它提高了 LLMs 生成回應的準確性和連貫性。
Self-consistency 給出了答案正確性的偽機率似然性,但成本顯然很高。
**步驟**:
1. **生成多樣化的推理路徑**: 多次向 LLM 提供相同的提示。使用高 Temperature 設定鼓勵模型生成不同的推理路徑和問題視角。
2. **從每個生成的回應中提取答案**。
3. **選擇最常見的答案**(多數投票)。
**範例 (表 14)**:電子郵件分類(重要/不重要)。
* **背景**: 一封關於網站 bug 的郵件,語氣友好但帶有諷刺 ("Harry the Hacker"),可能迷惑 LLM。
* **提示**: (Zero-shot CoT)
```
EMAIL:
... (郵件內容) ...
Classify the above email as IMPORTANT or NOT IMPORTANT. Let's think step by step and explain why.
```
* **多次運行 (高 Temperature)**:
* **嘗試 1 輸出**: ... (推理) ... **Conclusion: IMPORTANT**
* **嘗試 2 輸出**: ... (不同推理) ... **Conclusion: NOT IMPORTANT**
* **嘗試 3 輸出**: ... (又一種推理) ... **Conclusion: IMPORTANT**
* **最終結果**: 通過生成多個 CoT 並採用最常見的答案(此例中為 "IMPORTANT"),可以從 LLM 獲得更一致、更正確的答案。
### 思維樹 (Tree of Thoughts, ToT)
思維樹 (Tree of Thoughts, ToT) 是對 CoT 概念的推廣。它允許 LLMs **同時探索多個不同的推理路徑**,而不僅僅是遵循單一的線性思維鏈。
ToT 通過維護一個思想樹來工作,其中每個思想(節點)代表一個連貫的語言序列,作為解決問題的中間步驟。模型可以通過從樹中的不同節點分支出來探索不同的推理路徑。
這種方法使得 ToT 特別適用於需要探索的複雜任務。

**(圖 1)**:比較 CoT (左側,線性) 和 ToT (右側,樹狀)。
### 推理與行動 (ReAct - reason & act)
推理與行動 (Reason and act, ReAct) 提示是一種範式,旨在使 LLMs 能夠通過結合自然語言推理和 **外部工具**(例如搜索、程式碼解釋器、API 等)來解決複雜任務。它允許 LLM 執行某些操作,例如與外部 API 互動以檢索資訊,這是朝向代理建模 (agent modeling) 的第一步。
ReAct 模仿了人類在現實世界中的運作方式,我們進行口頭推理並採取行動以獲取信息。
ReAct 提示通過將推理和行動結合到一個 **思想-行動循環 (thought-action loop)** 中來工作:
1. LLM 首先對問題進行推理並生成一個行動計劃 (Thought)。
2. 然後執行計劃中的行動 (Action, Action Input)。
3. 觀察行動的結果 (Observation)。
4. LLM 利用觀察結果更新其推理,並生成新的行動計劃。
5. 這個過程持續進行,直到 LLM 達到問題的解決方案 (Final Answer)。
**範例 (代碼片段 1 & 2)**:找出 Metallica 樂隊成員總共有多少個孩子。
* **工具**: Python, LangChain 框架, VertexAI, Google Search (透過 SerpAPI)。
* **設置 (Snippet 1)**:導入庫,設置 LLM (VertexAI, 低溫),加載工具 ('serpapi'),初始化 ReAct 代理 (ZERO_SHOT_REACT_DESCRIPTION)。
* **運行 (Snippet 2)**:
```
> Entering new AgentExecutor chain...
Thought: Metallica has 4 members. (需要找出成員並計算孩子數量)
Action: Search
Action Input: How many kids does James Hetfield have?
Observation: three children
Thought: 1/4 Metallica band members have 3 children (累計3)
Action: Search
Action Input: How many kids does Lars Ulrich have?
Observation: 3
Thought: 2/4 Metallica band members have 6 children (累計6)
Action: Search
Action Input: How many kids does Kirk Hammett have?
Observation: Hammett has been married... They have two sons, Angel... and Vincenzo...
Thought: 3/4 Metallica band members have 8 children (累計8)
Action: Search
Action Input: How many kids does Robert Trujillo have?
Observation: 2
Thought: 4/4 Metallica band members have 10 children (累計10)
Final Answer: 10
```
* **說明**: ReAct 代理逐步推理,使用搜索工具獲取信息,並累加結果。在實踐中,需要持續重新發送先前的提示/響應(並可能修剪額外生成的內容),並使用適當的範例/指令設置模型。
### 自動提示工程 (Automatic Prompt Engineering, APE)
自動提示工程 (Automatic Prompt Engineering, APE) 是一種自動化創建提示的方法(即「編寫一個提示來編寫提示」)。
**方法**:
1. 提示一個模型為某個任務生成多個提示變體。
2. 通過基於選定指標(例如 BLEU, ROUGE)評分來評估所有候選指令。
3. 選擇評估分數最高的指令候選。這個候選將成為您可以在軟體應用程式或聊天機器人中使用的最終提示。
4. (可選)調整選定的提示並再次評估。重複此過程。
APE 不僅減輕了對人類輸入的需求,還增強了模型在各種任務上的性能。
**範例 (表 15)**:為購買樂隊 T 恤的聊天機器人生成不同的客戶訂購方式。
* **提示**: `We have a band merchandise t-shirt webshop, and to train a chatbot we need various ways to order: "One Metallica t-shirt size S". Generate 10 variants, with the same semantics but keep the same meaning.`
* **輸出**: (生成 10 種不同的說法,如)
```
1. I'd like to purchase a Metallica t-shirt in size small.
2. Can I order a small-sized Metallica t-shirt?
...
10. One Metallica small t-shirt, please.
```
### 程式碼提示 (Code prompting)
Gemini 主要關注基於文本的提示,但也包括用於返回程式碼的寫作提示。
#### 編寫程式碼的提示 (Prompts for writing code)
Gemini 可以幫助開發者編寫任何選擇的程式語言的程式碼,加速開發過程。
**範例 (表 16)**:生成 Bash 腳本以重命名文件夾中的文件。
* **目標**: 編寫 Bash 程式碼片段以重命名文件夾中的文件。
* **提示**: `Write a code snippet in Bash, which asks for a folder name. Then it takes the contents of the folder and renames all the files inside by prepending the name draft to the file name.`
* **輸出**: (生成帶註釋的 Bash 腳本)
```bash
#!/bin/bash
# Ask for the folder name
echo "Enter the folder name: "
read folder_name
# Check if the folder exists
if [ ! -d "$folder_name" ]; then
echo "Folder does not exist."
exit 1
fi
# Get the list of files in the folder
files=( "$folder_name"/* )
# Rename each file by prepending "draft" to the file name
for file in "${files[@]}"; do
new_file_name="draft_$(basename "$file")"
mv "$file" "$new_file_name"
done
echo "Files renamed successfully."
```
* **重要**: 務必閱讀和測試生成的程式碼。LLMs 不能真正推理,只是重複訓練數據。
#### 解釋程式碼的提示 (Prompts for explaining code)
Gemini 可以幫助理解他人編寫的程式碼。
**範例 (表 17)**:解釋之前生成的 Bash 腳本(移除註釋後)。
* **提示**: `Explain to me the below Bash code: ... (貼上無註釋的 Bash 代碼) ...`
* **輸出**: (分步解釋腳本的功能)
```
This Bash script performs the following tasks:
1. **User Input**: Prompts user for folder name...
2. **Folder Existence Check**: Checks if folder exists...
3. **File Listing**: Lists all files inside the folder...
4. **File Renaming**: Iterates through files, prepends "draft_", renames...
5. **Success Message**: Displays success message...
```
#### 翻譯程式碼的提示 (Prompts for translating code)
LLMs 可以幫助將程式碼從一種語言翻譯到另一種語言。
**範例 (表 18)**:將 Bash 腳本翻譯成 Python。
* **提示**: `Translate the below Bash code to a Python snippet. ... (貼上 Bash 代碼) ...`
* **輸出**: (生成對應的 Python 代碼)
```python
import os
import shutil
# Get the folder name from the user
folder_name = input("Enter the folder name: ")
# Check if the folder exists
if not os.path.isdir(folder_name):
print("Folder does not exist.")
exit(1)
# Get a list of all files in the folder
files = os.listdir(folder_name)
# Iterate over the files
for file in files:
# Create a new file name with the prefix "draft_"
new_file_name = f"draft_{file}"
# Move the file to the new name
shutil.move(os.path.join(folder_name, file),
os.path.join(folder_name, new_file_name))
# Print a success message
print("Files renamed successfully.")
```
* **注意**: 在 Vertex AI Studio 中提示 Python 程式碼時,需要點擊 'Markdown' 按鈕以獲得帶有正確縮進的純文本輸出,這對於運行 Python 程式碼至關重要。同樣需要閱讀和審查程式碼。
#### 調試和審查程式碼的提示 (Prompts for debugging and reviewing code)
LLMs 可以幫助調試和審查程式碼。
**範例 (代碼片段 3, 4 & 表 19)**:
1. 手動修改 Python 程式碼,引入 bug(使用未定義的 `toUpperCase` 函數,Snippet 3)。
2. 運行程式碼,得到 `NameError` (Snippet 4)。
3. 向 LLM 求助。
* **提示 (表 19)**:
```
The below Python code gives an error:
Traceback (most recent call last):
File "...", line 7, in <module>
text = toUpperCase(prefix)
NameError: name 'toUpperCase' is not defined
Debug what's wrong and explain how I can improve the code.
```python
import os
# ... (貼上有 bug 的 Python 代碼) ...
```
* **輸出**:
```
The code calls the `toUpperCase` function... but that function is not defined. To fix this issue, you can use the `upper()` method of the string class...
```
(提供了修正後的程式碼)
```python
# ...
text = prefix.upper()
# ...
```
(並提供了進一步的改進建議)
```
Additionally, there are a few other improvements...
1. The file extension... is not kept. It's better to extract the extension...
2. The code assumes... no spaces in the folder name. Handle spaces gracefully...
3. Using the `f` string syntax... is more readable...
4. The code doesn't handle errors... wrap the `shutil.move` call in a `try...except` block...
```
(提供了包含所有建議的改進後程式碼)
* **說明**: LLM 不僅能找出並修復 bug,還能發現其他潛在問題並提供改進建議。
### 多模態提示 (What about multimodal prompting?)
程式碼提示仍然使用常規的 LLM。多模態提示 (Multimodal prompting) 是一個獨立的概念,指使用多種輸入格式(文本、圖像、音頻、程式碼或其他格式,取決於模型能力和任務)來引導 LLM,而不僅僅依賴文本。
---
## 最佳實踐 (Best Practices)
找到正確的提示需要反覆試驗。Vertex AI Studio 是試驗提示並針對不同模型進行測試的理想場所。
### 提供範例 (Provide examples)
最重要的最佳實踐是在提示中提供(one-shot / few-shot)範例。這非常有效,因為它充當了強大的教學工具。這些範例展示了期望的輸出或類似的回應,使模型能夠從中學習並相應地調整其生成。這就像給模型一個參考點或目標,提高了其回應的準確性、風格和語氣,以更好地匹配您的期望。
### 簡潔設計 (Design with simplicity)
提示應該簡潔、清晰,易於您和模型理解。經驗法則是,如果提示對您來說已經很混亂,那麼它很可能對模型來說也很混亂。盡量不使用複雜的語言,也不提供不必要的資訊。
嘗試使用描述動作的動詞。例如:Act, Analyze, Categorize, Classify, Contrast, Compare, Create, Describe, Define, Evaluate, Extract, Find, Generate, Identify, List, Measure, Organize, Parse, Pick, Predict, Provide, Rank, Recommend, Return, Retrieve, Rewrite, Select, Show, Sort, Summarize, Translate, Write。
### 具體說明輸出 (Be specific about the output)
具體說明期望的輸出。簡潔的指令可能不足以引導 LLM,或者可能過於籠統。在提示中提供具體細節(通過 system 或 context prompting)可以幫助模型專注於相關內容,提高整體準確性。
**範例**:
* **做 (DO)**: `Generate a 3 paragraph blog post about the top 5 video game consoles. The blog post should be informative and engaging, and it should be written in a conversational style.`
* **不做 (DO NOT)**: `Generate a blog post about video game consoles.`
### 使用指令而非約束 (Use Instructions over Constraints)
指令 (Instruction) 和約束 (Constraint) 都用於在提示中引導 LLM 的輸出。
* **指令**: 提供關於期望格式、風格或內容的明確指示。它指導模型應該 *做* 什麼或產生什麼。
* **約束**: 為回應設定一組限制或邊界。它限制了模型 **不應該做** 或避免什麼。
研究表明,在提示中側重於正面指令比嚴重依賴約束更有效。這種方法與人類更喜歡正面指令而非「禁止做」列表的偏好一致。指令直接傳達期望的結果,而約束可能讓模型猜測允許的範圍。指令提供了靈活性並鼓勵在定義邊界內的創造力,而約束可能限制模型的潛力,且多個約束可能相互衝突。
約束在某些情況下仍然有價值:防止模型生成有害或有偏見的內容,或者當需要嚴格的輸出格式或風格時。
**如果可能,使用正面指令**:告訴模型該做什麼,而不是不該做什麼。這可以避免混淆並提高輸出的準確性。
**範例**:
* **做 (DO)**: `Generate a 1 paragraph blog post about the top 5 video game consoles. Only discuss the console, the company who made it, the year, and total sales.`
* **不做 (DO NOT)**: `Generate a 1 paragraph blog post about the top 5 video game consoles. Do not list video game names.`
最佳實踐是首先優先考慮指令,清楚說明您希望模型做什麼,僅在必要時(為了安全、清晰或特定要求)才使用約束。實驗和迭代測試不同的指令和約束組合,找到最適合您特定任務的方法,並記錄下來。
### 控制最大詞元長度 (Control the max token length)
可以通過在配置中設定最大詞元限制,或在提示中明確請求特定長度來控制生成的 LLM 回應的長度。例如:`"Explain quantum physics in a tweet length message."`。
### 在提示中使用變數 (Use variables in prompts)
為了重用提示並使其更具動態性,請在提示中使用變數,這些變數可以針對不同的輸入進行更改。例如 (表 20),一個提供城市事實的提示,與其硬編碼城市名稱,不如使用變數。變數允許您避免重複自己,從而節省時間和精力。如果需要在多個提示中使用相同的資訊片段,可以將其存儲在變數中,然後在每個提示中引用該變數。這在將提示集成到您自己的應用程式中時非常有意義。
**範例 (表 20)**:
* **Prompt**:
```
VARIABLES
{city} = "Amsterdam"
PROMPT
You are a travel guide. Tell me a fact about the city: {city}
```
* **Output**: `Amsterdam is a beautiful city full of canals, bridges, and narrow streets. It's a great place to visit for its rich history, culture, and nightlife.`
### 實驗 輸入格式和寫作風格 (Experiment with input formats and writing styles)
不同的模型、模型配置、提示格式、詞語選擇和提交方式**可能產生不同的結果**。因此,重要的是實驗提示屬性,如風格、詞語選擇和提示類型(zero shot, few shot, system prompt)。
例如,一個目標是生成關於革命性遊戲主機 Sega Dreamcast 文本的提示,可以表述為問題、陳述或指令,從而導致不同的輸出:
* **問題**: `What was the Sega Dreamcast and why was it such a revolutionary console?`
* **陳述**: `The Sega Dreamcast was a sixth-generation video game console released by Sega in 1999. It...`
* **指令**: `Write a single paragraph that describes the Sega Dreamcast console and explains why it was so revolutionary.`
### 對於少樣本分類任務,混合類別 (For few-shot prompting with classification tasks, mix up the classes)
一般來說,few-shots 範例的順序影響不大。但是,在進行分類任務時,請確保在 few shot 範例中混合可能的響應類別。否則,您可能會過度擬合範例的特定順序。通過混合可能的響應類別,您可以確保模型正在學習識別每個類別的關鍵特徵,而不僅僅是記住範例的順序。這將導致在未見數據上更穩健和可推廣的性能。通常從 6 個 few shot 範例開始測試準確性。
### 適應模型更新 (Adapt to model updates)
及時了解模型架構變化、新增數據和功能非常重要。嘗試更新的模型版本,並調整您的提示以更好地利用新模型特性。像 Vertex AI Studio 這樣的工具非常適合存儲、測試和記錄提示的各個版本。
### 實驗 輸出格式 (Experiment with output formats)
除了提示輸入格式外,考慮實驗輸出格式。對於非創意性任務,如提取、選擇、解析、排序、排名或分類數據,嘗試讓輸出以結構化格式返回,如 JSON 或 XML。
從提取數據的提示返回 JSON 物件有幾個好處:
* 總是以相同的風格返回。
* 專注於您想要接收的數據。
* 減少幻覺的可能性。
* 使其具有關係感知能力。
* 獲得數據類型。
* 可以對其進行排序。
(表 4 的 few-shot 提示部分展示瞭如何返回結構化輸出的範例)。
#### JSON 修復 (JSON Repair)
雖然以 JSON 格式返回數據具有許多優勢,但也有其缺點。JSON 的結構化特性雖然有利於解析和在應用程式中使用,但比純文本需要顯著更多的詞元,導致處理時間增加和成本更高。此外,JSON 的冗長性很容易消耗整個輸出窗口,當生成因詞元限制而被突然切斷時,問題尤其嚴重。這種截斷通常導致無效的 JSON,缺少關鍵的閉合大括號或方括號,使輸出無法使用。幸運的是,像 `json-repair` 庫(可在 PyPI 上獲得)這樣的工具在這些情況下可能非常寶貴。該庫會智能地嘗試自動修復不完整或格式錯誤的 JSON 物件,使其成為處理 LLM 生成的 JSON 時的關鍵盟友,尤其是在處理潛在截斷問題時。
### 使用模式 (Working with Schemas)
使用結構化 JSON 作為輸出是一個很好的解決方案。但輸入呢?雖然 JSON 非常適合構建 LLM 生成的輸出,但它對於構建您提供的 **輸入** 也可能非常有用。這就是 JSON Schemas 發揮作用的地方。JSON Schema 定義了 JSON 輸入的預期結構和數據類型。通過提供 schema,您可以為 LLM 提供其應期望的數據的清晰藍圖,幫助其將注意力集中在相關信息上,並降低誤解輸入的風險。此外,schemas 可以幫助建立不同數據片段之間的關係,甚至可以通過包含具有特定格式的日期或時間戳字段使 LLM 具有「時間感知」能力。
**範例**:使用 LLM 為電子商務目錄中的產品生成描述。與其僅提供產品的自由格式文本描述,不如使用 JSON schema 來定義產品的屬性:
* **Schema 定義 (Snippet 5)**:
```json
{
"type": "object",
"properties": {
"name": { "type": "string", "description": "Product name" },
"category": { "type": "string", "description": "Product category" },
"price": { "type": "number", "format": "float", "description": "Product price" },
"features": {
"type": "array",
"items": { "type": "string" },
"description": "Key features of the product"
},
"release_date": { "type": "string", "format": "date", "description": "Date the product was released"}
}
}
```
* **符合 Schema 的實際數據 (Snippet 6)**:
```json
{
"name": "Wireless Headphones",
"category": "Electronics",
"price": 99.99,
"features": ["Noise cancellation", "Bluetooth 5.0", "20-hour battery life"],
"release_date": "2023-10-27"
}
```
* **說明**: 通過預處理您的數據,並提供 schema 和數據(而不是完整的文檔),您可以讓 LLM 清楚地了解產品的屬性(包括其發布日期),使其更有可能生成準確且相關的描述。這種結構化的輸入方法在處理大量數據或將 LLMs 集成到複雜應用程式中時尤其有價值。
### 與其他提示工程師一起實驗 (Experiment together with other prompt engineers)
如果您需要提出一個好的提示,可以嘗試找多個人進行嘗試。當每個人都遵循最佳實踐(如本章所列)時,您將會看到所有不同提示嘗試之間的性能差異。
### CoT 最佳實踐 (CoT Best practices)
* 對於 CoT 提示,答案 **必須** 放在推理之後,因為推理的生成會改變模型預測最終答案時所獲得的詞元。
* 對於 CoT 和 self-consistency,您需要能夠從提示中提取最終答案,與推理分開。
* 對於 CoT 提示,將 Temperature 設定為 0。CoT 提示基於 greedy decoding,預測序列中的下一個詞基於語言模型分配的最高機率。一般來說,當使用推理得出最終答案時,很可能只有一個正確答案。因此,Temperature 應始終設置為 0。
### 記錄各種提示嘗試 (Document the various prompt attempts)
最後但同樣重要的一點是:**完整詳細地記錄您的提示嘗試**,以便您可以隨著時間的推移了解哪些方法有效,哪些無效。
提示輸出可能因模型、取樣設定甚至同一模型的不同版本而異。此外,即使對於同一模型的相同提示,輸出句子格式和詞語選擇也可能出現微小差異(例如,如果兩個詞元具有相同的預測機率,則可能隨機選擇,這會影響後續預測的詞元)。
**建議使用類似表 21 的模板創建記錄表(例如 Google Sheet)**:
* **Name**: [提示的名稱和版本]
* **Goal**: [此次嘗試目標的一句話解釋]
* **Model**: [使用的模型的名稱和版本]
* **Temperature**: [0-1 之間的值]
* **Top-K**: [數字]
* **Token Limit**: [數字]
* **Top-P**: [數字]
* **Prompt**: [寫下完整的提示]
* **Output**: [寫下輸出或多個輸出]
**其他有用的追蹤欄位**:
* **Iteration**: 提示的版本號。
* **Result Status**: OK / NOT OK / SOMETIMES OK。
* **Feedback**: 捕獲反饋。
* **Link (if using Vertex AI Studio)**: 保存提示的超鏈接。
**對於檢索增強生成 (Retrieval Augmented Generation, RAG) 系統**: 還應捕獲影響插入提示內容的 RAG 系統特定方面,包括查詢、塊設置、塊輸出和其他信息。
一旦您覺得提示接近完美,就將其納入您的項目程式碼庫。在程式碼庫中,將提示保存在與程式碼分開的文件中,以便於維護。理想情況下,您的提示應成為可操作化系統的一部分,作為提示工程師,您應依賴自動化測試和評估程序來了解您的提示在任務上的泛化程度。
**Prompt engineering 是一個迭代過程**:製作和測試不同的提示,分析和記錄結果。根據模型的性能改進您的提示。不斷實驗,直到達到期望的輸出。當您更改模型或模型配置時,返回並繼續使用先前使用的提示進行實驗。
---
## 總結 (Summary)
本白皮書討論了 Prompt Engineering,學習了各種提示技巧,例如:
* Zero prompting
* Few shot prompting
* System prompting
* Role prompting
* Contextual prompting
* Step-back prompting
* Chain of thought (CoT)
* Self consistency
* Tree of thoughts (ToT)
* ReAct
* Automatic Prompt Engineering (APE)
接著討論了生成式 AI 的挑戰,例如提示不足時可能出現的問題。最後以如何成為更好的提示工程師的最佳實踐作為結尾。