大家好,我是Java1234_小锋老师。
过去两年,大家聊 AI 应用,开口闭口都是 Python。Java 这边其实也没闲着。Quarkus 把大模型、RAG、工具调用和 MCP 直接嵌进了熟悉的开发体验里,写起来很像在写一个普通的 CDI 服务。
先认识一下 Quarkus
Quarkus 是面向云原生的 Java 框架,口号很直白:给 Java 开发者一套更轻、更快、更适合容器的开发方式。它在构建期就把大量工作做完,启动快、内存占用低,还能打成 GraalVM Native Image。日常开发里,热部署、Dev UI、统一配置这些东西,用过一次就很难回去。
很多人第一次接触 Quarkus,是冲着“微服务启动只要几十毫秒”去的。这几年它的重心已经不只是快,而是把 Java 生态里那些常用能力,REST、反应式、消息、安全、数据访问,都收成一套一致的扩展模型。你加一个扩展,配置几行属性,剩下的交给框架。
Quarkus 把云原生 Java 和大模型能力接到了一起。
AI 到来之后,这套思路被原封不动地带了过来。接入大模型不再是先搭一套 Python 服务,再让 Java 去 HTTP 调用;你可以直接在 Quarkus 应用里声明一个 AI 服务,像注入普通 Bean 一样用它。
为什么是 Quarkus 做 AI
Java 做 AI,以前总有点“隔了一层”的感觉:模型在外面,业务在里面,两边靠 REST 硬连。Quarkus 走的是另一条路,核心是 Quarkus LangChain4j 扩展。
它把 LangChain4j 的能力收进 Quarkus 的扩展体系里,常见能力大致就这几块:
- 声明式 AI Service:一个接口加上注解,就能对话、摘要、分类
- 多模型接入:OpenAI、Azure OpenAI、Ollama、Hugging Face 等,换模型主要是改配置
- Tools / Function Calling:模型可以调用你写好的 Java 方法
- RAG:把文档检索和大模型拼在一起,回答能落到自家资料上
- MCP:用标准协议发现和调用外部工具
- 可观测性:日志、指标、链路跟踪跟着 Quarkus 那套走
- Native Image:AI 应用也能打成原生镜像,启动仍然很快
AI Service、RAG、Tools、MCP,是现在这套能力的四块底座。
一次典型的调用,大概是这样:
看着复杂,落到代码上其实就几个注解。下面按使用顺序过一遍。
声明式 AI Service:写接口就能对话
这是最容易上手的一层。你不用自己拼 Prompt、不用自己管理 HTTP 客户端,定义一个接口就行。
/** * 客服助手,负责回答用户的自然语言问题。 */@RegisterAiServicepublicinterfaceCustomerAssistant{/** * 与用户对话,返回模型生成的回复。 */@SystemMessage("你是电商客服,回答要简洁,不确定的事情不要编造。")Stringchat(@UserMessageStringquestion);}配置也集中在application.properties里,本地用 Ollama、线上切 OpenAI,通常不用改 Java 代码:
# 本地开发可以用 Ollama quarkus.langchain4j.ollama.chat-model.model-name=llama3.1 quarkus.langchain4j.ollama.chat-model.temperature=0.2REST 层注入就能用,和普通业务服务没有两样:
/** * 对外提供对话接口。 */@Path("/chat")publicclassChatResource{@InjectCustomerAssistantassistant;/** * 接收用户问题并返回 AI 回复。 */@POSTpublicStringask(Stringquestion){returnassistant.chat(question);}}第一次写的时候会有点不习惯:一个没有实现类的接口,居然就能聊天。后面你会发现,Quarkus 在构建期就把模型调用、JSON 映射、CDI 装配这些事做掉了。这正是它一贯的风格。
Tools:让模型去调你的业务方法
纯聊天很快会碰到天花板。用户问“我的订单发了没”,模型自己并不知道仓库里有什么。这时就把业务方法暴露成 Tool,模型觉得需要时会自己调用。
/** * 订单查询工具,供大模型在对话中按需调用。 */@ApplicationScopedpublicclassOrderTools{@InjectOrderRepositoryorderRepository;/** * 根据订单号查询物流状态。 */@Tool("根据订单号查询当前物流状态")publicStringfindOrderStatus(StringorderNo){Orderorder=orderRepository.findByOrderNo(orderNo);if(order==null){return"未找到该订单";}return"订单 "+orderNo+" 当前状态:"+order.getStatus();}}AI 服务这边用@ToolBox把工具挂上去:
/** * 能查询订单的客服助手。 */@RegisterAiServicepublicinterfaceOrderAssistant{@SystemMessage("你是订单助手。只有在需要查真实订单时才调用工具,不要编造物流信息。")@ToolBox(OrderTools.class)Stringchat(Stringquestion);}用户说“帮我看看 A2026001 发货了没”,模型会先调用findOrderStatus,再把结果组织成自然语言。业务规则还是你自己的 Java 代码,模型只负责决定什么时候用、怎么把结果讲清楚。这个分工很重要:别把库存扣减、权限校验交给 Prompt。
RAG:先查资料,再开口说话
模型的训练数据停在某个时间点,也看不到你们公司的内部文档。RAG 的做法很朴素:先把文档切块、向量化、存起来;提问时先检索相关片段,再把片段塞进 Prompt。
Quarkus 这边可以自己实现RetrievalAugmentor,也可以用 Easy RAG 走配置。一个常见写法是这样:
/** * 文档问答助手,回答必须基于检索到的内容。 */@RegisterAiService@ApplicationScoped@SystemMessage("你是文档助手。优先根据检索到的资料作答,资料里没有的内容请直接说不知道。")publicinterfaceDocsAssistant{/** * 基于知识库回答问题。 */Stringask(Stringquestion);}检索增强器可以做成一个 CDI Bean,框架会自动挂到 AI 服务上:
/** * 把向量检索结果补充进用户问题。 */@ApplicationScopedpublicclassDocsRetrievalAugmentorimplementsSupplier<RetrievalAugmentor>{@InjectEmbeddingModelembeddingModel;@InjectEmbeddingStore<TextSegment>embeddingStore;@OverridepublicRetrievalAugmentorget(){EmbeddingStoreContentRetrieverretriever=EmbeddingStoreContentRetriever.builder().embeddingModel(embeddingModel).embeddingStore(embeddingStore).maxResults(3).build();returnDefaultRetrievalAugmentor.builder().contentRetriever(retriever).build();}}向量库可以接 Redis、PgVector、Chroma、Neo4j 这些常见存储。文档问答、内部知识库、制度查询,基本都是这个模式。
MCP:把外部能力接进模型
Tool 适合封装自家代码。可一旦工具散落在别的系统里,每个都手写适配就累了。MCP(Model Context Protocol)就是为这件事准备的标准协议:服务端暴露工具,客户端按需发现和调用。
Quarkus 两边都能做。你可以写一个 MCP Server,把已有接口贡献出去;也可以在 AI 服务里当 MCP Client,去调用别人提供的工具。
/** * 旅行助手,通过 MCP 调用外部天气服务。 */@RegisterAiServicepublicinterfaceTravelAssistant{@SystemMessage(""" 你是旅行助手。用户问天气时,先查地点,再查气温, 不要凭印象回答。 """)@McpToolBox("weather")Stringchat(Stringquestion);}对应配置大致如下:
quarkus.langchain4j.mcp.weather.transport-type=streamable-http quarkus.langchain4j.mcp.weather.url=http://localhost:8081/mcp本地方法用@ToolBox,远程能力用@McpToolBox,注解风格是统一的。对写 Java 的人来说,学习成本很低。
云原生这一套,AI 也能跟着吃
AI 功能接上之后,Quarkus 原来的好处并没有丢掉。
开发期可以用 Dev UI 看模型配置、试对话、检查工具有没有被扫描到。运行期日志、指标、链路跟踪仍然走 Micrometer 和 OpenTelemetry。部署时还能打成 Native Image,冷启动和内存占用依然是 Quarkus 的强项。这对 Serverless、缩容到零、边缘节点这类场景很有用,AI 服务不再必须是一个又重又慢的常驻进程。
启动快、镜像小、链路可观测,AI 服务也能按云原生的方式落地。
实际项目里,我比较推荐这个组合:
- 开发阶段用 Ollama 跑本地模型,调试 Prompt 和工具
- 知识类问题走 RAG,别把公司文档全塞进 System Message
- 业务动作走 Tool,把真正的规则留在 Java 里
- 跨系统能力走 MCP,避免每个外部服务都写一套胶水代码
- 上线前把模型切换、超时、限流和观测补齐
写在最后
Quarkus 拥抱 AI,不是另起一套框架,而是把大模型能力收进它本来就擅长的那套开发模型:构建期优化、声明式 API、统一配置、云原生部署。
如果你已经在用 Quarkus 做服务,补 AI 能力的路径很短。先写一个@RegisterAiService接口,再按需要挂上 Tool、RAG 或 MCP。Java 做智能应用,现在已经不必绕路了。