Spring AI ChatModel 使用记录

文章目录

Spring AI ChatModel 使用记录(入门 Demo)

最近简单体验了一下 Spring AI ,基于 spring-ai 1.1.0 写了一个最小可用的 Chat Demo,主要用于熟悉 ChatModel 的基本使用方式,顺便记录一下踩坑和实现思路。

当前 Demo 实现的功能非常基础,主要包括:

  • ✅ 简单对话调用
  • ✅ 基于内存的上下文缓存(多轮对话)

本文未引入持久化、并发隔离等复杂设计。


一、依赖配置

⚠️ 注意:Spring Boot 与 Spring AI 的版本要匹配,否则很容易遇到类缺失或 Bean 无法注入的问题。

当前使用版本:

  • Spring Boot:3.3.5
  • Spring AI:1.1.0
  • JDK:17
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
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.5</version>
        <relativePath/>
    </parent>

    <groupId>com.ljx.ai</groupId>
    <artifactId>demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
        <!-- Spring AI 版本 -->
        <spring-ai.version>1.1.0</spring-ai.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>group.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>group.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

二、配置项说明

这里使用的是 硅基流动提供的 OpenAI 兼容接口,如果想切换到:

  • 本地模型(如 Ollama)
  • 其他 OpenAI 兼容平台

只需要调整:

  • base-url
  • model

即可。

yml 复制代码
spring:
  application:
    name: ai
  ai:
    openai:
      # OpenAI 兼容接口(硅基流动)
      base-url: https://api.siliconflow.cn
      api-key: ${SILICONFLOW_API_KEY:自己的密钥}
      chat:
        options:
          model: deepseek-ai/DeepSeek-V3.2
          temperature: 0.7
          max-tokens: 1024

三、上下文存储设计

Spring AI 的多轮对话,本质就是 Prompt 中携带历史 Message 列表

这里用到了三个 Message 类型:

  • SystemMessage:系统指令(人设、规则)
  • UserMessage:用户输入
  • AssistantMessage:模型回复

设计思路

  • 使用一个 内存 List 保存对话历史
  • 第 0 条永远保留 SystemMessage
  • 限制最大上下文轮数,避免 prompt 过长

示例实现

java 复制代码
import groovy.util.logging.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 java.util.ArrayList;
import java.util.List;

@Slf4j
public class ChatStore {

    /**
     * 历史上下文
     */
    private static final List<Message> history = new ArrayList<>();

    /**
     * 最大保留轮数(不含 system)
     */
    private static final int MAX_HISTORY = 10;

    private static final Logger log = LoggerFactory.getLogger(ChatStore.class);

    /**
     * 将当前用户消息加入上下文,并返回裁剪后的历史
     */
    public static List<Message> trimHistory(String message) {
        if (ObjectUtils.isEmpty(history)) {
            history.add(new SystemMessage("你是一个金发兽耳小萝莉,请讨好你的主人"));
        }

        // system message 永远保留
        Message system = history.get(0);

        // 先加入用户消息
        history.add(new UserMessage(message));

        // 超出最大上下文长度则裁剪
        if (history.size() > MAX_HISTORY + 1) {
            List<Message> recent = history.subList(
                    history.size() - MAX_HISTORY,
                    history.size()
            );
            history.clear();
            history.add(system);
            history.addAll(recent);
        }

        return history;
    }

    /**
     * 记录模型回复
     */
    public static void addHistory(Message message) {
        history.add(message);
    }

    /**
     * 查看当前上下文内容
     */
    public static String showHistory() {
        StringBuilder sb = new StringBuilder();
        if (ObjectUtils.isNotEmpty(history)) {
            for (Message message : history) {
                if (message instanceof SystemMessage) {
                    continue;
                } else if (message instanceof UserMessage) {
                    sb.append("You say: ");
                } else if (message instanceof AssistantMessage) {
                    sb.append("She say: ");
                }
                sb.append(message.getContent()).append("\n");
            }
        }
        return sb.toString();
    }

    /**
     * 清空上下文
     */
    public static void clear() {
        history.clear();
    }
}

⚠️ 注意:

这是 全局静态上下文不支持多用户 ,真实项目应至少按 session / userId 隔离。


四、聊天调用逻辑

这里基本就是 Spring AI 的标准用法:

  1. 生成上下文 List<Message>
  2. 构造 Prompt
  3. 调用 ChatModel
  4. 保存 AssistantMessage
java 复制代码
import groovy.util.logging.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class ChatServiceImpl extends ChatService {

    private static final Logger log = LoggerFactory.getLogger(ChatServiceImpl.class);

    @Autowired
    private ChatModel chatModel;

    @Override
    public String sendMessage(String message) {
        // 生成上下文
        List<Message> messages = ChatStore.trimHistory(message);

        // 构造 Prompt
        Prompt prompt = new Prompt(messages);

        // 调用模型
        String result = chatModel
                .call(prompt)
                .getResult()
                .getOutput()
                .getContent();

        // 保存回复
        ChatStore.addHistory(new AssistantMessage(result));

        return result;
    }

    @Override
    public String show() {
        return ChatStore.showHistory();
    }

    @Override
    public void clear() {
        ChatStore.clear();
    }
}

相关推荐
AIbase20242 小时前
AI时代品牌流量争夺战:如何通过“品牌AI搜索监控”提升GEO可见度?
人工智能·chatgpt
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于SpringBoot的律师事务所管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
菜宾2 小时前
java-seata基础教学
java·开发语言·adb
老鱼说AI2 小时前
论文精读第七期:告别昂贵的人工标注!Math-Shepherd:如何用“零成本”自动化过程监督,让大模型数学能力暴涨?
人工智能·深度学习·神经网络·机器学习·语言模型·自然语言处理·boosting
好奇龙猫2 小时前
【人工智能学习-AI入试相关题目练习-第九次】
人工智能·学习
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于springboot的日用药品仓库管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
aspxiy2 小时前
知识求解器:教会大型语言模型从知识图谱中搜索领域知识
人工智能·语言模型·自然语言处理·知识图谱
梦想是成为算法高手2 小时前
带你从入门到精通——知识图谱(一. 知识图谱入门)
人工智能·pytorch·python·深度学习·神经网络·知识图谱