1. 从写业务代码到调用大模型:Java 开发者切入 AI 的真实路径
做了五六年 Java 后端的人,第一次认真想学 AI 的时候,大概率会经历一段挺拧巴的时期。你打开各种教程,满屏都是 Python,pip install、Jupyter Notebook、PyTorch 张量操作,看两天就开始怀疑自己这些年攒的 Spring 生态经验是不是白费了。我身边好几个做支付、做 SaaS 的朋友都问过我同一个问题:是不是得先把 Python 学一遍,才能碰 AI?
答案是不用。至少对于绝大多数做企业级应用的 Java 开发者来说,你真正要解决的不是训练模型,而是把已经存在的大模型能力接进你现有的系统里——做知识库问答、做智能客服、做文档理解、做流程自动化。这类活儿的核心难点根本不在模型本身,而在于工程化:怎么管理对话上下文、怎么做检索增强、怎么控制 token 成本、怎么保证输出稳定、怎么和现有的 Spring Boot 服务、数据库、权限体系对接。这些恰恰是 Java 开发者最擅长的事情。
所以这篇东西我想聊的是一条更务实的路线:不追求让你成为算法工程师,而是让你在现有 Java 技术栈的基础上,用最短的路径把 AI 能力真正落到项目里。关键词会围绕Spring AI、LangChain4j、RAG、Agent这些你最近肯定反复看到的东西展开,但重点不是罗列概念,而是讲清楚每个环节为什么这么选、坑在哪里、怎么少走弯路。适合有 Java 基础、想往 AI 应用方向转、或者被老板要求"给系统加个 AI 功能"的开发者。
2. 先想清楚你要做的是哪一类 AI 开发
2.1 三种角色,路线完全不同
很多人一上来就焦虑"要不要学深度学习",其实是因为没分清自己在 AI 产业链里的位置。粗略分一下,Java 开发者能切入的方向大概有三种:
| 方向 | 典型工作 | 是否需要训练模型 | 对 Java 开发者的友好度 |
|---|---|---|---|
| 模型训练/微调 | 数据清洗、调参、LoRA 微调 | 需要 | 低,基本是 Python 生态 |
| AI 应用开发 | 调用 API、编排流程、做 RAG | 不需要 | 极高,就是后端工程 |
| AI 平台/基础设施 | 推理服务部署、网关、监控 | 部分需要 | 中高,偏运维和架构 |
绝大多数 Java 开发者真正该走的是第二条路。你不需要懂反向传播,但你需要懂怎么把大模型的输出变成系统里可靠的一环。这个定位一旦清晰,学习路径立刻就窄了,也轻松了。
2.2 为什么"应用开发"这条路对 Java 人特别友好
大模型应用开发本质上是一个编排问题,而不是一个数学问题。你要处理的是:用户输入进来,先做意图识别,再决定是查知识库还是调工具,拿到结果后拼装 prompt,调用模型,解析输出,做后处理,最后返回。这一整套流程,和你写一个复杂的业务编排服务没有本质区别。
而且企业级 AI 应用对稳定性、可观测性、事务一致性、权限控制的要求,恰恰是 Java 生态沉淀了二十年的强项。Python 那边做 demo 快,但真到了要接入公司统一认证、要打日志埋点、要做灰度发布、要保证接口 SLA 的时候,Spring 那一套东西的价值就体现出来了。我见过太多 Python 写的 AI demo 在进生产时被推倒重来,就是因为工程化能力跟不上。
2.3 一个反直觉的建议:先别急着学 LangChain
网上搜"Java AI 入门",十篇有八篇让你先学 LangChain4j。我的建议是反过来的:先用最原始的方式调通一次大模型 API,哪怕就是发个 HTTP 请求。你要亲眼看到请求体长什么样、messages数组的结构、role和content怎么组织、返回的 JSON 里choices和usage字段是什么。这一步花你半小时,但能让你后面用任何框架时都不至于"黑盒恐惧"。
我当初就是先手写了一个HttpClient调用,把 system prompt、user prompt、多轮对话的拼接方式全手动实现了一遍,之后再上 Spring AI,看它的ChatClient封装就一目了然——它无非是把你手写的那堆东西抽象成了流式 API。这个顺序很重要,先懂原理再用框架,和先抄框架再补原理,学习效率差好几倍。
3. 工具链选型:Spring AI 和 LangChain4j 到底怎么选
3.1 两个框架的定位差异
这是被问得最多的问题,没有之一。我直接给结论,再解释原因。
Spring AI是 Spring 官方团队做的,设计哲学是"把 AI 能力当成 Spring 生态里的一个普通组件"。它的 API 风格、配置方式、依赖注入、自动装配,全都和你写 Spring Boot 一模一样。如果你团队已经在用 Spring Boot,选它几乎没有学习成本。
LangChain4j是社区驱动的,灵感来自 Python 的 LangChain,功能覆盖面更广,尤其在RAG、Agent、工具调用这些高级编排能力上,抽象层次更高,玩法更多。
| 对比维度 | Spring AI | LangChain4j |
|---|---|---|
| 出身 | Spring 官方 | 社区项目 |
| 与 Spring Boot 集成 | 原生,自动装配 | 良好,需手动配置 |
| API 风格 | 声明式、模板化 | 链式、编排式 |
| RAG 支持 | 有,相对基础 | 丰富,模块化强 |
| Agent/工具调用 | 支持 | 支持更成熟 |
| 多模型适配 | 统一抽象 | 统一抽象 |
| 学习曲线 | 平缓 | 中等 |
3.2 我的实际选择逻辑
我自己的项目里是这么分的:如果只是给现有 Spring Boot 系统加一个对话或问答功能,用 Spring AI,因为它和你现有的@Service、@ConfigurationProperties、application.yml完全融为一体,代码风格统一,团队其他人接手也快。
如果要做复杂的 RAG 系统、多步骤 Agent、需要精细控制检索和重排流程,用 LangChain4j,它的EmbeddingStore、ContentRetriever、RetrievalAugmentor这些抽象做得更细,能让你在检索链路的每个环节插自己的逻辑。
提示:这两个不是非此即彼。我见过有项目用 Spring AI 做基础对话,用 LangChain4j 做 RAG 检索层,两者通过接口隔离,各取所长。别被"必须二选一"的思维框住。
3.3 模型接入层:别把自己绑死在一家
无论用哪个框架,都要注意一件事:把模型调用抽象成接口。今天用某家的模型,明天可能因为成本、合规、效果换另一家。Spring AI 和 LangChain4j 都提供了统一的ChatModel/ChatLanguageModel抽象,你要做的就是面向这个接口编程,而不是在业务代码里到处写具体厂商的 SDK。
配置上,模型名称、API 地址、密钥这些全部走配置文件,别硬编码。我踩过的坑是早期把模型名写死在代码里,后来要换模型做 A/B 测试,改了几十个文件,血的教训。
# application.yml 示例结构 spring: ai: openai: api-key: ${AI_API_KEY} base-url: ${AI_BASE_URL} chat: options: model: ${AI_MODEL_NAME} temperature: 0.7密钥走环境变量,这是底线。我见过有人把 key 直接提交到 Git 仓库,第二天就收到账单警告。
4. RAG:Java 开发者最该吃透的那块硬骨头
4.1 RAG 到底解决了什么问题
RAG(检索增强生成)这个词现在满天飞,但很多人没搞明白它为什么存在。大模型有两个硬伤:一是知识有截止日期,训练完之后的新信息它不知道;二是不知道你公司的私有数据。你问它"我们公司上季度的报销政策是什么",它只能瞎编。
RAG 的思路很朴素:在问模型之前,先去你的知识库里把相关资料捞出来,塞进 prompt 里,让模型基于这些资料回答。就像开卷考试,模型不用背下所有知识,只要会"读资料+总结"就行。
这个思路听起来简单,但真正做起来,难点全在"怎么捞得准"。捞错了资料,模型就会一本正经地胡说八道,这就是所谓的RAG 幻觉。
4.2 一条完整的 RAG 链路拆解
一条标准的 RAG 流程,我把它拆成六个环节,每个环节都有坑:
- 文档加载:把 PDF、Word、网页、数据库记录读进来。坑在于格式五花八门,PDF 里的表格和图片经常丢。
- 文本切分(Chunking):长文档要切成小块。切太大,检索不精准;切太小,语义不完整。常见做法是按 500-1000 字符切,块之间留 10%-20% 重叠。
- 向量化(Embedding):把每个文本块转成一串数字向量。这一步要调 embedding 模型。
- 存储:把向量存进向量数据库。Java 生态里常用的有 Redis(带向量搜索)、Milvus、PgVector、Elasticsearch 等。
- 检索:用户提问也转成向量,去库里找最相似的 top-k 个块。
- 生成:把检索到的块和用户问题拼成 prompt,交给大模型生成答案。
4.3 切分策略:最容易被忽视但最影响效果的一步
我做过一个内部文档问答,一开始效果很差,答非所问。排查了半天,问题出在切分上——我按固定长度硬切,结果一个完整的操作步骤被从中间劈开,检索到的块只有半截信息。
后来改成按语义结构切分:优先按标题、段落、列表项切,实在太长再按长度切。效果立刻上了一个台阶。LangChain4j 里有DocumentSplitter的各种实现,Spring AI 也有TokenTextSplitter,但你要根据自己文档的特点去调参数,没有万能配置。
注意:中文文档的切分和英文不一样。英文按空格和标点切很自然,中文得考虑标点符号和语义边界。如果你的文档中英混杂,切分逻辑要额外处理。
4.4 检索质量:RAG 的成败在这里
检索环节有几个提升手段,按性价比排序:
- 混合检索:向量检索(语义相似)+ 关键词检索(BM25)结合,能显著提升召回率。纯向量检索对专有名词、型号、代码这类精确匹配不敏感。
- 重排(Rerank):先粗召回 20-50 个块,再用重排模型精排出 top 3-5 个。这一步对最终效果提升明显,但会增加延迟。
- 查询改写:用户的问题往往很口语化,先用模型把它改写成更适合检索的形式,再去做检索。
我实测下来,混合检索 + 重排这个组合,能把 RAG 的命中率从"勉强能用"提升到"敢给客户看"。代价是链路变长、延迟增加,需要权衡。
4.5 一个最小可跑的 RAG 骨架
下面是一个用 LangChain4j 思路组织的伪代码骨架,帮你理解各组件怎么串起来:
// 1. 加载并切分文档 List<Document> documents = FileSystemDocumentLoader.loadDocuments("/docs"); List<TextSegment> segments = new DocumentSplitter(800, 100).splitAll(documents); // 2. 向量化并存储 EmbeddingModel embeddingModel = ...; EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>(); EmbeddingStoreIngestor.ingest(segments, store, embeddingModel); // 3. 构建检索增强的对话 ContentRetriever retriever = EmbeddingStoreContentRetriever.builder() .embeddingStore(store) .embeddingModel(embeddingModel) .maxResults(5) .minScore(0.7) .build(); RetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder() .contentRetriever(retriever) .build(); Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(chatModel) .retrievalAugmentor(augmentor) .build(); String answer = assistant.chat("我们公司的报销流程是什么?");这段代码的价值不在于能直接跑,而在于让你看清 RAG 的每个环节在代码里对应什么。maxResults和minScore这两个参数是调优的重点,前者控制塞给模型多少资料,后者控制检索的严格程度。
5. 从 RAG 到 Agent:能力边界的一次跃迁
5.1 Agent 和 RAG 的本质区别
RAG 是"查了再答",Agent 是"想清楚再动手"。RAG 的流程是固定的:检索→生成。而 Agent 会根据任务自己决定下一步做什么——可能需要查数据库、可能调用某个 API、可能先反问用户澄清需求,甚至可能连续调用多个工具完成一个复杂任务。
举个例子:用户说"帮我查一下上个月销售额最高的三个产品,然后生成一份对比报告"。RAG 做不了这个,因为它需要多步操作和工具调用。Agent 可以:先调销售数据接口,拿到数据,再调报告生成工具,最后组织语言输出。
5.2 Java 里怎么落地 Agent
LangChain4j 对 Agent 的支持比较成熟,核心是**工具调用(Tool Calling / Function Calling)**机制。你把自己的 Java 方法用注解标记成"工具",模型在需要时会主动"调用"它。
public class SalesTools { @Tool("查询指定月份的销售数据") public String querySales(@P("月份,格式 yyyy-MM") String month) { // 实际查数据库逻辑 return salesData; } }然后把这个工具类注册给 AI Service,模型就能在对话中自主决定是否调用它。这个机制是 Agent 的基础,理解透了,很多高级玩法都能自己搭出来。
5.3 Agentic RAG:把两者结合起来
现在很火的一个方向叫Agentic RAG,思路是让 Agent 来驱动 RAG 流程。传统 RAG 是"一次检索定生死",Agentic RAG 则是:先判断这个问题需不需要检索,需要的话检索一次,看看结果够不够,不够就换个查询词再检索,或者去调别的工具补充信息,直到信息足够再生成答案。
这个模式对复杂问题的效果提升很明显,但工程复杂度也上去了。我的建议是:先把基础 RAG 做扎实,再考虑上 Agent。基础 RAG 都没调好就上 Agent,只会让问题更难定位。
6. 那些没人告诉你但一定会踩的坑
6.1 Token 成本:比你想的烧得快
大模型按 token 计费,输入和输出都算钱。RAG 场景下,每次请求都要把检索到的资料塞进 prompt,token 消耗量是普通对话的好几倍。我见过一个没做任何优化的知识库问答,单次请求输入 token 上万,一天下来成本吓人。
控制成本的手段:精简检索结果(别一股脑塞 10 个块)、缓存高频问题(相同问题直接返回缓存答案)、用小模型做预处理(意图识别、查询改写用便宜的小模型,最终生成才用大模型)。这些优化做下来,成本能降一大半。
6.2 流式输出:用户体验的关键
大模型生成一段话可能要好几秒,如果等全部生成完再返回,用户会觉得卡死。**流式输出(Streaming)**是必须做的——模型生成一个字就推一个字给前端,用户能立刻看到内容在"打字"。
Spring AI 和 LangChain4j 都支持流式,Spring AI 里返回Flux<String>,配合 WebFlux 或 SSE 推给前端。这里有个坑:流式场景下错误处理更麻烦,因为响应已经开始推送了,中途出错没法简单返回错误码,得在流里发一个特殊的错误事件让前端处理。
6.3 上下文窗口:不是越大越好
模型有上下文长度限制,超过就报错或截断。但即使没超,塞太多内容也会让模型"注意力分散",反而答不好。我的经验是:检索结果控制在 3-5 个块,总长度别超过上下文窗口的一半,留足空间给模型思考和输出。
多轮对话也一样,历史消息不能无限累积。常见做法是保留最近 N 轮,或者对早期对话做摘要压缩。LangChain4j 有ChatMemory的各种实现,MessageWindowChatMemory就是按条数保留。
6.4 输出格式不稳定:结构化输出的痛
你让模型返回 JSON,它大部分时候听话,但偶尔会加个"好的,以下是结果:"的前缀,或者少个引号,导致解析失败。这在生产环境是致命的。
解决办法有几个层次:一是 prompt 里明确要求"只返回 JSON,不要任何其他文字";二是用模型的结构化输出能力(如果支持);三是在代码里做容错解析,比如用正则先提取 JSON 部分再解析。我一般三个一起上,尤其是容错解析,必须有。
6.5 数据一致性:AI 和业务系统的边界
这是 Java 开发者特别该关注的点。AI 生成的内容如果涉及写操作(比如 Agent 帮用户下单),一定要和业务系统的事务边界划清楚。我的原则是:AI 只负责"决策"和"生成",真正的写操作走原有的业务接口,由业务代码保证一致性。别让模型直接操作数据库,出了事没法回滚。
7. 一条可以照着走的 90 天学习路线
7.1 第一个月:打通基础链路
这个阶段的目标是"能跑通",不求深。具体任务:
- 手写 HTTP 调用一次大模型 API,理解请求响应结构
- 用 Spring AI 或 LangChain4j 搭一个最简单的对话接口
- 理解 prompt 的基本写法:system、user、assistant 三种角色的作用
- 把对话接口接进一个 Spring Boot 项目,能通过浏览器访问
这个月别碰 RAG,别碰 Agent,就把"调用模型"这件事做熟。我见过太多人一上来就搞 RAG,结果连 prompt 都没写明白,检索出来的东西也不知道怎么用。
7.2 第二个月:吃透 RAG
- 准备一份自己的文档(产品手册、技术文档都行)
- 完整走一遍加载、切分、向量化、存储、检索、生成
- 重点调优切分策略和检索参数,观察效果变化
- 加入混合检索和重排,对比效果差异
这个月的核心是建立对检索质量的直觉。你要能通过看检索结果,判断问题出在切分、embedding 还是检索参数上。这种直觉只能靠反复实验积累。
7.3 第三个月:进阶与工程化
- 学习工具调用,做一个能查数据库的简单 Agent
- 加入流式输出、对话记忆、错误处理
- 做成本监控和日志埋点
- 思考如何和现有系统的权限、审计体系对接
到这一步,你已经能独立负责一个 AI 应用模块了。剩下的就是在一个个真实项目里打磨,遇到问题解决问题,能力自然就上去了。
7.4 关于"要不要学 Python"
我的看法是:作为 Java 开发者,Python 不是必修课,但值得了解。你不需要用它写生产代码,但看懂 Python 的 AI 示例、能跑通一些开源工具,会让你获取信息的渠道宽很多。很多最新的 AI 玩法都是 Python 社区先出来的,能读懂就多一分先机。花两周学个基础语法,性价比很高。
8. 我在实际项目里攒下的几条经验
第一条,永远给模型输出留后路。不管 prompt 写得多好,都要假设模型会出错。解析失败要有降级方案,生成内容要有兜底文案,关键操作要有二次确认。把模型当成一个"能力很强但偶尔不靠谱的实习生",而不是一个确定性的函数。
第二条,日志和可观测性从第一天就要做。每次调用的输入、输出、token 消耗、耗时、检索到的文档 ID,全部记下来。出问题时这些日志就是你的救命稻草。我有个项目上线后效果突然变差,就是靠对比日志发现是上游文档更新导致切分结果变了。
第三条,别追求一步到位。AI 应用的效果是迭代出来的,不是设计出来的。先上线一个能用的版本,收集真实用户的提问,看哪些答得好哪些答得差,针对性优化。闭门造车调参数,往往调不到点子上。
第四条,关注社区动态但别追新。这个领域每周都有新框架新概念,追是追不完的。把 Spring AI 或 LangChain4j 其中一个用熟,理解透 RAG 和 Agent 的本质,比追十个新框架有用得多。工具会变,但"检索增强""工具调用""上下文管理"这些底层思路是稳定的。
最后分享一个我自己的习惯:我会维护一个"prompt 笔记本",把每个项目里调好的 prompt、踩过的坑、有效的参数配置都记下来。下次遇到类似场景,直接翻笔记,省下大量重复试错的时间。这个习惯看起来笨,但两年下来,它是我最值钱的资产之一。