Spring AI学习

46 阅读2分钟

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

添加依赖

<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

示例:

spring.ai.deepseek.api-key=YOUR_API_KEY
spring.ai.deepseek.chat.options.model=deepseek-chat
spring.ai.deepseek.chat.options.temperature=0.8

编写代码

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;
        }
    }
}