Spring AI 简介

官网: Spring AI

Spring AI 是一个人工智能工程应用框架。其目标是将Spring生态系统的设计原则(如可移植性和模块化设计)应用于人工智能领域,并推动使用POJO作为人工智能应用的构建单元。

支持情况:目前的稳定版本是1.1.2和1.0.3,支持jdk17+ 和spring boot 3.x,当前演示版本使用的是1.1.2版本

Spring AI的主要功能

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

srping AI 详解

ChatClient 接口

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

ChatClient 接口提供了构建和配置聊天客户端对象的灵活性,以及发起和处理聊天请求的能力。用户可以通过 ChatClient.Builder 来定制客户端的行为,然后使用 prompt() 和 prompt(Prompt prompt) 方法设置请求规范,最后通过 call() 方法发起聊天请求

流式输出和非流式输出

非流式输出 call:等待大模型把回答结果全部生成后输出给用户

流式输出 stream:逐个字符输出,一方面符合大模型生成方式的本质,另一方面当模型推理效率不是很高时,流式输出比起全部生成后再输出大大提高用户体验

ChatModel 接口

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

public interface ChatModel extends Model<Prompt, ChatResponse>, StreamingChatModel {
    default String call(String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        Generation generation = this.call(prompt).getResult();
        return generation != null ? generation.getOutput().getText() : "";
    }

    default String call(Message... messages) {
        Prompt prompt = new Prompt(Arrays.asList(messages));
        Generation generation = this.call(prompt).getResult();
        return generation != null ? generation.getOutput().getText() : "";
    }

    ChatResponse call(Prompt prompt);

    default ChatOptions getDefaultOptions() {
        return ChatOptions.builder().build();
    }

    default Flux<ChatResponse> stream(Prompt prompt) {
        throw new UnsupportedOperationException("streaming is not supported");
    }
}

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

但是在实际应用程序中,更常见的是使用 ChatResponse call() 方法,该方法采用 Prompt 实例并返回 ChatResponse。我们使用的 ChatClient 底层是使用 ChatModel 作为属性的,在初始化 ChatClient 的时候可以指定 ChatModel

--ChatClient构造器
static ChatClient create(ChatModel chatModel) {
		return create(chatModel, ObservationRegistry.NOOP);
	}

	static ChatClient create(ChatModel chatModel, ObservationRegistry observationRegistry) {
		return create(chatModel, observationRegistry, null, null);
	}

提示词

提示词是引导大模型生成特定输出的输入,提示词的设计和措辞会极大地影响模型的响应结果,包括限定大模型的输出等

在 prompt 我们是可以包含多组不同角色(System、User)的信息

  • 系统提示词(System Prompt):给模型定身份、规则、风格、边界
  • 用户提示词(User Prompt):用户真正的问题 / 需求

Spring AI 提供了 Prompt Template 提示词模板管理抽象,开发者可以预先定义好模板,并在运行时替换模板中的关键词。在 Spring AI 与大模型交互的过程中,处理提示词首先要创建包含动态内容占位符 {占位符} 的模板,然后,这些占位符会根据用户请求或应用程序中的其他代码进行替换。在提示词模板中,{占位符} 可以用 Map 中的变量动态替换

    @GetMapping("/prompt")
    public String prompt(@RequestParam("name") String name) {
        String userText = "帮我介绍下java的基本概念和进阶路线";
        // 用户提示词
        UserMessage userMessage = new UserMessage(userText);
        // 系统提示词
        String systemText = "你是一个java后台开发人员,可以帮助开发人员解决java相关问题。你的名字是{name}," +
                "你应该用你的名字和java相关的知识回复用户的请求。";
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
        //使用map换占位符
        Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name));
        Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
        //获取响应结果
        ChatClient.CallResponseSpec call = chatClient.prompt(prompt).call();
        return call.content();
    }

函数(工具)调用

  • Spring AI 的函数调用 (Function Calling) 功能允许大语言模型在生成回答时触发预定义的外部函数,从而实现动态数据获取或业务逻辑操作(如查询数据库、调用 API 等)
  • pringAI 帮我们规范了函数定义、注册等过程,并在发起模型请求之前自动将函数注入到 Prompt 中,而当模型决策在合适的时候去调用某个函数时,Spring AI 完成函数调用动作,最终将函数执行结果与原始问题再一并发送给模型,模型根据新的输入决策下一步动作。这其中涉及与大模型的多次交互过程,一次函数调用就是一次完成的交互过程

