SpingAiAlibaba

Sping Ai Aibaba介绍

Spring AI Alibaba 是基于 Spring AI 构建的框架,专注于与阿里云生态的深度集成。适合国内开发者,尤其是需要快速接入阿里云 AI 能力的场景。

官方地址:https://java2ai.com/

云端大模型-阿里百炼平台

官方地址:https://bailian.console.aliyun.com/

注意:建议往账户中充值5元,以便后续调用收费模型。

使用前准备

  • API Key
  • 模型名称
  • 调用地址

API Key的生成

  1. 从主页进入API Key页面
  1. 创建API Key
  1. 创建成功

选用模型

  1. 这里直接选择的是**Qwen3.6-Max-Preview**,纯文本模型。
  1. 确定模型名称
  1. 确定调用地址

项目集成大模型

创建Maven项目

这里因为要学习并测试多种大模型的使用,所以打算以微服务的架构方式来创建项目,不同的大模型的使用不同的微服务项目。

导入项目依赖

  1. Spring AI Alibaba 与 Spring AI、Spring Boot 的版本依赖关系,参照:《怎么确定 Spring AI Alibaba 与 Spring AI、Spring Boot 版本的兼容关系》
Spring AI Alibaba Spring AI Spring Boot
1.0.0.2 1.0.0 3.4.5
1.0.0-M6.1 1.0.0-M6 3.4.2
  1. 构建项目基础pom依赖
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目基础信息 -->
    <groupId>cn.mawenda</groupId>
    <artifactId>SpringAIAlibabaDemo</artifactId>
    <version>1.0.1</version>
    <packaging>pom</packaging>

    <!-- 子模块列表 -->
    <modules>
        <module>SpringAiAlibabaChatModel</module>
    </modules>

    <!-- 依赖版本统一管理 -->
    <properties>
        <!-- Java编译版本设置 -->
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <!-- 项目构建编码设置为UTF-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- Spring AI 框架版本 -->
        <spring-ai.version>1.0.0</spring-ai.version>
        <!-- Spring AI Alibaba 阿里云AI集成版本 -->
        <spring-ai-alibaba.version>1.0.0.2</spring-ai-alibaba.version>
        <!-- Spring Boot 框架版本 -->
        <spring-boot.version>3.4.5</spring-boot.version>
    </properties>

    <!-- dependencyManagement 依赖统一管控,子模块继承时不需要指定版本号 -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring AI Alibaba BOM: 阿里云AI组件依赖管理,包含通义千问等模型支持 -->
            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Spring Boot Dependencies BOM: Spring Boot核心依赖管理,确保各组件版本兼容 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Spring AI BOM: Spring AI框架依赖管理,提供统一的AI接口抽象 -->
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 构建插件配置 -->
    <build>
        <plugins>
            <!-- Spring Boot Maven插件: 用于打包可执行JAR文件、运行应用等 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
            </plugin>
        </plugins>
    </build>

</project>

ChatModel(入门尝试)

使用ChatModel来调用大模型

微服务构建SpringAIAlibabaChatModel
项目结构
yaml 复制代码
SpringAIAlibabaDemo/                              # 项目根目录(父工程)
├── SpringAiAlibabaChatModel/                     # 子模块:聊天模型演示
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/cn/mawenda/chatmodel/
│   │   │   │   ├── SpringAiAlibabaChatModelApplication.java    # 启动类
│   │   │   │   └── controller/
│   │   │   │       └── DemoController.java                      # 演示控制器
│   │   │   └── resources/
│   │   │       └── application.yaml                             # 应用配置文件
│   └── pom.xml                                                  # 子模块 Maven 配置
└── pom.xml                                                      # 父工程 Maven 配置
pom.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.mawenda</groupId>
        <artifactId>SpringAIAlibabaDemo</artifactId>
        <version>1.0.1</version>
    </parent>

    <artifactId>SpringAiAlibabaChatModel</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring Boot Web Starter: 提供Web开发基础功能,包括REST API支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring AI Alibaba DashScope Starter: 阿里云通义千问大模型集成依赖,提供ChatModel等AI能力 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
    </dependencies>
    
</project>
服务配置文件-application.yaml
yaml 复制代码
server:
  port: 8080  # 指定当前服务的端口
  servlet:
    encoding:
      enabled: true # 大模型对话中文乱码处理
      force: true
      charset: utf-8

spring:
  application:
    name: SpringAiAlibabaChatModel # 微服务名称
  #  Spring AI Alibaba 框架支持自动配置,引入对应依赖后,会将相关配置信息自动注入DashScopeChatModel等核心Bean
  ai:
    dashscope:
      # 密钥, 在云平台中申请的API Key
      api-key: sk-08ad3bf73bf645a9a0c0cc5ac68775a3
      # 模型请求地址,框架内针对不同模型已配置好默认地址,此处可不进行配置也可以实现同样效果
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          # 指定使用的模型版本
          model: qwen3.6-max-preview
服务启动类-SpringAiAlibabaChatModelApplication.java
java 复制代码
package cn.mawenda.chatmodel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAiAlibabaChatModelApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAiAlibabaChatModelApplication.class, args);
    }
}
服务控制层-DemoController.Java
java 复制代码
package cn.mawenda.chatmodel.controller;

import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * AI对话演示控制器
 * 提供与通义千问大模型交互的REST API接口
 */
@RestController
public class DemoController {

    /**
     * Spring AI ChatModel实例,用于调用大模型进行对话
     * 由Spring容器自动注入DashScope实现
     */
    @Autowired
    private ChatModel chatModel;

    /**
     * 调用大模型进行对话
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本
     */
    @GetMapping("/call")
    public String call(@RequestParam(name = "message", required = false, defaultValue = "你是谁?") String message){
        return chatModel.call(message);
    }
}
集成测试
  1. 启动服务,并访问服务API地址:http://localhost:8080/call
  1. 问题:当前是等模型将提问结果完全返回后再响应回页面,等待时间过长,用户体验差;针对该问题,大模型是支持流式输出的,那么什么是流式输出
实现流式输出
java 复制代码
package cn.mawenda.chatmodel.controller;

import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

/**
 * AI对话演示控制器
 * 提供与通义千问大模型交互的REST API接口
 */
@RestController
public class DemoController {

    /**
     * Spring AI ChatModel实例,用于调用大模型进行对话
     * 由Spring容器自动注入DashScope实现
     */
    @Autowired
    private ChatModel chatModel;

    /**
     * 调用大模型进行对话
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本
     */
    @GetMapping("/call")
    public String call(@RequestParam(name = "message", required = false, defaultValue = "你是谁?") String message){
        return chatModel.call(message);
    }

