在这里插入图片描述

Pre

大模型开发 - 01 Spring AI 核心特性一览

大模型开发 - 02 Spring AI Concepts

大模型开发 - 03 QuickStart_借助DeepSeekChatModel实现Spring AI 集成 DeepSeek

大模型开发 - 04 QuickStart_DeepSeek 模型调用流程源码解析:从 Prompt 到远程请求

大模型开发 - 05 QuickStart_接入阿里百炼平台:Spring AI Alibaba 与 DashScope SDK

大模型开发 - 06 QuickStart_本地大模型私有化部署实战:Ollama + Spring AI 全栈指南

大模型开发 - 07 ChatClient:构建统一、优雅的大模型交互接口

大模型开发 - 08 ChatClient:构建智能对话应用的流畅 API

大模型开发 - 09 ChatClient:基于 Spring AI 的多平台多模型动态切换实战

大模型开发 - 10 ChatClient:Advisors API 构建可插拔、可组合的智能对话增强体系

大模型开发 - 11 ChatClient:Advisor 机制详解:拦截、增强与自定义 AI 对话流程

大模型开发 - 12 Prompt:Spring AI 中的提示(Prompt)系统详解_从基础概念到高级工程实践

大模型开发 - 13 Prompt:提示词工程实战指南_Spring AI 中的提示设计、模板化与最佳实践

大模型开发 - 14 Chat Memory:实现跨轮次对话上下文管理

大模型开发 - 15 Tool Calling :从入门到实战,一步步构建智能Agent系统

大模型开发 - 16 Chat Memory:借助 ChatMemory + PromptChatMemoryAdvisor轻松实现大模型多轮对话记忆

大模型开发 - 17 Structured Output Converter:结构化输出转换器_从文本到结构化数据的可靠桥梁

大模型开发 - 18 Chat Memory:集成 JdbcChatMemoryRepository 实现大模型多轮对话记忆

大模型开发 - 19 Chat Memory:集成 BaseRedisChatMemoryRepository实现大模型多轮对话记忆

大模型开发 - 20 Chat Memory:多层次记忆架构_突破大模型对话中的 Token 上限瓶颈

大模型开发 - 21 Structured Output Converter:结构化输出功能实战指南

大模型开发 - 22 Multimodality API:多模态大模型与 Spring AI 的融合

大模型开发 - 23 Chat Model API:深入解析 Spring AI Chat Model API_构建统一、灵活、可扩展的 AI 对话系统

大模型开发 - 24 Embeddings Model API:深入解析 Spring AI Embeddings Model API_构建语义理解的基石

大模型开发 - 25 Image Model API:深入解析 Spring AI Image Model API_构建统一、灵活的 AI 图像生成系统


项目概述

为了更好的理解tools, 我们先收工实现一个初始版本。

本项目是一个基于Spring AI框架构建的智能票务助手系统,展示了如何使用Spring AI的多聊天客户端功能来实现结构化任务处理和流式响应。系统能够智能识别用户的票务相关请求(如退票、查询等),并根据不同的任务类型调用相应的AI模型进行处理。

核心特性

  • 多聊天客户端架构:使用不同的ChatClient处理不同类型的任务
  • 结构化输出:通过AI模型将用户输入解析为结构化的任务对象
  • 流式响应:支持实时流式输出,提升用户体验
  • 响应式编程:基于Reactor实现非阻塞的异步处理
  • 任务路由:根据AI解析的任务类型自动路由到相应的处理逻辑

技术栈

  • Spring Boot 3.x:应用框架
  • Spring AI:AI集成框架
  • 阿里云百炼(DashScope):AI模型服务
  • Reactor:响应式编程框架
  • Lombok:代码简化工具

项目结构

04-structured-mulit-chatclient/
├── src/main/java/com/artisan/
│   ├── MultiChatClientStructuredAgent.java    # 应用启动类
│   ├── config/
│   │   └── AiConfig.java                      # AI配置类
│   ├── controller/
│   │   └── MultiModelsController.java         # 控制器
│   └── commons/
│       ├── AiJob.java                         # 任务数据结构
│       └── JobType.java                       # 任务类型枚举
├── src/main/resources/
│   └── application.properties                 # 配置文件
└── pom.xml                                    # Maven配置

详细实现步骤

第一步:创建Maven项目

首先创建一个新的Maven项目,配置必要的依赖:

<?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>com.artisan</groupId>
        <artifactId>spring-ai-artisan</artifactId>
        <version>0.0.1</version>
    </parent>

    <artifactId>04-structured-mulit-chatclient</artifactId>
    <packaging>jar</packaging>

    <name>04-structured-mulit-chatclient</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--百炼-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId>
        </dependency>

        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

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

