当前位置: 首页 > java >正文

Spring AI Alibaba - 聊天机器人快速上手

本节对应 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。

image-20250812215118980

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();}
}

代码剖析

  1. 我们通过构造函数注入了 ChatClient.Builder,这是一个工厂类,用于以链式调用的方式构建和配置 ChatClient 实例。
  2. defaultSystem(): 设置一个系统级的提示词,这对于定义 AI 的角色和行为至关重要。
  3. defaultOptions(): 配置与模型交互时的默认参数。DashScopeChatOptions 提供了丰富的配置项。这些参数也可以在每次调用时动态指定,灵活性非常高。
  4. simpleChat(): 这是最基础的调用方式,一次性返回完整的模型响应。
  5. streamChat(): 通过返回 Flux<String>,实现了流式响应。这在前端可以轻松实现 “打字机” 的实时显示效果,极大地提升了用户体验。

上述简单聊天的完整流程:

用户Spring应用 (Controller)Spring AI ChatClient阿里云通义大模型GET /chat/simple?query=....prompt(query).call()构造并发送 API 请求返回模型生成的完整回答返回内容字符串HTTP 200 OK (响应体为回答)用户Spring应用 (Controller)Spring AI ChatClient阿里云通义大模型

基础调用测试结果如下:

image-20250812211602488

流式调用测试结果如下:

image-20250812211544572

2. 为你的机器人赋予记忆

上面的机器人虽然能回答问题,但它是 “健忘” 的。你问它第二个问题时,它完全不记得第一个问题是什么。为了实现真正的对话,我们必须为它增加记忆能力。

例如,当你再问他前面的信息时,他就忘记了:

image-20250812211726599

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();}
}

代码剖析

  1. 我们首先构造了一个 MysqlChatMemoryRepository,它是 ChatMemoryRepository 针对 MySQL 的具体实现。
  2. 然后,我们创建了一个 MessageWindowChatMemory 实例,它是一种常见的对话记忆策略(例如,只保留最近 N 轮对话)。
  3. 最核心的一步,是将 chatMemory 包装进 MessageChatMemoryAdvisor,并通过 .defaultAdvisors() 方法将其注册到 ChatClient 中。从此,这个 ChatClient 的所有调用都会经过记忆处理。
  4. memoryChat 方法中,我们增加了一个 chatId 参数。这个 ID 是区分不同用户或不同对话的关键。我们通过 .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId)) 将其传递给记忆顾问,以便它能为正确的会话加载和保存历史记录。

增加记忆功能后,系统的内部工作流程如下:

用户Spring应用 (Controller)Spring AI ChatClientMessageChatMemoryAdvisorJDBC RepositoryMySQL数据库阿里云通义大模型GET /chat/memory?query=...&chatId=123.prompt(query).advisors(chatId).call()调用前,触发 Advisor执行 Before-call 逻辑加载 chatId='1234' 的历史记录SELECT * FROM ai_chat_memory WHERE ...返回历史消息获得历史记录将历史记录预置到 Prompt 中发送包含完整上下文的 API 请求返回基于上下文的回答调用后,再次触发 Advisor执行 After-call 逻辑保存本次新的问答对 (for chatId='1234')INSERT INTO chat_memory ...返回最终内容HTTP 200 OK (响应体为回答)用户Spring应用 (Controller)Spring AI ChatClientMessageChatMemoryAdvisorJDBC RepositoryMySQL数据库阿里云通义大模型

现在,你可以连续调用 /chat/memory 接口,使用相同的 chatId,机器人将能够记住你们之前的对话内容,实现连贯的交流。

第一个问题:请记住,当我问你 “我是谁” 的时候,你只需要答复我,你是 JCode。

image-20250812214044636

此时,可以观察到我们的对话对信息(USER + ASSISTANT)已经持久化到数据库了:

image-20250812214122960

第二个问题:我是谁?

image-20250812214223768

可见,LLM 确实实现了 “记住” 的效果,再观察 ai_chat_memory,新的对话对同样被添加进来了:

image-20250812214316061

3. 总结

可以看到,我们使用 Spring AI Alibaba 构建一个简单的智能聊天机器人就是这么简单。我们从一个简单的问答服务开始,然后通过 Spring AI 强大且易于扩展的 AdvisorChatMemory 机制,为其无缝集成了持久化的对话记忆能力。

这仅仅是 Spring AI 世界的冰山一角。基于这套框架,你还可以进一步探索更高级的功能,例如:

  • RAG (Retrieval-Augmented Generation): 结合向量数据库,让机器人能根据你自己的私有知识库回答问题。
  • Function Calling: 允许 AI 模型调用你定义的 Java 方法,实现与外部工具和服务的交互。
  • 多模态能力: 处理和生成图像等非文本内容。

通过 Spring AI 的抽象设计理念,Java 仔们可以聚焦于业务逻辑创新,而不必深陷于与不同 AI 模型底层 API 对接的泥潭。

http://www.xdnf.cn/news/17737.html

相关文章:

  • 机器学习——DBSCAN
  • 读《精益数据分析》:UGC平台的数据指标梳理
  • Go面试题及详细答案120题(0-20)
  • 【工具】通用文档转换器 推荐 Markdown 转为 Word 或者 Pdf格式 可以批量或者通过代码调用
  • 【前端:Html】--3.进阶:图形
  • c#联合Halcon进行OCR字符识别(含halcon-25.05 百度网盘)
  • 解决H616用网络的IP地址连不上
  • 考研复习-计算机组成原理-第五章-CPU
  • MySQL User表入门教程
  • 计算机视觉(7)-纯视觉方案实现端到端轨迹规划(思路梳理)
  • 从爬虫新手到DrissionPage实践者的技术旅程
  • MCU中的液晶显示屏LCD(Liquid Crystal Display)控制器
  • Unity UnityWebRequest常用操作
  • 使用pyqt5实现可勾选的测试用例界面
  • 99、【OS】【Nuttx】【构建】cmake 配置实操:问题解决
  • 【模型剪枝2】不同剪枝方法实现对 yolov5n 剪枝测试及对比
  • Linux,docker知识补充
  • 自建知识库,向量数据库 体系建设(二)之BERT 与.NET 8
  • C++少儿编程(二十二)—条件结构
  • 通过限制对象的内存分配位置来实现特定的设计目标
  • powerbi本地报表发布到web,以得到分享链接
  • Day13 Vue工程化
  • SQL 语言分类
  • 人大BABEC地平线高效率具身导航!Aux-Think:探索视觉语言导航中数据高效的推理策略
  • @RequestMapping接收文件格式的形参(方法参数)
  • idea git commit特别慢,cpu100%
  • 13.深度学习——Minst手写数字识别
  • 嵌入式第二十六天(文件IO相关操作)
  • 基于PROFINET的西门子PLC通讯:S7-200与S7-1200在自动化仓储中的协同应用
  • NetworkManager配置热点