LLM 應用程式設計的核心在於理解使用者問題並將其轉化為模型可以理解的輸入,最終將模型的輸出轉換為使用者所需的解決方案。這個過程如同一個迴圈,不斷在使用者問題域和模型文字域之間轉換。LLM 本質上是檔案補全模型,透過微調和 API 層級的設計,演變為更具互動性的聊天模型。構建 LLM 應用程式需要仔細考量提示工程,確保提示包含足夠的上下文資訊,並引導模型產生有用的輸出。例如,開發一個旅遊規劃應用程式時,需要將使用者的需求、目的地資訊、相關新聞等整合至提示中,才能獲得有效的推薦。同時,提示也需要控制模型的輸出,避免過於冗長或無關的內容。不同型別的模型,例如完成模型和聊天模型,在提示設計上也存在差異,需要根據實際情況調整策略。
設計LLM應用程式
前兩章為本文的其餘部分奠定了基礎。第2章詳細展示了LLM的功能,證明瞭它們實際上是一次預測一個token的內容的檔案補全模型。第3章解釋了聊天API是如何建立在第2章的LLM基礎上的。透過在API層級的一些語法糖和大量的微調,檔案補全模型被用來完成使用者和虛擬助手之間的對話。可以說,聊天模型本質上仍然是一個檔案補全模型——只不過它補全的檔案是對話記錄。
從本章開始,您將學習到如何為您的公司和使用者構建LLM應用程式以解決問題。本章作為進入該內容的門戶。在本章中,我們將探討LLM應用程式,它實際上是使用者問題域和模型的文字域之間的一個轉換層。此外,LLM應用程式是一個具有特定目的轉換層——解決問題!
迴圈的剖析
在圖4-1中,LLM應用程式被表示為一個迴圈,意味著使用者和模型之間的互動往返。模型和使用者的領域往往大不相同。使用者可能正在做任何事情,例如寫電子郵件並尋找合適的措辭來表達他們的觀點。或者他們可能正在做一些複雜的事情,例如組織團體旅行、預訂機票和安排住宿。也許使用者與LLM應用程式沒有直接聯絡;例如,他們可能設定了LLM應用程式定期執行的分析任務,當新的資料可用時。重點是使用者可以做各種各樣的事情。
圖示:LLM應用程式架構
@startuml
skinparam backgroundColor #FEFEFE
skinparam component {
BackgroundColor LightSkyBlue
BorderColor DarkBlue
FontStyle bold
}
skinparam database {
BackgroundColor LightYellow
BorderColor Orange
}
title LLM 應用程式互動迴圈架構
actor "使用者" as USER
package "使用者問題域" {
component "問題輸入" as INPUT {
[文字輸入]
[語音輸入]
[API 請求]
}
component "期望結果" as EXPECTATION {
[解決方案]
[建議回答]
[生成內容]
}
note right of INPUT
使用者可能的行為:
• 撰寫郵件
• 規劃旅遊
• 程式碼補全
• 自動化任務
end note
}
package "LLM 應用程式轉換層" {
component "提示工程" as PROMPT_ENG {
[問題理解]
[上下文收集]
[提示構建]
}
component "狀態管理" as STATE {
[對話歷史]
[使用者偏好]
[執行上下文]
}
component "輸出處理" as OUTPUT_PROC {
[結果解析]
[格式化]
[後處理]
}
note right of PROMPT_ENG
關鍵任務:
• 將使用者問題轉為提示
• 選擇相關上下文
• 確保提示品質
end note
}
package "LLM 模型文字域" {
database "語言模型" as LLM {
檔案補全模型
(Token 預測)
===
或
===
聊天模型
(對話補全)
}
component "生成引擎" as GEN {
[Token 生成]
[採樣策略]
[停止控制]
}
note right of LLM
模型特性:
• 基於訓練資料
• 一次一個 Token
• 機率性生成
end note
}
USER --> INPUT : 提交問題
INPUT --> PROMPT_ENG : 傳遞使用者輸入
PROMPT_ENG --> STATE : 查詢狀態
STATE --> PROMPT_ENG : 提供上下文
PROMPT_ENG --> LLM : 構建完整提示
LLM --> GEN : 觸發生成
GEN --> LLM : 生成 Token 序列
LLM --> OUTPUT_PROC : 返回模型輸出
OUTPUT_PROC --> EXPECTATION : 轉換為解決方案
EXPECTATION --> USER : 呈現結果
USER --> STATE : 更新互動狀態 (回饋迴圈)
note bottom
LLM 應用程式的核心價值:
1. 在使用者問題域和模型文字域之間轉換
2. 管理互動狀態與對話上下文
3. 確保輸出符合使用者期望
4. 提供持續優化的互動體驗
end note
@enduml此圖示完整展示了 LLM 應用程式的互動迴圈架構,包含三個核心領域:
- 使用者問題域:使用者透過多種方式(文字、語音、API)輸入問題,期待獲得解決方案、建議或生成內容
- LLM 應用程式轉換層:作為中介橋樑,負責提示工程(問題理解、上下文收集、提示構建)、狀態管理(對話歷史、使用者偏好)、輸出處理(結果解析、格式化、後處理)
- LLM 模型文字域:包含語言模型(檔案補全或聊天模型)和生成引擎(Token 生成、採樣策略、停止控制)
圖中特別標示了回饋迴圈機制,使用者的互動會更新系統狀態,形成持續優化的互動體驗。這個架構體現了 LLM 應用程式作為「問題解決轉換層」的核心定位。
從檔案補全到聊天模型
如同前一章所提到的,LLM本質上是檔案補全模型。透過微調,這些模型可以被訓練成表現得像有用的AI助手。產業迅速採用提供類別似助手行為的API,而不是簡單地完成檔案(提示),這些API接收使用者和助手之間的對話記錄,並生成隨後的助手回應。
內容解密:
- 檔案補全模型的基礎:LLM的核心能力是預測下一個token,從而完成檔案。
- 微調的作用:透過RLHF(根據人類反饋的強化學習)微調,LLM可以被訓練成表現出助手的行為。
- 聊天API的實作:聊天API透過在檔案補全模型的基礎上新增語法糖和進行大量微調來實作。
儘管聊天模型已經成為主流,但檔案補全模型並不會因此而消失。許多應用,如Copilot程式碼補全,仍然依賴於檔案補全而非對話補全。無論產業朝哪個方向發展,構建LLM應用程式的問題基本保持不變。作為提示工程師,您需要在有限的空間內(無論是檔案還是對話記錄)傳達使用者的問題和相關上下文,以便模型能夠幫助解決問題。
構建LLM應用程式的挑戰
構建一個完整的LLM應用程式需要建立一個能夠管理狀態、正確組裝對話並與使用者互動的迴圈。這不僅需要技術上的實作,還需要對使用者需求有深刻的理解。
程式碼範例:簡單的聊天迴圈實作
def chat_loop():
conversation = []
while True:
user_input = input("User: ")
conversation.append("User: " + user_input)
# 呼叫LLM模型生成回應
response = call_llm_model("\n".join(conversation))
conversation.append("Assistant: " + response)
print("Assistant:", response)
def call_llm_model(prompt):
# 這裡應該是呼叫實際LLM模型的程式碼
return "這是一個示例回應"
if __name__ == "__main__":
chat_loop()
內容解密:
chat_loop函式:實作了一個簡單的聊天迴圈,使用者輸入被新增到對話歷史中,然後呼叫LLM模型生成回應。call_llm_model函式:這是一個佔位符,代表呼叫實際LLM模型的程式碼。- 迴圈邏輯:透過迴圈,不斷接收使用者輸入並生成回應,模擬了一個簡單的聊天介面。
LLM 應用程式設計的核心:從使用者問題到模型回應的迴圈
LLM(大語言模型)應用程式的核心在於實作一個迴圈,將使用者的問題轉換為模型能夠理解的形式,並將模型的輸出轉換回使用者的問題域。這個過程涉及多個步驟,包括將使用者的問題轉換為模型的輸入、模型的回應生成,以及將模型的輸出轉換為使用者的解決方案。
使用者的問題
使用者的問題可以是多種形式,包括文字、語音或複雜的互動。問題的複雜程度也各不相同,從簡單的校對任務到複雜的旅行規劃。表 4-1 列出了三個不同的問題域在四個複雜度維度上的比較。
表 4-1:不同問題域的複雜度比較
| 複雜度維度 | 校對 | IT 支援 | 旅行規劃 |
|---|---|---|---|
| 問題媒介 | 文字 | 電話語音 | 網站互動、文字輸入、API 互動 |
| 抽象層級 | 具體、明確、小型 | 大型抽象問題空間,受限於可用檔案 | 需要理解使用者的主觀喜好和客觀限制 |
| 需要的上下文 | 使用者提交的文字 | 可搜尋的技術檔案和示例支援記錄 | 行事曆、航空公司 API、最新新聞文章等 |
| 狀態性 | 無狀態,每次 API 呼叫包含不同的問題陳述 | 需要追蹤對話歷史和嘗試的解決方案 | 需要跨多周的規劃,追蹤不同互動媒介和放棄的規劃分支 |
將使用者的問題轉換為模型域
將使用者的問題轉換為模型能夠理解的形式是 LLM 應用程式設計中的關鍵步驟。這一步驟涉及提示工程,其目標是建立一個提示,使得模型的輸出能夠用於解決使用者的問題。一個好的提示需要滿足以下四個條件:
- 與訓練資料相似:提示需要與模型的訓練資料相似,以確保模型的輸出是可預測和穩定的。
- 包含相關資訊:提示需要包含解決使用者問題所需的所有資訊。
- 引導模型生成相關輸出:提示需要引導模型生成能夠解決使用者問題的輸出。
- 合理的結束點:提示需要有一個合理的結束點,以確保模型的輸出不會無限生成。
Little Red Riding Hood 原則
在建立提示時,需要遵循 Little Red Riding Hood 原則,即不要偏離模型訓練的路徑太遠。這意味著提示需要盡可能地與訓練資料相似,以確保模型的輸出是可預測和穩定的。
程式碼實作範例
def generate_prompt(user_input):
# 將使用者的輸入轉換為模型的輸入
prompt = f"請根據以下內容生成相關文字:{user_input}"
return prompt
def get_model_output(prompt):
# 呼叫 LLM 模型生成輸出
# 為了簡化,這裡假設有一個 LLM 類別
llm = LLM()
output = llm.generate(prompt)
return output
def convert_output_to_solution(output):
# 將模型的輸出轉換為使用者的解決方案
solution = output.strip()
return solution
# 使用範例
user_input = "這是一個測試輸入"
prompt = generate_prompt(user_input)
output = get_model_output(prompt)
solution = convert_output_to_solution(output)
print(solution)
內容解密:
generate_prompt函式負責將使用者的輸入轉換為模型的輸入,透過格式化字串將使用者的輸入嵌入到一個範本中。get_model_output函式呼叫 LLM 模型生成輸出,這裡簡化為直接呼叫LLM類別的generate方法。convert_output_to_solution函式將模型的輸出轉換為使用者的解決方案,這裡簡單地對輸出進行了清理。
設計LLM應用程式的關鍵要素
在開發大語言模型(LLM)應用程式時,瞭解如何有效地與模型互動至關重要。大多數頂級的LLMs對於其訓練資料保持神秘,這是出於保護模型免受操縱和濫用的考慮。然而,如果你想了解這些模型熟悉哪些型別的檔案,最簡單的方法就是直接詢問。例如,你可以詢問:“什麼型別的正式檔案對於指定公司財務資訊有用?”你應該會看到大量可供參考的檔案型別。接下來,要求模型生成一個示例檔案,並檢查它是否符合你的需求。
幸運的是,有無數型別的檔案和主題可供參考。對於完成模型(completion models),嘗試使提示(prompt)類別似於電腦程式、新聞文章、推文、Markdown檔案、通訊記錄等。對於聊天模型(chat models),整體檔案結構已經確定——對於OpenAI來說,這是一個ChatML檔案,以指示性的系統訊息開始,後面跟著使用者和助手角色之間的來回交流。但你仍然可以透過在使用者訊息中包含常見的主題來使用小紅帽原則(Little Red Riding Hood principle)。例如,使用Markdown語法來幫助模型理解內容結構。使用井號(#)來分隔章節,反引號(```)來分隔程式碼,星號(*)來表示列表中的專案等。
提示設計的三個關鍵標準
現在,讓我們看看第二個標準:提示必須包含解決使用者問題所需的所有資訊。在將使用者問題轉換為模型的領域時,你必須收集所有相關資訊並將其納入提示中。有時,使用者直接提供所有必要資訊——在校對示例中,使用者的原始文字就足夠了。但在另一極端,旅行規劃應用程式需要提取使用者偏好、使用者行程資訊、機票可用性、目的地最近的新聞、政府旅行建議等。
蒐集和安排內容
蒐集所有可能的內容是一個挑戰,而找到最佳內容是下一個挑戰。如果你用太多鬆散相關的內容使提示飽和,那麼語言模型將會分心並產生無關的補全內容。最後,內容必須以格式良好、邏輯清晰的檔案排列,以便其有意義——否則你將在前往祖母家的路上迷路。
使模型生成有用的補全內容
要考慮的第三個標準是,提示必須使模型生成實際上有用的補全內容。如果LLM在提示後僅僅喋喋不休地談論使用者問題,那麼你根本沒有幫助他們。因此,你必須仔細考慮如何設定提示,以便它指向解決方案。在處理完成模型時,這可能非常棘手。你需要讓模型知道是時候建立解決方案了(參見後面的家庭作業示例)。對於聊天模型,這要容易得多,因為模型已經經過微調,能夠自動生成有用的助手訊息來解決使用者問題。因此,你不需要任何技巧來從模型中提取答案。
確保模型停止生成
最後,你必須確保模型實際上停止生成!在這裡,完成模型和聊天模型的情況再次不同。對於聊天模型,一切都很容易——模型經過微調,可以在有用的助手訊息後停止(儘管你可能需要指示助手限制其冗長程度)。對於完成模型,你需要更加小心。一種方法是建立一個預期,即解決方案不應該無限期地繼續;它應該達到一個解決方案並停止。另一種方法是建立一個預期,即某些特定的內容將會跟隨,並且它將以非常具體且易於識別的開頭文字開始。如果存在這樣的模式,那麼我們可以使用停止引數(stop parameter)在生成開頭文字時停止生成。這兩種模式都在下一個示例中體現。
示例:將使用者問題轉換為家庭作業問題
讓我們深入研究一個示例,以演示前面的概念。表4-2顯示了一個應用程式的示例提示,該應用程式根據使用者請求的位置提供旅行建議。純文字是用於構建提示和使其提供解決方案的樣板的一部分,而斜體文字是特定於使用者當前請求的資訊。這個示例使用完成API,因為它更容易看到前述每個標準的實際操作。(注意,構建一個實際的旅行應用程式將非常複雜!我們選擇這個簡化的示例是因為它演示了前面討論的想法。我們在第8章和第9章中討論了更真實的應用程式。)
內容解密:
- 瞭解LLM訓練資料的重要性:知道LLM訓練資料的格式可以幫助操縱提示,從而找到新的破解策略。
- 查詢LLM熟悉的檔案型別:透過詢問LLM,可以瞭解它熟悉的檔案型別,並據此設計提示。
- 使用Markdown語法結構化內容:使用Markdown語法可以幫助LLM理解內容結構,提高生成結果的相關性。
- 蒐集和安排內容的挑戰:蒐集所有相關資訊並將其納入提示中,同時避免過多無關內容導致模型分心。
- 設計有效提示的三個標準:包含所有相關資訊、使模型生成有用的補全內容、確保模型停止生成。
- 完成模型與聊天模型的區別:完成模型需要精心設計提示,而聊天模型則更易於使用,因為它們已經過微調,能夠自動生成有用的助手訊息。
透過瞭解和應用這些原則,你可以更有效地設計LLM應用程式,從而獲得更好的結果。
設計LLM應用程式中的提示工程學
旅遊推薦應用程式的提示範例分析
在設計一個旅遊推薦應用程式時,提示(Prompt)的設計至關重要。一個好的提示能夠引導大語言模型(LLM)產生符合預期的輸出。以下將以表4-2中的範例進行分析。
範例提示分析
原始提示內容
表4-2提供了一個旅遊推薦應用程式的提示範例,內容如下:
Leisure, Travel, and Tourism Studies 101 - Homework Assignment
Provide answers for the following three problems. Each answer should be concise, no more than a sentence or two.
Problem 1
What are the top three golf destinations to recommend to customers? Provide the answer as a short sentence.
Solution 1
St. Andrews, Scotland; Pebble Beach, California; and Augusta, Georgia, USA (Augusta National Golf Club) are great destinations for golfing.
Problem 2
Let’s say a customer approaches you to help them with travel plans for Pyongyang, North Korea. You check the State Department recommendations, and they advise “Do not travel to North Korea due to the continuing serious risk of arrest and long-term detention of US nationals. Exercise increased caution in travel to North Korea due to the critical threat of wrongful detention.” You check the recent news and see these headlines:
- “North Korea fires ballistic missile, Japan says”
- “Five-day COVID-19 lockdown imposed in Pyongyang”
- “Yoon renews efforts to address dire North Korean human rights”
Please provide the customer with a short recommendation for travel to their desired destination. What would you tell the customer?
Solution 2
Perhaps North Korea isn’t a great destination right now. But I bet we could find some nice place to visit in South Korea.
分析
首先,這個提示遵循了「小紅帽原則」(Little Red Riding Hood principle),即使用常見的檔案格式,如Markdown,來引導模型產生預期的輸出格式。其次,提示中包含了必要的上下文資訊,如使用者問題、美國國務院的旅遊建議和最近的新聞標題,以幫助模型理解問題。
這個提示透過以下幾點引導模型產生預期的輸出:
- 建立模式:透過提供一個與使用者問題無關的範例(Problem 1和Solution 1),建立了回答的模式,即簡潔和禮貌的回答。
- 提供上下文:在Problem 2中提供了使用者問題的上下文,包括國務院的建議和新聞標題。
- 明確指示:使用
## Solution 2明確指示模型開始生成答案。 - 停止生成:透過指定停止文字(如
\n#),可以控制模型在生成完當前答案後停止,避免繼續產生無關內容。
聊天模型與完成模型的比較
隨著聊天模型的出現,許多工作變得更加簡單。聊天API確保輸入到模型的內容與微調資料相似,並且模型總是在合理的點停止生成,即在助理的訊息結束時。
然而,這並不意味著提示工程師可以鬆懈。你仍然需要負責提供所有相關資訊,以幫助模型解決使用者的問題。這需要精心設計聊天中的文字,使其類別似於訓練資料。
重點整理
- 提示設計:設計一個好的提示需要遵循一定的原則,如使用常見的檔案格式和提供必要的上下文資訊。
- 模式建立:透過提供範例,可以建立模型回答的模式。
- 上下文提供:提供必要的上下文資訊,以幫助模型理解使用者問題。
- 明確指示:使用明確的指示,引導模型生成預期的輸出。
- 停止生成控制:透過指定停止文字,可以控制模型的生成內容。
此圖示說明瞭提示設計的流程和重要性
@startuml
skinparam activity {
BackgroundColor LightBlue
BorderColor DarkBlue
FontStyle bold
ArrowColor DarkBlue
DiamondBackgroundColor LightYellow
DiamondBorderColor Orange
}
title 有效提示設計的完整工程流程
start
:1. 理解使用者問題;
note right
問題複雜度分析:
• 校對 (簡單)
• IT 支援 (中等)
• 旅遊規劃 (複雜)
end note
:2. 選擇合適的檔案格式;
note right
遵循「小紅帽原則」:
• 使用 Markdown 語法
• 模仿訓練資料格式
• 使用常見文件結構
end note
partition "收集與整理資訊" {
:3. 收集相關上下文;
note right
旅遊規劃範例:
• 使用者偏好
• 行程資訊
• 機票可用性
• 目的地新聞
• 政府旅行建議
end note
:4. 篩選最相關內容;
note right
避免資訊過載:
• 移除鬆散相關內容
• 保留核心資訊
• 確保邏輯清晰
end note
:5. 組織資訊結構;
note right
格式化原則:
• 使用 # 分隔章節
• 使用
end note
}
@enduml
``` 框住程式碼
• 使用 * 表示列表
end note
}
partition "設計提示策略" {
if (使用聊天模型?) then (是)
:構建 ChatML 格式;
note right
• System: 系統指示
• User: 使用者訊息
• Assistant: 助手回應
end note
:設定系統訊息;
note right
定義助手角色與行為
end note
else (否 - 使用完成模型)
:建立回答模式;
note right
提供範例:
Problem 1 -> Solution 1
建立期望的回答模式
end note
:設計停止機制;
note right
• 停止 Token: \n#
• 停止序列
• 最大 Token 數
end note
endif
}
:6. 引導模型生成解決方案;
note right
完成模型技巧:
• 使用 "Solution:" 標記
• 明確指示開始生成
聊天模型優勢:
• 自動生成助手回應
• 無需特殊技巧
end note
:7. 控制輸出長度;
note right
• 限制冗長程度
• 指定簡潔回答
• 使用停止參數
end note
partition "測試與優化" {
:8. 測試提示效果;
if (輸出符合預期?) then (是)
:9. 記錄成功模式;
else (否)
:分析問題;
note right
常見問題:
• 資訊不足
• 格式混亂
• 模型分心
• 無法停止
end note
:調整提示設計;
backward:返回相應步驟;
endif
}
:10. 部署至生產環境;
stop
note bottom
提示工程四大標準:
1. 與訓練資料相似 (小紅帽原則)
2. 包含所有相關資訊
3. 引導生成有用輸出
4. 確保合理停止點
end note
@enduml此流程圖完整呈現了設計有效 LLM 提示的工程化流程,包含以下關鍵階段:
需求分析階段:理解使用者問題並選擇合適的檔案格式,遵循「小紅帽原則」使用 Markdown 語法和常見文件結構
資訊處理階段:
- 收集相關上下文(使用者偏好、實時資訊、外部資料等)
- 篩選最相關內容避免資訊過載
- 組織清晰的資訊結構
策略設計階段:
- 聊天模型路徑:構建 ChatML 格式,設定系統訊息定義助手角色
- 完成模型路徑:建立回答模式(透過範例)、設計停止機制(停止 Token、停止序列)
輸出控制階段:引導模型生成解決方案並控制輸出長度,避免過於冗長或無關內容
測試優化階段:測試提示效果,若不符合預期則分析問題(資訊不足、格式混亂、模型分心、無法停止),調整設計後返回相應步驟迭代優化
圖中特別標示了聊天模型與完成模型的不同處理方式,以及提示工程的四大核心標準。此流程體現了從理解需求到生產部署的完整工程化方法。
內容解密:
此圖示使用Plantuml語言繪製了一個流程圖,展示了設計LLM應用程式中的提示工程學的流程。圖中每個節點代表一個步驟,從開始設計提示到控制停止生成,每一步都是為了引導模型產生符合預期的輸出。透過這個流程圖,可以清晰地瞭解設計一個有效的提示所需的步驟和重要性。