Skip to content

Spring AI ​

Spring AI 概述 ​

[Spring AI](Spring AI)是一个 AI 工程领域的应用程序框架,提供开发 AI 大模型所需的模型 API,简化 AI 大模型应用的开发工作

image-20260917153420357

主要功能

  • 对主流 AI 大模型供应商提供了支持,比如:OpenAI、DeepSeek、Microsoft、Ollama、Amazon、Google HuggingFace 等。
  • 支持 AI 大模型类型包括:聊天、文本到图像、文本到声音等。
  • 支持主流的 Embedding Models(嵌入模型)和向量数据库,比如:Azure Vector Search、Chroma、Milvus、Neo4j、Redis、PineCone、PostgreSQL/PGVector 等。
  • 把 AI 大模型输出映射到简单的 Java 对象(POJOs)上。
  • 支持了函数调用(Function calling)功能。
  • 为数据工程提供 ETL(数据抽取、转换和加载)框架。
  • 支持 Spring Boot 自动配置和快速启动,便于运行 AI 模型和管理向量库。

Spring AI DeepSeek 入门 ​

引入依赖,Spring AI 2.0 支持 Spring Boot 4.x.x,以 DeepSeek 接入为例。

如果接入百炼模型,通常通过 Spring AI Alibaba 提供的方式接入,但是 Spring AI Alibaba 目前版本暂不支持 Spring AI 2.0,因此可以通过 deepseek 的方式接入百炼模型。

xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.1.1</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <java.version>17</java.version>
    <spring-ai.version>2.0.1</spring-ai.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc</artifactId>
    </dependency>
    <!-- 接入 Deepseek 模型 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-deepseek</artifactId>
    </dependency>
    <!-- 接入 Ollama 本地模型 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-ollama</artifactId>
    </dependency>
    <!-- 接入 OpenAI 模型 -->
        <!--        <dependency>-->
<!--            <groupId>org.springframework.ai</groupId>-->
<!--            <artifactId>spring-ai-starter-model-openai</artifactId>-->
<!--        </dependency>-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<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>

增加配置

yaml
spring:
  application:
    name: spring-ai-hello-demo
  ai:
    deepseek:
      api-key: sk-69fb442178ab4c13a40dd7429ca21cda
      base-url: https://api.deepseek.com
      chat:
        model: deepseek-v4-flash
        temperature: 0.8 # 用于控制 DeepSeek 模型输出随机性与创造性的核心参数,默认 1.0

测试

java
@RestController
@RequestMapping("/deepseek")
public class DeepseekController {

    @Autowired
    private DeepSeekChatModel deepSeekChatModel;

    @GetMapping("/generate")
    public String generate(@RequestParam String message) {
        String answer = deepSeekChatModel.call(message);
        System.out.println(answer);
        return answer;
    }
}

image-20260917180140654

Spring AI Ollama 本地模型 ​

Ollama 是一个用于本地化部署和管理大型语言模型(LLM)的工具。它支持多种开源模型(如 LLaMA、Alpaca 等),并提供了简单的 API 接口,方便开发者调用。Ollama 可以让你在自己的电脑上运行各种强大的 AI 模型,就像运行普通软件一样简单。

image-20260920164320641

引入依赖

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

配置

yaml
spring:
  ai:
    ollama:
      base-url: https://ollama.tintinly.top/
      chat:
        model: qwen2.5:0.5b
        temperature: 0.7

创建 ollama 聊天模型客户端

java
@Configuration
public class AiConfig {

    @Bean
    ChatClient chatClient(OllamaChatModel ollamaChatModel) {
        return ChatClient.builder(ollamaChatModel).build();
    }

}

测试

java
@RestController
@RequestMapping("/ollama")
public class OllamaController {

    private ChatClient chatClient;

    public OllamaController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping("/chat")
    public String ollama(@RequestParam String message) {
        String answer = chatClient.prompt() // 提示词
                .user(message) // 用户输入
                .call() // 请求 LLM
                .content(); // 返回文本
        System.out.println(answer);
        return answer;
    }
}

Spring AI 聊天模型 ​

ChatModel ​

ChatModel 接口作为核心,定义了与 AI 模型交互的基本方法。

java
public interface ChatModel extends Model<Prompt, ChatResponse> {
    default String call(String message) {...} 
    @Override
    ChatResponse call(Prompt prompt); 
}

在 ChatModel 接口中,带有 String 参数的 call() 方法简化了实际的使用,避免了更复杂的 Prompt 和 ChatResponse 类的复杂性。