关键依赖说明:

  1. spring-ai-alibaba-starter-dashscope:阿里云百炼AI服务集成
  2. spring-ai-autoconfigure-model-chat-memory:聊天记忆功能
  3. spring-boot-starter-web:Web服务支持
  4. lombok:简化代码编写

第二步:定义数据结构

2.1 创建任务类型枚举

package com.artisan.commons;

public enum JobType{
    CANCEL,  // 退票任务
    QUERY,   // 查询任务
    OTHER,   // 其他任务
}

2.2 创建任务数据结构

package com.artisan.commons;

import java.util.Map;

/**
 * AiJob类用于定义AI任务相关的数据结构
 */
public class AiJob {
     /**
      * Job记录类,用于表示一个AI任务的基本信息
      * @param jobType 任务类型,指定该AI任务的分类
      * @param keyInfos 关键信息映射,存储任务相关的键值对信息
      */
     public record Job(JobType jobType, Map<String,String> keyInfos) {}
}

设计说明:

  • 使用Java Record简化数据类的定义
  • JobType枚举定义了三种任务类型:退票、查询、其他
  • keyInfos用于存储从用户输入中提取的关键信息(如姓名、订单号等)

第三步:配置AI服务

3.1 应用配置文件

spring.application.name=structured-multi-chat-client(agent)

# ali百炼
spring.ai.dashscope.api-key=${DASHSCOPE_API_KEY}

配置说明:

  • 设置应用名称为结构化多聊天客户端
  • 配置阿里云百炼的API密钥(通过环境变量设置)

3.2 AI配置类

package com.artisan.config;

import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatProperties;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiConfig {

        /**
     * 任务规划聊天客户端配置
     *
     * 该函数用于构建一个专门用于任务规划的聊天客户端,配置了特定的系统提示词、
     * 聊天内存顾问和模型参数,用于识别和拆分用户的票务相关任务。
     *
     * @param chatModel 通义千问聊天模型实例,用于实际的对话处理
     * @param options DashScope聊天配置属性,包含模型的基础配置选项
     * @param chatMemory 聊天内存管理器,用于维护对话历史状态
     * @return 配置完成的任务规划聊天客户端实例
     */
    // 任务规划
    @Bean
    public ChatClient planningChatClient(DashScopeChatModel chatModel,
                                         DashScopeChatProperties options,
                                         ChatMemory chatMemory) {
        DashScopeChatOptions dashScopeChatOptions = DashScopeChatOptions.fromOptions(options.getOptions());
        // 设置温度参数为0.4,平衡创造性和确定性
        dashScopeChatOptions.setTemperature(0.4);

        // 构建聊天客户端,配置系统提示词、内存顾问和模型选项
        return  ChatClient.builder(chatModel)
                .defaultSystem("""
                        # 票务助手任务拆分规则
                        ## 1.要求
                        ### 1.1 根据用户内容识别任务
                        
                        ## 2. 任务
                        ### 2.1 JobType:退票(CANCEL) 要求用户提供姓名和预定号, 或者从对话中提取;
                        ### 2.2 JobType:查票(QUERY) 要求用户提供预定号, 或者从对话中提取;
                        ### 2.3 JobType:其他(OTHER)
                        """)
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(chatMemory).build()
                )
                .defaultOptions(dashScopeChatOptions)
                .build();
    }


    /**
     * 创建智能客服聊天客户端Bean
     *
     * @param chatModel 聊天模型实例,用于处理对话请求
     * @param options DashScope聊天配置属性,包含模型配置选项
     * @param chatMemory 聊天记忆存储,用于保存对话历史
     * @return 配置好的ChatClient实例,用于智能客服对话
     */
    // 智能客服
    @Bean
    public ChatClient botChatClient(DashScopeChatModel chatModel,
                                    DashScopeChatProperties options,
                                         ChatMemory chatMemory) {

        // 配置DashScope聊天选项,设置温度参数以控制回复的随机性
        DashScopeChatOptions dashScopeChatOptions = DashScopeChatOptions.fromOptions(options.getOptions());
        dashScopeChatOptions.setTemperature(1.2);

        // 构建并返回聊天客户端,设置默认系统提示词、记忆顾问和配置选项
        return  ChatClient.builder(chatModel)
                .defaultSystem("""
                           你是Artisan航空智能客服代理, 请以友好的语气服务用户。
                            """)
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(chatMemory).build()
                )
                .defaultOptions(dashScopeChatOptions)
                .build();
    }
}

配置详解:

  1. planningChatClient(任务规划客户端)

    • 温度设置为0.4,确保任务分类的准确性
    • 系统提示词定义了票务助手的任务拆分规则
    • 配置了聊天记忆功能,保持对话上下文
  2. botChatClient(智能客服客户端)

    • 温度设置为1.2,增加回复的创造性
    • 系统提示词设定为友好的航空客服角色
    • 同样配置了聊天记忆功能

第四步:实现控制器

package com.artisan.controller;

