Spring AI实战:使用Java对接DeepSeek等大模型

Spring AI简化Java大模型应用开发,通过统一API对接DeepSeek等模型,实现流式响应和监控,助力企业智能化。

原文标题:Spring AI 实战|Spring AI入门之DeepSeek调用

原文作者:阿里云开发者

冷月清谈:

本文介绍了如何使用Spring AI框架,通过Java方式调用DeepSeek等大模型,简化AI应用开发流程。首先阐述了Spring AI的核心能力,包括通过统一的Java对象封装大模型调用,降低开发复杂度。 接着,详细讲解了如何手动和自动地通过代码对接DeepSeek API,以及如何利用Reactor框架实现流式响应,优化用户体验。最后,解释了Spring AI如何通过“可移植API”设计,兼容不同的AI服务,并介绍了如何为AI应用添加监控,为生产环境提供保障。

怜星夜思:

1、Spring AI宣称可以一套代码多处使用,那么在实际项目中,如果需要对不同大模型返回的内容进行定制化处理,该如何优雅地实现呢?会不会导致代码变得臃肿?
2、文章提到了Spring AI可以兼容OpenAI的API规范,那么如果我想使用一些DeepSeek或者通义千问特有的功能,Spring AI是否支持?如果不支持,有没有什么替代方案?
3、文章最后提到了给AI应用装上监控,那么除了监控API的调用次数和耗时,还有哪些指标是我们在生产环境中需要重点关注的?

原文内容

引言:当Spring遇上AI,会擦出怎样的火花?

作为一名Java开发者,是否曾经眼红Python阵营那些花里胡哨的AI应用?是否在对接各种大模型API时,被五花八门的接口规范搞得头大?好消息是,Spring家族的新成员——Spring AI,正在用Java开发者最熟悉的方式,为我们打开AI应用开发的新世界大门。

一、Spring AI初探 - 你的AI管家

1.1 为什么需要Spring AI?

场景假设

  • 你的老板说:"我们要做个智能客服,先用OpenAI,下个月换Claude,年底可能用Gemini..."

  • 产品经理要求:"这个AI回答要能直接转成我们的领域对象"

  • 运维大哥抱怨:"AI调用太慢了,能不能给个监控看板?"

解决方案

将Spring AI框架集成到应用当中,它是一个专注于AI工程的应用框架;旨在将Spring生态的设计原则(如可移植性、模块化)引入AI领域,简化企业数据或者API服务与大模型的集成,将大模型的调用通过普通Java对象来封装,降低开发复杂度‌,从而高效构建企业智能应用。

// 不管底层是哪个AI服务,调用方式都一样
String joke = aiClient.generate("讲个程序员笑话");

1.2 核心能力

二、实战DeepSeek - 从手动到自动

2.1 手动执行请求

API-KEY的获取

进入DeepSeek开放平台 https://platform.deepseek.com/usage,完成账号的注册与充值(开发学习时可以少充一点费用),点击 API keys创建个人专属API key 并保存下来。

curl手动执行

填写上正确的Key后执行curl发起Http请求,快速得到响应结果。

