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。

1.2 项目初始化和依赖配置

首先,我们需要在 pom.xml 中引入 spring-ai-alibaba-starter-dashscope 依赖。它会通过 Spring Boot 的自动装配机制,为我们准备好与通义模型通信所需的核心实例,如 ChatClient。

xml 复制代码
<!-- 管理 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 会自动读取该变量。

bash 复制代码
export AI_DASHSCOPE_API_KEY=${替换为你的有效API-KEY}

或者你可以在 application.yml 中进行如下配置:

yaml 复制代码
spring:
  ai:
    dashscope:
      api-key: <替换为你的有效API-KEY>

1.4 编写核心代码

接下来,我们创建一个 Controller 来处理用户的聊天请求。

java 复制代码
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 阿里云通义大模型

基础调用测试结果如下:

流式调用测试结果如下:

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 驱动的依赖。

xml 复制代码
<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 文件中配置数据库连接信息。

yaml 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8
    username: your_username
    password: your_password
  # 建议开启,让 Hibernate 自动创建或更新表结构
  jpa:
    hibernate:
      ddl-auto: update

注意 : JdbcChatMemoryRepository 在应用启动时会自动检测并创建名为 ai_chat_memory 的数据表,用于存储对话记录。确保你的数据库用户有 DDL 权限,或提前手动建表。

sql 复制代码
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,为其注入记忆能力。

java 复制代码
@RestController
@RequestMapping("/chat")
public class ChatController {

    private final ChatClient dashScopeChatClient;

    // 注入 JdbcTemplate 用于数据库操作
    public ChatController(JdbcTemplate jdbcTemplate, ChatClient.Builder chatClientBuilder) {
        // 1. 构造基于 JDBC 的 ChatMemoryRepository
        ChatMemoryRepository chatMemoryRepository = MysqlChatMemoryRepository.mysqlBuilder()
            .jdbcTemplate(jdbcTemplate)
            .build();

        // 2. 构造一个窗口化的 ChatMemory,它使用上面的 Repository
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
            .chatMemoryRepository(chatMemoryRepository)
            .build();

        // 3. 将 ChatMemory 包装成一个 Advisor,并注册到 ChatClient
        this.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 ChatClient MessageChatMemoryAdvisor JDBC Repository MySQL数据库 阿里云通义大模型 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 ChatClient MessageChatMemoryAdvisor JDBC Repository MySQL数据库 阿里云通义大模型

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

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

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

第二个问题:我是谁?

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

3. 总结

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

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

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

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

相关推荐
意法半导体STM3219 分钟前
STM32N6引入NPU,为边缘AI插上“隐形的翅膀”
单片机·ai·npu·st·stm32n6·边缘人工智能
沫儿笙37 分钟前
焊接机器人保护气体效率优化
人工智能·机器人
青岛前景互联信息技术有限公司1 小时前
应急救援智能接处警系统——科技赋能应急,筑牢安全防线
人工智能·物联网·智慧城市
楚韵天工1 小时前
基于多分类的工业异常声检测及应用
人工智能·深度学习·神经网络·目标检测·机器学习·分类·数据挖掘
爱分享的飘哥1 小时前
第六十五章:AI的“精良食材”:图像标注、视频帧抽帧与字幕提取技巧
人工智能·语音识别·ai训练·视频处理·数据预处理·图像标注·字幕提取
技术老金1 小时前
给你的AI应用“降本增效”:吃透模型级联、智能缓存等三大成本优化策略
人工智能·架构
self_examinat1 小时前
基于多模型的零售销售预测实战指南
人工智能·零售
居然JuRan1 小时前
每天拆解一个AI知识点:Scaling Law
人工智能
设备管理系统-YDYD2 小时前
设备 AI 知识库,管理效率新飞跃
人工智能·设备管理·设备管理系统
黎燃2 小时前
数字孪生技术如何优化工厂生产流程:从概念到代码落地
人工智能