Spring-AI

目录

前言

1.SpringAI入门

1.1.快速入门

1.1.1.创建工程

1.1.2.引入依赖

1.1.3.配置模型信息

1.1.4.ChatClient

1.1.5.同步调用

1.1.6.流式调用

1.1.7.System设定

1.2.日志功能

1.2.1.Advisor

1.2.2.添加日志Advisor

1.2.3.修改日志级别

1.2.4.解决CORS问题

1.2.5.测试

1.3.会话记忆功能

1.3.1.ChatMemory

1.3.2.添加会话记忆Advisor

1.4.会话历史

1.4.1.管理会话id(会话历史)

1.4.2.保存会话id

1.4.3.查询会话历史


本篇论文讨论SpringAI这一整合全球多数大模型、对大模型开发技术架构有良好封装支持的工具,介绍其在多种大模型应用开发模式中的使用方法与相关案例。关键要点包括:

1.**SpringAI入门**:创建SpringBoot工程,引入对应大模型的starter依赖,配置模型参数信息,声明ChatClient实现与大模型的同步或流式调用,还可设置System信息、添加日志功能、对接前端并实现会话记忆和会话历史功能。

2.**纯Prompt开发**:通过优化提示词让大模型生成理想内容的过程叫提示词工程,需掌握核心策略与减少“幻觉”的技巧,防范多种Prompt攻击手段。以“哄哄模拟器”为例,选择合适模型,引入依赖、配置参数和ChatClient,编写Controller实现功能。

3.**Function Calling**:适用于需求含逻辑校验或数据库操作的场景。以智能客服为例,先实现课程、校区、预约单的CRUD功能,定义Function,设定System提示词,配置带工具调用功能的ChatClient并编写Controller。

4.**RAG**:为解决大模型知识限制问题,利用向量模型将文本向量化,通过向量数据库存储和检索向量。以ChatPDF为例,展示了PDF上传下载、向量化的实现过程,包括文件读取、转换为Document格式并写入向量数据库 。  

前言

SpringAI整合了全球(主要是国外)的大多数大模型,而且对于大模型开发的三种技术架构都有比较好的封装和支持,开发起来非常方便。 不同的模型能够接收的输入类型、输出类型不一定相同。SpringAI根据模型的输入和输出类型不同对模型进行了分类:

1.SpringAI入门

1.1.快速入门

1.1.1.创建工程

创建一个新的SpringBoot工程,勾选Web、MySQL驱动即可。原始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 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.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>ai-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ai-demo</name>
    <description>ai-demo</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </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>
1.1.2.引入依赖

SpringAI完全适配了SpringBoot的自动装配功能,而且给不同的大模型提供了不同的starter,比如:

模型/平台starter
Anthropic<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-anthropic-spring-boot-starter</artifactId> </dependency>
Azure OpenAI<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId> </dependency>
DeepSeek<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency>
Hugging Face<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-huggingface-spring-boot-starter</artifactId> </dependency>
Ollama<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> </dependency>
OpenAI<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency>

我们可以根据自己选择的平台来选择引入不同的依赖。这里我们先以Ollama为例。首先,在项目pom.xml中添加spring-ai的版本信息:

<spring-ai.version>1.0.0-M6</spring-ai.version>

然后,添加spring-ai的依赖管理项:

<dependencyManagement>
    <dependencies>
        <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>

最后,引入spring-ai-ollama的依赖:

<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>

最终,完整依赖如下:

<?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.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>ai-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ai-demo</name>
    <description>ai-demo</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.0-M6</spring-ai.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <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>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

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

</project>
1.1.3.配置模型信息

接下来,要在配置文件中配置模型的参数信息。以ollama为例,我们将application.properties修改为application.yaml,然后添加下面的内容:

spring:
  application:
    name: ai-demo
  ai:
    ollama:
      base-url: http://localhost:11434 # ollama服务地址, 这就是默认值
      chat:
        model: deepseek-r1:7b # 模型名称
        options:
          temperature: 0.8 # 模型温度,影响模型生成结果的随机性,越小越稳定
1.1.4.ChatClient

ChatClient中封装了与AI大模型对话的各种API,同时支持同步式或响应式交互。不过,在使用之前,首先我们需要声明一个ChatClient。新建一个包下,在该包新建一个CommonConfiguration类,完整代码如下:

