本节对应 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.pswp.cn/web/92881.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92881.shtml
英文地址,请注明出处:http://en.pswp.cn/web/92881.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

串口通信学习

不需要校验位就选8位&#xff0c;需要校验位就选9位&#xff01;USRTUSART框图STM32的外设引脚这是USART的基本结构。数据帧&#xff0c;八位是这个公式还是很重要的&#xff01;如果在编辑器里面使用printf打印汉字的话&#xff0c;会出现乱码的话&#xff0c;前提是你的编码格…

面试经典150题[001]:合并两个有序数组(LeetCode 88)

合并两个有序数组&#xff08;LeetCode 88&#xff09; https://leetcode.cn/problems/merge-sorted-array/?envTypestudy-plan-v2&envIdtop-interview-150 1. 题目背景 你有两个已经排好序的数组&#xff1a; nums1&#xff1a;前面是有效数字&#xff0c;后面是空位&…

快速安装达梦8测试库

计划&#xff1a;数据库名实例名PORT_NUMMAL_INST_DW_PORTMAL_HOSTMAL_PORTMAL_DW_PORTDMDWDBINST_1533615101192.168.207.612510135101*****[2025-08-11 15:14:34]***** Last login: Fri Jul 25 17:36:04 2025 from 192.168.88.48 [rootdm01 ~]# ip a 1: lo: <LOOPBACK,UP,…

Hive中优化问题

一、小文件合并优化Hive中的小文件分为Map端的小文件和Reduce端的小文件。(1)、Map端的小文件优化是通过CombineHiveInputFormat操作。相关的参数是&#xff1a;set hive.input.formatorg.apache.hadoop.hive.ql.io.CombineHiveInputFormat;(2)、Reduce端的小文件合并Map端的小…

tlias智能学习辅助系统--Maven高级-继承

目录 一、打包方式与应用场景 二、父子工程继承关系 1. 父工程配置 2. 子工程配置 三、自定义属性与引用属性 1. 定义属性 2. 在 dependencyManagement 中引用 3. 子工程中引用 四、dependencyManagement 与 dependencies 的区别 五、项目结构示例 六、小结 在实际开…

把 AI 押进“小黑屋”——基于 LLM 的隐私对话沙盒设计与落地

标签&#xff1a;隐私计算、可信执行环境、LLM、沙盒、内存加密、TEE、SGX、Gramine ---- 1. 背景&#xff1a;甲方爸爸一句话&#xff0c;“数据不能出机房” 我们给某三甲医院做智能问诊助手&#xff0c;模型 70 B、知识库 300 GB。 甲方只给了两条铁律&#xff1a; 1. 患者…

Java 大视界 -- Java 大数据在智能教育学习效果评估指标体系构建与精准评估中的应用(394)

Java 大视界 -- Java 大数据在智能教育学习效果评估指标体系构建与精准评估中的应用&#xff08;394&#xff09;引言&#xff1a;正文&#xff1a;一、传统学习评估的 “数字陷阱”&#xff1a;看不全、说不清、跟不上1.1 评估维度的 “单行道”1.1.1 分数掩盖的 “学习真相”…

Dubbo 3.x源码(33)—Dubbo Consumer接收服务调用响应

基于Dubbo 3.1&#xff0c;详细介绍了Dubbo Consumer接收服务调用响应 此前我们学习了Dubbo Provider处理服务调用请求的流程&#xff0c;现在我们来学习Dubbo Consumer接收服务调用响应流程。 实际上接收请求和接收响应同属于接收消息&#xff0c;它们的流程的很多步骤是一样…

栈和队列:数据结构中的基础与应用​

栈和队列&#xff1a;数据结构中的基础与应用在计算机科学的领域中&#xff0c;数据结构犹如大厦的基石&#xff0c;支撑着各类复杂软件系统的构建。而栈和队列作为两种基础且重要的数据结构&#xff0c;以其独特的特性和广泛的应用&#xff0c;在程序设计的舞台上扮演着不可或…

服务端配置 CORS解决跨域问题的原理

服务端配置 CORS&#xff08;跨域资源共享&#xff09;的原理本质是 浏览器与服务器之间的安全协商机制。其核心在于服务器通过特定的 HTTP 响应头声明允许哪些外部源&#xff08;Origin&#xff09;访问资源&#xff0c;浏览器根据这些响应头决定是否放行跨域请求。以下是详细…

