Spring4 / SpringBoot1.x 老项目想接入 AI?不用升级框架!3 套无痛落地方案

不知不觉已经2个多月,感谢各位朋友的认可和支持!

随着AI的日新月异,很多公司都开展了AI相关的业务,这也使得很多公司的老板都想去沾沾边,而他却不知道自己公司的项目即屎山代码还是老的架构,所以很多朋友问:"老项目呢?大量Spring 4/Spring Boot 1.x的核心系统,想做AI但新框架都用不了,升级风险又大" 这个问题问得太真实了。不少公司的核心系统还跑在Spring Framework 4.x / Spring Boot 1.x上,想做大模型功能,但一查文档就懵了------Spring AI要求Spring Boot 3.x,LangChain4j的Spring Boot集成也要2.7起步,直接引入全是javax.*和jakarta.*的冲突,编译都过不了。 这个问题问得太真实了。很多公司的核心系统还跑在Spring Framework 4.x / Spring Boot 1.x上,想做大模型功能,但一查文档就懵了------Spring AI要求Spring Boot 3.x,LangChain4j的Spring Boot集成也要2.7起步,直接引入全是javax.*和jakarta.*的冲突,编译都过不了。

升级框架?那可是核心业务系统,回归测试跑一遍半个月,出了事故谁背锅?

但Spring 4就真的没法做AI了吗?当然不是。 大模型本质上就是个HTTP接口,和你调第三方支付、调短信网关没有任何区别。今天给3种方案,从最简单的零依赖手写调用,到官方SDK,再到微服务拆分,不用升级一行Spring代码,Spring 4项目也能接入大模型。


先搞清楚:为什么新框架在Spring 4里用不了?

很多人以为是版本太低,其实核心原因是Java EE和Jakarta EE的不兼容。

  • Spring 4 / Spring Boot 1.x → 用的是 Java EE ,包名是javax.servlet.*、javax.persistence.*
  • Spring Boot 3.x / Spring 6 → 用的是 Jakarta EE ,包名是jakarta.servlet.*、jakarta.persistence.*

这两个包名不兼容,所以Spring AI、LangChain4j的Spring Boot Starter这些基于Spring Boot 3的框架,直接在Spring 4项目里引入就会报类冲突。但注意:不兼容的是"Spring集成层",不是"大模型调用本身"。 只要不用那些Spring Boot Starter,纯Java的大模型调用在任何Spring版本里都能跑。

理解了这一点,下面3种方案就顺理成章了。


方案1:OkHttp手写调用大模型API(零依赖,首选)

这是最简单、最通用、最不容易出问题的方案。大模型的接口就是标准的HTTP POST,返回JSON,你用OkHttp发请求、用fastjson解析响应,完事。

优点 :零Spring依赖,JDK 6+就能跑,不侵入现有项目,不会有任何依赖冲突 缺点:需要自己封装重试、超时、流式输出(但这些都不难)

第一步:引入依赖(Spring 4兼容版本)

注意版本选择,不要用最新版,最新版可能要求高版本JDK:

xml 复制代码
<!-- OkHttp 3.12.x是最后一个支持JDK 7的版本,JDK 8用3.14.x也没问题 -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.14.9</version>
</dependency>

<!-- fastjson 1.2.x,兼容低版本JDK,不要用fastjson2 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>

第二步:封装大模型客户端

java 复制代码
package com.example.ai;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 大模型通用客户端(Spring 4兼容,零Spring依赖)
 * 基于通义千问OpenAI兼容接口,其他模型改base-url即可
 */
public class LlmClient {

    private final OkHttpClient httpClient;
    private final String apiKey;
    private final String baseUrl;
    private final String model;