但是在实际应用程序中,更常见的是使用返回 ChatResponse 的 call() 方法,该方法采用 Prompt 实例并返回 ChatResponse。

ChatClient 底层就是使用 ChatModel 作为属性的,在初始化 ChatClient 的时候可以指定 ChatModel,这里我们直接看底层源码:

java
public interface ChatClient {

    static ChatClient create(ChatModel chatModel) {
        return create(chatModel, ObservationRegistry.NOOP);
    }
}

简单对话 ​

java
@RestController
@RequestMapping("/deepseek")
public class DeepseekController {


    // 直接 ChatModel 调用 请求响应大模型
    @Autowired
    private DeepSeekChatModel deepSeekChatModel;

    @GetMapping("/generate")
    public String generate(@RequestParam String message) {
        String content = deepSeekChatModel.call(message);
        System.out.println(content);
        return content;
    }
}

提示词 ​

  • 提示词是引导大模型生成特定输出的输入,提示词的设计和措辞会极大地影响模型的响应结果
  • Prompt 提示词是与模型交互的一种输入数据组织方式,本质上是一种复合结构的输入,在 prompt 我们是可以包含多组不同角色(System、User、Aissistant 等)的信息。如何管理好 Prompt 是简化 AI 应用开发的关键环节。
  • Spring AI 提供了 Prompt Template 提示词模板管理抽象,开发者可以预先定义好模板,并在运行时替换模板中的关键词。在 Spring AI 与大模型交互的过程中,处理提示词首先要创建包含动态内容占位符 {占位符} 的模板,然后,这些占位符会根据用户请求或应用程序中的其他代码进行替换。在提示词模板中,{占位符} 可以用 Map 中的变量动态替换。
java
@GetMapping("/prompt")
    public String prompt(@RequestParam("name")
                         String name,
                         @RequestParam("voice")
                         String voice){
        String userText= """
            给我推荐北京的至少三种美食
            """;
        UserMessage userMessage = new UserMessage(userText);
        String systemText= """
            你是一个美食咨询助手,可以帮助人们查询美食信息。
            你的名字是{name},
            你应该用你的名字和{voice}的饮食习惯回复用户的请求。
            """;
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
        //替换占位符
        Message systemMessage = systemPromptTemplate
                .createMessage(Map.of("name", name, "voice", voice));
        Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
        List<Generation> results = chatModel.call(prompt).getResults();
        return results.stream().map(x->x.getOutput().getText()).collect(Collectors.joining(""));
    }

image-20260917190458799

ChatClient ​

ChatClient 是一个接口,它定义了一个与聊天服务交互的客户端。这个接口主要用于创建聊天客户端对象,设置请求规范,以及发起聊天请求。

简单对话 ​

java
@RestController
@RequestMapping("/deepseek")
public class DeepseekController {


    // 直接 ChatModel 调用 请求响应大模型
    @Autowired
    private DeepSeekChatModel deepSeekChatModel;

    @GetMapping("/generate")
    public String generate(@RequestParam String message) {
        String content = deepSeekChatModel.call(message);
        System.out.println(content);
        return content;
    }

    // 装配 ChatClient 调用 在ChatModel进行加强:记忆、tools、advisor
    ChatClient chatClient;

    public DeepseekController(DeepSeekChatModel deepSeekChatModel) {
        this.chatClient = ChatClient.builder(deepSeekChatModel).build();
    }

    @GetMapping(value = "/generate2")
    public String generate2(@RequestParam String message) {
        String content = chatClient.prompt().user(message).call().content();
        System.out.println(content);
        return content;
    }
}

image-20260917180015890

角色预设 ​

系统提示词:隐式 预设信息:告诉大模型干嘛的、怎么做

用户提示词:显式

java
ChatClient systemChatClient;

public DeepseekController(DeepSeekChatModel deepSeekChatModel) {
        this.systemChatClient = ChatClient.builder(deepSeekChatModel)
                .defaultSystem("""
                        你是一个 helpful的助手。
                        """)
                .build();
    }

或

java
	// 预设角色
    @GetMapping(value = "/generate-role", produces = "text/html;charset=UTF-8")
    public Flux<String> generateRole(@RequestParam String message) {
        Flux<String> content = chatClient.prompt().user(message).system("""
                你是一位中学生物老师,回答问题时请使用中学生能听懂的语言。
                语气要亲切,耐心详细地回答学生的问题。
                现在请回答学生的问题和互动。
                """).stream().content();
        return content.concatWith(Flux.just("[complete]"));
    }