    /**
     * 调用大模型进行对话,并返回一个流式响应
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本流
     */
    @GetMapping("/streamCall")
    public Flux<String> streamCall(@RequestParam(name = "message", required = false, defaultValue = "你是谁?") String message){
        return chatModel.stream(message);
    }
}
  • 测试
  • 通过chatModel.stream(message); 会返回一个Flux,Flux 是 Project Reactor 中的响应式编程类型

代表一个异步数据流,可以发射 0 到 N 个元素,这里表示会持续不断地返回字符串片段;

多模型共存

除qwen3.6-max-preview外,在项目中在集成一个其他大模型,比如deepseek,进行如下改造。

选择模型版本

此处可以按照此方式多选择几个文本型的模型。

项目兼容改造
涉及到改造的文件目录
yaml 复制代码
SpringAIAlibabaDemo/                              # 项目根目录(父工程)
├── SpringAiAlibabaChatModel/                     # 子模块:聊天模型演示
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/cn/mawenda/chatmodel/
│   │   │   │   └── config/
│   │   │   │       └── LlmProperties.java											 # 模型配置属性
│   │   │   │       └── LLmConfig.java													 # 大模型配置类
│   │   │   └── resources/
│   │   │       └── application.yaml                             # 应用配置文件
服务配置文件-application.yaml
yaml 复制代码
server:
  port: 8080  # 指定当前服务的端口
  servlet:
    encoding:
      enabled: true # 大模型对话中文乱码处理
      force: true
      charset: utf-8

spring:
  application:
    name: SpringAiAlibabaChatModel # 微服务名称

  ai:
    dashscope:
      # 密钥, 在云平台中申请的API Key
      api-key: sk-08ad3bf73bf645a9a0c0cc5ac68775a3
      # 模型请求地址
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          # 指定使用的模型版本
          model: qwen3.6-max-preview

# 在此处增加多模型的名称,后续按需可以拓展单独的APIKey以及请求地址,目前使用的都是阿里百炼平台,APIKey与请求地址使用同样的即可。
llm:
  # 为了方便测试,除了默认的qwen3.6-max-preview模型,还集成了以下两种模型
  models:
    deepseek-v4-pro: deepseek-v4-pro
    qwen3-max: qwen3-max

增加llm相关配置。

增加读取配置类-LlmProperties.java
java 复制代码
package cn.mawenda.chatmodel.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * 大模型配置属性
 * 从application.yaml中读取llm.models配置
 */
@Component
@ConfigurationProperties(prefix = "llm")
public class LlmProperties {

    /**
     * 模型映射
     * key: 模型标识(如 qwen, deepseek)
     * value: DashScope 模型名称
     */
    private Map<String, String> models;

    public Map<String, String> getModels() {
        return models;
    }

    public void setModels(Map<String, String> models) {
        this.models = models;
    }
}
增加大模型配置类-LLmConfig.java
java 复制代码
package cn.mawenda.chatmodel.config;

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.HashMap;
import java.util.Map;

/**
 * 大模型配置类
 * <p>
 * 负责管理和初始化多个 DashScope ChatModel 实例,支持:
 * 1. 默认模型的自动加载
 * 2. 多模型共存和动态切换
 * 3. 通过 YAML 配置灵活管理模型
 * </p>
 */
@Configuration
public class LLmConfig {

    @Value("${spring.ai.dashscope.api-key}")
    private String apiKey;

    @Value("${spring.ai.dashscope.chat.options.model}")
    private String defaultModel;

    private final LlmProperties llmProperties;

    public LLmConfig(LlmProperties llmProperties) {
        this.llmProperties = llmProperties;
    }

    /**
     * 默认 ChatModel
     */
    @Bean
    @Primary
    public ChatModel chatModel() {
        // 使用配置文件中的默认模型
        System.out.println("加载默认模型: " + defaultModel);
        return createChatModel(defaultModel);
    }

    /**
     * 所有模型的 Map
     * 可以通过 @Autowired Map<String, ChatModel> 注入使用
     */
    @Bean
    public Map<String, ChatModel> chatModelMap() {
        Map<String, ChatModel> modelMap = new HashMap<>();

        if (llmProperties.getModels() != null) {
            llmProperties.getModels().forEach((key, modelName) -> {
                modelMap.put(key, createChatModel(modelName));
            });
        }
        System.out.println("共注册 {" +modelMap.size() + "} 个模型");
        return modelMap;
    }

    /**
     * 创建 ChatModel 实例
     */
    private ChatModel createChatModel(String modelName) {
        return DashScopeChatModel.builder()
                .dashScopeApi(
                        DashScopeApi.builder()
                                .apiKey(apiKey)
                                .build()
                )
                .defaultOptions(
                        DashScopeChatOptions.builder()
                                .withModel(modelName)
                                .build()
                )
                .build();
    }

}
修改服务控制层-DemoController.java
java 复制代码
package cn.mawenda.chatmodel.controller;

import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.Map;

/**
 * AI对话演示控制器
 * 提供与通义千问大模型交互的REST API接口
 */
@RestController
public class DemoController {

    /* 此处省略之前代码 */

    @Autowired
    private Map<String, ChatModel> chatModelMap;
    
    /**
     * 调用指定的模型进行对话,并返回一个流式响应
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @param modelName 模型名称
     * @return 大模型返回的响应文本流
     */
    @GetMapping("/streamByModel")
    public Flux<String> streamCallByModelName(
            @RequestParam(name = "message", required = false, defaultValue = "你是谁?") String message,
            @RequestParam(name = "modelName", required = false) String modelName) {

        // 未指定模型,使用默认模型
        if (!StringUtils.hasLength(modelName)) {
            return chatModel.stream(message);
        }

        // 指定了模型,检查是否存在
        ChatModel selectedModel = chatModelMap.get(modelName);
        if (selectedModel == null) {
            return Flux.just("错误:不支持的模型 '" + modelName + "'。可用模型:" + chatModelMap.keySet());
        }

        // 获取到模型实例,并发起请求
        return selectedModel.stream(message);
    }

}
集成测试
  1. 重新启动服务,查看日志以展示摸摸人模型与加载的模型数量
  1. 访问 http://localhost:8080/streamByModel
  • 没有传入任何参数,message参数为默认的你是谁?modelName参数为空,执行chatModel.stream(message)方法。
  1. 访问 http://localhost:8080/streamByModel?modelName=deepseek-v4-pro
  • message参数为默认的你是谁?modelName参数为deepseek-v4-pro,执行chatModelMap.get(modelName)获取到deepseek-v4-pro大模型实例,并请求了selectedModel.stream(message)方法。
  1. 访问 http://localhost:8080/streamByModel?modelName=qwen3-max
  • message参数为默认的你是谁?modelName参数为deepseek-v4-pro,执行chatModelMap.get(modelName)获取到qwen3-max大模型实例,并请求了selectedModel.stream(message)方法。
  1. 访问 http://localhost:8080/streamByModel?modelName=qwen3-max123
  • message参数为默认的你是谁?modelName参数为qwen3-max123,执行chatModelMap.get(modelName),没有获取到该模型,直接响应回错误信息。

