Day1-SpringAI-1.0.0版本

**引言:**SpringAI支持SpringBoot3.2.x版本和SpringBoot3.3.x版本。

1.SpringAI案例:

第一步已入SpringAI依赖:

html 复制代码
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <spring-ai.version>1.0.0-M5</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-openai-spring-boot-starter</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>

第二步建立Controller:

ChatModel是继承了OpenAiChatModel这个类,这里我们直接使用OpenAiChatModel。

java 复制代码
@RestController
public class DeepSeekController {

    @Autowired
    private OpenAiChatModel chatModel;

    @GetMapping("/hello")
    public String hello(@RequestParam(value = "message", defaultValue = "hello")
                            String message) {
        String result = chatModel.call(message);
        System.out.println(result);
        return  result;
    }
}

第三步创建properties文件:

java 复制代码
server.port=8881
spring.application.name=deepseek-demo

spring.ai.openai.api-key=在deepseek开放平台申请自已的API
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.options.model=deepseek-chat
#值越高,生成文本越多样化,但也可能包含刚多的随机性和不可预测的内容
#值越低,生成文本越接近确定性的结果,即生成的文本会更加一致和可预测。
spring.ai.openai.chat.options.temperature=0.7

2.ChatClient:

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

java 复制代码
@RestController
public class ChatController {

    //注入,通过构造方法
    
    private final ChatClient chatClient;
    
    public ChatController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    //1 实现简单对话功能
    
    @GetMapping("/chat")
    public String chat(@RequestParam(value = "msg",defaultValue = "你是谁")
                           String message) {
        return chatClient.prompt()    //提示词
                .user(message) //用户输入信息
                .call() //请求大模型
                .content(); //返回文本
    }
}

模型会根据prompt来回应或响应你的要求。

每个大模型都有自已的角色预设,但是我们可以通过配置进行1角色预设。

那么我们就可以写一个配置类:

java 复制代码
@Configuration
public class AiConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder.defaultSystem("你是一位六级英语老师,你精通六级英语," +
                "你的名字叫隔壁老王。").build();
    }
}

创建一个新的Controller:

call和stream的区别,一个是非流式输出,一个是流式输出。

流式输出对于用户的体验更好。

java 复制代码
@RestController
public class ChatAiController {

    @Resource
    private ChatClient chatClient;

    //角色预设,使用非流式响应

    @GetMapping("/chatai")
    public String chatAi(@RequestParam(value = "msg") String message) {
        return chatClient.prompt().user(message).call().content();
    }

    //角色预设,使用流式响应

    @GetMapping(value = "/chataiStream",produces = "text/html;charset=UTF-8")//设置UTF-8防止乱码
    public Flux<String> chatAiStream(@RequestParam(value = "msg") String message) {
        return chatClient.prompt().user(message).stream().content();
    }
}
java 复制代码
@RestController
public class ChatModelController {

    @Resource
    private ChatModel chatModel;

    //提示词操作
    // name:名字
    // voice: 习惯

    @GetMapping("/prompt")
    public String prompt(@RequestParam("name")
                         String name,
                         @RequestParam("voice")
                         String voice) {
        //设置用户输入信息
        String userText = """
                给我推荐广州的至少三种美食
                """;
        UserMessage userMessage = new UserMessage(userText);

        //设置系统提示信息
        String systemText = """
                你是一个美食咨询助手,可以帮助人们查询美食信息。
                你的名字是{name},
                你应该用你的名字和{voice}的饮食习惯回复用户的请求。
                """;
        //使用Prompt Template 设置信息
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);

        //替换占位符
        Message systemMessage =
                systemPromptTemplate
                        .createMessage(Map.of("name", name, "voice", voice));

        //使用Prompt封装
        Prompt prompt = new Prompt(List.of(userMessage, systemMessage));

        //调用chatModel方法
        ChatResponse response = chatModel.call(prompt);
        List<Generation> results = response.getResults();
        return
                results.stream().map(x -> x.getOutput().getContent())
                        .collect(Collectors.joining(""));
    }

    //String call(String message)

    @GetMapping("/chatModel01")
    public String chatModel01(@RequestParam("msg") String msg) {
        return chatModel.call(msg);

    }

    //ChatResponse call(Prompt prompt);

    @GetMapping("/chatModel02")
    public String chatModel02(@RequestParam("msg") String msg) {
        ChatResponse chatResponse = chatModel.call(
                new Prompt(
                        msg,
                        OpenAiChatOptions.builder()
                                .model("deepseek-chat")
                                .temperature(0.8)
                                .build()
                )
        );
        return chatResponse.getResult().getOutput().getContent();

    }
}

ChatModel接口作为核心,定义了与AI模型交互的基本方法。他继承自Model<Prompt,ChatResponse>,提供了两个重载的call方法。

ChatModel中重载的两个call方法:

java 复制代码
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");
    }
}

3、Prompt提示词工程:

使用ChatModel。

java 复制代码
@RestController
public class ChatModelController {

    @Resource
    private ChatModel chatModel;


    //String call(String message)

    @GetMapping("/chatModel01")
    public String chatModel01(@RequestParam("msg") String msg) {
        return chatModel.call(msg);

    }

    //ChatResponse call(Prompt prompt);

    @GetMapping("/chatModel02")
    public String chatModel02(@RequestParam("msg") String msg) {
        ChatResponse chatResponse = chatModel.call(
                new Prompt(
                        msg,
                        OpenAiChatOptions.builder()
                                .model("deepseek-chat")
                                .temperature(0.8)
                                .build()
                )
        );
        return chatResponse.getResult().getOutput().getContent();

    }
}

