使用 Spring AI 實現 AI 助手
1. 概述
在本教程中,我們將討論 Spring AI 的概念,它可以幫助使用 ChatGPT、Ollama、Mistreal 等 LLM 創建 AI 助理。
企業越來越多地採用人工智慧助理來增強各種現有業務功能的使用者體驗:
- 回答用戶詢問
- 根據使用者輸入執行交易
- 總結冗長的句子和文檔
雖然這些只是法學碩士的一些基本能力,但它們的潛力遠遠超出了這些功能。
2. Spring AI特性
Spring AI 框架提供了一系列令人興奮的功能來提供 AI 驅動的功能:
- 可與底層LLM服務和Vector DB無縫整合的接口
- 使用 RAG 和函數呼叫 API 產生上下文感知回應和執行操作
- 結構化輸出轉換器,用於將 LLM 回應轉換為 POJO 或機器可讀格式(如 JSON)
- 透過 Advisor API 提供的攔截器豐富提示並套用護欄
- 透過維護對話狀態來增強用戶參與度
我們也可以將其視覺化:
為了說明其中一些功能,我們將在舊的訂單管理系統 (OMS) 中建立一個聊天機器人:
OMS 的典型功能包括:
- 建立訂單
- 取得用戶訂單
3. 先決條件
首先,我們需要訂閱 OpenAI 才能使用其 LLM 服務。然後在 Spring Boot 應用程式中,我們將新增 Spring AI 庫的 Maven 依賴項。我們已經在其他文章中詳細介紹了先決條件,因此我們不會進一步詳細說明該主題。
此外,我們將使用記憶體 HSQLDB 資料庫來快速入門。讓我們建立必要的表並在其中插入一些資料:
CREATE TABLE User_Order (
order_id BIGINT NOT NULL PRIMARY KEY,
user_id VARCHAR(20) NOT NULL,
quantity INT
);
INSERT INTO User_Order (order_id, user_id, quantity) VALUES (1, 'Jenny', 2);
INSERT INTO User_Order (order_id, user_id, quantity) VALUES (2, 'Mary', 5);
INSERT INTO User_Order (order_id, user_id, quantity) VALUES (3, 'Alex', 1);
INSERT INTO User_Order (order_id, user_id, quantity) VALUES (4, 'John', 3);
INSERT INTO User_Order (order_id, user_id, quantity) VALUES (5, 'Sophia', 4);
--and so on..
我們將在 Spring application.properties
檔案中使用一些與初始化 HSQLDB 和 OpenAI 客戶端相關的標準配置屬性:
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.datasource.url=jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=none
spring.ai.openai.chat.options.model=gpt-4o-mini
spring.ai.openai.api-key=xxxxxxx
選擇適合用例的正確模型是一個複雜的迭代過程,涉及大量的試驗和錯誤。不過,對於本文的簡單演示應用程式來說,經濟高效的GPT-4o 迷你模型就足夠了。
4. 函數呼叫API
此功能是基於 LLM 的應用程式中流行的代理概念的支柱之一。它使應用程式能夠執行一系列複雜的精確任務並獨立做出決策。
例如,它可以極大地幫助在舊的訂單管理應用程式中建立聊天機器人。 聊天機器人可以幫助用戶提出訂單請求、檢索訂單歷史記錄以及透過自然語言執行更多操作。
這些是由一個或多個應用程式功能提供支援的專業技能。我們在發送給法學碩士的提示中定義演算法以及支援函數模式。法學碩士收到此模式並確定執行所需技能的正確功能。隨後,它將其決定發送給應用程式。
最後,應用程式執行該函數並向 LLM 發送回更多資訊:
首先,讓我們來看看遺留應用程式的主要元件:
OrderManagementService
類別有兩個重要的功能:建立訂單和取得使用者訂單歷史記錄。這兩個函數都使用OrderRepository
bean 與資料庫整合:
@Service
public class OrderManagementService {
@Autowired
private OrderRepository orderRepository;
public Long createOrder(OrderInfo orderInfo) {
return orderRepository.save(orderInfo).getOrderID();
}
public Optional<List<OrderInfo>> getAllUserOrders(String userID) {
return orderRepository.findByUserID(userID);
}
}
現在,讓我們看看 Spring AI 如何幫助在遺留應用程式中實作聊天機器人:
在類別圖中, OmAiAssistantConfiguration
類別是一個 Spring 設定 bean。它註冊函數回呼 bean、 createOrderFn
和getUserOrderFn:
@Configuration
public class OmAiAssistantConfiguration {
@Bean
@Description("Create an order. The Order ID is identified with orderID. "
+ The order quantity is identified by orderQuantity."
+ "The user is identified by userID. "
+ "The order quantity should be a positive whole number."
+ "If any of the parameters like user id and the order quantity is missing"
+ "then ask the user to provide the missing information.")
public Function<CreateOrderRequest, Long> createOrderFn(OrderManagementService orderManagementService) {
return createOrderRequest -> orderManagementService.createOrder(createOrderRequest.orderInfo());
}
@Bean
@Description("get all the orders of an user. The user ID is identified with userID.")
public Function<GetOrderRequest, List<OrderInfo>> getUserOrdersFn(OrderManagementService orderManagementService) {
return getOrderRequest -> orderManagementService.getAllUserOrders(getOrderRequest.userID()).get();
}
}
@Description
註解有助於產生函數模式。隨後,應用程式將此架構作為提示的一部分傳送給 LLM 。由於這些函數使用OrderManagementService
類別的現有方法,因此提高了可重複使用性。
此外, CreateOrderRequest
和GetOrderRequests
是 Record 類,可協助 Spring AI 為下游服務呼叫產生 POJO:
record GetOrderRequest(String userID) {}
record CreateOrderRequest(OrderInfo orderInfo) {}
最後,讓我們來看看新的OrderManagementAIAssistant
類,它將向 LLM 服務發送使用者查詢:
@Service
public class OrderManagementAIAssistant {
@Autowired
private ChatModel chatClient;
public ChatResponse callChatClient(Set<String> functionNames, String promptString) {
Prompt prompt = new Prompt(promptString, OpenAiChatOptions
.builder()
.withFunctions(functionNames)
.build()
);
return chatClient.call(prompt);
}
}
callChatClient()
方法可協助註冊 Prompt 物件中的函數。隨後,它會呼叫ChatModel#call()
方法以取得來自 LLM 服務的回應。
5. 函數呼叫場景
對於向人工智慧助理發出的使用者查詢或指令,我們將介紹一些基本場景:
- LLM 決定並確定要執行的一項或多項職能
- LLM 抱怨執行函數的資訊不完整
- LLM 有條件地執行語句
到目前為止我們已經討論了這些概念;因此,接下來,我們將使用此功能來建立聊天機器人。
5.1.執行回調函數一次或多次
現在,讓我們研究一下當我們使用由使用者查詢和函數模式組成的提示來呼叫 LLM 時它的行為。
我們將從建立訂單的範例開始:
void whenOrderInfoProvided_thenSaveInDB(String promptString) {
ChatResponse response = this.orderManagementAIAssistant
.callChatClient(Set.of("createOrderFn"), promptString);
String resultContent = response.getResult().getOutput().getContent();
logger.info("The response from the LLM service: {}", resultContent);
}
令人驚訝的是,利用自然語言,我們得到了預期的結果:
迅速的 | 法學碩士回應 | 觀察 |
---|---|---|
為使用者 ID Jenny 建立數量為 20 的訂單,且 | ||
隨機產生一個正整數作為訂單ID | 訂單已成功創建,詳細資訊如下: | |
– **訂單 ID:** 123456 | ||
– **使用者 ID:** 珍妮 | ||
– **訂單數量:** 20 | 程式使用提示中提供的資訊建立訂單。 | |
建立兩個訂單。第一個訂單是使用者 ID Sophia,數量為 30。 | 訂單已成功建立: | |
1. **Sophia 訂單**:訂單 ID 1,數量 30。 | ||
2. **瑪麗的訂單**:訂單 ID 2,數量為 40。 |
如果您還有其他需要,請隨時詢問!
| 該程式創建兩個訂單。 LLM 很聰明地要求執行該函數兩次。 |
接下來,讓我們看看 LLM 能否理解請求獲取用戶訂單詳細資訊的提示:
void whenUserIDProvided_thenFetchUserOrders(String promptString) {
ChatResponse response = this.orderManagementAIAssistant
.callChatClient(Set.of("getUserOrdersFn"), promptString);
String resultContent = response.getResult().getOutput().getContent();
logger.info("The response from the LLM service: {}", resultContent);
}
結果與先前的情況類似。 LLM 成功識別要執行的註冊函數。隨後,Spring Boot 應用程式呼叫請求的函數並傳回一個或多個使用者的訂單詳細資訊。
5.2.有條件地執行回調函數
讓我們考慮一下僅當滿足某些條件時才會建立訂單的程序:
void whenUserIDProvided_thenCreateOrderIfUserHasLessThanTwoOrders(String promptString) {
ChatResponse response = this.orderManagementAIAssistant
.callChatClient(Set.of("getUserOrdersFn", "createOrderFn"), promptString);
String resultContent = response.getResult()
.getOutput()
.getContent();
logger.info("The response from the LLM service: {}", resultContent);
}
我們已在ChatModel
bean 中註冊了getUserOrderFn
和CreateOrderFn
函數。此外,法學碩士必須確定哪個功能將為所請求的行動產生最佳結果。
就像以前一樣,結果令人鼓舞:
迅速的 | 輸出 | 觀察 |
---|---|---|
為使用者 id Alex 建立訂單,數量為 25。建立訂單時,隨機產生訂單ID的正整數 | 用戶 Alex 已經有超過 2 個訂單(具體來說,4 個訂單)。因此,我不會建立新訂單。 | LLM 可以根據先前函數的輸出有條件地呼叫下游函數。 |
為使用者 ID David 建立訂單,數量為 25。建立訂單時,隨機產生訂單ID的正整數 | 用戶ID為「David」的訂單已成功創建,訂單數量為25,訂單ID為42。 | 這次getUserOrderFn 為 David 回傳了不到 2 個訂單。因此,LLM決定請求執行createOrderFn。 |
建立數量為 20 的訂單 | 請提供您的用戶 ID 以建立訂單。 | 法學碩士一開始就發現使用者 ID 遺失,並中止了進一步處理。 |
6. Spring AI Advisors API
在前面的部分中,我們討論了應用程式的功能方面。然而,所有功能都存在一些常見問題,例如:
- 防止使用者輸入敏感訊息
- 用戶查詢的記錄和審核
- 維持對話狀態
- 豐富提示
幸運的是,Advisors API 可以幫助一致解決這些問題。我們已經在一篇文章中詳細解釋了這一點。
7. Spring AI結構化輸出API和Spring AI RAG
法學碩士主要以自然語言產生對使用者查詢的回應訊息。然而,下游服務大多理解機器可讀格式的訊息,如 POJO、JSON 等。
與 Advisors API 一樣,我們在一篇文章中對此進行了詳細解釋。因此,我們不會對此進行更多討論並轉向下一個主題。
有時,應用程式必須查詢向量資料庫以對儲存的資料執行語義搜尋以檢索附加資訊。隨後,從 Vector DB 取得的結果將在提示中使用,為 LLM 提供上下文資訊。這稱為 RAG 技術,也可以使用 Spring AI 來實現。
八、結論
在本文中,我們探討了有助於創建 AI 助理的 Spring AI 關鍵功能。 Spring AI 不斷發展,具有許多開箱即用的功能。然而,無論程式框架如何,正確選擇底層 LLM 服務和 Vector DB 都至關重要。此外,實現這些服務的最佳配置可能很棘手並且需要付出大量努力。儘管如此,這對於應用程式的廣泛採用還是很重要的。
和往常一樣,本文使用的原始程式碼可以在 GitHub 上參考。