Spring AI 实战指南:使用 Java 构建基于大模型的智能客服聊天机器人

2026-06-05 0 242

在生成式 AI 席卷技术领域的今天,Java 开发者终于迎来了一站式的解决方案——Spring AI。这一由 Spring 官方推出的框架将大型语言模型(LLM)的调用、向量存储、提示词模板等能力以熟悉的 Spring 风格封装,使得 Java 应用能够快速集成 AI 功能。本文将通过一个完整的智能客服聊天机器人项目,带你从零配置 Spring AI,实现流式对话、历史记录管理,并探索函数调用等高级特性,让你在 Java 生态中轻松驾驭大模型。

一、项目准备与依赖配置

我们将创建一个 Spring Boot 3.2 项目,并添加 Spring AI 的 OpenAI Starter。由于 Spring AI 目前处于快速迭代阶段,需引入其里程碑仓库。

<!-- pom.xml 关键依赖 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.5</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        <version>1.0.0-M3</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

application.yml 中配置 OpenAI API 密钥(可从 platform.openai.com 获取),并设置模型参数:

spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      model: gpt-3.5-turbo
      temperature: 0.7
      max-tokens: 500

环境变量 OPENAI_API_KEY 应在启动前设置,避免将密钥硬编码。至此,项目已具备调用大模型的能力。

二、第一个简单对话:Hello, Spring AI

Spring AI 提供了 AiClient 接口(实现类为 OpenAiChatClient)来发送和接收消息。我们先编写一个简单的 REST 接口测试连通性。

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/ai")
public class SimpleAiController {

    private final ChatClient chatClient;

    public SimpleAiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

启动项目后访问 http://localhost:8080/ai/chat?message=你好,即可获得模型回复。此时对话是无状态的,每次请求都是独立的。

三、实现带历史记忆的对话

智能客服需要上下文记忆。我们可以使用 Prompt 对象携带对话历史列表,让模型理解之前的对话。下面创建一个会话服务,使用简单的 Map 按会话 ID 存储消息历史。

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.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ChatService {

    private final ChatClient chatClient;
    private final Map<String, List<Message>> sessionHistory = new ConcurrentHashMap<>();

    public ChatService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public String chat(String sessionId, String userMessage) {
        // 获取或创建当前会话的历史记录
        List<Message> history = sessionHistory.computeIfAbsent(sessionId, key -> new ArrayList<>());

        // 将用户消息加入历史
        history.add(new UserMessage(userMessage));

        // 构建包含历史的 Prompt
        Prompt prompt = new Prompt(history, OpenAiChatOptions.builder()
                .withModel("gpt-3.5-turbo")
                .withTemperature(0.7f)
                .build());

        // 调用模型并获取回复
        String assistantReply = chatClient.prompt(prompt).call().content();

        // 将助手回复加入历史
        history.add(new AssistantMessage(assistantReply));

        // 限制历史长度,防止超出 token 限制
        if (history.size() > 20) {
            history.subList(0, 10).clear();
        }

        return assistantReply;
    }
}

控制器使用该服务,并生成 sessionId 存入 cookie 或由前端传入:

@RestController
@RequestMapping("/api")
public class ChatController {

    private final ChatService chatService;

    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }

    @PostMapping("/chat")
    public Map<String, String> chat(@RequestHeader("X-Session-Id") String sessionId,
                                     @RequestBody Map<String, String> request) {
        String userMessage = request.get("message");
        String reply = chatService.chat(sessionId, userMessage);
        return Map.of("reply", reply);
    }
}

四、流式对话(Server-Sent Events)

为了提升用户体验,我们通常会希望像 ChatGPT 那样逐字显示回复。Spring AI 支持流式响应,可以通过 Flux<String> 返回,浏览器使用 EventSource 接收。

import reactor.core.publisher.Flux;

@GetMapping(value = "/stream", produces = "text/event-stream")
public Flux<String> streamChat(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .stream()
            .content();
}

前端使用简单的 JavaScript 即可读取流:

const eventSource = new EventSource('/ai/stream?message=' + encodeURIComponent(userInput));
eventSource.onmessage = (event) => {
    // 将收到的文本追加到对话框
    appendToChat(event.data);
};
eventSource.onerror = () => eventSource.close();

结合历史记录,我们可以扩展 ChatService 的流式方法:

public Flux<String> streamChat(String sessionId, String userMessage) {
    List<Message> history = sessionHistory.computeIfAbsent(sessionId, key -> new ArrayList<>());
    history.add(new UserMessage(userMessage));

    Prompt prompt = new Prompt(history);
    StringBuilder fullReply = new StringBuilder();

    return chatClient.prompt(prompt).stream().content()
            .doOnNext(fullReply::append)
            .doOnComplete(() -> history.add(new AssistantMessage(fullReply.toString())));
}

