Prompts
Prompts (提示) 是引導 AI 模型產生特定輸出的輸入。這些提示的設計和措辭會顯著影響模型的反應。
在 Spring AI 中與 AI 模型互動的最低層級,處理提示在某種程度上類似於管理 Spring MVC 中的「View」。這涉及到建立帶有動態內容預留位置的大量文字。然後根據使用者請求或應用程式中的其他程式碼替換這些預留位置。另一個類似之處是包含特定表達式預留位置的 SQL 陳述式。
隨著 Spring AI 的發展,它將引入更高層級的抽象概念,以便與 AI 模型互動。本節中描述的基礎類別可以比作 JDBC 在其角色和功能方面的作用。例如,ChatModel
類別類似於 JDK 中的核心 JDBC 函式庫。ChatClient
類別可以比作 JdbcClient
,它建立在 ChatModel
之上,並透過 Advisor
提供更進階的結構,以考量過去與模型的互動、使用額外的上下文文件來擴充提示,並引入代理行為。
提示的結構在 AI 領域中隨著時間演進。最初,提示是簡單的字串。隨著時間的推移,它們擴展到包含特定輸入的預留位置,例如 AI 模型可辨識的「USER:」。OpenAI 透過將多個訊息字串分類為不同的角色,進一步為提示引入了結構,然後再由 AI 模型處理。
API 總覽
Prompt (提示)
通常使用 ChatModel
的 call()
方法,該方法接受 Prompt
實例並傳回 ChatResponse
。
Prompt
類別的功能是作為 Message
物件和請求 ChatOptions
的有組織序列的容器。每個 Message
都體現了提示中獨特的角色,其內容和意圖各不相同。這些角色可以包含各種元素,從使用者查詢到 AI 產生的回應,再到相關的背景資訊。這種安排使與 AI 模型能夠進行複雜而詳細的互動,因為提示是由多個訊息構成,每個訊息都被指定在對話中扮演特定的角色。
以下是 Prompt 類別的截斷版本,為了簡潔起見,省略了建構子和公用程式方法
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;
private ChatOptions chatOptions;
}
Message (訊息)
Message
介面封裝了 Prompt
文字內容、中繼資料屬性的集合以及稱為 MessageType
的分類。
介面定義如下
public interface Content {
String getContent();
Map<String, Object> getMetadata();
}
public interface Message extends Content {
MessageType getMessageType();
}
多模態訊息類型也實作了 MediaContent
介面,提供 Media
內容物件的清單。
public interface MediaContent extends Content {
Collection<Media> getMedia();
}
Message
介面的各種實作對應於 AI 模型可以處理的不同類別的訊息。模型根據對話角色區分訊息類別。