image-20260917175937712

流式响应 ​

  • 非流式输出 call:等待大模型把回答结果全部生成后输出给用户;
  • 流式输出 stream:逐个字符输出,一方面符合大模型生成方式的本质,另一方面当模型推理效率不是很高时,流式输出比起全部生成后再输出大大提高用户体验。
java
// 流式响应
    @GetMapping(value = "/generate-stream", produces = "text/html;charset=UTF-8")
    public Flux<String> generateStream(@RequestParam String message) {
        Flux<String> content = chatClient.prompt().user(message).stream().content();
        return content;
    }

记忆存储 ​

ChatMemory 已自动配置 MessageWindowChatMemory,默认将数据存在 InMemoryChatMemoryRepository 中的 Map 容器中,最多存储 DEFAULT_MAX_MESSAGES=20 条数据(10 轮对话)

java
@AutoConfiguration
@ConditionalOnClass({ ChatMemory.class, ChatMemoryRepository.class })
public class ChatMemoryAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	ChatMemoryRepository chatMemoryRepository() {
		return new InMemoryChatMemoryRepository();
	}

	@Bean
	@ConditionalOnMissingBean
	ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository) {
		return MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).build();
	}

}

搭配 advisors 拦截存储数据。

java
ChatClient memoryChatClient;

public DeepseekController(DeepSeekChatModel deepSeekChatModel, ChatMemory chatMemory) {
    this.memoryChatClient = ChatClient.builder(deepSeekChatModel)
        .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
        .build();
}

需要传入 唯一标识 chat_memory_conversation_id

java
// 增加记忆
    @GetMapping(value = "/generate-memory", produces = "text/html;charset=UTF-8")
    public Flux<String> generateMemory(@RequestParam String message) {
        Flux<String> content = memoryChatClient.prompt()
                .user(message)
                .advisors(a->a.param(ChatMemory.CONVERSATION_ID, "用户id_xxx"))
                .stream().content();
        return content;
    }

这种属于短期记忆,单用户量存储对话不多,且用户量过多也会导致 OOM。

解决方法就是换存储方式,如 redis 、mongodb、数据库、neo4j

还有个问题是,token 达到上限。哪怕你解决了服务端的记忆存储上限,对话最终也会达到大模型平台的 Token 窗口限制。因此需要记忆压缩,每一轮请求前,根据 Token 大小或对话轮数决定消息是否进行压缩,精简记忆,摘要。

针对中期记忆存储。将其存入向量数据库,每次对话时,根据关键词到数据库中提取相似性记忆(相似性搜索)

针对长期记忆存储。将其存为结构化信息,key value,例如用户画像、用户偏好。AI 模型得到了处理经验,越用越好用,Harness。存入多个 markdown 文件,user-info.md,user-profile.md,memory.md

Spring AI 函数调用 Function Call ​

Spring Al 的函数调用(Function Calling)功能允许大语言模型在生成回答时触发预定义的外部函数,从而实现动态数据获取或业务逻辑操作(如查询数据库、调用 API 等)。

SpringAl 帮我们规范了函数定义、注册等过程,并在发起模型请求之前自动将函数注入到 Prompt 中,而当模型决策在合适的时候去调用某个函数时,SpringAI 完成函数调用动作,最终将函数执行结果与原始问题再一并发送给模型,模型根据新的输入决策下一步动作。这其中涉及与大模型的多次交互过程,一次函数调用就是一次完成的交互过程。

Spring AI 工具调用 Tool Call ​

Spring AI 1.0.0 M6 版本。官方将“函数调用”这个术语更新为更准确的“工具调用”,以更好地反映其让模型与外部工具/API 交互的能力。

Tool Call 概述 ​

Tool Calling 工具调用(亦称函数调用)是 AI 应用的常见模式,允许模型通过与一组 API(即工具)交互来扩展其能力。

应用场景:

  • 信息检索。此类工具可用于从外部源检索信息,例如数据库、网络服务、文件系统或网络搜索引擎,来增强模型的知识,使其能够回答原本无法回答的问题。
  • 执行操作。用于在软件系统中执行操作,调用内部系统 API ,协助完成原本需要人工的任务。

当调用发生时,大模型层通常返回一段 JSON 数据到应用层,记录了调用方法和调用参数,由 Spring AI 进行解析与通过反射调用方法。

基于注解声明 Tool ​

声明 tool

java
@Service
public class DeepSeekTools {

    @Autowired
    private DeepSeekService deepseekService;

