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;
        }
    }
}
相关推荐
mCell1 小时前
用 Knip 清理 AI Coding 留下的冗余代码
前端·ai编程·前端工程化
名字还没想好☜1 小时前
Go context.AfterFunc 实战(Go 1.21):context 一取消就自动跑清理,告别手写 goroutine 监听 Done
后端·golang·go
明月_清风2 小时前
为什么最近开始关注 JEV?几个实战案例告诉你答案
人工智能·后端
GetcharZp3 小时前
5 分钟拥有自己的 S3:RustFS 上手(MinIO 的 Rust 替代,Apache 2.0 可商用)
后端
杨杨杨大侠3 小时前
RAG 到底是怎么工作的?从用户提问到模型回答的完整链路
spring·openai·ai编程
行百里er3 小时前
Redis 版本演进、新特性与协议那些事儿
redis·后端
Joy T4 小时前
Spring AI 2.0 Agent 进阶:Memory、State 与 Context Engineering 常见技术全景
java·人工智能·后端·spring·agent入门·agent state
打工仔折腾 AI4 小时前
FastAPI 从本机到生产服务器:Nginx+Gunicorn+Uvicorn 完整部署实录
人工智能·后端·python·nginx·fastapi·gunicorn
IT_陈寒4 小时前
Java空指针这次真把我坑惨了
前端·人工智能·后端