ChatClient(进阶)

使用ChatClient调用,玩法更多,适合复杂AI服务。

微服务构建-SpringAIAlibabaChatClient
项目结构
java 复制代码
SpringAIAlibabaDemo/                              # 项目根目录(父工程)
├── SpringAIAlibabaChatClient/                    # 子模块:聊天客户端演示
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/cn/mawenda/chatclient/
│   │   │   │   ├── SpringAiAlibabaChatClientApplication.java    # 启动类
│   │   │   │   ├── config/
│   │   │   │   │   └── LLmConfig.java                            # LLM 配置类
│   │   │   │   └── controller/
│   │   │   │       └── DemoController.java                       # 演示控制器
│   │   │   └── resources/
│   │   │       └── application.yaml                              # 应用配置文件
│   │   └── test/java/                          # 测试代码目录
│   ├── target/                                 # Maven 构建输出目录
│   └── pom.xml                                 # 子模块 Maven 配置
└── pom.xml                                   # 父工程 Maven 配置
pom.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.mawenda</groupId>
        <artifactId>SpringAIAlibabaDemo</artifactId>
        <version>1.0.1</version>
    </parent>

    <artifactId>SpringAIAlibabaChatClient</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring Boot Web Starter: 提供Web开发基础功能,包括REST API支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring AI Alibaba DashScope Starter: 阿里云通义千问大模型集成依赖,提供ChatModel等AI能力 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
    </dependencies>
</project>
服务配置文件-application.yaml
yaml 复制代码
server:
  port: 8081  # 指定当前服务的端口
  servlet:
    encoding:
      enabled: true # 大模型对话中文乱码处理
      force: true
      charset: utf-8

spring:
  application:
    name: SpringAIAlibabaChatClient # 微服务名称

  ai:
    dashscope:
      # 密钥, 在云平台中申请的API Key
      api-key: sk-08ad3bf73bf645a9a0c0cc5ac68775a3
      # 模型请求地址
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          # 指定使用的模型版本
          model: qwen3.6-max-preview
llm:
  models:
    deepseek-v4-pro: deepseek-v4-pro
    qwen3-max: qwen3-max
服务启动类-SpringAiAlibabaChatClientApplication.java
java 复制代码
package cn.mawenda.chatclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAiAlibabaChatClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAiAlibabaChatClientApplication.class, args);
    }
}
增加大模型配置类-LLmConfig.Java
java 复制代码
package cn.mawenda.chatclient.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 大模型配置类
 */
@Configuration
public class LLmConfig {

    /**
     * 创建 ChatClient 实例
     */
    @Bean
    public ChatClient chatClient(ChatModel dashscopeChatModel){
        return ChatClient.builder(dashscopeChatModel).build();
    }
}
服务控制层-DemoController.Java
java 复制代码
package cn.mawenda.chatclient.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * AI对话演示控制器
 * 提供与通义千问大模型交互的REST API接口
 */
@RestController
public class DemoController {

    /**
     * Spring AI ChatModel实例,用于调用大模型进行对话
     * 由Spring容器自动注入DashScope实现
     */
    @Autowired
    private ChatClient chatClient;

    /**
     * 调用大模型进行对话
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本
     */
    @GetMapping("/call")
    public String call(@RequestParam(name = "message", required = false, defaultValue = "你是谁?") String message){
        return chatClient.prompt().user(message).call().content();
    }
}

chatClient构建解析

  1. prompt()
    • 创建一个新的对话提示(Prompt)构建器
    • 开始构建一次对话请求
  2. .user()
    • 设置用户输入的消息内容,也是用户想AI问的问题
  3. .call()
    • 执行同步调用,向大模型发送请求并等待响应,这是一个阻塞操作,会等待 AI 返回结果
  4. .content()
    • 从响应对象中提取纯文本内容,返回字符串类型的 AI 回复
集成测试
  1. 启动服务,并访问服务API地址:http://localhost:8081/call
提示词(Prompt)基础概念
什么是 Prompt?

Prompt(提示词) 是用户发送给大语言模型的输入文本,用于引导模型生成期望的输出。可以理解为"向 AI 提问或下达指令的方式"。

阿里百炼平台:Prompt指南

DeepSeekApi文档:提示库样例

