Spring Ai 从Demo到搭建套壳项目(一)初识与实现与deepseek对话模式

前言

为什么说Java长青,主要是因为其生态圈完善,Spring又做了一款脚手架,把对接各个LLM厂商的sdk做了一遍,形成一系列的spring-ai-starter-** 的依赖。 目前为止版本去到1.0.0.M6,golang跟不上了吧, Make Java Greate Again!!

我打算这个系列介绍这个spring-ai-starter和各个LLM的关系,介绍实际操作,演示一下官网的一些关键点和没讲到的细节,还有后续会讲如何使用spring-ai搭建一个套壳项目(啥是套壳项目下一章会讲),从后端,到spring-ai对接,到前端的制作。比较希望大家已经对LLM有些基础的理解。

一、技术框架

如果没有框架,你需要做什么?

  1. 你要自己写http调用代码,来分别对各个LLM模型接口(或者SDK,例如api-docs.deepseek.com/zh-cn/api/c... 的请求,等待他结果的返回,解析响应。spring-ai就同一个了接口。
  2. 还有支持Advisor,就像面向切面那样,发送请求前,检查文本有没有命中禁用词,就例如企业不允许把代码透露出去,也不允许使用某些黑词,就可以这里检查。
  3. 还有支持MCP调用能力,如果不对接spring-ai,你就要自己实现MCP协议的调用代码,来达到调用别的服务。例如:后续会实现的使用高德地图mcp,得到高德查看坐标工具,交通工具,路线规划工具,天气工具。
  4. 支持会话跟踪,如果你不接spring-ai,你还需要自己记录会话到表,或者让前端把说过的话,一次过传给后端,后端再告诉ai来做context上下文跟踪。
  5. RAG检索增强,可以通过他告诉ai又额外的一套文本,让某个LLM分析这个文本,得到你想要的答案。我觉得这个点可以用于客服话术,先拟定好话术,通过RAG解析话术的文本,当用户跟ai对话的时候,附带这个解析后的spring-ai的Document类对象,得到话术的结果。例如:设定话术用户发送一串数字,就回复"这个订单有什么问题?"

那目前市面上有什么框架呢?

  1. 目前看到的java相关的有org.springframework.ai这个group下的

    spring-ai-starter-**

这个前缀的依赖。其后缀包括open-ai, aliyun , deepseek, anthropic等,他就是整合了对多个LLM厂商的接口,统一封装,底层还是调用各个LLM厂商的SDK。

那为什么spring要封装呢?其实你看名字叫starter就知道了,一般叫starter的都是脚手架,就如springcloud,springboot那样,通过yml或者properties的配置,来实现自动装配,生成一个springbean, 方便你去调用。

yaml 复制代码
spring:
  ai:
    openai:
      api-key: ${你的key}
      base-url: ${请求openai的地址}
    deepseek:
      api-key: ${你的key}
      base-url: "https://api.deepseek.com"
      chat:
        options:
          model: deepseek-chat

如这里就固定了层级格式,让你填写地址和key就可以了。

  1. 还有alibaba提供的框架,他基于上面这个依赖做的封装,这种就是套壳

大家有没有发现上面代码需要对每个大预言模型都生成分别的api-key,所以就有人就想自己做一个统一的使用各个LLM地方,就如Cursor、Pandora,你看这些软件上,可以访问各个LLM的模型而不用对各个模型分别付费,这种统一地方的软件就是给钱包月或者按次数买1个apikey,就可以用各个LLM模型了

所以spring-ai-alibaba-stater-**系列,也是要去阿里百炼(旧名灵积)上生成一个key,就可以去使用不同的模型的一款套壳框架(bailian.console.aliyun.com/), 现在也是免费的,但他可以给你免费使用这么多个LLM也是有成本的,以后还是得收费。

二、现在就演示一下,如何对接spring-ai,并使用deepseek模型进行对话

当前先了解spring-ai这个基础框架,第三章再来演示如何对接spring-ai-alibaba版的。因为spring-ai-alibaba现在免费,你当前可以基于这个套壳框架,再套壳后,给商用起来,但是当alibaba开始收费,你又要对接各个厂商了,而且某些公司还不能用alibaba的api-key,所以spring-ai这个基础框架还是要了解的。

建立maven 工程

引入依赖,一定要使用jdk 17 ,因为springboot已经3了

xml 复制代码
<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.3.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-deepseek</artifactId>
        <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId> 
        <version>3.3.4</version>
    </dependency>

</dependencies>

spring-boot-starter-webflux这个东西就是响应式接口的关键,没有他,就没有持续输出文字的效果 spring-ai-starter-model-deepseek 这个就是spring对deepseek的封装。

配置application.xml

yaml 复制代码
server:
  port: 8081

spring:
  application:
  name: spring-ai-deepseek-chat-model-example
  ai:
    deepseek: ## 这一行是你选择的LLM模型,如果是openai,这里就填openai, base-url就是填对应厂商的地址
      api-key: ${你申请的apikey}
      base-url: "https://api.deepseek.com"
      chat:
        options:
          model: deepseek-chat
      embedding:
        enabled: false

创建主类

typescript 复制代码
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

创建Controller

less 复制代码
@RequestMapping("/openai")
@ResponseBody
@Controller
public class DeepSeekChatModelController {

    private final ChatModel deepSeekChatModel;
    
    // 主要就是这个地方,springboot已经把yml里的配置,生成好一个叫ChatModel的bean,注入进来controller里就可以直接使用了
    public DeepSeekChatModelController(ChatModel chatModel) {
        this.deepSeekChatModel = chatModel;
    }

    // 这个是同步等待LLM的结果,再回复给前端。
    @GetMapping("/simple/chat/{prompt}")
    public String simpleChat (@PathVariable(value = "prompt") String prompt) {

        return deepSeekChatModel.call(new Prompt(prompt)).getResult().getOutput().getText();
    }
    /**
     * Stream 流式调用。可以使大模型的输出信息实现打字机效果。
     * 这个就是sse方式回复内容给前端,就不用等所有的内容都收到才给前端
     * @return Flux<String> types.
     */
    @GetMapping("/stream/chat/{prompt}")
    public Flux<String> streamChat (@PathVariable(value = "prompt") String prompt,HttpServletResponse response) {
        response.setCharacterEncoding("UTF-8");
        Flux<ChatResponse> stream = deepSeekChatModel.stream(new Prompt(prompt));
        return stream.map(resp -> resp.getResult().getOutput().getText());
    }
}

实验结果

通过请求与deepseek对话,用localhost:8081/openai/simple/chat/或者localhost:8081/openai/stream/chat/ 两个接口都是可以的。

三、 但是大家有没有发现,拿不到实时数据,而是只教你怎么去拿实时数据

因为deepseek只是一个文本类搜索和推荐的工具,他的数据是一年以前的搜索库里的数据,不是最新的。 那么要如何获取最新的数据呢?请看下一章。

公------------地藏思维

相关推荐
NAGNIP5 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab6 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab6 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
点光9 小时前
使用Sentinel作为Spring Boot应用限流组件
后端
不要秃头啊10 小时前
别再谈提效了:AI 时代的开发范式本质变了
前端·后端·程序员
AngelPP10 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年10 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
有志10 小时前
Java 项目添加慢 SQL 查询工具实践
后端
九狼10 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS11 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能