五、构建智能客服场景:提示词模板与上下文注入

客服机器人需要系统级提示词限定身份和行为。使用 SystemMessage 作为根消息,并将其添加到每次请求的历史列表中。

private static final String SYSTEM_PROMPT = """
        你是一个电商平台的智能客服助手,名字叫“小慧”。
        请用友好、专业的语气回答用户问题。
        如果用户询问订单状态,请引导其提供订单号。
        如果用户询问退货政策,请回复:我们支持7天无理由退货。
        """;

public String chatWithSystem(String sessionId, String userMessage) {
    List<Message> history = sessionHistory.computeIfAbsent(sessionId, key -> {
        List<Message> msgs = new ArrayList<>();
        msgs.add(new SystemMessage(SYSTEM_PROMPT));
        return msgs;
    });

    // 确保系统消息始终在第一位(在历史删除时也要保留)
    if (history.isEmpty() || !(history.get(0) instanceof SystemMessage)) {
        history.add(0, new SystemMessage(SYSTEM_PROMPT));
    }

    history.add(new UserMessage(userMessage));
    Prompt prompt = new Prompt(history);
    String reply = chatClient.prompt(prompt).call().content();
    history.add(new AssistantMessage(reply));
    trimHistory(history);
    return reply;
}

这样,无论对话进行多少轮,模型始终知道自己是一名客服,并遵循预设规则。

六、高级特性:函数调用(Function Calling)

智能客服经常需要查询真实数据(如运单号、订单详情),可通过函数调用让大模型产生结构化参数,然后由应用执行并返回结果。Spring AI 支持简化的 @Tool 注解和 FunctionCallback

首先定义一个运单查询的服务,并将方法标注为 @Tool

import org.springframework.ai.tool.Tool;
import org.springframework.stereotype.Component;

@Component
public class LogisticsService {

    @Tool(description = "根据运单号查询物流状态")
    public String queryLogistics(String trackingNumber) {
        // 模拟查询数据库或第三方API
        if (trackingNumber.equals("123456")) {
            return "运单号123456:已到达目的地,正在派送中。";
        }
        return "未找到运单信息。";
    }
}

然后在配置中注册 FunctionCallback Bean:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder, LogisticsService logisticsService) {
        return builder
                .defaultTools(logisticsService)
                .build();
    }
}

现在,当用户询问“我的快递123456到哪了”,大模型会自动生成函数调用请求,Spring AI 会拦截执行本地方法并将结果注入回模型,最终返回自然语言答复。整个过程对业务代码完全透明。

七、集成向量数据库实现知识库问答

为了回答关于公司政策、产品手册等非结构化知识,可以使用 Spring AI 的向量存储支持。以 Milvus 或 PGVector 为例,先将文档嵌入并存储,然后在对话中检索相关内容作为上下文。

# 添加依赖(以PGVector为例)
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pgvector-store</artifactId>
</dependency>

# application.yml
spring:
  ai:
    vectorstore:
      pgvector:
        host: localhost
        port: 5432
        database: aistore
        username: postgres
        password: secret

然后通过 VectorStore 进行相似性检索,将结果拼接到系统提示词中:

String userQuestion = "退货流程是什么?";
List<Document> relevantDocs = vectorStore.similaritySearch(userQuestion);
String context = relevantDocs.stream()
        .map(Document::getContent)
        .collect(Collectors.joining("n"));
String enrichedPrompt = "根据以下信息回答问题:n" + context + "n问题:" + userQuestion;

这种 RAG(检索增强生成)模式显著提升了回答的准确性和时效性。

八、总结与展望

通过本文的实战案例,我们使用 Spring AI 构建了一个功能完备的智能客服聊天机器人,涵盖基础调用、历史记忆、流式输出、提示词模板、函数调用和向量检索。Spring AI 延续了 Spring 生态的“约定优于配置”理念,让 Java 开发者无需离开舒适区就能深度集成大模型能力。

当前 Spring AI 仍处于里程碑版本,但其设计已经足够稳定用于原型和生产环境。未来它将支持更多模型(如 Azure OpenAI)、更丰富的向量存储以及更简洁的多模态交互。现在正是将 AI 能力融入 Java 应用的最佳时机,赶快在你的下一个 Spring Boot 项目中试试 Spring AI 吧。

Spring AI 实战指南:使用 Java 构建基于大模型的智能客服聊天机器人
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 java Spring AI 实战指南:使用 Java 构建基于大模型的智能客服聊天机器人 https://www.taomawang.com/server/java/2089.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务