SpringAI+DeepSeek大模型应用开发

目录

大模型应用开发

模型部署

模型部署方案对比

模型部署-云部署

模型部署-本地部署

调用大模型

AI应用开发技术架构

SpringAI

对话机器人-快速入门

对话机器人-会话日志

对话机器人-会话记忆

一、定义会话存储方式

二、配置会话记忆Advisor

三、添加会话id

对话机器人-会话历史记录功能

大模型应用开发

模型部署

模型部署方案对比

云部署

优点:

  • 前期成本低
  • 部署维护简单
  • 弹性扩展
  • 全球访问

缺点:

  • 数据隐私性不高
  • 网络依赖性强
  • 长期成本高
    本地部署

优点:

  • 数据安全
  • 不依赖外部部署
  • 长期成本低
  • 高度定制

缺点:

  • 初始成本高
  • 维护复杂
  • 部署周期长
    开放API

优点:

  • 前期成本极低
  • 无需部署
  • 无需维护
  • 全球访问

缺点:

  • 数据隐私性不高
  • 网络依赖性强
  • 定制限制

小型企业开发以及个人学习应用开发可以使用开放API,如果要长期使用的话,用云部署或本地部署较好。

模型部署-云部署

云平台 公司 地址
阿里百炼 阿里巴巴 https://bailian.console.aliyun.com
腾讯TI平台 腾讯 https://cloud.tencent.com/product/ti
千帆平台 百度 https://console.bce.baidu.com/gianfan/overview
SiliconCloud 硅基流动 https://siliconflow.cn/zh-cn/siliconcloud
火山方舟-火山引擎 字节跳动 https://www.volcengine.com/product/ark

模型部署-本地部署

本地部署最简单的一种方案就是使用ollama,官网地址:https://ollama.com

打开ollama的官网可以选择系统下载

左上角Models里面会有各个AI大模型

点击你要选择的大模型,下面会有许多版本让你选择,后面的1.5b,7b指的是它的算力,数值越大对电脑配置要求越高,数值最大的就是我们说的满血版,其余都是阉割版,右上角是对应使用的命令,打开命令提示符并输入指令它就会自动为你下载。

调用大模型

下面是DeepSeek官方给出的一段API示例代码:

AI应用开发技术架构

SpringAI

对话机器人-快速入门

1.引入依赖(可以在创建项目时在加入依赖时AI下边勾选对应依赖)

复制代码
    <properties>
		<java.version>17</java.version>
		<spring-ai.version>1.0.3</spring-ai.version>
	</properties>

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

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

2.配置大模型

复制代码
spring:
  application:
    name: demo
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        model: deepseek-r1:8b

3.配置客户端

复制代码
package com.example.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CommonConfiguration {

    @Bean
    public ChatClient chatClient(OllamaChatModel model) {
        return ChatClient
                .builder(model)
                .build();
    }
}

都配置好以后就能书写请求然后启动项目发送请求了

复制代码
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {

    private final ChatClient chatClient;

    @RequestMapping("/chat1")
//    阻塞式返回(全部输出完才返回)
    public String chat(String prompt) {
        return chatClient.prompt()
                .user(prompt)
                .call()
                .content();
    }

//    流式返回(输出过程中返回)
    //这里要在返回值加上 produces = "text/html;charset=utf-8",否则会乱码
    @RequestMapping(value = "/chat2", produces = "text/html;charset=utf-8")
    public Flux<String> stream(String prompt) {
        return chatClient.prompt()
                .user(prompt)
                .stream()
                .content();
    }
}

对话机器人-会话日志

SpringAI利用AOP原理提供了AI会话时的拦截、增强等功能,也就是Advisor。

SpringAI在提示词发送到AI大模型之前(②Before advising)和大模型结果产生后但是发送到用户之前(⑤After advising)进行了环绕增强,我们可以在②位置处记录提示词(作为记忆功能),在⑤处记录输出的内容(记录返回日志)。

SpringAI为我们提供了Advisor的实现,可以直接使用不需要我们自己去写。

配置日志选项并且设置日志级别为DEBUG

复制代码
@Configuration
public class CommonConfiguration {

    @Bean
    public ChatClient chatClient(OllamaChatModel model) { //创建ChatClient工厂实例
        return ChatClient
                .builder(model)
                .defaultSystem("你是皮卡丘,请以皮卡丘的视角回答")
                
                .defaultAdvisors(new SimpleLoggerAdvisor()) //配置日志Advisor
                
                .build(); //创建ChatClient实例
    }
}

#配置日志级别为debug
logging:
  level:
    org.springframework.ai.chat.client: DEBUG
    com.example.demo: DEBUG

对话机器人-会话记忆

大模型是不具备记忆能力的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与新的提示词一起发给大模型。

一、定义会话存储方式

要定义会话存储方式,可以去实现ChatMemory接口,然后重写对应方法去实现。

SpringAI也提供了一个默认的实现InMemoryChatMemory(最新1.0.3版本已经换成MessageWindowChatMemory了),但这个是存储在内存中的,服务器重启记忆就没了。

二、配置会话记忆Advisor

三、添加会话id

上面advisors里的AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY 在最新的1.0.3中已经修改为ChatMemory.CONVERSATION_ID

最后综合代码如下:

复制代码
@Configuration
public class CommonConfiguration {

    @Bean
    public ChatMemory chatMemory() {
        // 创建Memory实例
        return MessageWindowChatMemory.builder().build();
    }

