1. 从写 CRUD 到调大模型:Java 开发者转 AI 的真实门槛在哪
干了五六年 Java 的人,第一次打开 Python 的 AI 教程,大概率会有一种很微妙的挫败感。不是看不懂 Transformer 的注意力公式,也不是搞不定梯度下降的推导,而是——明明这些东西我都懂个大概,但真让我跑一个能用的东西出来,我居然不知道从哪下手。环境是 conda 还是 venv,模型是本地跑还是调 API,向量库选哪个,Prompt 写在哪一层,这些东西在 Java 的世界里全都有对应物,但就是没人给你翻译一遍。
我身边不少做 Java 后端的朋友,包括我自己,都经历过这个阶段。一开始觉得 AI 嘛,不就是调个接口的事,HttpClient发个 POST 就完了。真上手才发现,事情没那么简单。你要处理流式响应、要管理对话上下文、要做 RAG 检索增强、要控制 Token 成本、要保证输出格式稳定可解析——这些需求在 Java 生态里其实都有成熟的解法,只是它们散落在 Spring AI、LangChain4j、各种向量数据库客户端里,没有一个统一的入口告诉你"先学什么、再学什么"。
这篇东西就是想把这条路捋清楚。我不打算讲什么"AI 改变世界"的宏大叙事,也不准备从感知机开始给你补机器学习基础。我想做的是:以一个写了多年 Java 的从业者视角,把从传统后端开发转向 AI 应用开发这条路上,真正需要补的东西、真正会踩的坑、真正值得投入时间的工具链,一个一个说清楚。适合谁看?适合那些 Java 基础扎实、想往 AI 方向靠但不知道从哪切入的人;也适合已经在用 Spring Boot 做业务、想在自己项目里加一点 AI 能力的开发者。
核心关键词就几个:Java、AI、路线图、工具链、Spring AI。这几个词基本概括了整条路径的骨架。下面我会按"先搞清楚 AI 应用开发到底在做什么"、"Java 侧的工具链怎么选"、"Spring AI 到底解决了什么问题"、"RAG 和 Agent 这些热门概念在 Java 里怎么落地"、"实际项目里怎么一步步接进去"这个顺序展开。每个部分都会给具体的依赖、代码片段、配置参数,以及我自己踩过的坑。
2. 先搞清楚 AI 应用开发到底在做什么
2.1 大模型不是数据库,别用 CRUD 思维去理解它
很多 Java 开发者第一次接触大模型 API 的时候,会下意识地把它当成一个"远程服务"来理解:我传参数进去,它返回结果,跟调一个 REST 接口没区别。这个理解不能说错,但会误导你做出很多错误的架构决策。
大模型和传统后端服务最本质的区别在于:它的输出是不确定的。同一个输入,两次调用可能得到不同的结果。这意味着你不能像写单元测试那样去断言"返回值必须等于某个字符串"。你的代码必须能容忍输出的多样性,同时又要保证业务逻辑的稳定性。这个矛盾是 AI 应用开发的核心挑战之一。
另一个区别是上下文窗口的有限性。传统接口你传多少参数都行,大模型不行,它有 Token 上限。你塞进去的历史对话、检索到的文档、系统提示词,全都占 Token。Token 用完了,要么截断,要么报错。所以在 Java 里做 AI 应用,你得时刻关注"我这次请求到底发了多少 Token 出去",这跟传统后端关注内存占用是一个性质的事情。
还有一个容易被忽略的点:大模型调用是慢的。一次请求几秒到几十秒都正常。在 Java 的同步阻塞模型里,这意味着你的线程会被长时间占用。如果你的 Web 应用用的是传统的 Tomcat 线程池,并发一上来,线程全被 AI 调用占住了,整个服务就卡死了。这个问题在后面讲 Spring AI 的时候会详细说怎么处理。
2.2 AI 应用开发的四层结构
我把 AI 应用开发拆成四层来理解,这样 Java 开发者能更快找到自己的位置:
| 层级 | 做什么 | Java 开发者的熟悉程度 |
|---|---|---|
| 模型层 | 训练、微调、推理优化 | 基本不涉及,除非专门做算法 |
| 接口层 | 调用大模型 API、管理 Token、处理流式响应 | 需要重点补,但概念不难 |
| 编排层 | Prompt 管理、对话上下文、RAG、Agent 流程 | 核心战场,Spring AI 主要在这一层 |
| 应用层 | 业务集成、权限、监控、成本控制 | Java 开发者的主场 |
大部分 Java 开发者要切入的是接口层往上的部分。你不需要会训练模型,但你需要知道怎么高效地调用它、怎么组织 Prompt、怎么把检索到的知识喂给模型、怎么让模型按照你想要的格式输出。这些事情的复杂度,说实话,不比写一个中等规模的业务系统低。
2.3 为什么 Java 开发者不应该转 Python
我见过太多人一上来就说"做 AI 得学 Python",然后花三个月学 Python 语法、学 NumPy、学 PyTorch,最后发现自己还是不知道怎么把 AI 集成到实际项目里。这个路径对 Java 开发者来说效率极低。
原因很简单:你的优势在工程能力,不在算法研究。企业里真正缺的不是能训模型的人,而是能把模型能力稳定、可靠、低成本地集成到现有系统里的人。而现有系统大部分是 Java 写的。你放着 Java 的工程优势不用,去跟算法岗的人拼 Python 和数学,这是用自己的短板去碰别人的长板。
正确的做法是:用 Java 做 AI 应用的工程化。Spring AI、LangChain4j 这些框架就是为这个场景生的。它们让你用熟悉的 Spring 风格去调大模型、做 RAG、搭 Agent,不需要你切换到 Python 生态。等你真的需要做模型微调或者自定义推理的时候,再考虑用 Python 做那部分,通过服务化的方式跟 Java 主系统对接。
3. Java AI 工具链怎么选:别被框架名字唬住
3.1 Spring AI 和 LangChain4j 的定位差异
Java 生态里做 AI 应用,目前主流的选择就两个:Spring AI和LangChain4j。很多人纠结选哪个,其实它们的定位有明确差异。
Spring AI 是 Spring 官方团队做的,设计哲学跟 Spring 全家桶一脉相承:约定优于配置、自动装配、starter 依赖。如果你的项目本来就是 Spring Boot 的,用 Spring AI 几乎零成本接入。它的 API 抽象层次比较高,ChatClient一个接口就把对话、流式、函数调用都覆盖了。缺点是相对年轻,有些高级功能(比如复杂的 Agent 编排)还在演进中。
LangChain4j 是社区驱动的,灵感来自 Python 的 LangChain。它的抽象层次更细,组件更多,适合需要精细控制流程的场景。比如你想自定义一个检索策略、想手动编排多个模型的调用链,LangChain4j 的灵活性更好。但它的学习曲线比 Spring AI 陡一些,配置也更繁琐。
我的建议是:新项目、Spring Boot 技术栈、需求以对话和 RAG 为主,直接上 Spring AI。需要复杂 Agent 编排、或者团队已经有 LangChain 使用经验的,考虑 LangChain4j。两者不是互斥的,理论上可以在一个项目里混用,但没必要给自己找麻烦。
3.2 模型接入:别只盯着一个供应商
Spring AI 的一个核心价值是模型抽象。它把不同厂商的模型 API 统一成一套接口,你切换模型供应商的时候,业务代码基本不用改。
<!-- pom.xml 中引入 OpenAI 兼容的 starter --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>配置也很直接:
spring: ai: openai: api-key: ${AI_API_KEY} base-url: https://api.example.com chat: options: model: gpt-4o-mini temperature: 0.7 max-tokens: 2048这里有几个参数值得说清楚。temperature控制输出的随机性,0 到 2 之间,越低越确定。做数据提取、格式转换这类任务,建议设 0 到 0.3;做创意生成、头脑风暴,可以设 0.7 到 1.0。max-tokens限制单次响应的最大长度,设太小会导致输出被截断,设太大浪费成本,一般根据你的业务场景预估。
注意:不同厂商对
temperature的取值范围定义不一样,有些是 0 到 1,有些是 0 到 2。切换模型的时候一定要确认这个参数的范围,否则可能得到意料之外的结果。
3.3 向量数据库:RAG 的地基
做 RAG(检索增强生成)绕不开向量数据库。Java 生态里常用的选择有:
- PGVector:如果你已经在用 PostgreSQL,加个扩展就能用,运维成本最低
- Milvus:专业向量库,性能好,但需要单独部署
- Redis Stack:如果已经在用 Redis,可以顺便用它的向量检索能力
- Chroma:轻量级,适合本地开发和原型验证
我的经验是:原型阶段用 Chroma 或者 PGVector,生产环境根据数据量和并发量再决定要不要上 Milvus。很多项目其实几万到几十万条向量,PGVector 完全扛得住,没必要一上来就搞一套独立的向量集群。
Spring AI 对这些向量库都有对应的 starter,切换成本很低。关键是要理解向量检索的本质:把文本转成高维向量,然后算余弦相似度,找最接近的。这个过程中,Embedding 模型的选择比向量库的选择更重要。同一个文本,用不同的 Embedding 模型转出来的向量,检索效果可能差很多。
3.4 工具链全景速查表
| 环节 | 推荐工具 | 替代方案 | 备注 |
|---|---|---|---|
| 框架 | Spring AI | LangChain4j | Spring 项目首选前者 |
| 模型接入 | OpenAI 兼容接口 | 各厂商原生 SDK | 优先选兼容接口,方便切换 |
| 向量库 | PGVector | Milvus / Redis Stack | 按现有基础设施选 |
| Embedding | text-embedding-3-small | BGE 系列本地模型 | 成本敏感场景用本地模型 |
| 流式响应 | SSE | WebSocket | SSE 更简单,够用 |
| 文档解析 | Apache Tika | PDFBox | Tika 格式支持更全 |
| 本地推理 | Ollama | llama.cpp | 开发调试用,生产慎用 |
这张表不是让你全用上,而是让你知道每个环节有哪些选项。实际项目里,大部分场景只需要其中三四个组件就能跑起来。
4. Spring AI 到底解决了什么问题
4.1 ChatClient:把大模型调用变成一行代码
没有 Spring AI 的时候,你调大模型大概是这样的:手动构造 HTTP 请求、拼 JSON、处理各种错误码、解析响应、管理重试。代码又长又容易出错。Spring AI 的ChatClient把这些都封装了:
@RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient.Builder builder) { this.chatClient = builder .defaultSystem("你是一个专业的 Java 技术顾问,回答要简洁准确。") .build(); } @GetMapping("/chat") public String chat(@RequestParam String message) { return chatClient.prompt() .user(message) .call() .content(); } }这段代码背后,Spring AI 帮你做了:请求构造、认证、超时控制、错误处理、响应解析。你只需要关注业务逻辑。这就是 Spring 生态一贯的风格——把重复的样板代码藏起来。
但要注意,ChatClient的call()方法是阻塞的。在高并发场景下,这会占用 Web 线程。Spring AI 也提供了stream()方法返回Flux<String>,配合 Spring WebFlux 可以做非阻塞的流式响应。如果你的应用是传统 MVC 架构,又需要处理高并发 AI 请求,建议把 AI 调用放到独立的线程池里,或者用CompletableFuture做异步包装。
4.2 PromptTemplate:别在代码里硬拼字符串
新手最容易犯的错误,就是在 Java 代码里用字符串拼接来构造 Prompt:
// 不推荐的做法 String prompt = "请根据以下内容回答问题:" + context + "\n问题:" + question;这种做法的问题在于:Prompt 散落在代码各处,改一个措辞要重新编译部署;没法做版本管理;测试困难。Spring AI 提供了PromptTemplate来解决这个问题:
PromptTemplate template = new PromptTemplate(""" 请根据以下参考资料回答问题。如果资料中没有相关信息,请明确说明"资料中未提及"。 参考资料: {context} 问题:{question} """); Prompt prompt = template.create(Map.of( "context", retrievedContext, "question", userQuestion ));把 Prompt 模板化之后,你可以把它放到配置文件里、放到数据库里、甚至做一个 Prompt 管理界面让运营人员来调。这在生产环境里非常重要,因为 Prompt 的微调频率往往比代码高得多。
4.3 结构化输出:让模型返回你能解析的东西
大模型默认返回的是自然语言文本。但业务代码需要的是结构化数据——JSON、对象、枚举。让模型稳定地输出 JSON,是 AI 应用开发里一个不大不小的难题。
Spring AI 提供了StructuredOutputConverter来解决这个问题:
public record ProductInfo( String name, BigDecimal price, String category, List<String> tags ) {} ProductInfo info = chatClient.prompt() .user("从这段描述中提取商品信息:" + description) .call() .entity(ProductInfo.class);Spring AI 会自动在 Prompt 里加上格式说明,然后把模型返回的 JSON 解析成 Java 对象。但这里有个坑:模型不总是能返回合法的 JSON。它可能多写一段解释文字,可能字段名拼错,可能类型不对。所以生产环境里一定要加异常处理和重试机制。我的做法是:解析失败时,把错误信息连同原始输出一起发回给模型,让它修正后重新输出。这个"自我修正"的循环通常一两次就能成功。
4.4 函数调用:让模型能操作你的系统
函数调用(Function Calling)是让大模型从"聊天机器人"变成"智能助手"的关键能力。简单说,就是你把一些 Java 方法注册给模型,模型在需要的时候会告诉你"我要调用这个方法,参数是这些",然后你的代码执行方法,把结果返回给模型,模型再基于结果继续对话。
@Bean @Description("查询指定城市的当前天气") public Function<WeatherRequest, WeatherResponse> weatherFunction() { return request -> weatherService.getWeather(request.city()); }注册之后,用户在对话里问"北京今天天气怎么样",模型会自动识别出需要调用weatherFunction,传入{"city": "北京"},拿到结果后组织成自然语言回复。整个过程对用户是透明的。
这个能力在 Java 企业应用里想象空间很大:查订单、查库存、发起审批、生成报表,都可以封装成函数让模型调用。但要注意权限控制。模型调用函数的时候,你的代码必须校验当前用户有没有权限执行这个操作。不能因为请求来自模型就跳过安全检查。
5. RAG 在 Java 里怎么落地:从文档到答案的完整链路
5.1 RAG 的本质是"开卷考试"
RAG(Retrieval-Augmented Generation)这个词听起来高大上,本质其实很简单:让模型开卷考试。模型本身的知识是有限的、可能过时的,但如果你在提问的时候,把相关的参考资料一起塞给它,它就能基于这些资料给出准确的回答。
这个思路在 Java 企业应用里特别实用。因为企业最值钱的知识往往在内部文档、Wiki、工单系统里,这些内容不在模型的训练数据里。RAG 就是把这些内部知识"喂"给模型的标准化流程。
完整链路分三步:文档入库、检索、生成。每一步都有讲究。
5.2 文档入库:切分策略决定检索质量
文档入库的第一步是切分(Chunking)。你不能把一整本 200 页的手册塞给模型,得切成小块。但怎么切,直接影响检索效果。
// Spring AI 的文档切分示例 TokenTextSplitter splitter = new TokenTextSplitter(500, 100, 5, 10000, true); List<Document> chunks = splitter.apply(documents);这里的参数含义:每个 chunk 目标 500 Token,相邻 chunk 重叠 100 Token,最小 chunk 5 Token,最大 10000 Token。重叠是为了避免关键信息刚好被切在边界上导致丢失。
我的经验是:技术文档按标题层级切,对话记录按轮次切,代码按方法切。不要无脑按固定长度切,那样会把一个完整的逻辑单元切碎。比如一份 API 文档,一个接口的说明应该是一个完整的 chunk,而不是从中间截断。
还有一个容易忽略的点:给每个 chunk 加上元数据。来源文件、章节标题、更新时间,这些信息在检索和展示的时候都有用。Spring AI 的Document对象支持metadata字段,别浪费它。
5.3 检索:相似度不是唯一标准
检索环节,大部分人只知道向量相似度。但实际项目里,纯向量检索经常不够用。原因有几个:专有名词的向量表示可能不准;短查询的向量信息量太少;用户可能用不同的词表达同一个意思。
我的做法是混合检索:向量检索 + 关键词检索,然后合并排序。Spring AI 支持通过VectorStore做向量检索,关键词检索可以用 Elasticsearch 或者数据库的全文索引。两路结果用 RRF(Reciprocal Rank Fusion)算法合并,效果比单路好很多。
// 伪代码示意混合检索的合并逻辑 List<Document> vectorResults = vectorStore.similaritySearch(query); List<Document> keywordResults = keywordSearch(query); List<Document> merged = rrfMerge(vectorResults, keywordResults, 60);RRF 里的 60 是个经验常数,控制排名衰减速度。这个值不需要精确调,50 到 100 之间都差不多。
5.4 生成:Prompt 里怎么放检索结果
检索到相关文档后,怎么放进 Prompt 也有讲究。最直接的做法是把所有检索结果拼在一起:
参考资料: [1] {doc1} [2] {doc2} [3] {doc3} 问题:{question}但这样有几个问题:文档多了会超 Token 限制;模型可能被不相关的文档干扰;没法追溯答案来自哪个文档。
更好的做法是:限制检索结果数量(通常 3 到 5 条),按相关度排序,给每条编号,要求模型在回答时引用编号。这样既控制了 Token 消耗,又让答案可追溯。
请基于以下参考资料回答问题,并在答案中标注引用的资料编号。 如果参考资料中没有相关信息,请明确说明。 参考资料: [1] ... [2] ... [3] ... 问题:...这个 Prompt 模板实测下来,答案的准确率和可追溯性都明显好于不加编号的版本。
6. 把 AI 接进现有 Java 项目:一个渐进式落地路径
6.1 第一步:从"辅助功能"开始,别动核心链路
我见过不少团队,一上来就想用 AI 重构核心业务流程,结果项目延期、效果不达预期、团队信心受挫。正确的做法是从边缘功能切入。
什么算边缘功能?比如:给客服系统加一个"智能回复建议",给内部 Wiki 加一个"语义搜索",给日志系统加一个"异常摘要生成"。这些功能的特点是:失败了不影响主流程,成功了能明显提升效率,而且能快速积累 AI 应用的经验。
技术上也简单:在现有 Spring Boot 项目里加一个 Spring AI 的 starter,写一个独立的 Controller,跟主业务代码解耦。跑通了再考虑往核心链路渗透。
6.2 第二步:建立 Prompt 管理和版本控制
当 AI 功能从 1 个变成 5 个的时候,Prompt 管理就成了问题。我的做法是:
- 所有 Prompt 模板放在
resources/prompts/目录下,用.st或.txt文件存储 - 文件名带版本号,比如
customer-service-v2.st - 用 Git 管理,每次修改 Prompt 都走代码审查
- 在应用启动时加载到内存,支持热更新
这样做的目的是让 Prompt 的变更可追溯、可回滚。Prompt 改坏了导致线上回答质量下降,跟代码改坏了导致 Bug 是一个性质的事情,必须有同等的管理流程。
6.3 第三步:监控和成本控制
AI 应用上线后,必须监控三个指标:调用量、Token 消耗、响应延迟。
调用量好理解,就是每天多少次请求。Token 消耗直接关系到成本,输入 Token 和输出 Token 的单价通常不一样,要分开统计。响应延迟影响用户体验,特别是流式响应,首 Token 延迟比总延迟更重要。
Spring AI 提供了ChatModel的拦截器机制,可以在调用前后埋点:
@Bean public ChatClient chatClient(ChatClient.Builder builder) { return builder .defaultAdvisors(new TokenUsageAdvisor()) .build(); }TokenUsageAdvisor可以记录每次调用的 Token 消耗,输出到 Micrometer 或者日志系统。有了这些数据,你才能知道钱花在哪了,哪个功能的性价比最高。
提示:设置每日 Token 消耗上限,超过阈值自动降级到更便宜的模型或者直接拒绝服务。我见过因为 Prompt 写错导致无限循环调用、一天烧掉几千块的案例,这个防护必须有。
6.4 第四步:处理并发和超时
前面提过,大模型调用是慢的。在 Spring MVC 的同步模型下,一个请求占用一个线程,并发量上不去。解决方案有几个:
- 异步化:用
CompletableFuture或者@Async把 AI 调用放到独立线程池 - 流式响应:用 SSE 返回
Flux<String>,用户体验好,服务端资源占用也低 - 限流降级:对 AI 接口做独立的限流,超过阈值返回缓存结果或者友好提示
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamChat(@RequestParam String message) { return chatClient.prompt() .user(message) .stream() .content(); }流式响应配合前端的 EventSource,用户能看到文字一个个蹦出来,感知延迟大幅降低。这是目前 AI 对话类应用的标准做法。
7. 几个我踩过的坑和对应的解法
7.1 中文乱码和编码问题
Spring AI 默认的编码处理在大部分情况下没问题,但如果你从数据库或者文件读取中文内容作为 Prompt 的一部分,偶尔会遇到乱码。根源通常是某一段链路的编码不是 UTF-8。我的排查顺序是:文件读取编码 → 数据库连接编码 → HTTP 请求编码 → 响应解析编码。Spring Boot 的server.servlet.encoding.charset=UTF-8和force=true能解决大部分 Web 层的问题。
7.2 模型返回的 JSON 带 Markdown 代码块标记
让模型输出 JSON 的时候,它经常会在外面包一层```json和```。Spring AI 的StructuredOutputConverter在大部分情况下能处理,但偶尔会失败。我的做法是在 Prompt 里明确说"直接输出 JSON,不要用 Markdown 代码块包裹",同时在解析失败时做一次清洗:去掉首尾的代码块标记再解析。
7.3 向量检索的"语义漂移"
做 RAG 的时候,我发现一个现象:用户问"怎么配置数据库连接池",检索出来的却是"数据库连接超时处理"。这两个话题相关但不完全一致。原因是 Embedding 模型把"配置"和"超时处理"的向量拉得比较近。
解法是在检索前做查询改写:先用模型把用户问题改写成更适合检索的形式,再去向量库查。比如把"怎么配置数据库连接池"改写成"数据库连接池 配置 参数 设置"。这个改写步骤能明显提升检索准确率。
7.4 流式响应的错误处理
流式响应(SSE)的错误处理比普通请求麻烦。因为 HTTP 状态码在流开始的时候就已经返回 200 了,后续如果模型调用出错,你没法再改状态码。我的做法是:在流里发送一个特殊的事件类型表示错误,前端收到后展示错误提示。
return chatClient.prompt() .user(message) .stream() .content() .onErrorResume(e -> Flux.just("[ERROR] " + e.getMessage()));这样虽然不够优雅,但至少用户能知道出错了,而不是一直等一个永远不会来的响应。
7.5 本地开发用 Ollama,生产用云 API
开发阶段频繁调用云 API 成本高、速度受网络影响。我的做法是本地用 Ollama 跑一个小模型(比如 Qwen2.5 7B),开发和测试都用它。Spring AI 对 Ollama 有专门的 starter,切换只需要改配置:
# 开发环境 spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b生产环境再切回云 API。这样开发效率高,成本也可控。但要注意:本地小模型和云端大模型的能力差距可能很大,Prompt 在小模型上跑通了,不代表在大模型上效果一样。关键 Prompt 还是要在目标模型上验证。
8. 路线图:从今天开始,三个月能走到哪
如果你是一个 Java 开发者,想系统地切入 AI 应用开发,我给一个实际可执行的节奏:
第 1 到 2 周:跑通第一个 Spring AI 项目。不需要复杂功能,就是一个能对话的接口。重点是把依赖配好、把 API Key 管好、把流式响应跑通。这个阶段的目标是消除陌生感。
第 3 到 4 周:加上 RAG。找一份你熟悉的内部文档,做切分、入库、检索、生成。重点理解切分策略和检索效果之间的关系。这个阶段你会第一次感受到"AI 真的能基于我的数据回答问题"。
第 5 到 8 周:把 AI 能力接进一个真实的业务场景。选一个边缘功能,做完整的监控、限流、降级。重点积累生产环境的经验:成本怎么控、延迟怎么降、错误怎么处理。
第 9 到 12 周:尝试函数调用和 Agent。让模型能操作你的系统,完成多步骤的任务。这个阶段开始涉及复杂的编排逻辑,也是最能体现 Java 工程能力的地方。
三个月之后,你不敢说自己是 AI 专家,但至少能在团队里承担 AI 应用开发的任务,能判断一个需求用 AI 做靠不靠谱,能估算成本和工期。这就够了。剩下的深度,是在具体项目里磨出来的。
我在实际项目里最大的体会是:AI 应用开发的难点不在 AI,在应用。模型能力是现成的,但怎么把它稳定、可靠、低成本地集成到业务里,这是工程问题,而工程问题恰恰是 Java 开发者的强项。别被那些花哨的算法名词吓住,你手里的 Spring Boot 和工程思维,才是真正的入场券。