Spring AI学习

spring 的ai是一个应用框架,它可以帮助开发者快速构建智能应用。

模型(models)

一种算法,用于生成信息,常见模型有:

  • LLM(Large Language Model)
  • Embedding
  • image generation
  • text-to-voice / voice-to-text

提示符(prompt)

一种文本,用于指导模型生成信息

有多种文本输入,每种都被指派一个角色,例如:

  • system:系统角色,用于指导模型的行为
  • user:用户角色,来自用户的输入

token

AI模型处理的最小单位

在英文中,一个token相当于已给单词的75%

举个例子,莎士比亚的作品,大概90万个单词,大约需要120万个token

实践

接入deepseek聊天模型

环境准备

  • 版本选择
    Spring AI 支持 Spring Boot 3.4.x and 3.5.x.
    jdk 17+
  • API key
    在deepseek官网注册账号,获取API key

添加依赖

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

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

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

配置参数

配置参数详见:chat_properties

示例:

properties 复制代码
spring.ai.deepseek.api-key=YOUR_API_KEY
spring.ai.deepseek.chat.options.model=deepseek-chat
spring.ai.deepseek.chat.options.temperature=0.8

编写代码

java 复制代码
package com.example.demo.conroller;

import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekAssistantMessage;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
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.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
public class ChatController {

    private final DeepSeekChatModel chatModel;
    // 存储对话历史
    private final Map<String, List<Message>> conversationMap = new ConcurrentHashMap<>();

    @Autowired
    public ChatController(DeepSeekChatModel chatModel) {
        this.chatModel = chatModel;
    }

    // 单轮对话
    @GetMapping("/ai/generate")
    public Flux<String> generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return chatModel.stream(message);
    }

    @GetMapping("/ai/generateStream")
    public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        var prompt = new Prompt(new UserMessage(message));
        return chatModel.stream(prompt);
    }

    // 多轮对话
    @GetMapping("/ai/generateMultiRoundStream")
    public Flux<String> generateMultiRoundStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message,String conversationId) {
        if(!StringUtils.hasText(conversationId)){
            conversationId = System.currentTimeMillis()+"";
        }
        // 获取当前对话的历史对话
        List<Message> messages = getMessage(conversationId);
        // 添加用户消息
        messages.add(new UserMessage(message));

        // 设置模型类型 DEEPSEEK_REASONER 推导模型
        DeepSeekChatOptions promptOptions = DeepSeekChatOptions.builder()
                .model(DeepSeekApi.ChatModel.DEEPSEEK_REASONER.getValue())
                .build();

        // 创建提示符
        var prompt = new Prompt(messages, promptOptions);
        StringBuffer sb = new StringBuffer();
        return chatModel.stream(prompt).map(chatResponse -> {
            // 获取响应中的文本
            DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) chatResponse.getResult().getOutput();
            String text = deepSeekAssistantMessage.getText();
            if(StringUtils.hasText(text)){
                sb.append(text);
            }else{
                text = "";
            }
            return text;
        }).doAfterTerminate(() -> {
            // 把返回的消息添加到对话历史中
            messages.add(new AssistantMessage(sb.toString()));});
    }

    private List<Message> getMessage(String conversationId) {
        List<Message> messages = conversationMap.get(conversationId);
        if(CollectionUtils.isEmpty(messages)){
            ArrayList<Message> list = new ArrayList<>();
            conversationMap.put(conversationId, list);
            return list;
        }else{
            return messages;
        }
    }
}
相关推荐
ServBay9 分钟前
WordPress 核心漏洞 wp2shell,波及超 5 亿网站
后端·php
Jackson__1 小时前
问到你想清楚,这个 skill 专治没想明白就写代码!
前端·github·ai编程
分布式存储与RustFS1 小时前
RustFS Beta.10 性能解读:PUT 全面反超 MinIO,Rust 重写对象存储成了?
开发语言·后端·rust
Reart1 小时前
Leetcode 309.买卖股票的最佳时期含冷冻期(你也想成为股票高手吗o〃ω〃o,718)
后端
Reart1 小时前
Leetcode 188.买卖股票的最佳时机4(718)
后端·算法
Reart2 小时前
Leetcode 123.买卖股票的最佳时期3(内有随心谈,718)
后端·算法
只与明月听2 小时前
LangChain 学习-掌握LangChain Core API
前端·人工智能·后端
无相求码2 小时前
数组越界为什么有时候不崩溃?VS2013 下栈上变量的幽灵布局解密
c语言·后端
KylinLab2 小时前
TRAE Work 沙箱文件系统隔离机制深度解析:从三个诡异 Bug 到正确工作流
ai编程
HONG````4 小时前
HarmonyOS ArkUI Image 组件完全指南:objectFit、占位图与加载回调
后端