主要的作用
  • 引导大模型生成期望的输出,也可以理解为用户对AI提问或下达指令,如下简单的提问(任何一个模型都可以,此处我直接在爱李云百炼平台模型广场中选择的立即体验,跳转地址
    • 你是谁?(根据这个提示词,AI可以将当前模型的一些基础信息响应给用户)
  • 设定角色,用户可以通过Prompt可以要求AI扮演特定角色
    • 你现在扮演 Java 后端资深开发,熟悉SpringAIAlibaba框架,帮我介绍下这个框架以及企业级的组件封装方案。
  • 优化结果质量,通过提供示例、约束条件或背景信息,提升内容的相关性与准确性
    • 请你以 Java 后端开发视角,结合 Spring Boot 项目背景,遵循代码简洁、注释完整、兼容 JDK8 的约束条件,参考常规工具类写法示例,帮我写一个字符串判空通用工具类,要求逻辑严谨、可直接项目复用。
提示词的角色

查看SpringAi源码

ChatModel -> UserMessage -> AbstractMessage -> MessageType

java 复制代码
/*
 * Copyright 2023-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.ai.chat.messages;

/**
 * Enumeration representing types of {@link Message Messages} in a chat application. It
 * can be one of the following: USER, ASSISTANT, SYSTEM, FUNCTION.
 */
public enum MessageType {

	/**
	 * A {@link Message} of type {@literal user}, having the user role and originating
	 * from an end-user or developer.
	 * @see UserMessage
	 */
	USER("user"),

	/**
	 * A {@link Message} of type {@literal assistant} passed in subsequent input
	 * {@link Message Messages} as the {@link Message} generated in response to the user.
	 * @see AssistantMessage
	 */
	ASSISTANT("assistant"),

	/**
	 * A {@link Message} of type {@literal system} passed as input {@link Message
	 * Messages} containing high-level instructions for the conversation, such as behave
	 * like a certain character or provide answers in a specific format.
	 * @see SystemMessage
	 */
	SYSTEM("system"),

	/**
	 * A {@link Message} of type {@literal function} passed as input {@link Message
	 * Messages} with function content in a chat application.
	 * @see ToolResponseMessage
	 */
	TOOL("tool");

	private final String value;

	MessageType(String value) {
		this.value = value;
	}

	public static MessageType fromValue(String value) {
		for (MessageType messageType : MessageType.values()) {
			if (messageType.getValue().equals(value)) {
				return messageType;
			}
		}
		throw new IllegalArgumentException("Invalid MessageType value: " + value);
	}

	public String getValue() {
		return this.value;
	}

}

基于以上源码,可以看到有4个枚举值,如下所示。

枚举名称 对应字符串值 核心含义 核心作用与说明 对应实体类 典型应用场景
USER user 用户消息 承载终端用户或业务端输入的提问、指令、对话内容,是整个 AI 对话的输入发起方 UserMessage 1. 人类向 AI 发起业务提问、日常对话2. 前端传入用户输入的文本指令3. 多轮对话中用户每一轮的发言记录
ASSISTANT assistant AI 助手消息 承载大模型生成的回复内容,保存 AI 应答结果,用于多轮对话上下文拼接与历史记录留存 AssistantMessage 1. 大模型返回给用户的回答内容2. 会话历史中存储 AI 过往回复3. 作为下一轮对话的上下文上下文上下文参考
SYSTEM system 系统指令消息 设定 AI 行为边界、角色定位、回答规则与输出格式,约束 AI 的身份人设、思考逻辑、语言风格,引导 AI 按指定要求解读问题并给出合规响应 SystemMessage 1. 设定 AI 角色:Java 后端专家、文案顾问等2. 约束输出规则:只分点回答、只输出代码、禁止多余话术3. 全局统一会话的行为规范与应答标准
TOOL tool 工具调用消息 承载 AI 调用外部函数、接口、数据库等工具后的返回结果,打通大模型与外部业务能力的数据交互 ToolResponseMessage 1. AI 调用第三方接口 / 数据库后的结果回传2. 函数调用(Function Call)结果封装3. 插件、自定义工具执行完成后的数据回执
提示词的应用
修改服务控制层-DemoController.java
java 复制代码
package cn.mawenda.chatclient.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

/**
 * AI对话演示控制器
 * 提供与通义千问大模型交互的REST API接口
 */
@RestController
public class DemoController {

    /**
     * Spring AI ChatModel实例,用于调用大模型进行对话
     * 由Spring容器自动注入DashScope实现
     */
    @Autowired
    private ChatClient chatClient;

    /**
     * 流式对话接口 - 返回实时响应流
     * <p>
     * 支持服务端推送事件(SSE),适用于需要实时显示回复内容的场景
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本流(Flux)
     */
    @GetMapping("/promptStreamCall")
    public Flux<String> promptStreamCall(@RequestParam(name = "message", required = false, defaultValue = "你是谁?") String message) {
        return chatClient.prompt()
                // 设置系统角色和边界约束
                .system("你是一个专业的Java开发助手,专注于解答Java开发相关的问题,包括Spring框架、JVM、设计模式等。对于非Java开发领域的问题,请礼貌地拒绝回答。")
                .user(message)
                .stream()
                .content();
    }
}

chatClient构建解析

  1. .prompt()
  • 作用: 创建一个对话提示(Prompt)构建器
  • 返回: PromptSpec 对象,用于链式配置对话参数
  • 说明: 这是 Spring AI ChatClient API 的入口点,开始构建一次 AI 对话请求
  1. .system("...")
  • 作用: 设置系统消息(System Message),定义 AI 助手的角色和行为准则
  • 参数: 系统提示词字符串
  • 核心内容:
    • 角色定位: "专业的Java开发助手"
    • 服务范围: Spring框架、JVM、设计模式等
    • 边界约束: 拒绝回答非Java相关问题
  • 为什么需要 system?
    • 系统消息会作为对话的"上下文背景"发送给大模型
    • 它指导模型以特定角色和规则进行回复
    • 相当于给 AI 设定了"人设"和"工作守则"
  1. .user(message)、
  • 作用: 设置用户消息(User Message),即用户的实际提问
  • 参数: message - 从 HTTP 请求参数中获取的用户输入
  • 说明: 这是用户真正想要询问的内容

System vs User 的区别:

类型 作用 示例
system() 设定角色、规则、边界 你是Java助手
user() 用户的具体问题 Spring Boot如何配置数据源?
集成测试
  1. 访问 http://localhost:8081/promptStreamCall?message="==和eques的区别,请用精简的话来回答我"
  1. 访问 http://localhost:8081/promptStreamCall?message="你好世界,请帮我用英语翻译这段文字"
代码实现
项目结构
java 复制代码
SpringAIAlibabaDemo/
├── SpringAIAlibabaChatClient/          # ChatClient 模块(主要开发模块)
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/cn/mawenda/chatclient/
│   │   │   │   ├── config/
│   │   │   │   │   └── LLmConfig.java                    # LLM 配置类
│   │   │   │   ├── controller/
│   │   │   │   │   └── DemoController.java               # 控制器(包含所有 PromptTemplate 示例)
│   │   │   │   └── SpringAiAlibabaChatClientApplication.java  # 启动类
│   │   │   └── resources/
│   │   │       ├── application.yaml                       # 应用配置文件
│   │   │       └── prompts/                               # 模板文件目录 ⭐
│   │   │           ├── onboarding-notification.txt        # 入职通知 User 模板
│   │   │           ├── system-onboarding.txt              # 入职通知 System 模板
│   │   │           └── weather.txt                        # 天气播报模板
│   │   └── test/java/                                     # 测试目录
│   ├── target/                                            # 编译输出目录
│   └── pom.xml                                            # Maven 配置文件
├── pom.xml                             # 父 POM 文件
增加模板文件

在resource目录下增加prompts目录,用于保存提示词模板。

  1. 创建weather.txt模板文件
java 复制代码
请帮我写一段天气播报文案:
城市:{city}
天气:{weather}
温度:{temperature}摄氏度

要求:语言生动活泼,适合发朋友圈。
  1. 创建onboarding-notification.txt模板文件
java 复制代码
请帮我生成一份入职通知书,具体信息如下:

- 候选人姓名:{candidateName}
- 入职职位:{position}
- 所属部门:{department}
- 入职日期:{startDate}
- 入职时间:{startTime}
- 报到地点:{location}
- 薪资:{salary}
- 试用期:{probationPeriod}
- 联系人:{contactPerson}
- 联系电话:{contactPhone}

请生成完整的入职通知书,包含以下内容:
1. 欢迎语和录用确认
2. 职位和部门信息
3. 入职时间和地点
4. 薪资待遇说明
5. 需要携带的材料清单
6. 联系方式和温馨提示
  1. 创建system-onboarding.txt系统提示词文件
java 复制代码
你是一位资深的人力资源专家,擅长撰写专业、温馨的入职通知邮件。
请根据用户提供的信息,生成一份规范的入职通知书,要求:
1. 语气正式且温馨,体现公司文化
2. 结构清晰,包含所有必要信息
3. 格式规范,易于阅读
4. 中文输出
5. 输出格式为html
服务控制层-DemoController.Java
java 复制代码
package cn.mawenda.chatclient.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * AI对话演示控制器
 * 提供与通义千问大模型交互的REST API接口
 */
@RestController
public class DemoController {

    /**
     * Spring AI ChatModel实例,用于调用大模型进行对话
     * 由Spring容器自动注入DashScope实现
     */
    @Autowired
    private ChatClient chatClient;

    /**
     * 【入门】多个占位符的模板示例
     * 展示如何在一个模板中使用多个变量
     *
     * 访问示例: http://localhost:8081/prompt-template/multi-params?city=北京&weather=晴天&temperature=25
     */
    @GetMapping("/prompt-template/multi-params")
    public String multiParamsTemplate(
            @RequestParam("city") String city,
            @RequestParam("weather") String weather,
            @RequestParam("temperature") String temperature) {

        // 1. 从文件加载模板
        String template = loadTemplate("weather.txt");

        // 2. 创建模板对象
        PromptTemplate promptTemplate = new PromptTemplate(template);

        // 3. 准备多个变量
        Map<String, Object> variables = Map.of(
                "city", city,
                "weather", weather,
                "temperature", temperature
        );

        // 4. 渲染模板
        String content = promptTemplate.render(variables);

        // 5. 调用大模型并返回流式响应
        return chatClient.prompt()
                .user(content)
                .call()
                .content();
    }

    /**
     * 【进阶】入职通知生成器 - 综合应用 PromptTemplate
     * 结合 System 和 User 模板,生成专业的入职通知书
     *
     * 模板文件:
     * - resources/prompts/system-onboarding.txt (System模板)
     * - resources/prompts/onboarding-notification.txt (User模板)
     *
     * 访问示例: http://localhost:8081/prompt-template/onboarding?candidateName=张三&position=Java开发工程师&department=技术部&startDate=2024-05-20&startTime=09:00&location=北京市朝阳区XX大厦10层人力资源部&salary=15000&probationPeriod=3个月&contactPerson=李四&contactPhone=010-12345678
     */
    @GetMapping("/prompt-template/onboarding")
    public Flux<String> onboardingNotification(
            @RequestParam("candidateName") String candidateName,
            @RequestParam("position") String position,
            @RequestParam("department") String department,
            @RequestParam("startDate") String startDate,
            @RequestParam("startTime") String startTime,
            @RequestParam("location") String location,
            @RequestParam("salary") String salary,
            @RequestParam("probationPeriod") String probationPeriod,
            @RequestParam("contactPerson") String contactPerson,
            @RequestParam("contactPhone") String contactPhone) {

        // 从文件加载 System 模板:设定HR专家角色
        String systemTemplate = loadTemplate("system-onboarding.txt");
        PromptTemplate systemPromptTemplate = new PromptTemplate(systemTemplate);
        SystemMessage systemMessage = new SystemMessage(
                systemPromptTemplate.render(Map.of())  // System模板没有变量,传空Map
        );

        // 从文件加载 User 模板:入职通知具体内容
        String userTemplate = loadTemplate("onboarding-notification.txt");
        PromptTemplate userPromptTemplate = new PromptTemplate(userTemplate);

        // 准备变量(key必须和模板中的占位符名称完全一致)
        Map<String, Object> userVars = Map.of(
                "candidateName", candidateName,      // 对应模板中的 {candidateName}
                "position", position,                // 对应模板中的 {position}
                "department", department,            // 对应模板中的 {department}
                "startDate", startDate,              // 对应模板中的 {startDate}
                "startTime", startTime,              // 对应模板中的 {startTime}
                "location", location,                // 对应模板中的 {location}
                "salary", salary,                    // 对应模板中的 {salary}
                "probationPeriod", probationPeriod,  // 对应模板中的 {probationPeriod}
                "contactPerson", contactPerson,      // 对应模板中的 {contactPerson}
                "contactPhone", contactPhone         // 对应模板中的 {contactPhone}
        );

        // 渲染User模板,将占位符替换为实际值
        String userContent = userPromptTemplate.render(userVars);
        UserMessage userMessage = new UserMessage(userContent);

        // 组合消息并调用大模型
        Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

        return chatClient.prompt(prompt)
                .stream()
                .content();
    }

    /**
     * 从 resources/prompts 目录下读取模板文件
     *
     * @param fileName 模板文件名(相对于 resources/prompts 目录)
     * @return 模板文件的内容字符串
     */
    private String loadTemplate(String fileName) {
        try {
            // 从 classpath:prompts/ 目录下读取文件
            ClassPathResource resource = new ClassPathResource("prompts/" + fileName);
            return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("读取模板文件失败: " + fileName, e);
        }
    }

}

此处增加了两个接口和一个内部工具方法,解释如下:

  • loadTemplate,用于读取 resources/prompts 目录下模板文件
  • multiParamsTemplate,将多个变量占位符通过PromptTemplate渲染weather.txt中的模板
  • onboardingNotification,同时使用 System 模板和 User 模板来渲染onboarding-notification.txt中模板实现入职通知生成器的功能
集成测试
  1. 访问 http://localhost:8081/prompt-template/multi-params?city=北京&weather=晴天&temperature=25
  1. 访问 http://localhost:8081/prompt-template/onboarding?candidateName=张三&position=Java开发工程师&department=技术部&startDate=2024-05-20&startTime=09:00&location=北京市朝阳区XX大厦10层人力资源部&salary=15000&probationPeriod=3个月&contactPerson=李四&contactPhone=010-12345678
对话记忆
什么是对话记忆?

大模型对话记忆,就是大模型能记住你们之前聊过的内容、上下文信息、你的偏好、历史提问,不用你重复说背景,就能连贯接着聊的能力。如下示例所示:

  • 有对话记忆
  • 无对话记忆

根据如上示例所示,对话记忆 = 把历史聊天存下来,每次提问带着历史上下文一起给大模型,实现连贯对话、不用重复交代背景。

代码实现【手动管理】
实现原理
java 复制代码
# 实现流程
用户请求 → 查询历史记忆 → 调用大模型(携带历史) → 保存新记忆 → 返回响应

# 时序图
用户浏览器                    Controller                 ChatMemory               MySQL数据库
    │                           │                           │                          │
    │── GET /call?userId=xxx ──▶│                           │                          │
    │                           │                           │                          │
    │                           │── chatMemory.get(userId) ─▶│                          │
    │                           │                           │── SELECT * FROM ... ────▶│
    │                           │                           │◀── 返回历史记录 ──────────│
    │                           │◀── List<Message> ────────│                          │
    │                           │                           │                          │
    │                           │── chatClient.prompt() ──▶ 大模型API                  │
    │                           │     .messages(history)    │                          │
    │                           │◀── ChatResponse ───────── 大模型API                  │
    │                           │                           │                          │
    │                           │── chatMemory.add(...) ──▶│                          │
    │                           │                           │── INSERT INTO ... ──────▶│
    │                           │                           │◀── 保存成功 ─────────────│
    │                           │                           │                          │
    │◀── assistantAnswer ──────│                           │                          │
项目结构
java 复制代码
SpringAIAlibabaDemo/  									# 父项目根目录
├
└── SpringAIAlibabaChatMemory/                          # 子模块3:带会话记忆的对话
    ├── pom.xml
    ├── db/
    │   └── create_table.sql                            # AI聊天记忆表建表SQL
    ├── src/
    │   ├── main/
    │   │   ├── java/cn/mawenda/chatmemory/
    │   │   │   ├── SpringAIAlibabaChatMemoryApplication.java  # 启动类
    │   │   │   ├── config/
    │   │   │   │   └── LLmConfig.java                  # 大模型配置
    │   │   │   ├── controller/
    │   │   │   │   └── DemoController.java             # 演示控制器
    │   │   │   ├── entity/
    │   │   │   │   └── AiChatMemory.java               # 聊天记忆实体
    │   │   │   ├── mapper/
    │   │   │   │   └── AiChatMemoryMapper.java         # MyBatis-Plus Mapper
    │   │   │   └── service/
    │   │   │       ├── AiChatMemoryService.java        # 聊天记忆服务接口
    │   │   │       └── impl/
    │   │   │           └── AiChatMemoryServiceImpl.java # 聊天记忆服务实现
    │   │   └── resources/
    │   │       └── application.yaml                    # 应用配置
 └──pom.xml                                             # 父POM(统一管理依赖版本)
根目录pom.xml

增加Mysql驱动依赖版本与MybatisPlus依赖版本

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目基础信息 -->
    <groupId>cn.mawenda</groupId>
    <artifactId>SpringAIAlibabaDemo</artifactId>
    <version>1.0.1</version>
    <packaging>pom</packaging>

    <!-- 子模块列表 -->
    <modules>
        <module>SpringAiAlibabaChatModel</module>
        <module>SpringAIAlibabaChatClient</module>
        <module>SpringAIAlibabaChatMemory</module>
    </modules>

    <!-- 依赖版本统一管理 -->
    <properties>
        <!-- Java编译版本设置 -->
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <!-- 项目构建编码设置为UTF-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- Spring AI 框架版本 -->
        <spring-ai.version>1.0.0</spring-ai.version>
        <!-- Spring AI Alibaba 阿里云AI集成版本 -->
        <spring-ai-alibaba.version>1.0.0.2</spring-ai-alibaba.version>
        <!-- Spring Boot 框架版本 -->
        <spring-boot.version>3.4.5</spring-boot.version>
        <!-- MySQL JDBC Driver版本 -->
        <mysql.version>8.0.29</mysql.version>
        <!-- MyBatis-Plus 框架版本 -->
        <mybatis-plus.version>3.5.12</mybatis-plus.version>
    </properties>

    <!-- dependencyManagement 依赖统一管控,子模块继承时不需要指定版本号 -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring AI Alibaba BOM: 阿里云AI组件依赖管理,包含通义千问等模型支持 -->
            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Spring Boot Dependencies BOM: Spring Boot核心依赖管理,确保各组件版本兼容 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Spring AI BOM: Spring AI框架依赖管理,提供统一的AI接口抽象 -->
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 构建插件配置 -->
    <build>
        <plugins>
            <!-- Spring Boot Maven插件: 用于打包可执行JAR文件、运行应用等 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
            </plugin>
        </plugins>
    </build>

</project>
微服务构建-SpringAIAlibabaChatMemory
pom.xml
java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.mawenda</groupId>
        <artifactId>SpringAIAlibabaDemo</artifactId>
        <version>1.0.1</version>
    </parent>

    <artifactId>SpringAIAlibabaChatMemory</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring Boot Web Starter: 提供Web开发基础功能,包括REST API支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring AI Alibaba DashScope Starter: 阿里云通义千问大模型集成依赖,提供ChatModel等AI能力 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>

        <!-- Spring Context: Spring框架核心上下文模块,提供依赖注入、Bean管理等基础功能 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <!-- MySQL Connector: MySQL数据库驱动程序 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- MyBatis-Plus Spring Boot Starter: MyBatis增强工具,简化数据库操作 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.4</version>
        </dependency>

        <!-- lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

</project>
在本地启动Mysql数据库,并执行如下sql

如果想使用自己的数据库,忽略建库语句直接在数据库中创建表即可

java 复制代码
-- 创建数据库 sa_db,使用 utf8mb4 编码 + 排序规则
CREATE DATABASE IF NOT EXISTS sa_db
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_general_ci;

-- 创建表
CREATE TABLE ai_chat_memory (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(64) NOT NULL COMMENT '用户ID',
    conversation_id VARCHAR(64) NOT NULL COMMENT '会话ID',
    message_type VARCHAR(32) NOT NULL COMMENT 'USER/ASSISTANT/SYSTEM',
    content TEXT NOT NULL,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_conversation (user_id, conversation_id)
);
服务配置文件-application.yaml
java 复制代码
server:
  port: 8082  # 指定当前服务的端口
  servlet:
    encoding:
      enabled: true # 大模型对话中文乱码处理
      force: true
      charset: utf-8

spring:
  application:
    name: SpringAIAlibabaChatMemory # 微服务名称
  # 数据源信息,根据上一步骤的内容,配置对应的数据源即可
  datasource:
    url: jdbc:mysql://localhost:3306/sa_db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

  ai:
    dashscope:
      # 密钥, 在云平台中申请的API Key
      api-key: sk-08ad3bf73bf645a9a0c0cc5ac68775a3
      # 模型请求地址
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          # 指定使用的模型版本
          model: qwen3.6-max-preview
服务启动类-SpringAIAlibabaChatMemoryApplication.java
java 复制代码
package cn.mawenda.chatmemory;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAIAlibabaChatMemoryApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAIAlibabaChatMemoryApplication.class, args);
    }
}
模型配置类-LLmConfig.java
java 复制代码
package cn.mawenda.chatmemory.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 大模型配置类
 */
