最近在尝试将AI能力集成到Java应用中时发现市面上针对Java开发者的AI应用开发框架选择不多且配置复杂。Spring AI的出现特别是其与阿里云等国内服务的集成为Java开发者提供了一条开箱即用的捷径。本文将手把手带你从零开始基于Spring AI Alibaba构建一个完整的AI应用涵盖环境搭建、核心概念、代码实战、常见问题及生产级最佳实践无论你是刚接触AI的Java开发者还是希望快速落地AI能力的技术团队都能从中获得一套可直接复用的解决方案。1. Spring AI Alibaba 背景与核心概念在深入代码之前我们有必要理解Spring AI是什么以及它如何与Alibaba生态结合这能帮助我们在后续开发中做出更合理的技术决策。1.1 什么是Spring AISpring AI是一个由Spring官方社区孵化的项目旨在将生成式人工智能Generative AI能力无缝集成到Spring应用程序中。它的核心目标是为Java开发者提供一个抽象层屏蔽不同AI服务提供商如OpenAI、Azure OpenAI、Anthropic、阿里云百炼等在API调用、参数格式、响应解析等方面的差异。你可以把它想象成Spring Data对数据库操作的抽象或者Spring Cloud对微服务治理的抽象只不过这次抽象的对象是AI大模型。它解决了什么问题供应商锁定应用代码不直接依赖某一家AI服务商的SDK通过更换配置即可切换底层模型提供商。开发复杂度统一了Prompt构建、模型调用、流式响应处理、上下文管理等通用模式开发者只需关注业务逻辑。Spring生态集成天然支持Spring Boot的自动配置、依赖注入、外部化配置application.yml、Actuator监控等特性与现有Spring技术栈无缝融合。1.2 Spring AI Alibaba 是什么“Spring AI Alibaba”并非一个独立的官方项目名称而是指Spring AI框架与阿里巴巴云智能集团提供的AI服务进行集成的实践。目前Spring AI官方通过spring-ai-alibaba模块或相关starter提供了对阿里云百炼平台Model Studio上多种大语言模型LLM和嵌入模型Embedding Model的支持。阿里云百炼是一个企业级大模型服务平台提供了通义千问系列等多种模型。通过Spring AI接入开发者可以使用统一的ChatClient、EmbeddingClient等接口来调用这些模型而无需直接处理阿里云API的签名、鉴权等底层细节。核心价值合规与可控对于国内企业和开发者使用国内云服务商的AI模型在数据合规、网络延迟、服务稳定性方面更有保障。开箱即用Spring Boot的“约定大于配置”理念得以延续只需添加依赖、配置API Key和端点即可开始调用AI模型。统一编程模型无论后端连接的是OpenAI的GPT还是阿里云的通义千问你的业务代码如服务层、控制器层几乎不需要改动。1.3 核心组件与抽象理解以下几个关键接口和概念是高效使用Spring AI的基础ChatClient聊天客户端用于与大语言模型进行对话交互。这是最常用的接口。Prompt表示发送给模型的请求通常包含一个或多个Message对象。Message代表对话中的一条消息有系统消息SystemMessage、用户消息UserMessage、助手消息AssistantMessage等类型。ChatResponse模型调用后返回的响应其中包含模型生成的AssistantMessage。EmbeddingClient嵌入客户端用于将文本转换为高维向量Embedding常用于检索增强生成RAG应用。VectorStore向量存储抽象用于存储和检索EmbeddingSpring AI支持PgVector、Redis、Milvus等多种实现。AiStream和ResponseEntityFluxT用于处理模型的流式响应实现打字机效果提升用户体验。2. 环境准备与项目初始化我们将创建一个标准的Spring Boot 3.x项目并集成Spring AI Alibaba相关依赖。2.1 基础环境要求JDK: 17 或更高版本Spring Boot 3.x 要求构建工具: Maven 3.6 或 Gradle 7.xIDE: IntelliJ IDEA, VS Code, Eclipse等推荐使用IntelliJ IDEA其对Spring Boot支持最好阿里云账号: 需要开通百炼平台服务并获取API Key下文会详细说明。2.2 创建Spring Boot项目使用 Spring Initializr 或IDE的创建向导生成一个项目。关键依赖选择Project: MavenLanguage: JavaSpring Boot: 3.2.5 (建议选择当前稳定版本)Packaging: JarJava: 17Dependencies:Spring Web- 用于构建RESTful API。Lombok- 简化Java Bean代码可选但推荐。Spring AI- 这是总依赖。在Initializr中可能尚未收录我们可以手动添加。2.3 手动添加Spring AI Alibaba依赖由于Spring AI Alibaba的依赖可能不在Initializr默认列表中我们需要在创建项目后手动修改pom.xml文件。首先添加Spring AI的BOMBill of Materials来统一管理所有Spring AI模块的版本。!-- 在 pom.xml 的 project 标签下添加 -- dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version0.8.1/version !-- 请检查并使用最新稳定版 -- typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement然后在dependencies部分添加具体的starter依赖。要使用阿里云百炼我们需要添加对应的连接器。dependencies !-- Spring Boot 基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency !-- Spring AI Alibaba 百炼 Starter -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-alibaba-bailian-spring-boot-starter/artifactId /dependency !-- 如果你还需要使用Embedding等功能可能需要添加其他starter如Ollama本地测试用 -- !-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-ollama-spring-boot-starter/artifactId /dependency -- /dependencies版本说明Spring AI版本迭代较快请务必访问 Spring AI官方文档 或 GitHub仓库 查看最新稳定版本。本文基于0.8.1版本编写核心概念和API基本稳定。2.4 获取阿里云百炼API密钥登录 阿里云官网 。进入百炼控制台产品全称模型服务平台灵积。在左侧菜单找到API-KEY管理。创建一个新的API Key并妥善保存。你会得到类似sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx的密钥。同时你还需要知道服务的Endpoint端点地址。通常格式为https://dashscope.aliyuncs.com/compatible-mode/v1。具体地址请以百炼平台官方文档为准。3. 核心配置与第一个AI对话应用配置是连接Spring AI和阿里云服务的关键一步。3.1 配置application.yml在src/main/resources/application.yml文件中添加Spring AI Alibaba的配置。spring: application: name: spring-ai-alibaba-demo ai: # 配置阿里云百炼 alibaba: bailian: # 从百炼控制台获取的API Key api-key: sk-你的实际API-KEY # 百炼服务的端点地址 base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 # 默认使用的聊天模型例如通义千问Max chat: options: model: qwen-max temperature: 0.7 # 创造性0-2之间越高越随机 max-tokens: 2000 # 最大输出token数 # 可选开启Actuator端点查看AI相关的健康信息和指标 management: endpoints: web: exposure: include: health,info,metrics,ai配置项详解spring.ai.alibaba.bailian.api-key: 必填你的身份凭证。spring.ai.alibaba.bailian.base-url: 必填服务地址。注意/compatible-mode/v1路径是为了兼容OpenAI API格式方便Spring AI调用。spring.ai.alibaba.bailian.chat.options.model: 指定默认使用的模型。百炼平台提供多个模型如qwen-max通义千问Max、qwen-plus、qwen-turbo等请根据你的需求和服务开通情况选择。temperature: 采样温度控制输出的随机性。值越低如0.1输出越确定、保守值越高如1.0输出越多样、有创意。根据任务类型调整。max-tokens: 限制模型单次响应的最大长度。设置此值可以控制成本并防止生成过长内容。安全提示永远不要将真实的api-key提交到代码仓库。在生产环境中应使用环境变量、配置中心如Nacos、Apollo或云厂商的密钥管理服务来注入这些敏感信息。例如api-key: ${ALIBABA_BAILIAN_API_KEY:}然后在启动应用时设置环境变量ALIBABA_BAILIAN_API_KEY。3.2 创建聊天服务接下来我们创建一个Spring Service来封装AI对话逻辑。// 文件路径src/main/java/com/example/demo/service/AiChatService.java package com.example.demo.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.SystemPromptTemplate; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; Service Slf4j RequiredArgsConstructor public class AiChatService { // 注入Spring AI自动配置的ChatClient private final ChatClient chatClient; /** * 简单的单轮对话 * param userMessage 用户输入的问题 * return 模型的回答 */ public String simpleChat(String userMessage) { log.info(用户提问: {}, userMessage); // 方式1使用ChatClient的fluent API推荐更简洁 String response chatClient.prompt() .user(userMessage) .call() .content(); log.info(模型回答: {}, response); return response; } /** * 带系统指令的对话更可控 * param userMessage 用户问题 * return 模型的回答 */ public String chatWithSystemPrompt(String userMessage) { // 定义系统指令约束模型的行为 String systemText 你是一个专业的Java技术专家擅长用简洁、准确的语言回答Spring框架和AI相关的问题。 如果用户的问题超出这个范围请礼貌地告知。 你的回答需要结构清晰必要时使用列表或代码示例。 ; // 构建Prompt包含系统消息和用户消息 Prompt prompt new Prompt( List.of( new SystemPromptTemplate(systemText).createMessage(), // 系统消息 new UserMessage(userMessage) // 用户消息 ) ); // 调用模型 ChatResponse chatResponse chatClient.call(prompt); String response chatResponse.getResult().getOutput().getContent(); log.info(带系统指令的对话回答: {}, response); return response; } /** * 使用参数化系统提示词 * param userMessage 用户问题 * param role 为模型设定的角色 * return 模型的回答 */ public String chatWithDynamicRole(String userMessage, String role) { // 使用模板动态插入角色信息 SystemPromptTemplate systemPromptTemplate new SystemPromptTemplate( 你是一个{role}。请根据你作为{role}的专业知识来回答用户的问题。 回答要体现专业性和针对性。 ); Message systemMessage systemPromptTemplate.createMessage(Map.of(role, role)); Prompt prompt new Prompt(List.of(systemMessage, new UserMessage(userMessage))); return chatClient.call(prompt).getResult().getOutput().getContent(); } }代码解析RequiredArgsConstructor是Lombok注解为final字段chatClient生成构造函数实现依赖注入。ChatClient是Spring AI的核心接口Spring Boot会根据application.yml的配置自动为我们创建一个连接到阿里云百炼的ChatClientBean。simpleChat方法展示了最简洁的调用方式chatClient.prompt().user(...).call().content()。chatWithSystemPrompt方法展示了如何添加SystemMessage来引导模型行为这对于提升回答质量和安全性至关重要。SystemPromptTemplate允许我们创建带占位符的模板使系统指令更灵活。3.3 创建REST控制器创建一个简单的Controller来暴露HTTP API。// 文件路径src/main/java/com/example/demo/controller/ChatController.java package com.example.demo.controller; import com.example.demo.service.AiChatService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/ai) RequiredArgsConstructor public class ChatController { private final AiChatService aiChatService; PostMapping(/chat) public String chat(RequestParam String message) { return aiChatService.simpleChat(message); } PostMapping(/chat/system) public String chatWithSystem(RequestParam String message) { return aiChatService.chatWithSystemPrompt(message); } PostMapping(/chat/role) public String chatWithRole(RequestParam String message, RequestParam(defaultValue 技术文档编写助手) String role) { return aiChatService.chatWithDynamicRole(message, role); } }3.4 运行与测试启动Spring Boot应用。使用curl、Postman或浏览器插件进行测试。测试简单对话curl -X POST http://localhost:8080/api/ai/chat?message用Java写一个Hello World程序测试带系统指令的对话curl -X POST http://localhost:8080/api/ai/chat/system?message解释一下Spring Bean的生命周期测试动态角色对话curl -X POST http://localhost:8080/api/ai/chat/role?message分析一下新能源汽车行业的现状role行业分析师如果一切配置正确你将收到来自阿里云通义千问模型的JSON格式响应Spring AI已自动处理我们得到的是纯文本内容。4. 进阶功能实战掌握了基础对话后我们探索Spring AI更强大的功能。4.1 流式响应Streaming流式响应允许模型一边生成我们一边接收非常适合需要实时显示的场景如聊天界面。Spring AI对此有很好的支持。// 在 AiChatService 中添加方法 import org.springframework.ai.chat.client.fluent.Response; import reactor.core.publisher.Flux; import java.util.concurrent.atomic.AtomicReference; public FluxString streamChat(String userMessage) { log.info(开始流式对话用户提问: {}, userMessage); // 使用ChatClient的流式调用 ResponseChatResponse response chatClient.prompt() .user(userMessage) .stream() .call(); // 将ChatResponse的Flux转换为字符串内容的Flux return response.content() .map(chunk - { // chunk是流式返回的每一块内容 String content chunk; log.debug(收到流式块: {}, content); return content; }); }// 在 ChatController 中添加新的端点 import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import reactor.core.publisher.Flux; GetMapping(value /chat/stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString streamChat(RequestParam String message) { return aiChatService.streamChat(message); }测试流式接口 可以使用支持Server-Sent Events (SSE)的客户端进行测试如浏览器EventSource或curl。curl -N http://localhost:8080/api/ai/chat/stream?message用一百字介绍Spring AI你会看到回答内容以数据流的形式逐步返回。4.2 使用EmbeddingClient和向量数据库RAG雏形检索增强生成RAG是当前AI应用的热点。Spring AI提供了EmbeddingClient和VectorStore抽象。这里我们以简单的内存向量存储InMemoryVectorStore为例演示如何将本地知识库向量化并用于问答。首先添加相关依赖如果使用Ollama本地运行嵌入模型做测试dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-ollama-spring-boot-starter/artifactId /dependency并在application.yml中配置Ollama假设本地运行了Ollama服务spring: ai: ollama: base-url: http://localhost:11434 embedding: options: model: nomic-embed-text # 或其它嵌入模型然后创建RAG服务// 文件路径src/main/java/com/example/demo/service/SimpleRagService.java package com.example.demo.service; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingClient; import org.springframework.ai.reader.TextReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.InMemoryVectorStore; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import java.util.List; Service Slf4j RequiredArgsConstructor public class SimpleRagService { private final EmbeddingClient embeddingClient; private final ResourceLoader resourceLoader; private VectorStore vectorStore; PostConstruct public void init() { // 初始化内存向量存储 this.vectorStore new InMemoryVectorStore(embeddingClient); // 加载本地文档并存入向量库示例 loadDocuments(); } private void loadDocuments() { try { // 假设在 resources/documents 下有一个知识文件 Resource resource resourceLoader.getResource(classpath:documents/company_faq.txt); TextReader textReader new TextReader(resource); textReader.getCustomMetadata().put(source, company_faq.txt); // 读取文档 ListDocument documents textReader.get(); // 文本分割器将长文档切分成适合嵌入的小块 TokenTextSplitter textSplitter new TokenTextSplitter(); ListDocument splitDocuments textSplitter.apply(documents); // 将文档块添加到向量存储会自动调用EmbeddingClient生成向量 vectorStore.add(splitDocuments); log.info(成功加载并向量化了 {} 个文档块。, splitDocuments.size()); } catch (Exception e) { log.error(加载文档失败, e); } } /** * 基于向量检索的问答 * param question 用户问题 * return 结合检索内容的回答 */ public String ragChat(String question) { // 1. 检索从向量库中查找与问题最相关的文档片段 ListDocument similarDocuments vectorStore.similaritySearch(question); log.info(检索到 {} 个相关文档片段。, similarDocuments.size()); // 2. 构建增强后的Prompt StringBuilder context new StringBuilder(); for (Document doc : similarDocuments) { context.append(doc.getContent()).append(\n---\n); } String enhancedPrompt String.format( 请基于以下上下文信息回答用户的问题。如果上下文信息不足以回答问题请根据你的知识回答并说明信息不足。 上下文信息 %s 用户问题%s 回答 , context.toString(), question); // 3. 调用ChatClient这里需要注入ChatClient为了示例清晰假设已注入 // ChatClient chatClient ... // return chatClient.prompt().user(enhancedPrompt).call().content(); // 此处为示例实际需要注入ChatClient return 这是一个RAG回答示例实际需要结合检索到的上下文和模型调用。检索到的上下文片段数 similarDocuments.size(); } }这个示例展示了RAG的基本流程文档加载-文本分割-向量化存储-相似性检索-构建增强Prompt-调用LLM。在生产环境中你需要将InMemoryVectorStore替换为PgVectorStorePostgreSQL、RedisVectorStore等持久化方案。5. 常见问题与排查思路在集成Spring AI Alibaba过程中你可能会遇到以下问题。问题现象可能原因排查步骤与解决方案启动报错Failed to configure a DataSource引入了数据库相关的starter如JPA但未配置数据源。1. 检查pom.xml如果不需要数据库排除相关依赖。2. 或者在application.yml中配置正确的数据库连接信息。调用API返回401 UnauthorizedAPI Key配置错误或失效Endpoint地址错误。1. 检查application.yml中的api-key和base-url确保无误。2. 登录阿里云百炼控制台确认API Key状态是否正常、是否有余额或调用额度。3. 确认base-url的路径是否正确特别是/compatible-mode/v1部分。调用API返回404 Not Found或Model not found配置的模型名称不正确或该模型在你所在区域未开通。1. 检查spring.ai.alibaba.bailian.chat.options.model的值。2. 前往百炼控制台“模型广场”或“模型部署”页面查看你可用的模型列表并使用正确的模型标识符。应用启动正常但ChatClient注入失败Spring AI Alibaba Starter未正确引入或版本冲突配置缺失。1. 检查pom.xml中spring-ai-alibaba-bailian-spring-boot-starter依赖是否存在且版本与BOM一致。2. 检查application.yml中是否有spring.ai.alibaba.bailian配置节。3. 查看启动日志是否有关于ChatClient或EmbeddingClientBean创建失败的警告。流式响应不工作一次性返回全部内容客户端未正确支持SSEController produces媒体类型设置错误。1. 确保Controller方法返回FluxString并且注解为GetMapping(produces MediaType.TEXT_EVENT_STREAM_VALUE)。2. 使用正确的客户端如curl -N或前端使用EventSource进行测试。3. 检查模型本身是否支持流式输出。响应速度慢网络延迟模型本身生成速度首次冷启动。1. 检查网络连接。2. 尝试使用响应更快的模型如qwen-turbo。3. 对于生产环境考虑使用连接池、异步调用、缓存常见回答等优化策略。6. 生产环境最佳实践与工程建议将Spring AI Alibaba应用到生产环境需要考虑更多工程化因素。6.1 配置管理与安全密钥分离绝对不要将API Key硬编码在代码或配置文件中。必须使用环境变量、JVM参数或专业的密钥管理服务如阿里云KMS、HashiCorp Vault来注入。spring: ai: alibaba: bailian: api-key: ${ALIBABA_BAILIAN_API_KEY}多环境配置使用Spring Profiles为开发、测试、生产环境配置不同的模型、参数和端点如果需要。例如开发环境使用较小、较快的模型生产环境使用更强大、更稳定的模型。配置中心在微服务架构中将AI相关配置如模型名称、temperature、max-tokens统一管理在Nacos、Apollo等配置中心实现动态刷新和统一治理。6.2 性能与稳定性超时与重试在application.yml中配置合理的超时时间和重试策略。Spring AI的HTTP客户端通常基于RestTemplate或WebClient可以配置连接超时、读取超时。spring: ai: alibaba: bailian: client: connect-timeout: 10s read-timeout: 30s # LLM生成可能需要较长时间熔断与降级使用Resilience4j或Sentinel为AI服务调用添加熔断器。当AI服务不稳定或超时时快速失败并返回预设的降级内容如“服务繁忙请稍后再试”或缓存的历史答案避免拖垮整个应用。异步与非阻塞对于耗时较长的AI调用务必使用异步处理如Async、CompletableFuture或响应式编程WebFlux Mono/Flux避免阻塞Web容器线程影响应用整体吞吐量。6.3 可观测性与监控日志记录详细记录AI调用的请求和响应注意脱敏不要记录完整的Prompt和包含敏感信息的Response。记录耗时、token使用量如果API提供、模型名称等信息便于问题排查和成本分析。Actuator与MetricsSpring AI Actuator端点/actuator/ai提供了模型调用次数、耗时、错误率等指标。确保这些指标被集成到你的监控系统如Prometheus Grafana中。链路追踪在微服务调用链中将AI服务调用也作为一个Span加入分布式追踪如SkyWalking, Jaeger便于分析端到端延迟。6.4 提示词工程与内容安全系统指令标准化为不同的业务场景客服、代码生成、内容创作设计标准化的系统指令模板并将其作为配置或数据库条目管理而不是硬编码在代码中。用户输入校验与过滤对用户输入的Prompt进行严格的校验、过滤和长度限制防止注入攻击Prompt Injection和资源滥用。输出内容审核对于面向公众的应用必须对模型的输出内容进行二次审核。可以结合阿里云的内容安全API或自建规则引擎过滤不当、偏见或有害信息。上下文管理对于多轮对话需要设计合理的上下文管理策略。是保存全部历史还是只保存最近N轮上下文长度会影响token消耗和模型性能。Spring AI提供了ChatMemory相关组件来辅助管理。6.5 成本控制监控Token消耗密切关注API调用返回的token使用情况输入输出。阿里云百炼等平台通常按token计费。建立成本预警机制。缓存策略对于常见、重复性高且答案相对固定的问题如产品FAQ可以将AI的回答结果缓存起来使用Redis等直接返回缓存结果避免重复调用产生费用。模型选型根据业务场景的精度和响应速度要求选择合适的模型。非关键场景或简单任务可以使用成本更低的轻量模型如qwen-turbo。从环境搭建、核心概念理解到完成第一个AI对话接口再到探索流式响应和RAG进阶功能我们走完了Spring AI Alibaba入门的核心路径。关键在于理解Spring AI的抽象层设计它让我们能用一套统一的代码应对不同的AI服务商。在实际项目中建议先从一两个核心场景如智能客服问答、代码注释生成切入将本文的示例代码跑通并集成到你的Spring Boot应用中。然后再逐步深入考虑生产级的需求如何管理配置密钥、如何设计提示词模板、如何实现异步调用和熔断降级、如何监控成本和性能。Spring AI生态仍在快速发展除了聊天和嵌入其还在扩展函数调用Function Calling、多模态图片、音频等能力。保持对官方文档和社区动态的关注将能让你更好地利用这个强大的框架在Java世界中高效地构建智能应用。