import com.artisan.commons.AiJob;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
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 reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
import reactor.core.scheduler.Schedulers;

@Slf4j
@RestController
public class MultiModelsController {

    @Resource
    ChatClient planningChatClient;

    @Resource
    ChatClient botChatClient;

    /**
     * 处理流式响应的HTTP GET请求,根据用户输入的消息执行不同的AI任务
     * 使用纯Reactor响应式编程方式
     *
     * @param message 用户输入的消息内容
     * @return 返回Flux流,包含处理过程中的实时消息推送
     */
    @GetMapping(value = "/stream", produces = "text/stream;charset=UTF8")
    Flux<String> stream(@RequestParam String message) {
        
        // 使用Reactor方式处理AI调用
        return Mono.fromCallable(() -> {
            // 调用AI模型解析用户意图并获取任务对象
            return planningChatClient.prompt().user(message)
                    .call()
                    .entity(AiJob.Job.class);
        })
        .subscribeOn(Schedulers.boundedElastic()) // 在弹性调度器上执行阻塞操作
        .flatMapMany(job -> {
            // 根据任务类型执行相应的业务逻辑
            switch (job.jobType()) {
                case CANCEL -> {
                    return handleCancelJobReactive(job);
                }
                case QUERY -> {
                    return handleQueryJobReactive(job);
                }
                case OTHER -> {
                    // 直接返回AI流式响应
                    return botChatClient.prompt().user(message).stream().content();
                }
                default -> {
                    log.warn("未知的任务类型: {}", job);
                    return Flux.just("解析失败");
                }
            }
        })
        .onErrorResume(e -> {
            log.error("处理AI任务时出现异常", e);
            return Flux.just("系统繁忙,请稍后再试。");
        })
        .startWith("hi, 正在计划任务...<br/>"); // 在流开始时推送初始消息
    }

    /**
     * 响应式处理退票任务
     */
    private Flux<String> handleCancelJobReactive(AiJob.Job job) {
        log.info("处理退票任务: {}", job);
        if (job.keyInfos().isEmpty()) {
            return Flux.just("请输入姓名和订单号.");
        } else {
            // todo.. 执行业务 ticketService.cancel
            return Flux.just("退票成功!");
        }
    }

    /**
     * 响应式处理查询任务
     */
    private Flux<String> handleQueryJobReactive(AiJob.Job job) {
        log.info("处理查询任务: {}", job);
        if (job.keyInfos().isEmpty()) {
            return Flux.just("请输入订单号.");
        }
        // todo.. 执行业务 ticketService.query()
        return Flux.just("查询预定信息:xxxx");
    }

    // 传统方式实现(用于对比)
    @GetMapping(value = "/streamOrigin", produces = "text/stream;charset=UTF8")
    Flux<String> streamOrigin(@RequestParam String message) {
        // 创建一个用于接收多条消息的
        Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
        // 推送消息
        sink.tryEmitNext("正在计划任务...<br/>");

        new Thread(() -> {
            AiJob.Job job = planningChatClient.prompt().user(message)
                    .call().entity(AiJob.Job.class);

            switch (job.jobType()){
                case CANCEL ->{
                    System.out.println(job);
                    if(job.keyInfos().size()==0){
                        sink.tryEmitNext("请输入姓名和订单号.");
                    }
                    else {
                        // todo.. 执行业务  ticketService.cancel
                        // --->springai --->json
                        sink.tryEmitNext("退票成功!");
                    }
                }
                case QUERY -> {
                    System.out.println(job);
                    if(job.keyInfos().size()==0){
                        sink.tryEmitNext("请输入订单号.");
                    }
                    // todo.. 执行业务 ticketService.query()
                    sink.tryEmitNext("查询预定信息:xxxx");
                }
                case OTHER -> {
                    Flux<String> content = botChatClient.prompt().user(message).stream().content();
                    content.doOnNext(sink::tryEmitNext) // 推送每条AI流内容
                            .doOnComplete(() -> sink.tryEmitComplete())
                            .subscribe();
                }
                default -> {
                    System.out.println(job);
                    sink.tryEmitNext("解析失败");
                }
            }
        }).start();

        return sink.asFlux();
    }
}

控制器详解:

  1. 依赖注入

    • 注入两个不同的ChatClient:planningChatClientbotChatClient
    • 分别用于任务规划和智能客服
  2. 流式响应实现

    • 使用Flux<String>返回流式数据
    • 设置响应头为text/stream;charset=UTF8
  3. 响应式编程

    • 使用Mono.fromCallable()处理阻塞的AI调用
    • 通过subscribeOn(Schedulers.boundedElastic())在弹性线程池中执行
    • 使用flatMapMany()将任务对象转换为流式响应
  4. 任务路由

    • 根据AI解析的任务类型路由到相应的处理方法
    • 支持退票、查询、其他三种任务类型

