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;
        }
    }
}
相关推荐
爻渡1 小时前
异步编程演进史:从回调到Promise再到Async/Await
后端·程序员
唐老板1 小时前
MCP协议实战:从零写个Agent工具
ai编程·mcp
counterxing1 小时前
最近发现一个 Mac 工具,有点像把 Raycast、语音输入法、截图和录屏塞到了一起
macos·ai编程·claude
薛定喵的谔2 小时前
Term Proxy — 用 Tauri 2 打造跨平台终端配置管理工具
electron·ai编程·全栈
小溪彼岸2 小时前
CC Switch可视化管理Skill、提示词、会话
aigc·ai编程
要阿尔卑斯吗2 小时前
企业级 RAG 系统的文件标签管理:三层架构与层级优化实战
后端
要阿尔卑斯吗2 小时前
Agent开发之为什么有了LangChain4j框架,我们却不能直接使用它?——桥接层设计详解
后端
用户7713970207062 小时前
从CMD到PowerShell:一个.NET开发者的命令行进化之路
后端
祎雪双十Gy2 小时前
从 DataX 的配置加载说起:我用 FastJson2 做了一个轻量级动态配置管理库
java·后端
Csvn4 小时前
Nginx 配置与运维管理 — 从安装到 SSL 反向代理
后端