本節對應 Github:https://github.com/JCodeNest/JCodeNest-AI-Alibaba/tree/master/spring-ai-alibaba-helloworld
本文將以阿里巴巴的通義大模型為例,通過 Spring AI Alibaba 組件,手把手帶你完成從零到一的構建過程:首先,創建一個基礎的智能聊天機器人;然后,為其賦予核心的 “記憶” 能力,讓它能夠理解上下文,進行連貫的多輪對話。
阿里云通義大模型: 這是由阿里云推出的一系列功能強大的語言模型。通過阿里云百煉平臺,Java 仔們可以方便地獲取 API-KEY,從而在自己的應用中調用這些模型,實現文本生成、對話、嵌入等多種 AI 功能。
1. 構建聊天機器人
我們的第一步是構建一個可以進行單次問答的聊天機器人。它能接收用戶的問題,并返回通義模型的回答。
1.1 環境準備
在開始之前,請確保你的開發環境滿足以下要求:
- JDK 17 或更高版本: Spring AI 基于 Spring Boot 3.x,因此需要 Java 17+。
- Maven 或 Gradle: 用于項目構建和依賴管理。
- 阿里云 API-KEY: 訪問并登錄阿里云百煉平臺,創建并獲取一個有效的 API-KEY。
1.2 項目初始化和依賴配置
首先,我們需要在 pom.xml 中引入 spring-ai-alibaba-starter-dashscope 依賴。它會通過 Spring Boot 的自動裝配機制,為我們準備好與通義模型通信所需的核心實例,如 ChatClient。
<!-- 管理 Spring AI Alibaba 的所有依賴版本 -->
<dependencyManagement><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-bom</artifactId><version>1.0.0.2</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><!-- 核心依賴:連接通義大模型 -->
<dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency>
</dependencies>
1.3 配置 API-KEY
獲取到 API-KEY 后,最安全和推薦的方式是將其配置為環境變量。Spring AI Alibaba 會自動讀取該變量。
export AI_DASHSCOPE_API_KEY=${替換為你的有效API-KEY}
或者你可以在 application.yml 中進行如下配置:
spring:ai:dashscope:api-key: <替換為你的有效API-KEY>
1.4 編寫核心代碼
接下來,我們創建一個 Controller 來處理用戶的聊天請求。
package cn.jcodenest.ai.hello.controller;import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;/*** 用戶聊天 Controller** @author JCodeNest* @version 1.0.0* @since 2025/8/12* <p>* Copyright (c) 2025 JCodeNest-AI-Alibaba* All rights reserved.*/
@RestController
@RequestMapping("/chat")
public class ChatController {private final ChatClient dashScopeChatClient;/*** 通過構造函數注入 ChatClient.Builder*/public ChatController(ChatClient.Builder chatClientBuilder) {this.dashScopeChatClient = chatClientBuilder// 設置默認的系統級提示詞(System Prompt),為 AI 設定角色和行為準則.defaultSystem("你是一個博學的智能聊天助手,請根據用戶提問,結合上下文進行友好、專業地回答!")// 設置默認的模型參數,如 topP、溫度等.defaultOptions(DashScopeChatOptions.builder()// topP 參數,控制生成文本的多樣性.withTopP(0.8).build()).build();}/*** 簡單問答接口** @param query 用戶問題* @return 模型回答*/@GetMapping("/simple")public String simpleChat(@RequestParam(value = "query", defaultValue = "你好,請介紹一下你自己。") String query) {// 使用 prompt() 方法包裝用戶問題,調用 call().content() 獲取模型回答return dashScopeChatClient.prompt(query).call().content();}/*** 流式響應接口,實現打字機效果** @param query 用戶問題* @return 模型回答流*/@GetMapping("/stream")public Flux<String> streamChat(@RequestParam(value = "query", defaultValue = "請給我講一個關于程序員的笑話") String query) {// 調用 stream().content() 返回一個 Flux<String> 對象return dashScopeChatClient.prompt(query).stream().content();}
}
代碼剖析:
- 我們通過構造函數注入了
ChatClient.Builder
,這是一個工廠類,用于以鏈式調用的方式構建和配置ChatClient
實例。 defaultSystem()
: 設置一個系統級的提示詞,這對于定義 AI 的角色和行為至關重要。defaultOptions()
: 配置與模型交互時的默認參數。DashScopeChatOptions
提供了豐富的配置項。這些參數也可以在每次調用時動態指定,靈活性非常高。simpleChat()
: 這是最基礎的調用方式,一次性返回完整的模型響應。streamChat()
: 通過返回Flux<String>
,實現了流式響應。這在前端可以輕松實現 “打字機” 的實時顯示效果,極大地提升了用戶體驗。
上述簡單聊天的完整流程:
基礎調用測試結果如下:
流式調用測試結果如下:
2. 為你的機器人賦予記憶
上面的機器人雖然能回答問題,但它是 “健忘” 的。你問它第二個問題時,它完全不記得第一個問題是什么。為了實現真正的對話,我們必須為它增加記憶能力。
例如,當你再問他前面的信息時,他就忘記了:
2.1 為什么需要記憶?
HTTP 協議本身是無狀態的,LLM 的 API 調用在默認情況下也是如此。每一次請求都是獨立的,模型不會保留之前的對話信息。要讓對話持續下去,我們必須在每次請求時,將之前的聊天記錄一并發送給模型。
雖然可以手動在代碼中維護一個對話歷史列表,但這會迅速增加代碼的復雜性和維護成本。幸運的是,Spring AI 提供了優雅的解決方案——Chat Memory。
2.2 Spring AI 的記憶解決方案
Spring AI 通過 ChatMemory
接口和 Advisor
(AOP 中的 “通知”)設計模式來解決記憶問題。Advisor
可以在 ChatClient
調用前后執行額外的邏輯,例如:
- 調用前: 從存儲中加載歷史對話記錄,并將其添加到當前的請求中。
- 調用后: 將本次新的問答對(用戶問題和模型回答)保存到存儲中。
Spring AI Alibaba 提供了多種開箱即用的記憶存儲方案,如 jdbc, redis, elasticsearch。下面我們以最通用的 JDBC (使用 MySQL) 為例進行演示。
2.3 使用 JDBC 持久化記憶
在 pom.xml 中追加 jdbc-memory 和 mysql 驅動的依賴。
<dependencies><!-- Spring AI JDBC 記憶組件 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-memory-jdbc</artifactId></dependency><!-- MySQL 數據庫驅動 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency>
</dependencies>
在 application.yaml 文件中配置數據庫連接信息。
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8username: your_usernamepassword: your_password# 建議開啟,讓 Hibernate 自動創建或更新表結構jpa:hibernate:ddl-auto: update
注意:
JdbcChatMemoryRepository
在應用啟動時會自動檢測并創建名為ai_chat_memory
的數據表,用于存儲對話記錄。確保你的數據庫用戶有 DDL 權限,或提前手動建表。create table ai_chat_memory (id bigint auto_increment primary key,conversation_id varchar(256) not null,content longtext not null,type varchar(100) not null,timestamp timestamp not null,constraint chk_message_type check (`type` in ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL')) );
現在,我們來改造 ChatController,為其注入記憶能力。
@RestController
@RequestMapping("/chat")
public class ChatController {private final ChatClient dashScopeChatClient;// 注入 JdbcTemplate 用于數據庫操作public ChatController(JdbcTemplate jdbcTemplate, ChatClient.Builder chatClientBuilder) {// 1. 構造基于 JDBC 的 ChatMemoryRepositoryChatMemoryRepository chatMemoryRepository = MysqlChatMemoryRepository.mysqlBuilder().jdbcTemplate(jdbcTemplate).build();// 2. 構造一個窗口化的 ChatMemory,它使用上面的 RepositoryChatMemory chatMemory = MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();// 3. 將 ChatMemory 包裝成一個 Advisor,并注冊到 ChatClientthis.dashScopeChatClient = chatClientBuilder.defaultSystem("你是一個博學的智能聊天助手,請根據用戶提問,結合上下文進行友好、專業地回答!")// 關鍵:注冊 MessageChatMemoryAdvisor.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).defaultOptions(DashScopeChatOptions.builder().withTopP(0.8).build()).build();}/*** 帶有記憶的聊天接口* @param chatId 用于區分不同對話的會話 ID*/@GetMapping("/memory")public String memoryChat(@RequestParam String query,@RequestParam(defaultValue = "default-chat-001") String chatId) {return dashScopeChatClient.prompt(query)// 關鍵:在每次調用時,通過 Advisor 參數傳遞當前的會話 ID.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId)).call().content();}
}
代碼剖析:
- 我們首先構造了一個
MysqlChatMemoryRepository
,它是ChatMemoryRepository
針對 MySQL 的具體實現。 - 然后,我們創建了一個
MessageWindowChatMemory
實例,它是一種常見的對話記憶策略(例如,只保留最近 N 輪對話)。 - 最核心的一步,是將
chatMemory
包裝進MessageChatMemoryAdvisor
,并通過.defaultAdvisors()
方法將其注冊到ChatClient
中。從此,這個ChatClient
的所有調用都會經過記憶處理。 - 在
memoryChat
方法中,我們增加了一個chatId
參數。這個 ID 是區分不同用戶或不同對話的關鍵。我們通過.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
將其傳遞給記憶顧問,以便它能為正確的會話加載和保存歷史記錄。
增加記憶功能后,系統的內部工作流程如下:
現在,你可以連續調用 /chat/memory
接口,使用相同的 chatId
,機器人將能夠記住你們之前的對話內容,實現連貫的交流。
第一個問題:請記住,當我問你 “我是誰” 的時候,你只需要答復我,你是 JCode。
此時,可以觀察到我們的對話對信息(USER + ASSISTANT)已經持久化到數據庫了:
第二個問題:我是誰?
可見,LLM 確實實現了 “記住” 的效果,再觀察 ai_chat_memory,新的對話對同樣被添加進來了:
3. 總結
可以看到,我們使用 Spring AI Alibaba 構建一個簡單的智能聊天機器人就是這么簡單。我們從一個簡單的問答服務開始,然后通過 Spring AI 強大且易于擴展的 Advisor
和 ChatMemory
機制,為其無縫集成了持久化的對話記憶能力。
這僅僅是 Spring AI 世界的冰山一角。基于這套框架,你還可以進一步探索更高級的功能,例如:
- RAG (Retrieval-Augmented Generation): 結合向量數據庫,讓機器人能根據你自己的私有知識庫回答問題。
- Function Calling: 允許 AI 模型調用你定義的 Java 方法,實現與外部工具和服務的交互。
- 多模態能力: 處理和生成圖像等非文本內容。
通過 Spring AI 的抽象設計理念,Java 仔們可以聚焦于業務邏輯創新,而不必深陷于與不同 AI 模型底層 API 對接的泥潭。