第五步:创建应用启动类

package com.artisan;

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

@SpringBootApplication
public class MultiChatClientStructuredAgent
{
    /**
     * 程序入口点,启动Spring Boot应用
     *
     * @param args 命令行参数数组,用于传递启动参数
     */
    public static void main( String[] args )
    {
        SpringApplication.run(MultiChatClientStructuredAgent.class, args);
    }
}

测试和使用

环境准备

  1. 设置环境变量

    export DASHSCOPE_API_KEY=your_dashscope_api_key
    
  2. 启动应用

    mvn spring-boot:run
    

API测试

1. 退票任务测试

 http://localhost:8080/stream?message=我要退票,姓名张三,订单号12345 

在这里插入图片描述

2. 查询任务测试

 http://localhost:8080/stream?message=查询我的订单12345 

在这里插入图片描述

3. 其他任务测试

 http://localhost:8080/stream?message=你好,我想了解一下航班信息 

在这里插入图片描述

核心特性解析

1. 多聊天客户端架构

优势:

  • 职责分离:不同的ChatClient处理不同类型的任务
  • 配置灵活:可以为不同的客户端设置不同的系统提示词和参数
  • 扩展性强:易于添加新的客户端处理新的任务类型

实现要点:

// 任务规划客户端 - 低温度,确保准确性
dashScopeChatOptions.setTemperature(0.4);

// 智能客服客户端 - 高温度,增加创造性
dashScopeChatOptions.setTemperature(1.2);

2. 结构化输出

实现原理:

  • 使用Spring AI的entity()方法将AI响应解析为Java对象
  • 通过系统提示词指导AI输出符合预期格式的JSON
  • 利用Java Record简化数据类的定义

关键代码:

AiJob.Job job = planningChatClient.prompt().user(message)
        .call()
        .entity(AiJob.Job.class);

3. 流式响应

技术实现:

  • 使用Reactor的Flux实现流式数据推送
  • 通过Sinks创建可控制的流式数据源
  • 支持实时消息推送,提升用户体验

响应式编程优势:

return Mono.fromCallable(() -> {
    // 阻塞操作
    return planningChatClient.prompt().user(message)
            .call()
            .entity(AiJob.Job.class);
})
.subscribeOn(Schedulers.boundedElastic()) // 异步执行
.flatMapMany(job -> {
    // 转换为流式响应
    return handleJobReactive(job);
});

4. 任务路由机制

路由逻辑:

switch (job.jobType()) {
    case CANCEL -> return handleCancelJobReactive(job);
    case QUERY -> return handleQueryJobReactive(job);
    case OTHER -> return botChatClient.prompt().user(message).stream().content();
    default -> return Flux.just("解析失败");
}

最佳实践

1. 系统提示词设计

任务规划提示词:

  • 明确任务分类规则
  • 指定输出格式要求
  • 包含示例和边界情况处理

智能客服提示词:

  • 设定角色和语气
  • 定义服务范围
  • 保持友好和专业的语调

2. 错误处理

.onErrorResume(e -> {
    log.error("处理AI任务时出现异常", e);
    return Flux.just("系统繁忙,请稍后再试。");
})

错误处理策略:

  • 记录详细的错误日志
  • 返回用户友好的错误信息
  • 避免暴露系统内部错误

3. 性能优化

异步处理:

  • 使用subscribeOn(Schedulers.boundedElastic())处理阻塞操作
  • 避免阻塞主线程
  • 合理使用线程池资源

流式响应:

  • 及时推送处理状态
  • 避免长时间等待
  • 提供良好的用户体验

4. 扩展性设计

添加新任务类型:

  1. JobType枚举中添加新类型
  2. 在控制器中添加对应的处理逻辑
  3. 更新系统提示词以识别新任务

添加新的聊天客户端:

  1. AiConfig中配置新的ChatClient Bean
  2. 注入到控制器中
  3. 在路由逻辑中使用新的客户端

总结

本项目展示了如何使用Spring AI构建一个智能的多聊天客户端系统,主要特点包括:

  1. 架构清晰:通过多聊天客户端实现职责分离
  2. 技术先进:使用响应式编程和流式响应
  3. 扩展性强:易于添加新的任务类型和客户端
  4. 用户体验好:支持实时流式响应

这个项目为构建更复杂的AI应用提供了良好的基础架构,可以作为企业级AI应用的参考实现。

后续扩展建议

  1. 持久化存储:集成数据库存储对话历史和任务记录
  2. 用户认证:添加用户身份验证和权限控制
  3. 监控告警:集成监控系统,实时监控AI服务状态
  4. 多模型支持:支持多个AI模型提供商,提高系统可用性
  5. 缓存机制:添加缓存层,提高响应速度
  6. API文档:使用Swagger生成API文档
  7. 单元测试:添加完整的单元测试和集成测试

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