@Configuration
public class LLmConfig {

    /**
     * 创建 ChatClient 实例
     */
    @Bean
    public ChatClient chatClient(ChatModel dashscopeChatModel){
        return ChatClient.builder(dashscopeChatModel).build();
    }
}
实体类-AiChatMemory.java
java 复制代码
package cn.mawenda.chatmemory.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * AI聊天记忆实体类
 * 用于存储用户与AI助手的对话历史记录
 *
 * @author mawenda
 * @since 2026-05-28
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("ai_chat_memory")
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AiChatMemory implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键ID,自增
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 用户ID,标识不同的用户
     */
    @TableField("user_id")
    private String userId;

    /**
     * 会话ID,标识同一用户的不同会话
     */
    @TableField("conversation_id")
    private String conversationId;

    /**
     * 消息类型:USER(用户消息)/ASSISTANT(助手回复)/SYSTEM(系统消息)
     */
    @TableField("message_type")
    private String messageType;

    /**
     * 消息内容
     */
    @TableField("content")
    private String content;

    /**
     * 创建时间,默认为当前时间
     */
    @TableField("create_time")
    private LocalDateTime createTime;
}
Mapper层-AiChatMemoryMapper.java
java 复制代码
package cn.mawenda.chatmemory.mapper;

import cn.mawenda.chatmemory.entity.AiChatMemory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * AI聊天记忆Mapper接口
 * 继承MyBatis Plus的BaseMapper,自动提供基础CRUD操作
 *
 * @author mawenda
 * @since 2026-05-28
 */