函数调用的核心流程如下

  • 定义函数:声明可供模型调用的函数(名称、描述、参数结构)。
  • 模型交互:将函数信息与用户输入一起发送给模型,模型决定是否需要调用函数。
  • 执行函数:解析模型的函数调用请求,执行对应的业务逻辑。
  • 返回结果:将函数执行结果返回给模型,生成最终回答
@Configuration
public class ToolService {
    public record AddOperation(int a, int b) {

    }

    public record MulOperation(int m, int n) {

    }

    @Bean
    public Function<AddOperation, Integer> addOperation() {
        return request -> {
            System.out.println("执行加法运算");
            return request.a + request.b;
        };
    }

    @Bean
    public Function<MulOperation, Integer> mulOperation() {
        return request -> {
            System.out.println("执行乘法运算");
            return request.m * request.n;
        };
    }
}

spring AI使用zhipuAI(这里可以替换为Deepseek等其他模型)

智普AI: https://bigmodel.cn/usercenter/proj-mgmt/apikeys

pom文件

<?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.5.10</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>aidemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aidemo</name>
    <description>aidemo</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.1.2</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-zhipuai</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-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>

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

</project>

配置文件

spring.application.name=aidemo
server.port=10090
# 需要自己申请
spring.ai.zhipuai.api-key=35b030a3bffb4580a65ab66bd917a8

工具service

package com.example.aidemo.tool;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.function.Function;

@Configuration
public class ToolService {
    public record AddOperation(int a, int b) {

    }

    public record MulOperation(int m, int n) {

    }

    @Bean
    public Function<AddOperation, Integer> addOperation() {
        return request -> {
            System.out.println("执行加法运算");
            return request.a + request.b;
        };
    }

    @Bean
    public Function<MulOperation, Integer> mulOperation() {
        return request -> {
            System.out.println("执行乘法运算");
            return request.m * request.n;
        };
    }
}

AI controller

package com.example.aidemo.controller;

import org.springframework.ai.chat.client.ChatClient;
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.chat.prompt.SystemPromptTemplate;
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 java.util.List;
import java.util.Map;

@RestController
public class MyController {
    private final ChatClient chatClient;

    public MyController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    @GetMapping("/ai")
    String generation(String userInput) {
        return this.chatClient.prompt()
                .user(userInput)
                .call()
                .content();
    }

    @GetMapping(value = "/stream", produces = "text/html;charset=UTF-8")
    public Flux<String> chatStream(String userInput) {
        return chatClient.prompt().user(userInput).stream().content();
    }

    @GetMapping("/prompt")
    public String prompt(@RequestParam("name") String name) {
        String userText = "帮我介绍下java的基本概念和进阶路线";
        // 用户提示词
        UserMessage userMessage = new UserMessage(userText);
        // 系统提示词
        String systemText = "你是一个java后台开发人员,可以帮助开发人员解决java相关问题。你的名字是{name}," +
                "你应该用你的名字和java相关的知识回复用户的请求。";
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
        //使用map换占位符
        Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name));
        Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
        //获取响应结果
        ChatClient.CallResponseSpec call = chatClient.prompt(prompt).call();
        return call.content();
    }

    @GetMapping("/func")
    public String function(String userInput) {
        return chatClient.prompt()
                .system("""
                    你是算术计算器的代理。你能够支持加法运算、乘法运算等操作。
                    当用户询问数学计算时,你必须调用相应的函数或者工具来处理。
                    支持的函数或者工具列表如下:
                    - addOperation: 加法运算,需要两个数字参数,a和b
                    - mulOperation: 乘法运算,需要两个数字参数,m和n
                    调用函数的条件:
                    1. 用户明确要求计算
                    2. 问题涉及加法或乘法
                    3. 能够从问题中提取出两个数字
                    
                    请用中文回复,并在适当的时候调用函数。
                """)
                .user(userInput)
                .toolNames("addOperation", "mulOperation")
                .call()
                .content();
    }


}

AI 非流式返回

AI 流式返回

AI提示词返回

AI工具调用

Logo

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

更多推荐