    // @Tool告诉大模型工具是用来做什么的
    // @ToolParam 指定需要提供的参数
    @Tool(description = "查询考试分数")
    public String queryExamScore(@ToolParam String studentNum, @ToolParam String courseName) {
        return deepseekService.queryExamScore(studentNum, courseName);
    }
}

调用逻辑层方法

java
@Service
public class DeepSeekService {
    public String queryExamScore(String studentNum, String courseName) {
        System.out.println("Querying exam score for student " + studentNum + " in " + courseName + "...");
        return "85";
    }
}

客户端需要传入支持的工具类

java
ChatClient toolsChatClient;

public DeepSeekController(DeepSeekChatModel deepSeekChatModel, ChatMemory chatMemory, DeepSeekTools deepseekTools) {
    this.toolsChatClient = ChatClient.builder(deepSeekChatModel)
        .defaultSystem("你是一个经验丰富的班主任,负责班级管理。")
        .defaultAdvisors(
        MessageChatMemoryAdvisor.builder(chatMemory).build()
    )
        .defaultTools(deepseekTools)
        .build();
}

// 调用 tool
@GetMapping(value = "/generate-tool", produces = "text/html;charset=UTF-8")
public Flux<String> generateTool(@RequestParam String message) {
    Flux<String> content = toolsChatClient.prompt()
        .advisors(a->a.param(ChatMemory.CONVERSATION_ID, "用户id_xxx"))
        .user(message)
        .stream().content();
    return content;
}

image-20260921170115811

image-20260921170324100

Tool 数量 ​

建议:tool 数量限制在个位数 ,让大模型接收过多的 tool 比较占用 token,还引发较大的噪音,影响推理质量,或者容易出现调用错误的 tool。

解决:将 tool 描述 存入向量数据库,每次对话只会获取相似性高的 tool

Tool 权限 ​

Spring AI 模型上下文协议 MCP ​

MCP 定义 ​

MCP(Model Context Protocol,模型上下文协议),是 2024 年 11 月底由 Anthropic 推出的一种开放标准。旨在为大语言模型(LLM)提供统一的、标准化的方式与外部数据源和工具之间进行通信。

MCP 实践 ​

引入依赖

xml
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

Spring AI 技能 Skills ​

提示词痛点 ​

AI 应用需要提供很多能力的提示词,用来告诉大模型怎么做,有时候一个综合型的 AI 应用需要支持的功能很多,提示词便会变得很长,而用户每次使用只需要做单一的事情,其他功能提示词就等于无意义,占用了 token 窗口,同样伴随延迟问题,噪音问题。

这个问题通过 skill 可以解决,Skills 体现为一个目录结构,每个目录下包含一个 SKILL.md 文件,其中记录了技能的名称、描述和详细指令。如果不是每轮对话都需要用到的提示词,就不要放入系统提示词,而可以放入 skill 中。初次对话时,Spring AI 只会解析 skill 的名称和描述发给 LLM;直到大模型命中了才会将 skill 的详细指令全部发给大模型。

Skills 来源 ​

  • 手动写
  • 通过 AI 动态创建
  • 在平台查找通用 skill
  • 通过 AI 动态查找,例如使用叫做 Find-Skill 的 skill

Spring AI Alibaba ​

随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、Llamalndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。

因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践,通过提供一种方便的 API 抽象,帮助 Java 开发者我们加速和简化 Java 智能体应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。

Spring AI Alibaba 已完整提供 Model、Prompt、RAG、Tools 等 AI 应用开发所需的必备能力,将兼具提示词模板、函数调用、格式化输出等低层次抽象,以及 RAG、智能体、对话记忆等高层次抽象。

引入依赖(目前还未支持 springboot 4.x.x ,建议降级至 3.5.x)

xml
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-agent-framework</artifactId>
    <version>1.1.2.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    <version>1.1.2.1</version>
</dependency>

Spring AI 图像模型 ​

在 SpringAI 框架中,ImageModelAPI 旨在为与专注于图像生成的各种 AI 模型进行交互提供一个简单且可移植的接口,使开发者能够以最小的代码改动切换不同的图像相关模型。这一设计符合 Spring 模块化和互换性的理念,确保开发者可以快速调整其应用程序以适应不同的图像处理相关的 AI 能力。

Image Model API 接口及相关类

  • ImageModel 图像模型
  • ImagePrompt 图像提示
  • ImageMessage 图像消息
  • ImageOptions 图像选项
  • ImageResponse 图像响应
  • ImageGeneration 图像生成