以下是Prompt类的源码中的构造方法:

java 复制代码
public class Prompt implements ModelRequest<List<Message>> {
    private final List<Message> messages;
    private ChatOptions chatOptions;

    public Prompt(String contents) {
        this((Message)(new UserMessage(contents)));
    }

    public Prompt(Message message) {
        this(Collections.singletonList(message));
    }

    public Prompt(List<Message> messages) {
        this((List)messages, (ChatOptions)null);
    }

    public Prompt(Message... messages) {
        this((List)Arrays.asList(messages), (ChatOptions)null);
    }

    public Prompt(String contents, ChatOptions chatOptions) {
        this((Message)(new UserMessage(contents)), chatOptions);
    }

    public Prompt(Message message, ChatOptions chatOptions) {
        this(Collections.singletonList(message), chatOptions);
    }

    public Prompt(List<Message> messages, ChatOptions chatOptions) {
        this.messages = messages;
        this.chatOptions = chatOptions;
    }
}

提示词是引导大模型生成特定的输出的输入会极大地影响大模型的输出的内容。

SpringAI提供了Prompt Templete模板设置提示词信息,prompt可以包含多组不同的就角色(system,user,Aissitant)等。

处理提示词首先要创建包含动态内容占位符的模板,占位符可以用Map中的变量动态替换。

java 复制代码
@RestController
public class ChatModelController {

    @Resource
    private ChatModel chatModel;

    //提示词操作
    // name:名字
    // voice: 习惯

    @GetMapping("/prompt")
    public String prompt(@RequestParam("name")
                         String name,
                         @RequestParam("voice")
                         String voice) {
        //设置用户输入信息
        String userText = """
                给我推荐广州的至少三种美食
                """;
        UserMessage userMessage = new UserMessage(userText);

        //设置系统提示信息
        String systemText = """
                你是一个美食咨询助手,可以帮助人们查询美食信息。
                你的名字是{name},
                你应该用你的名字和{voice}的饮食习惯回复用户的请求。
                """;
        //使用Prompt Template 设置信息
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);

        //替换占位符
        Message systemMessage =
                systemPromptTemplate
                        .createMessage(Map.of("name", name, "voice", voice));

        //使用Prompt封装
        Prompt prompt = new Prompt(List.of(userMessage, systemMessage));

        //调用chatModel方法
        ChatResponse response = chatModel.call(prompt);
        List<Generation> results = response.getResults();
        return
                results.stream().map(x -> x.getOutput().getContent())
                        .collect(Collectors.joining(""));
    }
}

4.SpringAI函数调用

SpringAI的函数调用功能允许大模型在生成回答时允许调用外部准备好的外部函数。从而实现动态数据获取或业务逻辑操作。

函数调用实现:首先在配置包下创建需要用到的函数:

java 复制代码
@Configuration
public class CalculatorService {
    public record AddOperation(int a, int b) {

    }

    public record MulOperation(int m, int n) {

    }

    //注册方法

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

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

chatclient的配置类不变:

java 复制代码
@Configuration
public class AiConfig {
    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder.defaultSystem("你是一位六级英语老师,你精通六级英语," +
                "你的名字叫隔壁老王。").build();
    }
}

编写controller:

java 复制代码
@RestController
public class FunctionController {

    @Resource
    private ChatModel chatModel;

    @GetMapping(value = "/function",produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public String function01(@RequestParam("userMessage") String userMessage) {
        return ChatClient.builder(chatModel) //ChatClient的底层就是ChatModel
                .build().prompt()
                .system("""
         您是算术计算器的代理。
         您能够支持加法运算、乘法运算等操作,其余功能将在后续版本中添加,如果用户问的问题不支持请告        知详情。在提供加法运算、乘法运算等操作之前,您必须从用户处获取如下信息:两个数字,运算类型。
         请调用自定义函数执行加法运算、乘法运算。
         请讲中文。
         """)
                .user(userMessage)
                .functions("addOperation", "mulOperation")
                .call()
                .content();
    }
}

produces = MediaType.APPLICATION_STREAM_JSON_VALUE定义返回类型。

今天是SpringAI1.0.0版本介绍。

相关推荐
ZC跨境爬虫1 小时前
跟着 MDN 学CSS day_42:等分轨道、层叠放置与混合布局
前端·javascript·css·ui·html
Cheney95011 小时前
Vue 项目字体文件打包后 fonts 文件夹“消失”?原因分析与解决方案
前端·javascript·vue.js
老码观察1 小时前
设计模式实战解读(九):责任链模式——流水线上层层把关的艺术
java·设计模式·责任链模式
郝学胜-神的一滴1 小时前
Qt 高级开发 021:零基础吃透 QVBoxLayout 垂直布局
开发语言·c++·qt·程序人生·用户界面
问心无愧05131 小时前
ctf show web入门68,69
android·前端·笔记
basketball6161 小时前
C++进阶:2. std::move 和 std::forward 函数
java·开发语言·c++
jingling5551 小时前
Flutter | 从基本跳转到路由守卫
服务器·前端·网络·flutter·前端框架
_oP_i1 小时前
105、word 出现 {TOCO“1-2“HZ}
开发语言·c#·word
yong99901 小时前
基于MATLAB的雷达数字信号处理
开发语言·matlab·信号处理