    public LlmClient(String apiKey, String baseUrl, String model) {
        this.apiKey = apiKey;
        this.baseUrl = baseUrl;
        this.model = model;
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 最简对话调用
     * @param systemPrompt 系统提示词
     * @param userMessage 用户问题
     * @return 大模型回答
     */
    public String chat(String systemPrompt, String userMessage) throws IOException {
        // 1. 构建消息
        JSONObject systemMsg = new JSONObject();
        systemMsg.put("role", "system");
        systemMsg.put("content", systemPrompt);

        JSONObject userMsg = new JSONObject();
        userMsg.put("role", "user");
        userMsg.put("content", userMessage);

        JSONArray messages = new JSONArray();
        messages.addAll(Arrays.asList(systemMsg, userMsg));

        // 2. 构建请求体
        JSONObject requestBody = new JSONObject();
        requestBody.put("model", model);
        requestBody.put("messages", messages);
        requestBody.put("temperature", 0.3);

        // 3. 发送HTTP请求
        Request request = new Request.Builder()
                .url(baseUrl + "/chat/completions")
                .addHeader("Authorization", "Bearer " + apiKey)
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(
                        MediaType.parse("application/json; charset=utf-8"),
                        requestBody.toJSONString()))
                .build();

        // 4. 解析响应
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("大模型调用失败,HTTP状态码:" + response.code()
                        + ",响应:" + response.body().string());
            }
            String body = response.body().string();
            JSONObject json = JSON.parseObject(body);
            return json.getJSONArray("choices")
                    .getJSONObject(0)
                    .getJSONObject("message")
                    .getString("content");
        }
    }

    /**
     * 带重试的调用(生产环境必备)
     */
    public String chatWithRetry(String systemPrompt, String userMessage, int maxRetries) {
        for (int i = 0; i < maxRetries; i++) {
            try {
                return chat(systemPrompt, userMessage);
            } catch (IOException e) {
                System.err.println("第" + (i + 1) + "次调用失败:" + e.getMessage());
                if (i == maxRetries - 1) {
                    throw new RuntimeException("大模型调用失败,已重试" + maxRetries + "次", e);
                }
                try {
                    Thread.sleep(1000 * (i + 1)); // 指数退避
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        return null;
    }
}

第三步:在Spring 4项目里使用

kotlin 复制代码
package com.example.service;

import com.example.ai.LlmClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;

/**
 * 在Spring 4项目中使用大模型
 * 注意:这里用的是javax.annotation.PostConstruct(Java EE),
 * 不是jakarta.annotation.PostConstruct(Jakarta EE)
 */
@Service
public class AiService {

    @Value("${llm.api-key}")
    private String apiKey;

    @Value("${llm.base-url:[https://dashscope.aliyuncs.com/compatible-mode/v1](https://dashscope.aliyuncs.com/compatible-mode/v1)}")
    private String baseUrl;

    @Value("${llm.model:qwen-turbo}")
    private String model;

    private LlmClient llmClient;

    @PostConstruct
    public void init() {
        // 手动new出来,不需要Spring Boot Starter自动装配
        this.llmClient = new LlmClient(apiKey, baseUrl, model);
    }

    /**
     * 智能问答
     */
    public String ask(String question) {
        try {
            String systemPrompt = "你是一个 helpful 的智能助手,回答要简洁准确。";
            return llmClient.chatWithRetry(systemPrompt, question, 3);
        } catch (Exception e) {
            // 降级兜底:大模型不可用时返回默认回答
            return "抱歉,AI服务暂时不可用,请稍后重试。";
        }
    }
}

关键点:整个客户端没有任何Spring依赖,就是纯Java + OkHttp + fastjson。你把LlmClient这个类复制到任何Spring 4、Spring 3、甚至纯Servlet项目里,都能直接用。这是最稳妥的方案,没有之一。


方案2:引入官方SDK,不依赖Spring版本

如果你不想自己封装HTTP调用,可以用大模型厂商的官方SDK。这些SDK通常是纯Java库,不依赖Spring,所以在Spring 4项目里也能直接引入。

以阿里通义千问的官方SDK为例:

第一步:引入依赖

xml 复制代码
<!-- 通义千问官方SDK,纯Java库,不依赖Spring -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dashscope-sdk-java</artifactId>
    <version>2.14.6</version> <!-- 选兼容JDK 8的版本,不要用最新版 -->
</dependency>

第二步:使用SDK调用

java 复制代码
package com.example.ai;

import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;

import java.util.Arrays;

/**
 * 使用官方SDK调用大模型(不依赖Spring)
 */
public class DashScopeService {

    private final String apiKey;

    public DashScopeService(String apiKey) {
        this.apiKey = apiKey;
    }

    public String chat(String userMessage) throws Exception {
        // 1. 构建消息
        Message systemMsg = Message.builder()
                .role(Role.SYSTEM.getValue())
                .content("你是一个 helpful 的助手。")
                .build();

        Message userMsg = Message.builder()
                .role(Role.USER.getValue())
                .content(userMessage)
                .build();

        // 2. 构建请求参数
        GenerationParam param = GenerationParam.builder()
                .apiKey(apiKey)
                .model("qwen-turbo")
                .messages(Arrays.asList(systemMsg, userMsg))
                .temperature(0.3f)
                .build();

        // 3. 调用
        Generation gen = new Generation();
        GenerationResult result = gen.call(param);

        // 4. 解析结果
        return result.getOutput().getChoices().get(0).getMessage().getContent();
    }
}

优点 :官方维护,功能全(支持流式、Function Calling、多模态等),不用自己封装HTTP 缺点:

  • 引入额外依赖,老项目可能和现有依赖冲突(比如okhttp版本、gson版本)
  • SDK版本更新快,新版本可能要求高版本JDK,一定要选兼容你JDK版本的旧版本
  • 绑定特定厂商,换大模型要改代码

避坑提醒:引入官方SDK前,先看它的依赖树。很多SDK内部依赖了okhttp、gson、guava等,如果你的项目里已经有这些库且版本不同,很容易出现NoSuchMethodError。冲突了就用maven的exclusions排掉,或者干脆回方案1自己手写。


方案3:单独起AI微服务,老项目HTTP/RPC调用(长期推荐)

如果你的AI功能会越来越复杂(要做RAG、Agent、多轮对话、流式输出),方案1和2就不够用了------你会想要Spring AI、LangChain4j这些完整框架的能力,但又不想动老项目。

这时候最佳方案是:新起一个独立的AI微服务,用最新的Spring Boot 3 + LangChain4j,老项目通过HTTP或RPC调用它。

架构图

javascript 复制代码
┌─────────────────────┐      HTTP/Feign       ┌─────────────────────┐
│   老项目(Spring 4)│  ───────────────────>  │  AI微服务(Spring Boot 3)│
│   业务逻辑/数据库    │                        │  LangChain4j / RAG / Agent │
│   现有功能不变       │  <───────────────────  │  大模型调用 / 向量检索      │
└─────────────────────┘      JSON响应          └─────────────────────┘

老项目侧调用代码(Feign,Spring 4兼容)

typescript 复制代码
package com.example.ai;

import feign.Headers;
import feign.Param;
import feign.RequestLine;

/**
 * Feign客户端调用AI微服务(Spring 4兼容,用feign-core即可)
 */
public interface AiServiceClient {

    @RequestLine("POST /api/ai/chat")
    @Headers("Content-Type: application/json")
    String chat(ChatRequest request);

    class ChatRequest {
        private String question;
        private String userId;
        // getter/setter省略
        public String getQuestion() { return question; }
        public void setQuestion(String question) { this.question = question; }
        public String getUserId() { return userId; }
        public void setUserId(String userId) { this.userId = userId; }
    }
}
kotlin 复制代码
// 在Spring 4项目中配置Feign客户端
package com.example.config;

import com.example.ai.AiServiceClient;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiServiceConfig {

    @Value("${ai.service.url:[http://localhost:8081](http://localhost:8081)}")
    private String aiServiceUrl;

    @Bean
    public AiServiceClient aiServiceClient() {
        return Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .target(AiServiceClient.class, aiServiceUrl);
    }
}

优点:

  • AI能力独立演进,新技术随便用(Spring Boot 3、LangChain4j、流式输出、RAG全上)
  • 不影响老项目,老项目代码几乎不用改
  • 独立部署、独立扩容、独立监控,AI服务挂了不影响核心业务
  • 多个老项目可以共用一个AI微服务

缺点:

  • 多一个服务要运维(但现在容器化部署很简单)
  • 有网络开销(内网调用延迟很低,可忽略)
  • 需要处理服务发现、鉴权等微服务基础问题

核心判断:如果只是简单调大模型问答,方案1就够了;如果AI功能会持续迭代、越来越复杂,直接上方案3,一劳永逸。


三种方案对比

维度 方案1:OkHttp手写 方案2:官方SDK 方案3:微服务拆分
依赖侵入性 极低(仅OkHttp+fastjson) 中(SDK+传递依赖) 老项目零侵入
改造成本 最低(复制一个类) 低(引入依赖+调用) 中(新起服务+接口对接)
功能完整度 基础(需自己扩展) 高(官方全功能) 最高(任何框架都能用)
维护成本 低(自己控制代码) 中(跟SDK版本升级) 中(多一个服务)
依赖冲突风险 几乎为零 有(需排查传递依赖) 零
适用场景 简单问答、快速接入 需要官方高级功能 AI功能复杂、长期迭代

我的选型建议

  1. 你只是想给老项目加个智能问答/文案生成功能? → 方案1,OkHttp手写,半小时搞定,最稳妥
  2. 你需要流式输出、Function Calling等高级功能,又不想起新服务? → 方案2,官方SDK,注意选兼容版本
  3. 你要做完整的RAG/Agent系统,AI功能会持续迭代? → 方案3,微服务拆分,长期来看最省心
  4. 你的项目JDK版本特别低(JDK 6/7)? → 方案1,选OkHttp 3.12.x + fastjson 1.2.x,这是唯一能跑的方案

最后说一句:不要被"新框架必须高版本Spring"吓住。 大模型的本质就是HTTP接口,只要能发HTTP请求,任何Java项目都能做AI。先从方案1跑通最小闭环,看到效果再决定要不要升级,这才是老项目做AI的正确姿势。


📦 落地资源推荐

AI应用框架开发需要稳定的测试环境,我平时调试框架、跑RAG验证都用阿里云轻量应用服务器,2核4G跑SpringBoot + 大模型调用完全够用,新用户首年特惠性价比很高再加上现在可以领取的9折券,适合自己动手搭一个AI测试环境。有部署需求的朋友,可以点击查看www.aliyun.com/daily-act/e...

💡 领取完整源码

关注图片上水印即Java-AI工程师,后台回复【选型】,领取本文完整源码,含 OkHttp 手写客户端(带重试降级)、DashScope SDK 调用示例、Feign 微服务调用示例、Spring 4 兼容版本 pom.xml,复制到项目直接运行。

📢 下期预告

选型踩坑是Java开发者的普遍痛点,很多人为了技术而技术,盲目上框架,最后发现不匹配,重构成本极高。所以我们下一篇讲:Java AI 框架选型最容易踩的 5 个坑:90% 的人至少中 2 个 本文属于「Java AI工具选型」合集

相关推荐
znnnk1 小时前
【AI技术】Vibe Coding 实践指南:从项目规划到高效开发
人工智能·ai·ai编程·ai ide·vibe coding
BBmmo1 小时前
Java Stream 的 filter 为什么看起来没运行?
java
VimorphTech1 小时前
Java 文件缓存实战:如何避免读到未下载完成的视频?
java·spring boot
Simon_lca1 小时前
ZARA、H&M、SHEIN验厂差异全对比:一套底层记录,三套接口输出
大数据·人工智能·经验分享·科技·制造
爱喝雪碧的可乐1 小时前
DeepSeek 崩了近5小时:一次故障扒透「单点依赖、重试风暴与大模型高可用」
大数据·人工智能·deepseek
GlobalTradercrb1 小时前
独立站SEO先写博客还是先优化产品页?看站点阶段
数据库·人工智能·google·pdf·go·seo
田里的水稻1 小时前
FA_CNN卷积神经网络三---非线性激活函数PyTorch
人工智能·pytorch·神经网络·机器学习·cnn
白露与泡影1 小时前
后端 Java 面试核心八股汇总|高频面试题 + 解析,覆盖基础到进阶
java·开发语言·面试
Geek-Chow1 小时前
实验:用 Claude Code 一句提示词生成 three.js 3D V8 发动机剖视动画(附 GIF/MP4 导出)
人工智能