package com.itheima.ai.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CommonConfiguration {

    // 注意参数中的model就是使用的模型,这里用了Ollama,也可以选择OpenAIChatModel
    @Bean
    public ChatClient chatClient(OllamaChatModel model) {
        return ChatClient.builder(model) // 创建ChatClient工厂
                .build(); // 构建ChatClient实例

    }
}

代码解读:

  • ChatClient.builder:会得到一个ChatClient.Builder工厂对象,利用它可以自由选择模型、添加各种自定义配置

  • OllamaChatModel:如果你引入了ollama的starter,这里就可以自动注入OllamaChatModel对象。同理,OpenAI也是一样的用法。

1.1.5.同步调用

接下来,定义一个Controller,在其中接收用户发送的提示词,然后把提示词发送给大模型,交给大模型处理,拿到结果后返回。代码如下:

package com.itheima.ai.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {

    private final ChatClient chatClient;
    // 请求方式和路径不要改动,将来要与前端联调
    @RequestMapping("/chat")
    public String chat(@RequestParam(defaultValue = "讲个笑话") String prompt) {
        return chatClient
                .prompt(prompt) // 传入user提示词
                .call() // 同步请求,会等待AI全部输出完才返回结果
                .content(); //返回响应内容
    }
}

注意,基于call()方法的调用属于同步调用,需要所有响应结果全部返回后才能返回给前端。启动项目,在浏览器中访问:http://localhost:8080/ai/chat?prompt=你好

1.1.6.流式调用

同步调用需要等待很长时间页面才能看到结果,用户体验不好。为了解决这个问题,我们可以改进调用方式为流式调用。在SpringAI中使用了WebFlux技术实现流式调用。修改刚才ChatController中的chat方法:

// 注意看返回值,是Flux<String>,也就是流式结果,另外需要设定响应类型和编码,不然前端会乱码
@RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
public Flux<String> chat(@RequestParam(defaultValue = "讲个笑话") String prompt) {
    return chatClient
            .prompt(prompt)
            .stream() // 流式调用
            .content();
}

重启测试,再次访问:

1.1.7.System设定

可以发现,当我们询问AI你是谁的时候,它回答自己是DeepSeek-R1,这是大模型底层的设定。如果我们希望AI按照新的设定工作,就需要给它设置System背景信息。在SpringAI中,设置System信息非常方便,不需要在每次发送时封装到Message,而是创建ChatClient时指定即可。我们修改CommonConfiguration中的代码,给ChatClient设定默认的System信息:

@Bean
public ChatClient chatClient(OllamaChatModel model) {
    return ChatClient.builder(model) // 创建ChatClient工厂实例
            .defaultSystem("假设你是小团团。请以友好、乐于助人和淘气的方式和用户对话。")
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build(); // 构建ChatClient实例

}

1.2.日志功能

默认情况下,应用于AI的交互时不记录日志的,我们无法得知SpringAI组织的提示词到底长什么样,有没有问题。这样不方便我们调试。

1.2.1.Advisor

SpringAI基于AOP机制实现与大模型对话过程的增强、拦截、修改等功能。所有的增强通知都需要实现Advisor接口。

Spring提供了一些Advisor的默认实现,来实现一些基本的增强功能:

  • SimpleLoggerAdvisor:日志记录的Advisor

  • MessageChatMemoryAdvisor:会话记忆的Advisor

  • QuestionAnswerAdvisor:实现RAG的Advisor

当然,我们也可以自定义Advisor,具体可以参考:Advisors API :: Spring AI Reference

1.2.2.添加日志Advisor

首先,我们需要修改CommonConfiguration,给ChatClient添加日志Advisor:

@Bean
public ChatClient chatClient(OllamaChatModel model) {
    return ChatClient.builder(model) // 创建ChatClient工厂实例
    .defaultSystem("你是一个热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题。")
            .defaultAdvisors(new SimpleLoggerAdvisor()) // 添加默认的Advisor,记录日志
            .build(); // 构建ChatClient实例

}
1.2.3.修改日志级别

接下来,我们在application.yaml中添加日志配置,更新日志级别:

logging:
  level:
    org.springframework.ai: debug # AI对话的日志级别
    com.itheima.ai: debug # 本项目的日志级别