@Mapper
public interface AiChatMemoryMapper extends BaseMapper<AiChatMemory> {

}
Service层-AiChatMemoryService.java
java 复制代码
package cn.mawenda.chatmemory.service;

import cn.mawenda.chatmemory.entity.AiChatMemory;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 *
 * @Author: Ma.wenda
 * @Date: 2026-05-28 13:18
 * @Version: 1.0
 **/
public interface AiChatMemoryService  extends IService<AiChatMemory>{

}
Service实现-AiChatMemoryServiceImpl.java
java 复制代码
package cn.mawenda.chatmemory.service.impl;

import cn.mawenda.chatmemory.entity.AiChatMemory;
import cn.mawenda.chatmemory.mapper.AiChatMemoryMapper;
import cn.mawenda.chatmemory.service.AiChatMemoryService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * AI聊天记忆Service实现类
 * 继承MyBatis Plus的ServiceImpl,实现业务逻辑
 *
 * @author mawenda
 * @since 2026-05-28
 */
@Service
public class AiChatMemoryServiceImpl extends ServiceImpl<AiChatMemoryMapper, AiChatMemory> implements AiChatMemoryService, ChatMemory {

    /**
     * 批量添加会话记忆
     *
     * @param conversationId 会话ID
     * @param messages       会话记忆
     */
    @Override
    public void add(String conversationId, List<Message> messages) {
        // 参数校验
        if(!StringUtils.hasLength(conversationId)){
            throw new IllegalArgumentException("会话ID不能为空");
        }
        if(messages == null || messages.isEmpty()){
            return;
        }

        // 数据转换
        List<AiChatMemory> aiChatMemories = messages.stream()
                .filter(Objects::nonNull)
                .map(message -> {
                    return new AiChatMemory().builder()
                            .conversationId(conversationId)
                            .content(message.getText())
                            .messageType(message.getMessageType().name())
                            // TODO 此处后续可以替换为真实用户ID,目前使用会话ID临时代替
                            .userId(conversationId)
                            .createTime(LocalDateTime.now())
                            .build();
                })
                .collect(Collectors.toList());

        this.saveBatch(aiChatMemories);
    }