這些角色會有效地由 MessageType
對應,如下所述。
Roles (角色)
每個訊息都分配有一個特定的角色。這些角色對訊息進行分類,為 AI 模型釐清提示的每個區段的上下文和目的。這種結構化方法增強了與 AI 通訊的細微性和有效性,因為提示的每個部分都在互動中扮演著獨特且明確定義的角色。
主要角色包括
-
系統角色:引導 AI 的行為和回應風格,設定 AI 如何解讀和回覆輸入的參數或規則。這類似於在開始對話之前向 AI 提供指示。
-
使用者角色:代表使用者的輸入 - 他們對 AI 的問題、命令或陳述。此角色至關重要,因為它構成了 AI 回應的基礎。
-
助理角色:AI 對使用者輸入的回應。它不僅僅是一個答案或反應,對於維持對話流程至關重要。透過追蹤 AI 先前的回應(其「助理角色」訊息),系統確保連貫且符合上下文的互動。助理訊息也可能包含函式工具呼叫請求資訊。它就像 AI 中的一項特殊功能,用於在需要執行特定功能時使用,例如計算、擷取資料或超出僅僅交談的其他任務。
-
工具/函式角色:工具/函式角色的重點是傳回額外資訊,以回應工具呼叫助理訊息。
角色在 Spring AI 中表示為列舉,如下所示
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
TOOL("tool");
...
}
PromptTemplate (提示範本)
Spring AI 中提示範本化的關鍵組件是 PromptTemplate
類別。此類別使用 Terence Parr 開發的 OSS StringTemplate 引擎,用於建構和管理提示。PromptTemplate
類別旨在促進結構化提示的建立,然後將其傳送至 AI 模型進行處理
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {
// Other methods to be discussed later
}
此類別實作的介面支援提示建立的不同面向
PromptTemplateStringActions
專注於建立和呈現提示字串,代表最基本的提示產生形式。
PromptTemplateMessageActions
專為透過產生和操作 Message
物件來建立提示而量身打造。
PromptTemplateActions
旨在傳回 Prompt
物件,該物件可以傳遞至 ChatModel
以產生回應。
雖然這些介面在許多專案中可能不會被廣泛使用,但它們顯示了建立提示的不同方法。
實作的介面包括
public interface PromptTemplateStringActions {
String render();
String render(Map<String, Object> model);
}
方法 String render()
:將提示範本呈現為最終字串格式,而無需外部輸入,適用於沒有預留位置或動態內容的範本。
方法 String render(Map<String, Object> model)
:增強呈現功能以包含動態內容。它使用 Map<String, Object>
,其中 map 鍵是提示範本中的預留位置名稱,值是要插入的動態內容。
public interface PromptTemplateMessageActions {
Message createMessage();
Message createMessage(List<Media> mediaList);
Message createMessage(Map<String, Object> model);
}
方法 Message createMessage()
:建立不含額外資料的 Message
物件,用於靜態或預先定義的訊息內容。
方法 Message createMessage(List<Media> mediaList)
:建立具有靜態文字和媒體內容的 Message
物件。
方法 Message createMessage(Map<String, Object> model)
:擴展訊息建立以整合動態內容,接受 Map<String, Object>
,其中每個項目代表訊息範本中的預留位置及其對應的動態值。
public interface PromptTemplateActions extends PromptTemplateStringActions {
Prompt create();
Prompt create(ChatOptions modelOptions);
Prompt create(Map<String, Object> model);
Prompt create(Map<String, Object> model, ChatOptions modelOptions);
}
方法 Prompt create()
:產生不含外部資料輸入的 Prompt
物件,非常適合靜態或預先定義的提示。
方法 Prompt create(ChatOptions modelOptions)
:產生不含外部資料輸入且具有聊天請求特定選項的 Prompt
物件。
方法 Prompt create(Map<String, Object> model)
:擴展提示建立功能以包含動態內容,接受 Map<String, Object>
,其中每個 map 項目是提示範本中的預留位置及其關聯的動態值。
方法 Prompt create(Map<String, Object> model, ChatOptions modelOptions)
:擴展提示建立功能以包含動態內容,接受 Map<String, Object>
,其中每個 map 項目是提示範本中的預留位置及其關聯的動態值,以及聊天請求的特定選項。
範例用法
以下顯示一個取自 AI Workshop on PromptTemplates (提示範本 AI 工作坊) 的簡單範例。
PromptTemplate promptTemplate = new PromptTemplate("Tell me a {adjective} joke about {topic}");
Prompt prompt = this.promptTemplate.create(Map.of("adjective", adjective, "topic", topic));
return chatModel.call(prompt).getResult();
以下顯示另一個取自 AI Workshop on Roles (角色 AI 工作坊) 的範例。
String userText = """
Tell me about three famous pirates from the Golden Age of Piracy and why they did.
Write at least a sentence for each pirate.
""";
Message userMessage = new UserMessage(this.userText);
String systemText = """
You are a helpful AI assistant that helps people find information.
Your name is {name}
You should reply to the user's request with your name and also in the style of a {voice}.
""";
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemText);
Message systemMessage = this.systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));
Prompt prompt = new Prompt(List.of(this.userMessage, this.systemMessage));
List<Generation> response = chatModel.call(this.prompt).getResults();
這展示了如何透過使用 SystemPromptTemplate
建立具有系統角色的 Message
並傳入預留位置值來建立 Prompt
實例。然後將角色為 user
的訊息與角色為 system
的訊息結合,以形成提示。然後將提示傳遞至 ChatModel 以取得生成式回應。
使用資源而非原始字串
Spring AI 支援 org.springframework.core.io.Resource
抽象概念,因此您可以將提示資料放在檔案中,該檔案可以直接在 PromptTemplate
中使用。例如,您可以在 Spring 管理的組件中定義一個欄位來擷取 Resource
。
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
然後直接將該資源傳遞至 SystemPromptTemplate
。
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
Prompt Engineering (提示工程)
在生成式 AI 中,建立提示是開發人員的一項關鍵任務。這些提示的品質和結構顯著影響 AI 輸出的有效性。投入時間和精力設計周全的提示可以大大改善 AI 的結果。
在 AI 社群中,分享和討論提示是一種常見的做法。這種協作方法不僅創造了共享的學習環境,而且還有助於識別和使用高效提示。
該領域的研究通常涉及分析和比較不同的提示,以評估其在各種情況下的有效性。例如,一項重要的研究表明,以「深呼吸並逐步解決這個問題」開頭的提示顯著提高了問題解決效率。這突顯了精心選擇的語言可以對生成式 AI 系統的效能產生影響。
掌握提示的最有效使用方式,尤其是在 AI 技術快速發展的情況下,是一項持續的挑戰。您應該認識到提示工程的重要性,並考慮使用來自社群和研究的見解來改進提示建立策略。
建立有效提示
在開發提示時,整合幾個關鍵組件以確保清晰度和有效性非常重要
-
指示:向 AI 提供清晰且直接的指示,就像您與人溝通一樣。這種清晰度對於幫助 AI「理解」預期的內容至關重要。
-
外部上下文:在必要時包含相關的背景資訊或針對 AI 回應的特定指導。這種「外部上下文」為提示設定了框架,並有助於 AI 掌握整體情境。
-
使用者輸入:這是簡單的部分 - 使用者的直接請求或問題,構成提示的核心。
-
輸出指示器:這方面可能很棘手。它涉及到指定 AI 回應的所需格式,例如 JSON。但是,請注意,AI 可能不總是嚴格遵守此格式。例如,它可能會在實際 JSON 資料之前加上「這是您的 JSON」之類的短語,或者有時會產生不準確的類 JSON 結構。
在製作提示時,向 AI 提供預期問題和答案格式的範例非常有益。這種做法有助於 AI「理解」您的查詢的結構和意圖,從而產生更精確和相關的回應。雖然本文檔沒有深入探討這些技術,但它們為進一步探索 AI 提示工程提供了起點。
以下是供進一步研究的資源清單。
進階技術
-
Zero-shot (零樣本)、 Few-shot Learning (少樣本學習):
使模型能夠在幾乎或沒有特定問題類型先例的情況下做出準確的預測或回應,使用學習到的概括來理解和執行新任務。 -
Chain-of-Thought (思維鏈):
連結多個 AI 回應以建立連貫且具有上下文意識的對話。它有助於 AI 維持討論的主題,確保相關性和連貫性。 -
ReAct (Reason + Act) (推理 + 行動):
在此方法中,AI 首先分析(推理)輸入,然後確定最合適的行動方案或回應。它結合了理解和決策。
Microsoft Guidance (微軟指南)
-
Framework for Prompt Creation and Optimization (提示建立和最佳化框架):
Microsoft 提供了一種結構化的方法來開發和改進提示。此框架指導使用者建立有效的提示,從 AI 模型中引出所需的回應,並最佳化互動以提高清晰度和效率。
Tokens (tokens)
Tokens (tokens) 在 AI 模型如何處理文字方面至關重要,它充當橋樑,將單字(如我們所理解的)轉換為 AI 模型可以處理的格式。這種轉換分兩個階段進行:單字在輸入時轉換為 tokens,然後這些 tokens 在輸出中轉換回單字。
Tokenization (分詞化),將文字分解為 tokens 的過程,對於 AI 模型如何理解和處理語言至關重要。AI 模型使用這種分詞化格式來理解和回應提示。
為了更好地理解 tokens,請將它們視為單字的一部分。通常,一個 token 代表大約四分之三個單字。例如,莎士比亞的全集,總共約 900,000 個單字,將轉換為約 120 萬個 tokens。
試用 OpenAI Tokenizer UI (OpenAI 分詞器 UI),看看單字是如何轉換為 tokens 的。
Tokens 除了在 AI 處理中的技術角色外,還具有實際意義,尤其是在計費和模型功能方面
-
計費:AI 模型服務通常根據 token 使用量計費。輸入(提示)和輸出(回應)都會計入 token 總數,從而使較短的提示更具成本效益。
-
模型限制:不同的 AI 模型具有不同的 token 限制,定義了它們的「上下文視窗」- 它們一次可以處理的最大資訊量。例如,GPT-3 的限制為 4K tokens,而其他模型(如 Claude 2 和 Meta Llama 2)的限制為 100K tokens,而某些研究模型可以處理高達 100 萬個 tokens。
-
上下文視窗:模型的 token 限制決定了其上下文視窗。超出此限制的輸入將不會被模型處理。僅傳送最少有效的一組資訊進行處理至關重要。例如,在詢問「哈姆雷特」時,無需包含莎士比亞所有其他作品的 tokens。
-
回應中繼資料:來自 AI 模型的回應的中繼資料包括使用的 token 數量,這是管理使用量和成本的重要資訊。