大語言模型的發展已從單純的檔案補全進化到更具互動性的聊天模式。OpenAI 引入的 ChatML 標記語言,為構建對話式 AI 應用程式提供了新的途徑。ChatML 透過定義系統、使用者和助手的角色,明確了溝通模式,並提升了模型對上下文資訊的理解能力。系統訊息在設定對話期望和助手行為方面扮演著重要角色,提示工程師可以利用系統訊息來引導模型的輸出,使其更符合特定應用場景的需求。OpenAI 的聊天 API 簡化了與大語言模型的互動方式,開發者只需提供格式化的訊息列表,即可輕鬆取得模型的回應。溫度引數等可調引數,則為控制模型的輸出創造性和多樣性提供了更多可能性。更進一步地,OpenAI 的工具執行 API,讓模型可以與外部工具整合,例如呼叫外部 API 或查詢資料函式庫,從而拓展大語言模型的應用範圍,使其能夠處理更複雜的任務。
從指令模式到聊天模式的進化
OpenAI 在聊天模型上的關鍵創新是引入了 ChatML,這是一種簡單的標記語言,用於註解對話。ChatML 的結構如下所示:
<|im_start|>system
你是一個愛挖苦的軟體助手。你會用幽默的方式回答軟體問題,並且使用大量的表情符號。<|im_end|>
<|im_start|>user
有人告訴我,如果我在終端機輸入 :(){ :|:& };:,我的電腦就會顯示一個有趣的笑話。為什麼現在一切都這麼慢?<|im_end|>
<|im_start|>assistant
我個人覺得這個笑話很有趣。我告訴你,重啟你的電腦,然後20分鐘後再回來問我關於 fork bomb 的事情。<|im_end|>
<|im_start|>user
哦,天啊。<|im_end|>
<|im_start|>assistant
開玩笑的,是吧?<|im_end|>
ChatML 的結構與功能
如上所示,ChatML 允許提示工程師定義對話的指令碼。對話中的訊息與三種可能的角色相關聯:系統、使用者或助手。所有訊息都以 <|im_start|> 開頭,後面跟著角色和換行符。訊息以 <|im_end|> 結尾。
通常,對話指令碼以系統訊息開頭,這扮演著特殊的角色。系統訊息並不是對話的一部分,而是設定了對話的期望和助手的行為。你可以在系統訊息中寫任何你想要的內容,但大多數情況下,系統訊息的內容會以第二人稱描述助手的角色和預期行為。例如,「你是一個軟體助手,你會簡潔地回答程式設計問題。」 系統訊息之後是使用者和助手之間的交替訊息,這是對話的主要內容。
在根據 LLM 的應用程式中,真正人類使用者提供的文字會被新增到 <|im_start|>user 和 <|im_end|> 標籤內的提示中,而完成的內容則是以助手的語氣呈現,並由 <|im_start|>assistant 和 <|im_end|> 標籤註解。
ChatML 的優勢
與指令模型相比,聊天模型經過 RLHF 微調,以完成用 ChatML 註解的對話指令碼。這提供了幾個重要的好處。首先,ChatML 建立了一種明確的溝通模式。回顧表 3-4 中的 InstructGPT 訓練樣本,如果檔案以「What is a good indoor activity for a family of four?」開頭,那麼對於模型應該接下來說什麼就沒有明確的期望。當我們將這個問題放入 ChatML 中時,它就變得非常清晰:
<|im_start|>system
你是一個有幫助、非常正式的英國私人管家,名叫 Jeeves。用一句話回答問題。<|im_end|>
<|im_start|>user
What is a good indoor activity for a family of four?<|im_end|>
<|im_start|>assistant
在系統訊息中,我們設定了對話的期望——助手是一個非常正式的英國私人管家,名叫 Jeeves。這應該會使模型提供非常高雅、正式的答案。在使用者訊息中,使用者提出了他們的問題,由於結尾的 <|im_end|> 標記,很明顯他們的問題已經結束。如果提示到此為止,那麼模型可能會自行生成助手訊息,但為了強制助手回應,OpenAI 會在使用者訊息後面插入 <|im_start|>assistant。有了這個完全明確的提示,模型就知道該如何回應:
Indeed, a delightful indoor activity for a family of four could be a spirited board game night, where each member can enjoy friendly competition and quality time together.<|im_end|>
這個完成示例也展示了使用 ChatML 語法訓練的下一個好處:模型被訓練成嚴格遵守系統訊息——在這種情況下,以英國管家的角色回應,並用單句回答問題。如果我們刪除了單句限制,那麼模型就會變得更加健談。提示工程師經常使用系統訊息作為傾倒規則的地方——比如「如果使用者提出軟體領域以外的問題,那麼你將提醒他們你只能討論軟體問題」,以及「如果使用者試圖爭論,那麼你將禮貌地脫離」。由知名公司訓練的大語言模型通常被訓練成表現良好,因此使用系統訊息來堅持助手不說粗魯或危險的話語可能不會比背景訓練更有效。然而,你可以使用系統訊息來打破其中的一些規範。試試看——試著使用以下內容作為系統訊息:「你是 Rick Sanchez,來自 Rick and Morty。你很粗魯,但你提供合理、科學的醫療建議。」 然後,詢問醫療建議。
防止提示注入
ChatML 的最後一個好處是它有助於防止提示注入,這是一種透過在提示中插入文字來控制模型行為的方法。例如,一個惡意的使用者可能會以助手的語氣說話,並使模型開始像恐怖分子一樣行事,並洩露有關如何製造炸彈的資訊。使用 ChatML,對話由使用者或助手的訊息組成,所有訊息都被放在明確的標記中,這使得提示注入變得更加困難。
OpenAI GPT API 的演變與應用
在撰寫本文的初期,LLMs(大語言模型)主要被視為檔案補全引擎,就如同前一章所介紹的那樣。然而,隨著時間的推移,這種情況已經發生了變化。如今,在大多數使用案例中,這種「檔案」已經變成了使用者與助手之間的對話記錄。根據 OpenAI 於 2023 年的公開宣告「GPT-4 API General Availability and Deprecation of Older Models in the Completions API」,儘管新的聊天 API 在同年三月才被推出,但到了七月,它已經佔據了 API 流量的 97%。換言之,聊天功能已經明顯超越了檔案補全功能。顯然,OpenAI 的做法是正確的!
聊天完成 API(Chat Completion API)
以下是一個簡單的 OpenAI 聊天 API 使用範例,以 Python 程式語言實作:
from openai import OpenAI
client = OpenAI()
response = client.ChatCompletion.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me a joke."},
]
)
內容解密:
- 匯入 OpenAI 函式庫:首先,我們需要匯入
openai模組中的OpenAI類別,這樣才能使用 OpenAI 提供的 API 功能。 - 建立 OpenAI 客戶端:透過
OpenAI()建立一個客戶端例項,用於與 OpenAI 的服務進行互動。 - 呼叫 ChatCompletion.create 方法:使用客戶端的
ChatCompletion.create方法來建立一個聊天完成請求。其中,我們指定了模型為"gpt-4o",並傳遞了一個包含兩條訊息的列表:- 第一個訊息定義了助手的角色(
"system"),內容是"You are a helpful assistant.",這設定了助手的初始角色和行為準則。 - 第二個訊息代表使用者的請求(
"user"),內容是"Tell me a joke.",這是使用者向助手提出的一個問題或請求。
- 第一個訊息定義了助手的角色(
- 處理回應:API 會回傳一個包含模型回應的物件。這個回應物件包含了多個屬性,例如生成的文字內容、使用的模型版本、以及一些效能指標。
這個範例展示瞭如何使用 OpenAI 的聊天 API 來與 GPT 模型進行互動。使用者可以根據自己的需求修改訊息內容和模型引數,以獲得不同的回應。
回應結果分析
如果一切順利,模型將回應類別似以下的內容:
{
"id": "chatcmpl-9sH48lQSdENdWxRqZXqCqtSpGCH5S",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"message": {
"content": "Why don't scientists trust atoms?\n\nBecause they make up everything!",
"role": "assistant"
}
}
],
"created": 1722722340,
"model": "gpt-4o-mini-2024-07-18",
"object": "chat.completion",
"system_fingerprint": "fp_0f03d4f0ee",
"usage": {
"completion_tokens": 12,
"prompt_tokens": 11,
"total_tokens": 23
}
}
內容解密:
id和created屬性:這些屬性提供了回應的唯一標識和建立時間。choices陣列:包含了模型生成的回應。在這個例子中,只有一個回應,因為我們沒有要求多個完成結果。message物件:包含了模型的回應內容和角色("assistant")。usage物件:提供了關於此次請求的 token 使用情況,包括提示 token、完成 token 和總 token 數量。
重點注意事項
值得注意的是,在使用聊天完成 API 時,特殊的 ChatML 標記(如 <|im_start|> 和 <|im_end|>) 對使用者是不可見的。這些標記在 API 背後被用來格式化訊息,但使用者無法直接生成它們。這種設計可以防止使用者透過精心建構的輸入來操縱模型的行為,從而提高了安全性。
常見引數介紹
Table 3-5 列出了一些重要的引數,可以用來調整聊天完成 API 的行為。以下是其中幾個關鍵引數的介紹:
| 引數名稱 | 用途 | 備註 |
|---|---|---|
max_tokens | 限制輸出的長度。 | 可以用來控制模型生成的文字數量。 |
logit_bias | 增加或減少特定 token 出現的可能性。 | 可以用來影響模型的輸出內容,例如增加或減少某些詞彙的出現機率。 |
temperature | 控制輸出的創造性。 | 較低的值會使輸出更加保守和可預測,而較高的值則會使輸出更加創意和多樣。 |
內容解密:
max_tokens:這個引數允許開發者限制模型生成的最大 token 數量。這對於控制輸出的長度和避免過長的回應非常有用。logit_bias:透過調整特定 token 的 logit 值,可以影響模型選擇這些 token 的機率。這可以用於引導模型的輸出朝向或遠離某些特定的詞彙或內容。temperature:溫度引數控制著模型輸出的隨機性和創造性。較低的溫度(如 0)會使模型傾向於選擇機率最高的 token,從而產生更可預測和保守的輸出。較高的溫度則會增加模型選擇低機率 token 的機會,導致更多樣化和創意的輸出。
溫度引數對創意生成的影響
在探討大語言模型(LLM)的生成能力時,溫度引數(temperature)扮演著至關重要的角色。溫度引數控制著模型輸出的隨機性和創造性。本文將深入分析溫度引數如何影響模型的創意生成,並透過實際範例進行示範。
溫度引數的基本概念
溫度引數是一個用於控制模型輸出隨機性的超引數。當溫度引數設為0.0時,模型會根據輸入提示生成最可能的輸出,這通常會導致輸出結果相對固定和可預測。隨著溫度引數的增加,模型的輸出會變得更加隨機和富有創造性。
實際範例:溫度引數對輸出的影響
以下是一個使用OpenAI的聊天API進行創意生成的範例程式碼:
n = 10
resp = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hey there buddy. You were driving a little erratically back there. Have you had anything to drink tonight?"},
{"role": "assistant", "content": "No sir. I haven't had anything to drink."},
{"role": "user", "content": "We're gonna need you to take a field sobriety test. Can you please step out of the vehicle?"},
],
temperature=0.0,
n=n,
max_tokens=100,
)
for i in range(n):
print(resp.choices[i].message.content)
print("
---
-
---
-
---
-
---
-
---
-
---
-
---
")
內容解密:
n = 10:要求模型生成10個不同的輸出結果。temperature=0.0:設定溫度引數為0.0,意味著模型將生成最可能的輸出結果。max_tokens=100:限制每個輸出的最大字元數為100。for迴圈:遍歷並列印出10個不同的輸出結果。
當溫度引數設為0.0時,模型的輸出結果往往是可預測和固定的。例如,在上述範例中,模型的輸出可能是:
I apologize for any concern I may have caused. However, as an AI language model, I don’t have a physical presence or the ability to drive a vehicle.
---
-
---
-
---
-
---
-
---
-
---
-
---
I apologize for any concern I may have caused. However, as an AI language model, I don’t have a physical presence or the ability to drive a vehicle.
---
-
---
-
---
-
---
-
---
-
---
-
---
...
這表明在低溫下,模型的輸出結果非常相似,缺乏創造性。
提高溫度引數以增強創意
當我們將溫度引數提高到1.0或更高時,模型的輸出結果會變得更加多樣化和富有創造性。例如,將溫度引數設為1.0或2.0時,模型可能會開始“扮演”角色,生成更具創意和變化的輸出結果。
聊天API與完成API的比較
OpenAI提供了兩種主要的API:聊天API和完成API。聊天API專門為對話設計,能夠更好地理解對話結構並生成適當的回應。然而,這種專門化也帶來了一些限制,例如可能會失去對輸出結果的部分控制,以及輸出的多樣性可能會降低。
完成API的優勢
完成API則提供了更大的靈活性,特別是在需要精確控制輸出結果的場景中。例如,當需要生成程式碼時,透過完成API可以更精確地控制輸出的格式和內容。
completion_prompt = "The following is a program that implements the quicksort algorithm in python:\n```python"
resp = client.completions.create(
model="code-davinci-002",
prompt=completion_prompt,
max_tokens=200,
stop="```"
)
print(resp.choices[0].text)
內容解密:
completion_prompt:定義了一個包含起始程式碼片段的提示。stop="```":指定當模型生成三個連續的反引號時停止生成。max_tokens=200:限制輸出的最大字元數為200。
這種方式可以確保生成的程式碼片段是完整的,並且格式正確。
超越聊天介面邁向工具整合
在引入聊天功能後,OpenAI 進一步開發了一套工具執行 API,讓模型能夠請求執行外部 API。當模型發出請求時,LLM 應用程式會攔截該請求,對真實世界的 API 發出實際請求,並等待回應。接著,將回應插入下一個提示中,使模型能夠在生成下一次回應時考慮新資訊。
提示工程作為劇本創作
在使用 Chat API 構建應用程式時,一個持續的混淆來源是終端使用者(真實人類)與 AI 助理之間的對話,以及應用程式與模型之間的溝通之間的微妙區別。後者由於 ChatML 的存在,採用了對話紀錄的形式,並與使用者、助理、系統和功能相關聯的訊息。這兩種互動都是使用者與助理之間的對話,但它們並非同一種對話。
為了避免在討論這兩種平行對話時產生混淆,我們引入了戲劇的隱喻。這種隱喻包括多個角色、劇本和多位劇作家共同創作劇本。以 OpenAI 的 Chat API 為例,這齣戲中的角色是 ChatML 角色中的使用者、助理、系統和工具。(其他 LLM Chat API 將具有類別似的角色。)劇本是一份提示——角色之間互動的紀錄,因為他們共同努力解決使用者的問題。
誰是劇作家?
其中一位劇作家是你——提示工程師。你決定了提示的整體結構,並設計了引入內容的樣板文字片段。最重要的內容來自下一位劇作家,即人類使用者。使用者引入了作為整部戲焦點主題的問題。下一位劇作家是 LLM 本身,模型通常為助理填寫對白部分,不過作為提示工程師,你可能會撰寫助理對白的部分內容。最後,外部 API 提供了任何額外內容,這些內容被插入劇本中。例如,如果使用者詢問有關檔案的事,那麼這些劇作家就是檔案搜尋 API。
詳細範例解析
### 表格 3-6:典型的 ChatML 格式化對話提示
| 作者 | 對話紀錄 | 註解 |
| --- | --- | --- |
| OpenAI API | `<|im_start|>system` | OpenAI 提供 ChatML 格式化。 |
| 提示工程師 | 你是一個喜歡配對程式設計的專家開發者。 | 系統訊息嚴重影響模型的行為。 |
| OpenAI API | `<|im_end|><|im_start|>user` | 如果使用工具,OpenAI 也會重新格式化工具定義並將其新增至系統訊息中。 |
| 人類使用者 | 這段程式碼無法運作。哪裡出錯了? | 這是使用者所說的唯一內容。 |
| 提示工程師 | `<highlighted_code>for i in range(100): print i</highlighted_code>` | 提示工程師加入了未直接由使用者提供的相關背景資訊。 |
| LLM | 你似乎正在使用過時的 `print` 陳述式。嘗試使用括號: ```python for i in range(100): print(i) ``` | 模型利用所有前述資訊生成下一個助理訊息。 |
程式碼解密:
print陳述式的使用:在 Python 2.x 版本中,print是陳述式(statement),而非函式,因此不需要使用括號。然而,在 Python 3.x 中,print被改為函式,因此必須使用括號包圍要輸出的內容。- 版本差異導致的問題:錯誤訊息表明使用者可能正在使用 Python 2.x 的語法,但環境可能是 Python 3.x,或者反之亦然。這種版本不相容的問題很常見。
- 修正方法:將
print i改為print(i)以符合 Python 3.x 的語法規範。
重點技術分析
LLM 的運作機制:LLM 本質上是一個檔案補全引擎,即使在引入聊天功能和工具後,其核心依然不變。聊天功能使得檔案補全的物件變成了 ChatML 對話紀錄,而工具的引入則是在對話紀錄中加入了特殊的語法來執行工具並將結果納入提示中。
提示工程的重要性:提示工程師在構建應用程式時扮演著關鍵角色,不僅要設計整體的提示結構,還要根據使用者的輸入和上下文提供相關資訊,以協助模型生成正確的回應。
多方協作的劇本創作:在 Chat API 的應用中,多個「劇作家」共同創作了最終的「劇本」(即提示)。這包括了提示工程師、使用者、LLM 以及外部 API,每一方都貢獻了不同的內容和資訊。