    @Bean
    public ChatClient chatClient(OllamaChatModel model, ChatMemory chatMemory) { //创建ChatClient工厂实例
        return ChatClient
                .builder(model)
                .defaultSystem("你是皮卡丘,请以皮卡丘的视角回答")
                .defaultAdvisors(
                        new SimpleLoggerAdvisor(),
                        // 配置MemoryAdvisor
                        MessageChatMemoryAdvisor.builder(chatMemory).build()
                ) //配置日志Advisor
                .build(); //创建ChatClient实例
    }
}

//    流式返回(输出过程中返回)
    //这里要在返回值加上 produces = "text/html;charset=utf-8",否则会乱码
    @RequestMapping(value = "/chat2", produces = "text/html;charset=utf-8")
    //再传入一个chatId
    public Flux<String> stream(String prompt, String chatId) {
        return chatClient.prompt()
                .user(prompt)
                //这里的key值是一个固定的参数,不能随便修改
                .advisors(a -> a.param(CONVERSATION_ID, chatId) )
                .stream()
                .content();
    }
}

对话机器人-会话历史记录功能

第一个请求是要查询到对应AI会话业务下的所有会话ID,即上图中左侧列表中的两个就是该请求的返回值。 第二个请求是要根据会话类型和会话id返回用户和AI的对话记录。

我们先要写记录会话ID接口,然后再写查询会话id记录,最后根据会话id查询出具体的会话内容。

先写出记录会话记录和查询会话id记录的方法

复制代码
public interface ChatHistoryRepository {

    // 保存会话记录
    void save(String type, String chatId);

    // 获取会话ID记录
    List<String> get(String type);
}

public class InMemoryChatHistoryRepository implements ChatHistoryRepository{

    private final Map<String, List<String>> chatHistory = new HashMap<>();

    // 保存会话记录
    @Override
    public void save(String type, String chatId) {
        //先判断该类型会话是否已经存在会话id列表,如果不存在则创建一个空列表
        if (!chatHistory.containsKey(type)){
            chatHistory.put(type, List.of());
        }
        //从缓存中获取该类型会话的会话id列表
        List<String> chatHistoryList = chatHistory.get(type);
        //如果该类型列表中已经存在该会话id,则直接返回
        if (chatHistoryList.contains(chatId)){
            return;
        }
        //否则将新的会话id添加到该类型列表中
        chatHistoryList.add(chatId);
    }

//    根据会话类型获取会话ID记录
    @Override
    public List<String> get(String type) {
        List<String> chatHistoryList = chatHistory.get(type);
        //如果该类型列表不存在,则返回一个空列表
        return chatHistoryList != null ? chatHistoryList : List.of();
    }
}

在对话的时候对会话记录进行保存

我们创建实例时用的是spring ai提供的方法,我们对话的具体内容也由它进行存储记录,要查询到会话内容就要看它内部是如何查询的。

Ctrl+左键进去我们可以看到下面的方法,它需要会话id返回Message类型的集合。

进入到Message里面,我们需要看它返回的是否是我们需要的格式,Message是一个接口,里面有一个方法 getMessageType() 并且其继承了Content。

进入到 getMessageType() 方法里,其返回的是对话的角色(类型),我们只需要其中的 user(用户提问)和 assistant(ai回答)。

进入到Content中,里面的getText()方法就是获取对话具体内容的方法。

看完了spring ai提供的方法和返回格式,我们能知道其提供的格式不是我们想要的,因此我们就需要写一个VO类来编写我们需要的返回格式。

复制代码
@Data
@NoArgsConstructor
public class MessageVO {
    private String role;
    private String content;

    // 构造函数
    public MessageVO(Message message) {
        //我们从message中获取role和content
        switch (message.getMessageType()){
            //保留下来我们需要的角色
            case USER -> this.role = "user";
            case ASSISTANT -> this.role = "assistant";
            default -> this.role = "";
        }
        this.content = message.getText();
    }
}

最后我们把获取会话记录的方法写出来就完成了。

复制代码
    @GetMapping("/{type}/{chatId}")
    public List<MessageVO>  getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {
        //获取会话记录
        List<Message> messages = chatMemory.get(chatId);
        if (messages == null){
            return List.of();
        }
        return messages.stream().map(MessageVO::new).toList();
    }
相关推荐
GJGCY5 小时前
技术剖析:智能体工作流与RPA流程自动化的架构差异与融合实现
人工智能·经验分享·ai·自动化·rpa
极光JIGUANG9 小时前
GPTBots Multi-Agent架构解析:如何通过多Agent协同实现业务智能化升级
ai
知了一笑10 小时前
楼里网站开发完成,产品进入交代期
ai·项目·产品发布
Xxtaoaooo14 小时前
OCR文字识别前沿:PaddleOCR/DBNet++的端到端文本检测与识别
人工智能·ai·ocr·文本检测·dbnet++
哥布林学者15 小时前
吴恩达深度学习课程一:神经网络和深度学习 第三周:浅层神经网络 课后作业和代码实践
深度学习·ai
NocoBase15 小时前
11 个在 GitHub 上最受欢迎的开源无代码 AI 工具
低代码·ai·开源·github·无代码·ai agent·airtable·内部工具·app builder
带刺的坐椅16 小时前
LangChain4j 比 SolonAI 强在哪?弱在哪?
java·ai·langchain·solon·mcp
Kay_Liang17 小时前
大语言模型如何精准调用函数—— Function Calling 系统笔记
java·大数据·spring boot·笔记·ai·langchain·tools
从孑开始1 天前
ManySpeech.MoonshineAsr 使用指南
人工智能·ai·c#·.net·私有化部署·语音识别·onnx·asr·moonshine