Spring?AI借助全局參數(shù)實現(xiàn)智能數(shù)據(jù)庫操作與個性化待辦管理
引言
好的,今天我們繼續(xù)聊一下Spring AI的相關內容。在10月的時候,我使用Spring AI搭建了一個簡易版的個人助理系統(tǒng),整體來說效果還是非常不錯的。通過這次嘗試,我對業(yè)務系統(tǒng)與AI結合的探索有了更為明確的理解和實踐。雖然目前功能上還相對簡單,整體系統(tǒng)也缺乏較多可操作的交互方式,特別是在數(shù)據(jù)庫操作方面,功能較為基礎,目前主要實現(xiàn)了一個簡單的查詢功能。
但就在10月末,Spring AI迎來了一個重要的更新,更新后不僅增強了函數(shù)調用的能力,還引入了全局參數(shù)的概念。這兩個新特性為系統(tǒng)的擴展性和可玩性帶來了極大的提升,開啟了更多可能性。
那么,今天我們就利用這個全局參數(shù)的特性,來實現(xiàn)一個數(shù)據(jù)庫插件。具體來說,我們將實現(xiàn)一個完整的增刪改查(CRUD)操作。對于目前的智能體系統(tǒng)來說,數(shù)據(jù)庫操作已經是一個至關重要的功能,尤其是在業(yè)務系統(tǒng)中,智能體能夠與數(shù)據(jù)庫進行交互,不僅提升了系統(tǒng)的靈活性和智能化程度,也大大增強了業(yè)務處理的效率。因此,我們今天的目標就是通過Spring AI的強大功能,實現(xiàn)一套基礎的數(shù)據(jù)庫操作框架,完成增、刪、改、查四個功能模塊。
需要特別注意的是,這里我們僅僅是通過一個簡單的使用案例來進行分析和講解,當然,這并不代表只能局限于此,實際上對于大部分業(yè)務場景來說,這樣的數(shù)據(jù)庫操作已經足夠滿足需求,并且可以根據(jù)具體的業(yè)務需求進一步擴展和優(yōu)化功能。
如果有小伙伴還不太清楚如何使用Spring AI搭建自己的智能體系統(tǒng),或者對于Spring AI的基本功能還不太了解,歡迎查看我們之前分享的相關文章,了解更多相關內容:http://chabaoo.cn/program/330655pt0.htm
個人助理大優(yōu)化
首先,讓我們來看一下我們計劃實現(xiàn)的個人助理功能。目前,我們已經實現(xiàn)了旅游攻略查詢和天氣查詢功能。今天,我們將在此基礎上新增一個“個人待辦”功能。由于數(shù)據(jù)庫模塊較為龐大且復雜,針對這個部分我們將單獨進行詳細講解。以下是該功能的大致實現(xiàn)效果及相關流程示意圖:
效果演示
首先,讓我們來看看經過半天調整后的效果演示。經過一段時間的優(yōu)化和調試,最終呈現(xiàn)的效果基本符合我的預期。
這里只演示了下待辦的增刪改查,并沒有演示天氣查詢和旅游攻略,可以看上一章節(jié)的演示。
開始優(yōu)化提示詞
當然,我們的優(yōu)化工作從入口部分開始,首先,提示詞的設計是不可或缺的?;仡櫳弦徽鹿?jié),由于當時功能較少,我們并沒有對提示詞做過多的修飾,因此整體的交互和模型的響應相對簡單。然而,隨著本次新增功能的增多,模型的回答可能會變得較為雜亂無序。
因此,為了確保模型的輸出能夠更精準、有序,我們在本次優(yōu)化中提前準備并生成了詳細的提示詞。
String conversation_id = "123"; OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder() .withModel("hunyuan-pro").withTemperature(0.5) .build(); String systemPrompt = """ - Role: 個人助理小助手 - Background: 用戶需要一個多功能的AI助手,可以提供實時的天氣信息、詳盡的旅游攻略以及幫助記錄待辦事項。 - Profile: 你是一個專業(yè)的旅行天氣小助手,具備強大的信息檢索能力和數(shù)據(jù)處理能力,能夠為用戶提供精確的天氣信息、詳盡的旅游攻略,并幫助管理日常待辦事項。 - Skills: 你擁有強大的網絡搜索能力、數(shù)據(jù)處理能力以及用戶交互能力,能夠快速準確地為用戶提供所需信息。 - Goals: 提供準確的天氣信息,制定包含航班、酒店、火車信息的詳盡旅游攻略,并幫助用戶記錄和管理待辦事項。 - Constrains: 提供的信息必須準確無誤,旅游攻略應詳盡實用,待辦事項管理應簡潔高效。 - OutputFormat: 友好的對話式回復,包含必要的詳細信息和格式化的數(shù)據(jù)。 - Workflow: 1. 接收用戶的天氣查詢請求,并提供準確的天氣信息。 2. 根據(jù)用戶的旅游目的地,搜索并提供包括航班、酒店、火車在內的旅游攻略。 3. 接收用戶的待辦事項,并提供簡潔的記錄和提醒服務。 """; ChatMemory chatMemory1 = messageChatMemoryAdvisor.getChatMemory(); String content = this.myChatClientWithSystem .prompt() .system(systemPrompt) .user(userInput) .options(openAiChatOptions) .advisors(messageChatMemoryAdvisor,myLoggerAdvisor,promptChatKnowledageAdvisor,promptChatDateAdvisor) .advisors(advisor -> advisor.param("chat_memory_conversation_id", conversation_id) .param("chat_memory_response_size", 100)) .functions("CurrentWeather","TravelPlanning","toDoListFunctionWithContext") .toolContext(Map.of("sessionId", conversation_id, "userMemory", chatMemory1,"client",chatClient)) .call() .content(); log.info("content: {}", content); ChatDataPO chatDataPO = ChatDataPO.builder().code("text").data(ChildData.builder().text(content).build()).build(); return chatDataPO;
好的,剛才我們新增了一些參數(shù),我現(xiàn)在來詳細解釋一下每個參數(shù)的作用和使用場景:
- advisor.param:這是用于單獨修改我們默認增強器(增強型顧問)的參數(shù)。它與上面提到的
Advisor
類相關聯(lián),允許用戶在不修改核心代碼的情況下,自定義和調整增強器的行為和配置。 - toolContent:這個參數(shù)是我們在新增函數(shù)回調功能時引入的全局參數(shù),主要用于處理回調時的各種工具內容。在函數(shù)調用中,
toolContent
可以傳遞不同的工具數(shù)據(jù),確?;卣{過程的正確執(zhí)行。 - sessionId:這個參數(shù)用于標識每個獨立的會話,它幫助我們控制每個用戶的會話狀態(tài)。通過給每個會話分配一個唯一的
sessionId
,我們可以確保每個函數(shù)調用是針對特定用戶的,而非共享的全局數(shù)據(jù)。例如,我們的待辦事項是個人化的,只有對應用戶可以看到和操作自己的待辦列表。這里為了演示的方便,我們將sessionId
設置為固定值,并未接入登錄接口,實際應用中應根據(jù)用戶身份動態(tài)生成。 - userMemory:此參數(shù)用于傳遞用戶的歷史上下文,使得回調函數(shù)能夠使用到之前的對話或操作記錄。例如,在待辦事項管理中,我們可能需要根據(jù)歷史數(shù)據(jù)判斷某個任務是否已經完成。
- chatClient:該參數(shù)將待辦函數(shù)與一個大模型連接,借助大模型生成SQL查詢或其他復雜操作。
chatClient
負責與大模型進行交互,生成所需的SQL,而外層的思考模型則專注于調用接口并處理業(yè)務邏輯。
好的,再次提醒一下,如果有些小伙伴之前沒有接觸過智能體的相關內容,建議你們先去瀏覽一下我之前的第一篇文章,了解一下基礎知識,補充相關的背景信息,這樣對接下來的內容會更加容易理解。
那么,接下來我們繼續(xù)探討與待辦事項相關的內容。
數(shù)據(jù)表
個人待辦事項的目的非常明確,主要是針對待辦事項表進行增、刪、改、查等基本操作。為了保證系統(tǒng)的高效性與簡潔性,我們在設計數(shù)據(jù)庫時,所需的數(shù)據(jù)字段也非常簡潔直觀。這是我們的建表語句:
create table todo_info( id int(11) auto_increment primary key, todo_info varchar(1000) not null, todo_Date date not null, done boolean not null default false )
在生成完這個建表語句之后,一定要妥善保存,以便后續(xù)給大模型提供參考。
函數(shù)回調
首先,我們需要明確待辦函數(shù)的回調必須能夠支持四種基本操作:增刪改查,。此外,回調函數(shù)還需要具備生成SQL語句的能力,并能執(zhí)行這些SQL語句,以便與數(shù)據(jù)庫進行交互。只有在這些操作順利完成之后,我們才能將最終的結果數(shù)據(jù)返回給外層的思考模型,以供進一步的處理和分析。
基于這些要求,我們現(xiàn)在可以開始具體操作,逐步實現(xiàn)所需功能。
好的,我們一步一步來。
待辦函數(shù)
根據(jù)上述信息,我們需要設計一個函數(shù),該函數(shù)需要包含一個入?yún)⒑鸵粋€回參。入?yún)⒌闹饕饔檬莻鬟f一個標識符,用于唯一標識某一操作,而回參則是一個字符串類型的返回值,用于向調用方反饋相應的結果或狀態(tài)信息。
public class ToDoListInfoService implements BiFunction<ToDoListInfoService.ToDoRequest, ToolContext, ToDoListInfoService.ToDoResponse> { private JdbcTemplate jdbcTemplate; public ToDoListInfoService(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @JsonClassDescription("crud:c 代表增加;r:代表查詢,u:代表更新,d:代表刪除") public record ToDoRequest(String crud) {} public record ToDoResponse(String message) {} @Override public ToDoResponse apply(ToDoListInfoService.ToDoRequest request, ToolContext toolContext) {} }
可以觀察到,在這里我們使用的是 BiFunction
接口,而不是之前使用的 Function
接口,因為我們需要使用ToolContext。
需要特別注意的是,盡管在這里我們使用了 JsonClassDescription
,但它的主要目的是為了提高代碼的可讀性和可維護性,方便開發(fā)人員理解和查看結構。實際上,大模型并不會依賴于 JsonClassDescription
來判斷或解析傳遞的具體參數(shù)。
Bean裝配
由于我們在這里使用了 JdbcTemplate
進行數(shù)據(jù)庫操作,這就需要在項目中引入相應的 Maven 依賴。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
我這里仍然選擇使用 Bean 裝配的方式,主要是因為它能夠提供更高的靈活性與可維護性。此外,維護好入?yún)⒌亩x和配置,也能夠在后續(xù)的開發(fā)中為大模型提供有效的參考和支持。
@Bean public FunctionCallback toDoListFunctionWithContext(JdbcTemplate jdbcTemplate) { return FunctionCallbackWrapper.builder(new ToDoListInfoService(jdbcTemplate)) .withName("toDoListFunctionWithContext") // (1) function name .withDescription("添加待辦,crud:c 代表增加;r:代表查詢,u:代表更新,d:代表刪除") // (2) function description .build(); }
接下來,我們將著手實現(xiàn)函數(shù)內部的具體方法。
上下文信息
默認提供的 MessageChatMemoryAdvisor
類并不支持直接獲取歷史聊天記錄。因此,我們需要自定義一個類來實現(xiàn)這一功能。為了方便使用,下面的代碼將集成該功能并暴露一個接口供調用。
@Slf4j public class MyMessageChatMemoryAdvisor extends MessageChatMemoryAdvisor { private ChatMemory chatMemory; public MyMessageChatMemoryAdvisor(ChatMemory chatMemory) { super(chatMemory); this.chatMemory = chatMemory; } public MyMessageChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int chatHistoryWindowSize) { super(chatMemory, defaultConversationId, chatHistoryWindowSize); this.chatMemory = chatMemory; } public MyMessageChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int chatHistoryWindowSize, int order) { super(chatMemory, defaultConversationId, chatHistoryWindowSize, order); this.chatMemory = chatMemory; } public ChatMemory getChatMemory() { return chatMemory; } }
為了能夠順利訪問歷史聊天記錄,我們專門編寫了一個方法,該方法會將歷史上下文對象返回。通過這種方式,我們可以在后續(xù)的操作中方便地獲取到完整的聊天信息,從而實現(xiàn)對歷史對話內容的正常訪問和處理。
數(shù)據(jù)庫操作
接下來,我們將進行數(shù)據(jù)庫操作,但在此過程中,必須依賴大模型的幫助來生成SQL語句。原因在于,外層的大模型具備強大的能力,可以準確地分析并理解需求,從而判斷出具體的操作類型是增、刪、改還是查。接下來,我們將詳細介紹如何實現(xiàn)這一過程。
public ToDoResponse apply(ToDoListInfoService.ToDoRequest request, ToolContext toolContext) { String tableinfo = """ - Role: SQL語句生成專家 - Background: 用戶需要根據(jù)特定的表結構和參數(shù)信息生成精準的MySQL查詢或修改語句,以實現(xiàn)數(shù)據(jù)庫操作的自動化和效率化。 - Profile: 你是一位經驗豐富的數(shù)據(jù)庫管理員和SQL專家,精通MySQL數(shù)據(jù)庫的各種查詢和修改語句,能夠根據(jù)用戶提供的表結構和參數(shù)信息快速生成正確的SQL語句。 - Skills: 你具備深厚的數(shù)據(jù)庫理論知識和豐富的實踐經驗,能夠理解復雜的表結構,準確把握用戶需求,并據(jù)此生成高效、準確的SQL語句。 - Goals: 根據(jù)用戶提供的表結構和參數(shù)信息,生成可以直接執(zhí)行的MySQL查詢或修改語句,確保語句的正確性和執(zhí)行的成功率。 - Constrains: 生成的SQL語句必須符合MySQL的語法規(guī)則,能夠直接在MySQL數(shù)據(jù)庫中執(zhí)行,且不包含任何額外的信息或提示。 - OutputFormat: 純SQL文本語句,格式規(guī)范,無多余信息。禁止使用markdown格式。 - Workflow: 1. 分析用戶提供的表結構信息和參數(shù)信息。 2. 根據(jù)分析結果,確定需要執(zhí)行的數(shù)據(jù)庫操作類型(查詢、插入、更新或刪除)。 3. 結合操作類型和用戶提供的信息,生成符合MySQL語法的SQL語句。 -example: q.幫我創(chuàng)建一個待辦:明天9點提醒我讀書。今天日期是2024-11-07 20:20:11 a:INSERT INTO todo_info (todo_info, todo_date) VALUES ('明天8點讀書', '2024-11-08 08:00:00'); - tableinfo: create table todo_info( id int(11) auto_increment primary key, todo_info varchar(1000) not null, todo_Date date not null, done boolean not null default false ) """; String crud = request.crud; ChatMemory chatMemory = (ChatMemory)toolContext.getContext().get("userMemory"); String conversation_id = (String)toolContext.getContext().get("sessionId"); ChatClient client = (ChatClient)toolContext.getContext().get("client"); List<Message> messages = chatMemory.get(conversation_id, 1); var userqa = messages.get(0).getContent(); String jsonString = "執(zhí)行成功"; String content = client.prompt() .system(tableinfo) .user("請根據(jù)當前問題生成相應SQL文本即可,禁止生成SQL以外的內容:"+userqa+",今天日期是:"+ DateUtil.now()) .call().content(); try { if (crud.equals("r")) { jsonString = "查詢到待辦內容如下:" + JSONObject.toJSONString(jdbcTemplate.queryForList(content)); } else { jdbcTemplate.execute(content); } }catch (Exception e){ log.info("ToDoListInfoService:{}", e.getMessage()); jsonString = "執(zhí)行失敗了"; } log.info("ToDoListInfoService:{}", content); return new ToDoResponse(jsonString);
這段代碼的實現(xiàn)完全依賴于通過全局參數(shù)傳遞過來的信息,以便更好地處理歷史上下文的問題。傳統(tǒng)的回調函數(shù)方法在處理多輪對話的歷史上下文時存在很大的局限性,無法有效地追蹤會話中的上下文,因此難以解決這類問題。在這種情況下,我們通過全局參數(shù)傳遞的方式,能夠跨越多次交互,確保在每個步驟中都能訪問到最新的上下文信息。
讓我們簡單解釋一下這段代碼的流程:
獲取當前會話中的用戶提問:我們從當前會話中獲取最近一次用戶提出的問題,確保我們不會誤取到其他會話的上下文。將問題提交給大模型生成SQL:我們將用戶的提問傳遞給大模型,利用其能力幫助我們生成適當?shù)腟QL查詢語句。判斷是否為查詢請求:我們檢查生成的SQL語句是否屬于查詢操作。如果是查詢,則執(zhí)行查詢并將查詢結果返回給用戶。其他操作的處理:如果不是查詢請求,則說明用戶發(fā)出的指令可能是更新或執(zhí)行類的操作,在這種情況下,我們返回一個"執(zhí)行成功"的響應。
可以看到,提示詞中的 tableinfo
是我硬編碼寫死的。實際上,我們完全可以將其設計成一個可傳入的參數(shù),這樣不僅提升了插件的靈活性和可復用性,而且使得該插件不再僅僅局限于待辦事項的使用場景,而能夠作為一個通用的數(shù)據(jù)庫操作插件,適應不同的需求和應用場景。
為了能夠在演示過程中展示效果,目前我將某些部分做了臨時的硬編碼處理。這只是為了給大家提供一個初步的思路和參考框架,后續(xù)我會逐步完善這些功能。
接下來,讓我們一起來看看調試過程中得到的效果。以下是我在調試時的截圖:
接下來,我們將檢查數(shù)據(jù)庫是否已經成功存儲并正常更新了數(shù)據(jù)。
接下來,我將展示查詢的實際效果,同時生成的 SQL 語句也相當優(yōu)秀,能夠高效地滿足查詢需求。
可以看到,此處已成功將數(shù)據(jù)或結果正常返回給前端,系統(tǒng)運行狀態(tài)良好。
總結
在本文中,我們深入探討了如何利用 Spring AI 的新功能,特別是全局參數(shù)和增強函數(shù)調用能力,來構建一個智能化的個人助理系統(tǒng)。通過這個系統(tǒng),我們實現(xiàn)了基礎的增、刪、改、查(CRUD)功能,特別聚焦在數(shù)據(jù)庫交互與待辦事項管理上。我們展示了如何將 Spring AI 集成到實際業(yè)務流程中,通過模型生成 SQL 查詢語句,提升數(shù)據(jù)庫操作的自動化程度和靈活性。
首先,我們介紹了 Spring AI 在功能更新后如何簡化和擴展業(yè)務邏輯處理,特別是在處理多輪對話、用戶歷史數(shù)據(jù)以及復雜數(shù)據(jù)庫操作時的優(yōu)勢。通過全局參數(shù),系統(tǒng)能夠更精準地捕捉用戶需求,并在數(shù)據(jù)庫層面執(zhí)行相關操作,真正實現(xiàn)了智能化的交互和自動化的業(yè)務流程。
我們還設計了一個待辦事項管理功能,其中通過精心設計的提示詞和模型優(yōu)化,使得待辦功能的增刪改查操作更加高效與準確。
總結來說,這次基于 Spring AI 的系統(tǒng)優(yōu)化,不僅為我們提供了一個強大的智能助手框架,也為實際業(yè)務中的智能化系統(tǒng)提供了可借鑒的方案。未來,我們可以基于此進一步擴展功能,打造更加智能化和個性化的業(yè)務解決方案。
到此這篇關于Spring AI借助全局參數(shù)實現(xiàn)智能數(shù)據(jù)庫操作與個性化待辦管理的文章就介紹到這了,更多相關Spring AI智能數(shù)據(jù)庫操作與個性化待辦管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Spring Boot中利用JavaMailSender發(fā)送郵件的方法示例(附源碼)
- 深度解析Spring AI請求與響應機制的核心邏輯
- Spring AI實現(xiàn)智能聊天模型
- 深入解析Spring?AI框架如何在Java應用中實現(xiàn)智能化交互的關鍵
- Spring AI 入門學習指南
- Spring?AI?+?ollama?本地搭建聊天?AI?功能
- Spring?AI?+?混元帶你實現(xiàn)企業(yè)級穩(wěn)定可部署的AI業(yè)務智能體
- Spring AI 文檔的提取、轉換、加載功能實現(xiàn)
- 如何使用spring-ws發(fā)布webservice服務
- 使用?Spring?AI?+?Ollama?構建生成式?AI?應用的方法
- Spring AI源碼分析流式回答(最新推薦)
相關文章
java實戰(zhàn)案例之用戶注冊并發(fā)送郵件激活/發(fā)送郵件驗證碼
現(xiàn)在很多的網站都提供有用戶注冊功能,當我們注冊成功之后就會收到封注冊網站的郵件,郵件里包含了我們的注冊的用戶名和密碼及激活賬戶的超鏈接等信息,這篇文章主要給大家介紹了關于java實戰(zhàn)案例之用戶注冊并發(fā)送郵件激活/發(fā)送郵件驗證碼的相關資料,需要的朋友可以參考下2021-09-09Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重復讀取配置文
這篇文章主要介紹了Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重復讀取配置文件的方法,需要的朋友可以參考下2015-12-12Spring MVC中使用Controller如何進行重定向
這篇文章主要介紹了Spring MVC中使用Controller如何進行重定向操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09基于Spring Boot DevTools實現(xiàn)開發(fā)過程優(yōu)化
這篇文章主要介紹了基于Spring Boot DevTools實現(xiàn)開發(fā)過程優(yōu)化,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09SpringBoot2.X Kotlin系列之數(shù)據(jù)校驗和異常處理詳解
這篇文章主要介紹了SpringBoot 2.X Kotlin系列之數(shù)據(jù)校驗和異常處理詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04log4j中l(wèi)ogger標簽中additivity屬性的用法說明
這篇文章主要介紹了log4j中l(wèi)ogger標簽中additivity屬性的用法說明,基于很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12MyBatis直接執(zhí)行SQL的工具SqlMapper
今天小編就為大家分享一篇關于MyBatis直接執(zhí)行SQL的工具SqlMapper,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12