Unity笔记(五)知识补充——场景切换、退出游戏、鼠标隐藏锁定、随机数、委托

写在前面&#xff1a;写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解&#xff0c;方便自己以后快速复习&#xff0c;减少遗忘。主要是C#代码部分。十七、场景切换和退出游戏1、场景切换场景切换使用方法&#xff1a; SceneManager.LoadScene()&a…

用 Spring 思维快速上手 DDD——以 Kratos 为例的分层解读

用 Spring 思维理解 DDD —— 以 Kratos 为参照 ​ 在此前的学习工作中&#xff0c;使用的开发框架一直都是 SpringBoot&#xff0c;对 MVC 架构几乎是肌肉记忆&#xff1a;Controller 接请求&#xff0c;Service 写业务逻辑&#xff0c;Mapper 操作数据库&#xff0c;这套套路…

docspace|Linux|使用docker完全离线化部署onlyoffice之docspace文档协作系统(全网首发)

一、 前言 书接上回&#xff0c;Linux|实用工具|onlyoffice workspace使用docker快速部署&#xff08;离线和定制化部署&#xff09;-CSDN博客&#xff0c;如果是小公司或者比如某个项目组内部使用&#xff0c;那么&#xff0c;使用docspace这个文档协同系统是非常合适的&…

【教程】如何高效提取胡萝卜块根形态和颜色特征?

胡萝卜是全球不可或缺的健康食材和重要的经济作物&#xff0c; 从田间到餐桌&#xff0c;从鲜食到深加工&#xff0c;胡萝卜在现代人的饮食和健康中扮演着极其重要的角色&#xff0c;通过量化块根形态和色泽均匀性&#xff0c;可实现对高产优质胡萝卜品种的快速筛选。工具/材料…

Python初学者笔记第二十四期 -- (面向对象编程)

第33节课 面向对象编程 1. 面向对象编程基础 1.1 什么是面向对象编程面向过程&#xff1a;执行者 耗时 费力 结果也不一定完美 面向对象&#xff1a;指挥者 省时 省力 结果比较完美面向对象编程(Object-Oriented Programming, OOP)是一种编程范式&#xff0c;它使用"对象&…

Go 语言 里 `var`、`make`、`new`、`:=` 的区别

把 Go 语言 里 var、make、new、: 的区别彻底梳理一下。1️⃣ var 作用&#xff1a;声明变量&#xff08;可以带初始值&#xff0c;也可以不带&#xff09;。语法&#xff1a; var a int // 声明整型变量&#xff0c;默认值为 0 var b string // 默认值 ""…

计算机网络---IP(互联网协议)

一、IP协议概述 互联网协议&#xff08;Internet Protocol&#xff0c;IP&#xff09;是TCP/IP协议族的核心成员&#xff0c;位于OSI模型的网络层&#xff08;第三层&#xff09;&#xff0c;负责将数据包从源主机传输到目标主机。它是一种无连接、不可靠的协议&#xff0c;提供…

DataFun联合开源AllData社区和开源Gravitino社区将在8月9日相聚数据治理峰会论坛

&#x1f525;&#x1f525; AllData大数据产品是可定义数据中台&#xff0c;以数据平台为底座&#xff0c;以数据中台为桥梁&#xff0c;以机器学习平台为中层框架&#xff0c;以大模型应用为上游产品&#xff0c;提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xff…

【工具】通用文档转换器 推荐 Markdown 转为 Word 或者 Pdf格式 可以批量或者通过代码调用

【工具】通用文档转换器 推荐 可以批量或者通过代码调用 通用文档转换器 https://github.com/jgm/pandoc/ Pandoc - index 下载地址 https://github.com/jgm/pandoc/releases 使用方法: 比如 Markdown 转为 Word 或者 Pdf格式 pandoc -s MANUAL.txt -o example29.docx …

【UEFI系列】Super IO

文章目录一、什么是Super IO二、Super IO的作用常见厂商三、逻辑设备控制如何访问SIO逻辑设备的配置寄存器具体配置数值四、硬件监控&#xff08;hardware monitor&#xff09;一、什么是Super IO Super Input/Output超级输入输出控制器。 通过LPC&#xff08;low pin count&a…