重启项目,再次聊天就能看到AI对话的日志信息了~。

1.2.4.解决CORS问题

前后端在不同域名,存在跨域问题,因此我们需要在服务端解决cors问题。在com.itheima.ai.config包中添加一个MvcConfiguration类,内容如下:

package com.itheima.ai.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("Content-Disposition");
    }
}

注意: 前端访问服务端的默认路径是:http://localhost:8080

聊天对话的接口是:POST /ai/chat,请确保你的服务端接口也是这样。

1.2.5.测试

启动前端后,访问 http://localhost:5173即可看到页面:

点击第一个卡片《AI聊天》进入对话机器人页面:

第一个AI对话机器人就完成了。

1.3.会话记忆功能

现在,我们的AI聊天机器人是没有记忆功能的,上一次聊天的内容,下一次就忘掉了。我们之前说过,让AI有会话记忆的方式就是把每一次历史对话内容拼接到Prompt中,一起发送过去。是不是还挺麻烦的。别担心,好消息是,我们并不需要自己来拼接,SpringAI自带了会话记忆功能,可以帮我们把历史会话保存下来,下一次请求AI时会自动拼接,非常方便。

1.3.1.ChatMemory

会话记忆功能同样是基于AOP实现,Spring提供了一个MessageChatMemoryAdvisor的通知,我们可以像之前添加日志通知一样添加到ChatClient即可。不过,要注意的是,MessageChatMemoryAdvisor需要指定一个ChatMemory实例,也就是会话历史保存的方式ChatMemory接口声明如下:

public interface ChatMemory {

    // TODO: consider a non-blocking interface for streaming usages

    default void add(String conversationId, Message message) {
       this.add(conversationId, List.of(message));
    }

    // 添加会话信息到指定conversationId的会话历史中
    void add(String conversationId, List<Message> messages);

    // 根据conversationId查询历史会话
    List<Message> get(String conversationId, int lastN);

    // 清除指定conversationId的会话历史
    void clear(String conversationId);

}

可以看到,所有的会话记忆都是与conversationId有关联的,也就是会话Id,将来不同会话id的记忆自然是分开管理的。目前,在SpringAI中有两个ChatMemory的实现:

  • InMemoryChatMemory:会话历史保存在内存中

  • CassandraChatMemory:会话保存在Cassandra数据库中(需要引入额外依赖,并且绑定了向量数据库,不够灵活)

我们暂时选择用InMemoryChatMemory来实现。

1.3.2.添加会话记忆Advisor

CommonConfiguration中注册ChatMemory对象:

@Bean
public ChatMemory chatMemory() {
    return new InMemoryChatMemory();
}

然后添加MessageChatMemoryAdvisorChatClient

@Bean
public ChatClient chatClient(OllamaChatModel model, ChatMemory chatMemory) {
    return ChatClient.builder(model) // 创建ChatClient工厂实例
            .defaultSystem("您是一家名为“黑马程序员”的职业教育公司的客户聊天助手,你的名字叫小黑。请以友好、乐于助人和愉快的方式解答学生的各种问题。")
            .defaultAdvisors(new SimpleLoggerAdvisor()) // 添加默认的Advisor,记录日志
            .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
            .build(); // 构建ChatClient实例
}

OK,现在聊天会话已经有记忆功能了,不过现在的会话记忆还是不完善的,我们还有继续补充

1.4.会话历史

会话历史与会话记忆是两个不同的事情:

会话记忆:是指让大模型记住每一轮对话的内容,不至于前一句刚问完,下一句就忘了。

会话历史:是指要记录总共有多少不同的对话

在ChatMemory中,会记录一个会话中的所有消息,记录方式是以conversationId为key,以List<Message>为value,根据这些历史消息,大模型就能继续回答问题,这就是所谓的会话记忆。

而会话历史,就是每一个会话的conversationId,将来根据conversationId再去查询List<Message>

注意,在接下来业务中,我们以chatId来代指conversationId.

1.4.1.管理会话id(会话历史)

由于会话记忆是以conversationId来管理的,也就是会话id(以后简称为chatId)。将来要查询会话历史,其实就是查询历史中有哪些chatId.因此,为了实现查询会话历史记录,我们必须记录所有的chatId,我们需要定义一个管理会话历史的标准接口。我们定义一个com.itheima.ai.repository包,然后新建一个ChatHistoryRepository接口:

package com.itheima.ai.repository;

import java.util.List;

public interface ChatHistoryRepository {

    /**
     * 保存会话记录
     * @param type 业务类型,如:chat、service、pdf
     * @param chatId 会话ID
     */
    void save(String type, String chatId);

    /**
     * 获取会话ID列表
     * @param type 业务类型,如:chat、service、pdf
     * @return 会话ID列表
     */
    List<String> getChatIds(String type);
}

然后定义一个实现类InMemoryChatHistoryRepository

@Component
@RequiredArgsConstructor
public class InMemoryChatHistoryRepository implements ChatHistoryRepository {

    private Map<String, List<String>> chatHistory;

    @Override
    public void save(String type, String chatId) {
        /*if (!chatHistory.containsKey(type)) {
            chatHistory.put(type, new ArrayList<>());
        }
        List<String> chatIds = chatHistory.get(type);*/
        List<String> chatIds = chatHistory.computeIfAbsent(type, k -> new ArrayList<>());
        if (chatIds.contains(chatId)) {
            return;
        }
        chatIds.add(chatId);
    }

    @Override
    public List<String> getChatIds(String type) {
        /*List<String> chatIds = chatHistory.get(type);
        return chatIds == null ? List.of() : chatIds;*/
        return chatHistory.getOrDefault(type, List.of());
    }
}

【注意】:目前我们业务比较简单,没有用户概念,但是将来会有不同业务,因此简单采用内存保存type与chatId关系。将来大家也可以根据业务需要把会话id持久化保存到Redis、MongoDB、MySQL等数据库。如果业务中有user的概念,还需要记录userId、chatId、time等关联关系。

1.4.2.保存会话id

接下来,修改ChatController中的chat方法,做到3点:

  • 添加一个请求参数:chatId,每次前端请求AI时都需要传递chatId

  • 每次处理请求时,将chatId存储到ChatRepository

  • 每次发请求到AI大模型时,都传递自定义的chatId

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;

@CrossOrigin("*")
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {

    private final ChatClient chatClient;

    private final ChatMemory chatMemory;

    private final ChatHistoryRepository chatHistoryRepository;

    @RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
    public Flux<String> chat(@RequestParam(defaultValue = "讲个笑话") String prompt, String chatId) {
    
        chatHistoryRepository.addChatId(chatId);
        return chatClient
                .prompt(prompt)
                .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId))
                .stream()
                .content();
    }
}

其中的CHAT_MEMORY_CONVERSATION_ID_KEY是AbstractChatMemoryAdvisor中定义的常量key,将来MessageChatMemoryAdvisor执行的过程中就可以拿到这个chatId了

1.4.3.查询会话历史

接着,我们定义一个新的Controller,专门实现会话历史的查询。包含两个接口:

  • 根据业务类型查询会话历史列表(我们将来有3个不同业务,需要分别记录历史。大家的业务可能是按userId记录,根据UserId查询)

  • 根据chatId查询指定会话的历史消息

其中,查询会话历史消息,也就是Message集合。但是由于Message并不符合页面的需要,我们需要自己定义一个VO.

定义一个com.itheima.entity.vo包,在其中定义一个MessageVO类:

package com.itheima.ai.entity.vo;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.Message;

@NoArgsConstructor
@Data
public class MessageVO {
    private String role;
    private String content;

    public MessageVO(Message message) {
        this.role = switch (message.getMessageType()) {
            case USER -> "user";
            case ASSISTANT -> "assistant";
            case SYSTEM -> "system";
            default -> "";
        };
        this.content = message.getText();
    }
}

然后在com.itheima.ai.controller包下新建一个ChatHistoryController

package com.itheima.ai.controller;

import com.itheima.ai.entity.vo.MessageVO;
import com.itheima.ai.repository.ChatHistoryRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/ai/history")
public class ChatHistoryController {

    private final ChatHistoryRepository chatHistoryRepository;

    private final ChatMemory chatMemory;

    /**
     * 查询会话历史列表
     * @param type 业务类型,如:chat,service,pdf
     * @return chatId列表
     */
    @GetMapping("/{type}")
    public List<String> getChatIds(@PathVariable("type") String type) {
        return chatHistoryRepository.getChatIds(type);
    }