    /**
     * 获取会话记忆
     *
     * @param conversationId 会话ID
     * @return 会话记忆
     */
    @Override
    public List<Message> get(String conversationId) {
        // 参数校验
        if(!StringUtils.hasLength(conversationId)){
            throw new IllegalArgumentException("会话ID不能为空");
        }

        List<AiChatMemory> aiChatMemories = this.list(Wrappers.<AiChatMemory>lambdaQuery()
                .eq(AiChatMemory::getConversationId, conversationId)
                .orderByDesc(AiChatMemory::getCreateTime)
                .last("limit 10")
        );

        if(CollectionUtils.isEmpty(aiChatMemories)){
            return List.of();
        }

        // 数据转换
        return aiChatMemories.stream()
                .map(this::toMessage)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

    }

    /**
     * 清空会话记忆
     *
     * @param conversationId 会话ID
     */
    @Override
    public void clear(String conversationId) {
        // 参数校验
        if(!StringUtils.hasLength(conversationId)){
            throw new IllegalArgumentException("会话ID不能为空");
        }
        this.remove(Wrappers.<AiChatMemory>lambdaQuery()
                .eq(AiChatMemory::getConversationId, conversationId)
        );
    }

    /**
     * 数据转换
     *
     * @param aiChatMemory AI聊天记忆
     * @return 会话记忆
     */
    private Message toMessage(AiChatMemory aiChatMemory) {
        if (aiChatMemory == null || aiChatMemory.getMessageType() == null) {
            return null;
        }

        return switch (aiChatMemory.getMessageType()) {
            case "USER" -> new UserMessage(aiChatMemory.getContent());
            case "ASSISTANT" -> new AssistantMessage(aiChatMemory.getContent());
            case "SYSTEM" -> new SystemMessage(aiChatMemory.getContent());
            default -> null;
        };
    }
}
服务控制层-DemoController.java
java 复制代码
package cn.mawenda.chatmemory.controller;

import cn.mawenda.chatmemory.service.AiChatMemoryService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 *
 * @Author: Ma.wenda
 * @Date: 2026-05-28 13:40
 * @Version: 1.0
 **/

@RestController
@Slf4j
public class DemoController {

    @Resource
    private ChatClient chatClient;
    @Resource
    private ChatMemory chatMemory;

    /**
     * 调用大模型进行对话
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本
     */
    @GetMapping("/call")
    public String call(
            @RequestParam(name = "userId") String userId,
            @RequestParam(name = "message") String message
    ){
        // 查询历史会话记录
        List<Message> historyMessages = chatMemory.get(userId);
        log.info("查询历史会话记录条数为: {}", historyMessages.size());

        // 构造本次请求
        UserMessage userMessage = new UserMessage(message);

        // 调用模型,并将历史会话传入
        ChatResponse chatResponse = chatClient.prompt()
                .messages(historyMessages)
                .user(message)
                .call()
                .chatResponse();

        // 解析本次会话响应
        String assistantAnswer = chatResponse.getResult().getOutput().getText();

        // 创建 AssistantMessage
        AssistantMessage assistantMessage = new AssistantMessage(assistantAnswer);


        // 保存本次问答记录到MySQL(用户提问+AI回答)
        chatMemory.add(userId, List.of(userMessage, assistantMessage));

        return assistantAnswer;
    }
}
集成测试
  • 会话记录持久化
代码实现【Advisor 自动管理】
微服务构建-SpringAIAlibabaChatMemoryAdvisor
pom.xml
java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.mawenda</groupId>
        <artifactId>SpringAIAlibabaDemo</artifactId>
        <version>1.0.1</version>
    </parent>

    <artifactId>SpringAIAlibabaChatMemoryAdvisor</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 【关键】强制指定 Spring Framework 版本与 Spring Boot 3.4.5 匹配的 6.2.6 -->
        <spring-framework.version>6.2.6</spring-framework.version>
    </properties>

    <dependencies>
        <!-- Spring Boot Web Starter: 提供Web开发基础功能,包括REST API支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring AI Alibaba DashScope Starter: 阿里云通义千问大模型集成依赖,提供ChatModel等AI能力 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>

        <!-- Spring AI Model Chat Memory Repository JDBC: 集成JDBC的ChatMemoryRepository -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
        </dependency>

        <!-- MySQL Connector: MySQL数据库驱动程序 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
    </dependencies>