curl https://api.deepseek.com/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <DeepSeek API Key>" \
  -d '{
        "model": "deepseek-chat",
        "messages": [
          {"role": "system", "content": "You are a helpful assistant."},
          {"role": "user", "content": "讲一个笑话"}
        ],
        "stream": false
      }'
{
  "id": "0e8dd4b9-694e-417b-888a-7be54a77633f",
  "object": "chat.completion",
  "created": 1742744584,
  "model": "deepseek-chat",
  "choices":
  [
    {
      "index": 0,
      "message":
      {
        "role": "assistant",
        "content": "当然!这是一个经典的笑话:\n\n有一天,小明去面试。面试官问他:“你有什么特长吗?”\n\n小明想了想,认真地说:“我会预测未来。”\n\n面试官笑了笑:“那你预测一下,你什么时候能被录用?”\n\n小明淡定地回答:“这个嘛……我预测我不会被录用。”\n\n面试官愣了一下,笑着说:“你被录用了!我们需要你这样的人才!”\n\n😄"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage":
  {
    "prompt_tokens": 12,
    "completion_tokens": 74,
    "total_tokens": 86,
    "prompt_tokens_details":
    {
      "cached_tokens": 0
    },
    "prompt_cache_hit_tokens": 0,
    "prompt_cache_miss_tokens": 12
  },
  "system_fingerprint": "fp_3a5770e1b4_prod0225"
}

返回数据以JSON格式,解析格式中的content内容得到为大模型给我们讲的笑话。

2.2 代码自动发起

创建第一个Spring AI工程

访问 https://start.spring.io/按截图所示勾选依赖,生成代码框架。

Spring Boot 3.x

JDK 17+

spring-ai-openai-starter(是的,它能兼容DeepSeek)

将生成的代码导入到IDEA中,启动应用。

很遗憾,竟然没有启动起来,出现一个OpenAI API key must be set. Use the connection property: spring.ai.openai.api-key or spring.ai.openai.chat.api-key property的错误。

很明显是没有配置对应的API key,打开application.properties进入参数配置后发现启动成功。

配置application.properties

spring.application.name=hello

spring.ai.openai.api-key=换成个人的DeepSeek API key

spring.ai.openai.base-url=https://api.deepseek.com

spring.ai.openai.chat.options.model=deepseek-chat

编写Controller

@RestController
publicclassHelloController {

    private ChatClient chatClient;

    publicHelloController(ChatClient.Builder builder){
        this.chatClient = builder.build();
    }
    @GetMapping(“/hello”)
    public String hello(@RequestParam(value = “input”, defaultValue = “讲一个笑话”) String input){

        return chatClient.prompt(input).call().content();

    }
}

打开浏览器访问 http://localhost:8080/hello得到结果。

三、流式响应-打字机效果

3.1 Reactor初体验

通常大模型的响应耗时较长,为了优化用户体验,ChatGPT等厂商纷纷采用流式输出;我们可以通过Reactor框架来实现,它是一个响应式编程库,提供构建异步和非阻塞应用程序的能力。

private ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MICROSECONDS, new LinkedBlockingQueue<>(10));

@GetMapping(value = “/mock/stream”, produces = “text/html;charset=UTF-8”)
public Flux<String> mockStream(){

    Sinks.Many<String> sink = Sinks.many().multicast().onBackpressureBuffer();

    executor.submit(() -> {
        for (int i = 0; i < 100; i++) {

            sink.tryEmitNext(i + " ");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                thrownew RuntimeException(e);
            }
        }
    });

    return sink.asFlux();
}

Sinks.Many 用于创建多值(Multi-Value)的发布者(Publisher)的一种机制,它允许用户将数据从一个地方发送到多个订阅者,示例中启动异步线程做写入操作,通过asFlux获取Flux对象;启动看效果:

图片

3.2 大模型的流式输出

@GetMapping(value = "/hello/stream", produces = "text/html;charset=UTF-8")
    public Flux<String> helloStream(@RequestParam(value = "input", defaultValue = "讲一个笑话") String input){

        return chatClient.prompt(input).stream().content();

    }

把前面的call方法修改为stream即可,最终返回一个Flux对象,搞定流式输出~

图片

四、OpenAI的starter兼容DeepSeek?

DeepSeek

观察pom.xml文件发现配置的是spring-ai-openai-starter却配置DeepSeek的URL,是不是觉得有点魔幻?

<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>

其实这是Spring AI的"障眼法":

1.OpenAI的API规范已成为事实标准;

2.DeepSeek等国内服务兼容这套规范;

3.Spring AI利用"可移植API"设计,实现一套代码多处使用;

就像JDBC驱动可以连接不同数据库,Spring AI的客户端也能适配不同AI服务。

通义千问

类似的,阿里系通义大模型也同样适用OpenAI这套访问规范。

https://bailian.console.aliyun.com/?tab=model#/api-key创建个人专属API-KEY(有免费的额度)。

application.properties修改配置:

spring.ai.openai.api-key=sk-xxx

spring.ai.openai.base-url=https://dashscope.aliyuncs.com/compatible-mode

指定模型

spring.ai.openai.chat.options.model=qwen-plus

五、生产环境必备 - 给你的AI装上监控

老板问:"AI花了多少钱?效果怎么样?" ,不用慌,可以通过监控来解决。

添加监控依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

启动监控

management.endpoints.web.exposure.include=health,metrics,prometheus
spring.ai.observability.enabled=true

访问/actuator/prometheus,将看到:(如果配合grafana可视化效果会更加直观)。

结语:未来以来

Spring AI的出现,为Java开发者提供一整套大模型应用研发基础底座,为众多Java生态企业级的应用迈向AI领域开辟一条航向; AI时代已然到来,让我们一起扬帆起航~~~

触手可及,函数计算玩转 AI 大模型


AI的时代下,大模型类型丰富、功能强大,正推动着各行各业的智能化转型和创新突破。企业纷纷寻求部署自己的大模型,以满足特定业务需求,从而在激烈的市场竞争中获得优势。本方案介绍通过阿里云函数计算的按量付费、卓越弹性、快速交付能力,助力企业快速部署 AI 大模型。    


点击阅读原文查看详情。

同意楼上的观点!除了业务指标和模型指标,安全指标也很重要。比如,要监控用户的输入是否包含敏感信息,输出是否符合安全规范。 另外,成本也是一个需要重点关注的指标。调用大模型的成本通常比较高,我们需要监控API的调用量、Token的使用情况,以及各个模型的成本占比,以便优化成本。

这个问题问得好!虽然Spring AI提供了一层抽象,但完全避免针对不同模型进行特殊处理是不现实的。我的想法是,可以利用Spring的条件注解(@Conditional)或者策略模式,根据当前使用的模型,选择不同的处理逻辑。这样既能保持代码的灵活性,又能避免过度耦合。比如定义一个ModelResponseHandler接口,然后针对不同的模型实现不同的Handler,通过配置来决定使用哪个Handler。

兼容OpenAI规范是降低迁移成本的好方法,但如果想用特定模型的高级功能,可能需要绕过Spring AI的抽象层。一种方法是直接使用DeepSeek或通义千问的SDK,在Spring AI之外编写特定的代码。另一种是扩展Spring AI,自定义组件来支持这些特定功能,但这需要对Spring AI的内部实现有深入的了解。

楼上说的策略模式确实是个好主意!我补充一点,可以结合Spring Expression Language (SpEL) 来实现更细粒度的控制。比如,在配置文件中定义SpEL表达式,根据模型的类型或者版本,动态选择不同的属性或者方法。 另外,还可以考虑使用AOP,在调用大模型前后进行拦截,进行统一的日志记录、性能监控等操作。这样可以避免在业务代码中到处散落着重复的代码。

楼上说的有道理!我觉得还可以考虑使用Spring Integration。Spring Integration提供了丰富的消息通道、转换器、过滤器等组件,可以方便地将不同来源的数据进行整合和处理。我们可以将DeepSeek或通义千问的SDK集成到Spring Integration中,然后使用Spring Integration提供的组件来实现特定的功能。 另外,还可以考虑使用函数式编程的思想,将不同的处理逻辑封装成一个个独立的函数,然后使用组合的方式将这些函数串联起来。这样可以提高代码的灵活性和可测试性。

确实,框架的抽象是为了通用性,但有时候也会限制我们使用特定功能。我的建议是,可以先评估一下这些特有功能的重要性和使用频率。如果只是偶尔使用,直接用SDK可能更简单。如果使用频率很高,而且对性能有要求,可以考虑自己扩展Spring AI。 另外,还可以关注一下Spring AI社区,看看有没有人已经实现了对这些特有功能的扩展。也许可以直接拿来用,或者参考一下他们的实现思路。

监控当然不只是看调用次数和耗时,更重要的是看效果!比如,智能客服的解决率、用户满意度,推荐系统的点击率、转化率等等。这些业务指标才能真正反映AI应用的价值。 另外,还要关注AI模型的稳定性和准确性,比如定期评估模型的漂移情况,监控模型的输入输出分布是否发生变化。

我觉得可以考虑使用适配器模式,针对不同的大模型,创建不同的适配器,将它们的返回结果转换为统一的格式。这样,业务代码只需要处理统一格式的数据,而不需要关心底层大模型的差异。当然,如果不同大模型之间的差异太大,适配器模式可能会变得比较复杂。 另外,还可以考虑使用责任链模式,将不同的处理逻辑串联起来,每个处理逻辑只负责处理特定类型的大模型返回结果。这样可以提高代码的可维护性和可扩展性。

要我说,还得关注资源利用率!CPU、内存、GPU,这些都是钱啊!监控这些指标,可以帮助我们及时发现性能瓶颈,优化资源配置。 另外,日志也是很重要的监控手段。通过分析日志,我们可以了解用户的行为模式、发现潜在的问题,甚至可以用来改进AI模型。