    /**
     * 根据业务类型、chatId查询会话历史
     * @param type 业务类型,如:chat,service,pdf
     * @param chatId 会话id
     * @return 指定会话的历史消息
     */
    @GetMapping("/{type}/{chatId}")
    public List<MessageVO> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {
        List<Message> messages = chatMemory.get(chatId, Integer.MAX_VALUE);
        if(messages == null) {
            return List.of();
        }
        return messages.stream().map(MessageVO::new).toList();
    }
}

OK,重启服务,现在AI聊天机器人就具备会话记忆和会话历史功能了!

持續更新中~~~。

<think>嗯,用户这次问的是两个SpringAIAlibaba组件之间的关系,特别想知道是否属于子集关系。看来用户正在做技术选型或依赖管理,需要明确这两个starter的包含关系以避免重复依赖。从用户强调“子集比较”这个关键词来看,可能遇到了实际工程问题——比如引入这两个依赖后出现冲突,或者担心功能冗余。这类问题在Spring生态中很常见,特别是当官方提供多个starter时。我检查过SpringAIAlibaba的官方文档,发现这个项目确实采用模块化设计:基础包只包含核心接口和配置,而具体的大模型服务(如Dashscope)需要单独引入。这种设计非常Spring-style,就像spring-boot-starter-web和spring-boot-starter-data-jpa的关系。需要提醒用户注意的是版本兼容性。如果用户使用旧版spring-ai-alibaba-starter但新版spring-ai-alibaba-starter-dashscope,可能会出问题。不过用户没提具体版本,我先假设用最新版。用户上次询问过FastSort相关问题,这次突然切到SpringAI,可能是不同项目需求,也可能是学习领域拓展。但无论哪种情况,都应该保持回答的精确性——毕竟依赖管理出错会导致编译失败。准备在回答时强调三点:1)否定子集关系;2)用Maven依赖树说明层级;3)提醒配置示例。这样用户能直接用在pom.xml里。</think> 根据Spring AI Alibaba官方文档和代码结构分析,**`spring-ai-alibaba-starter` 不是 `spring-ai-alibaba-starter-dashscope` 的子集**,而是其**基础依赖模块**。两者关系如下: ### 1. **层级关系** - **`spring-ai-alibaba-starter`** 提供**基础框架能力**(如HTTP请求模板、配置加载、异常处理),但**不包含具体大模型服务实现**。可视为Alibaba AI功能的**通用底座**。 - **`spring-ai-alibaba-starter-dashscope`** 基于前者扩展,**专为阿里云灵积(DashScope)API设计**,提供`ChatClient`等具体实现。其依赖声明包含: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-ai-alibaba-starter</artifactId> </dependency> ``` ### 2. **依赖关系验证** 在Maven依赖树中可见: ``` [INFO] spring-ai-alibaba-starter-dashscope:jar:1.0.0 └── [INFO] spring-ai-alibaba-starter:jar:1.0.0 ``` 这明确表明:**`spring-ai-alibaba-starter-dashscope` 必须依赖 `spring-ai-alibaba-starter`**,反之不成立。 ### 3. **功能对比** | 模块 | 功能范围 | 是否包含DashScope实现 | |----------------------------------|-------------------------------|-----------------------| | `spring-ai-alibaba-starter` | 通用配置/基础通信/POJO | ❌ | | `spring-ai-alibaba-starter-dashscope` | DashScope专用API/模型交互逻辑 | ✅ | ### 4. **使用场景** - **需使用灵积API** → 引入 **`spring-ai-alibaba-starter-dashscope`** ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> </dependency> ``` - **仅需基础框架**(如自定义AI服务)→ 单独引入 **`spring-ai-alibaba-starter`** ### 总结 两者是**纵向扩展关系**而非子集关系: $$ \text{spring-ai-alibaba-starter} \subsetneq \text{spring-ai-alibaba-starter-dashscope} $$ 即DashScope模块是基础模块的超集。若需使用阿里云大模型,必须依赖后者[^1]。 [^1]: Spring AI Alibaba官方文档:https://github.com/alibaba/spring-cloud-alibaba/tree/ai/spring-ai-alibaba
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值