</project>
服务配置-application.yaml
java 复制代码
server:
  port: 8083  # 指定当前服务的端口
  servlet:
    encoding:
      enabled: true # 大模型对话中文乱码处理
      force: true
      charset: utf-8

spring:
  application:
    name: SpringAIAlibabaChatMemoryAdvisor # 微服务名称
  datasource:
    url: jdbc:mysql://localhost:3306/sa_db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

  ai:
    dashscope:
      # 密钥, 在云平台中申请的API Key
      api-key: sk-08ad3bf73bf645a9a0c0cc5ac68775a3
      # 模型请求地址
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          # 指定使用的模型版本
          model: qwen3.6-max-preview
    chat:
      memory:
        repository:
          jdbc:
            initialize-schema: always # 初始化数据库表
            platform: mariadb # MariaDB高度兼容Mysql
服务启动类-SpringAIAlibabaChatMemoryAdvisorApplication.java
java 复制代码
package cn.mawenda.advisor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAIAlibabaChatMemoryAdvisorApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAIAlibabaChatMemoryAdvisorApplication.class, args);
    }
}
模型配置类-LLmConfig.java
java 复制代码
package cn.mawenda.advisor.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 大模型配置类
 */
@Configuration
public class LLmConfig {

    /**
     * 创建 ChatMemory 存储实例
     */
    @Bean
    public ChatMemory chatMemory(JdbcChatMemoryRepository jdbcChatMemoryRepository){
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(jdbcChatMemoryRepository)
                .maxMessages(20)
                .build();
    }

    /**
     * 创建 ChatClient 实例
     */
    @Bean
    public ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory){
        return ChatClient.builder(chatModel)
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
                .build();

    }
}
服务控制层-DemoController.java
java 复制代码
package cn.mawenda.advisor.controller;

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 *
 * @Author: Ma.wenda
 * @Date: 2026-05-28 13:40
 * @Version: 1.0
 **/

@RestController
public class DemoController {

    @Resource
    private ChatClient chatClient;
    @Resource
    private ChatMemory chatMemory;

    /**
     * 调用大模型进行对话
     *
     * @param message 用户输入的消息内容,默认为"你是谁?"
     * @return 大模型返回的响应文本
     */
    @GetMapping("/call")
    public String call(
            @RequestParam(name = "uid") String userId,
            @RequestParam(value = "cid") String conversationID,
            @RequestParam(name = "message") String message
    ){
        String uniqueConversationId = userId + "_" + conversationID;

        return chatClient.prompt()
                .user(message)
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, uniqueConversationId))
                .call()
                .content();
    }
}
集成测试
  • 查看数据库
  • 总结,使用该框架,无感上手,但灵活性低,适用于简单场景。

多模态模型

什么是模态

模态指信息的载体形式,人类感知世界的不同渠道都属于模态:

  • 文本模态:文字、对话、代码、指令(普通大模型只处理这个)
  • 图像模态:图片、照片、截图、图表、手绘
  • 音频模态:语音、录音、音效
  • 视频模态:连续画面 + 音频(图像 + 音频组合)
  • 其他:深度图、3D 点云、传感器数值等

单模态模型:只能处理一种信息,比如早期纯文本 GPT、仅识图的 CNN 图像分类模型。

多模态模型:能同时接收、理解、融合两种及以上模态数据,跨模态推理、跨模态生成。

通义万象模型

  • 实现简单demo,文生图
代码实现
构建微服务-SpringAIAlibabaTextToImage
pom.xml
服务配置文件-application.yaml
yaml 复制代码
server:
  port: 8084  # 指定当前服务的端口
  servlet:
    encoding:
      enabled: true # 大模型对话中文乱码处理
      force: true
      charset: utf-8

spring:
  application:
    name: SpringAIAlibabaTextToImage # 微服务名称

  ai:
    dashscope:
      # 密钥, 在云平台中申请的API Key
      api-key: sk-08ad3bf73bf645a9a0c0cc5ac68775a3
      image:
        options:
          # 指定使用的模型版本
          model: wanx-v1
服务启动类-SpringAIAlibabaTextToImageApplication.java
yaml 复制代码
package cn.mawenda.image;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAIAlibabaTextToImageApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAIAlibabaTextToImageApplication.class, args);
    }
}
大模型配置类-LLmConfig.java
java 复制代码
package cn.mawenda.image.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

@Configuration
public class LLmConfig {

    /**
     * 覆盖默认的 RetryTemplate 配置
     * 针对通义万相生成图片较慢的情况,增加重试次数和间隔
     */
    @Bean
    public RetryTemplate imageRetryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        // 1. 设置重试策略:最多重试 30 次(可根据需求调整)
        // 总等待时间 = 重试次数 * 每次间隔时间
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(30); // 最大重试次数
        retryTemplate.setRetryPolicy(retryPolicy);

        // 2. 设置退避策略:每次重试间隔 2 秒(2000 毫秒)
        // 使用 Spring Retry 正确的 FixedBackOffPolicy 类
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(2000L); // 每次重试间隔2秒
        retryTemplate.setBackOffPolicy(backOffPolicy);

        return retryTemplate;
    }
}
服务控制层
java 复制代码
package cn.mawenda.image.controller;

import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import jakarta.annotation.Resource;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    // 从配置文件读取模型名
    @Value("${spring.ai.dashscope.image.options.model}")
    private String imageModelName;

    // ImageModel 是 Spring AI 框架 中定义的文生图模型核心接口
    @Resource
    private ImageModel imageModel;

    @GetMapping(value = "/toImage")
    public String image(@RequestParam(name = "prompt") String prompt)
    {
        DashScopeImageOptions build = DashScopeImageOptions.builder()
                .withModel(imageModelName)
                .build();

        ImageResponse response = imageModel.call(new ImagePrompt(prompt, build));

        return response.getResult().getOutput().getUrl();
    }
}
集成测试
  • 返回图片地址,打开图片后内容如下

向量化

向量数据库

RAG

什么是RAG?

检索增强生成(Retrieval-augmented Generation),简称RAG,是当下热门的大模型前沿技术之一。

检索增强生成模型结合了语言模型和信息检索技术。具体来说,当模型需要生成文本或者回答问题时,它会先从一个庞大的文档集合中检索出相关的信息,然后利用这些检索到的信息来指导文本的生成,从而提高预测的质量和准确性 。

https://baike.baidu.com/item/%E6%A3%80%E7%B4%A2%E5%A2%9E%E5%BC%BA%E7%94%9F%E6%88%90/64380539?fromtitle=RAG&fromid=64380547&fr=aladdin