
在实际技术项目中我们经常需要将 AI 能力集成到现有系统中无论是用于内容生成、数据分析还是智能交互。Spring AI 作为一个旨在简化 AI 应用开发的框架为 Java 开发者提供了与多种大模型如 OpenAI、Azure OpenAI、Ollama 等交互的统一 API。它抽象了底层细节让开发者能更专注于业务逻辑而非复杂的 HTTP 调用和响应解析。然而从“跑通 Demo”到“稳定上线”中间隔着配置管理、异常处理、生产级最佳实践等一系列工程挑战。本文面向正在或计划使用 Spring AI 进行应用开发的 Java 工程师。我们将从一个最小化的 Spring Boot 项目开始逐步集成 Spring AI完成一个简单的对话应用。然后我们会深入探讨关键配置项、如何有效处理 AI 模型的“幻觉”问题、构建本地化 AI 代理Agent的初步思路以及在生产环境中部署时需要考虑的稳定性、监控和成本控制。通过本文你将掌握使用 Spring AI 构建可维护、可观测的 AI 功能模块的核心方法。1. 理解 Spring AI 的核心价值与工作机制在直接编写代码之前我们需要理解 Spring AI 解决了什么问题以及它是如何工作的。这有助于我们在后续配置和编码时做出正确的设计决策。1.1 为什么需要 Spring AI直接调用大模型 API如 OpenAI 的 ChatGPT API通常涉及以下步骤构造包含模型、消息、温度等参数的复杂 JSON 请求体。处理 HTTP 客户端、认证头如 Bearer Token、超时和重试。解析返回的 JSON 响应提取所需内容并处理可能出现的错误如速率限制、token 超限。如果需要切换模型供应商例如从 OpenAI 换到 Anthropic几乎要重写所有调用逻辑。Spring AI 通过提供一组高层抽象接口如ChatClient、EmbeddingClient来封装这些底层操作。开发者只需通过简单的配置指定使用哪个供应商的哪个模型然后在业务代码中注入ChatClient并调用其call方法即可。这种抽象带来了几个关键好处降低集成复杂度无需手动管理 HTTP 客户端和 JSON 序列化/反序列化。提升可移植性通过更换配置可以轻松切换底层 AI 模型业务代码无需改动。统一异常处理框架将不同供应商的错误响应转换为统一的异常体系便于处理。便于测试可以轻松 MockChatClient进行单元测试。1.2 Spring AI 的核心模块与数据流Spring AI 的核心是spring-ai-core模块它定义了ChatClient、EmbeddingClient等通用接口。针对不同的模型供应商有相应的实现模块如spring-ai-openai、spring-ai-azure-openai、spring-ai-ollama等。一次典型的 AI 调用在 Spring AI 中的处理流程如下应用层业务代码调用ChatClient.call(String message)。客户端抽象层ChatClient接口将消息转换为供应商中立的Prompt对象。供应商实现层具体的实现如OpenAiChatClient将Prompt转换为对应供应商 API 所需的请求格式JSON并通过配置好的RestClient发起调用。响应处理层收到响应后供应商实现将 JSON 响应解析为统一的ChatResponse对象其中包含Generation列表每个Generation包含返回的文本内容。应用层业务代码从ChatResponse中提取出最终的文本结果。理解这个流程后当出现调用失败、响应解析错误等问题时我们就可以清晰地知道应该在哪个环节进行排查是配置错误第3步、网络问题第3步还是响应格式异常第4步。2. 环境准备与项目初始化我们将从零开始创建一个 Spring Boot 项目并集成 Spring AI 的 OpenAI 模块。这是最快速的上手路径。2.1 基础环境要求在开始之前请确保你的开发环境满足以下要求组件要求检查命令备注JavaJDK 17 或更高版本java -versionSpring AI 需要 Java 17。构建工具Maven 3.6 或 Gradle 7.xmvn -v或gradle -v本文使用 Maven 示例。IDEIntelliJ IDEA, VS Code, Eclipse 等-推荐使用支持 Spring Boot 的 IDE。网络能够访问 OpenAI API 或你选择的模型服务curl -I https://api.openai.com如果使用本地模型如 Ollama则无需此要求。API Key有效的 OpenAI API Key-从 OpenAI 平台获取。对于学习可使用其提供的免费额度。2.2 创建 Spring Boot 项目使用 Spring Initializr 创建项目是最简单的方式。你可以通过 start.spring.io 网站或 IDE 内置的初始化功能来完成。项目基本信息Project: MavenLanguage: JavaSpring Boot: 选择最新的稳定版如 3.2.xGroup:com.exampleArtifact:spring-ai-demoPackaging: JarJava: 17依赖选择在 Dependencies 中添加Spring Web用于创建简单的 REST 控制器来暴露 AI 服务。Spring AI OpenAI这是 Spring AI 对 OpenAI 的官方支持模块。如果网站上没有可以稍后在pom.xml中手动添加。点击“Generate”下载项目压缩包并导入到你的 IDE 中。2.3 手动添加 Spring AI 依赖可选如果你在 Initializr 中没有找到 Spring AI 依赖或者需要添加其他模块可以手动修改pom.xml。首先需要添加 Spring AI 的 BOMBill of Materials来统一管理版本。在你的pom.xml的project标签下添加dependencyManagement部分dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version0.8.1/version !-- 使用当时最新的稳定版本 -- typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement然后在dependencies部分添加你需要的具体模块。对于 OpenAIdependencies !-- Spring Boot Starter Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring AI OpenAI Starter -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency !-- 其他依赖... -- /dependencies注意Spring AI 版本迭代较快请务必查阅 Spring AI 官方文档 以获取最新的 BOM 版本号和可用模块。版本不匹配是导致启动失败的最常见原因之一。添加依赖后在 IDE 中刷新 Maven 项目确保所有依赖正确下载。3. 配置与第一个 AI 对话接口依赖就绪后下一步是配置 API 密钥并编写一个简单的对话服务。3.1 配置 OpenAI API 密钥Spring AI 的配置遵循 Spring Boot 的application.properties/application.yml模式。我们需要配置模型供应商的连接信息。在src/main/resources/application.yml文件中添加以下配置spring: ai: openai: api-key: ${OPENAI_API_KEY:your-openai-api-key-here} chat: options: model: gpt-3.5-turbo temperature: 0.7配置项解释spring.ai.openai.api-key你的 OpenAI API Key。强烈建议不要将真实密钥硬编码在配置文件中。${OPENAI_API_KEY:}是 Spring 的属性占位符。它会首先查找名为OPENAI_API_KEY的系统环境变量或 JVM 属性如果找不到则使用冒号后的默认值your-openai-api-key-here。在生产环境中你应该通过环境变量、配置中心或密钥管理服务来注入这个值。spring.ai.openai.chat.options.model指定要使用的聊天模型例如gpt-3.5-turbo,gpt-4,gpt-4-turbo-preview等。spring.ai.openai.chat.options.temperature控制模型输出的随机性创造性。范围 0.0 到 2.0。值越低如 0.1输出越确定、保守值越高如 0.9输出越随机、有创造性。对于需要稳定、事实性回答的场景建议使用较低的值如 0.2-0.5。3.2 创建简单的聊天控制器现在我们来创建一个 REST 控制器它注入ChatClient并提供一个端点来与 AI 对话。在src/main/java/com/example/springaidemo/controller目录下创建AiChatController.javapackage com.example.springaidemo.controller; import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Map; RestController public class AiChatController { private final ChatClient chatClient; Autowired // 构造器注入是推荐方式 public AiChatController(ChatClient chatClient) { this.chatClient chatClient; } /** * 最简单的对话接口 * param message 用户输入的消息 * return AI 的回复文本 */ GetMapping(/ai/chat) public String chat(RequestParam(value message, defaultValue Hello) String message) { // 直接调用 ChatClient传入用户消息 String response chatClient.call(message); return response; } /** * 使用 PromptTemplate 进行结构化提示词构建 * param topic 对话主题 * return AI 生成的关于该主题的诗 */ GetMapping(/ai/poem) public String generatePoem(RequestParam(value topic, defaultValue Spring) String topic) { // 定义一个提示词模板{topic} 是占位符 String template 请以 {topic} 为主题创作一首简短的中文诗。; PromptTemplate promptTemplate new PromptTemplate(template); // 将占位符替换为实际参数生成最终的 Prompt 对象 Prompt prompt promptTemplate.create(Map.of(topic, topic)); // 调用 ChatClient ChatResponse chatResponse chatClient.call(prompt); // 从 ChatResponse 中提取 Generation 的内容 return chatResponse.getResult().getOutput().getContent(); } }代码关键点解释依赖注入控制器通过构造器注入了ChatClient。Spring AI 的自动配置会根据application.yml中的配置自动创建并装配一个OpenAiChatClient或其他供应商的实现的 Bean。简单调用chat方法展示了最简单的用法直接将用户消息字符串传给chatClient.call()。使用 PromptTemplategeneratePoem方法展示了更结构化的用法。PromptTemplate允许你创建带有占位符的模板然后动态填充内容。这对于构建复杂、可复用的提示词非常有用是避免“提示词工程”代码混乱的好实践。ChatResponsechatClient.call(Prompt)返回一个ChatResponse对象它包含了更丰富的信息如多个候选回复Generations、使用量统计Usage等。通过getResult().getOutput().getContent()可以获取主回复的文本内容。3.3 运行与验证设置环境变量在启动应用前请确保设置了OPENAI_API_KEY环境变量。Linux/macOS:export OPENAI_API_KEYyour_actual_api_key_hereWindows (CMD):set OPENAI_API_KEYyour_actual_api_key_hereWindows (PowerShell):$env:OPENAI_API_KEYyour_actual_api_key_here在 IDE 中通常可以在运行配置Run Configuration里添加环境变量。启动应用运行SpringAiDemoApplication的main方法。观察控制台日志如果没有报错且看到类似Started SpringAiDemoApplication in X.XXX seconds的日志说明启动成功。测试接口打开浏览器或使用curl、Postman 等工具。访问http://localhost:8080/ai/chat?message什么是Spring AI你应该能收到一段由 AI 生成的关于 Spring AI 的解释。访问http://localhost:8080/ai/poem?topic月亮你应该能收到一首关于月亮的中文诗。至此你已经成功使用 Spring AI 构建了第一个 AI 对话应用。但这仅仅是开始接下来我们需要处理更实际的问题。4. 核心配置详解与高级功能要让 AI 功能在生产中可靠运行必须深入理解并妥善配置各项参数。4.1 连接与超时配置默认配置可能不适合生产环境。网络波动、模型服务响应慢都可能导致请求失败。我们需要配置超时和重试。在application.yml中补充以下配置spring: ai: openai: api-key: ${OPENAI_API_KEY} # 连接和超时配置 client: connect-timeout: 10s # 建立连接超时时间 read-timeout: 60s # 读取响应超时时间对于长文本生成可能需要更久 # 重试配置 (需要额外依赖 spring-retry) retry: enabled: true max-attempts: 3 backoff: initial-interval: 1s multiplier: 2.0 max-interval: 10s chat: options: model: gpt-3.5-turbo temperature: 0.7 max-tokens: 500 # 限制单次回复的最大 token 数控制成本配置说明connect-timeout和read-timeout根据你的网络状况和模型服务的 SLA 进行调整。对于生成任务read-timeout需要设置得足够长。retry启用重试机制可以有效应对短暂的网络故障或服务端过载。spring-ai-openai模块通常已包含对spring-retry的依赖。重试策略采用指数退避避免加重服务端压力。max-tokens这是一个重要的成本和内容控制参数。它限制了 AI 单次响应可以生成的最大 token 数约等于单词数。设置过低可能导致回答被截断设置过高则可能产生不必要的费用。需要根据业务场景权衡。4.2 处理 AI “幻觉”与输出约束AI “幻觉”是指模型生成看似合理但实际不正确或无关信息的情况。虽然无法完全根除但我们可以通过工程手段缓解。策略一优化提示词Prompt Engineering这是最直接有效的方法。在 Prompt 中明确约束模型的行为。GetMapping(/ai/fact-check) public String getFactualAnswer(RequestParam String question) { String template 你是一个严谨的百科知识助手。请基于公开、可信的事实来回答问题。 如果你对问题的答案不确定或不知道请明确说“根据现有信息我无法确认这一点”不要编造信息。 问题{question} ; PromptTemplate promptTemplate new PromptTemplate(template); Prompt prompt promptTemplate.create(Map.of(question, question)); return chatClient.call(prompt).getResult().getOutput().getContent(); }策略二使用函数调用Function Calling进行结构化输出对于需要精确结构化数据的场景如从文本中提取实体、生成特定格式的 JSON可以利用模型的函数调用能力强制其输出符合预定 schema 的数据。Spring AI 对此有良好支持通过ChatOptions配置函数定义但这需要更复杂的设置。策略三后处理与验证对于关键业务不能完全信任 AI 的原始输出。应该设计后处理流程格式校验如果期望是 JSON用 JSON 解析器验证。内容过滤使用关键词过滤或敏感词库。事实核验对于重要事实陈述可尝试通过内部知识库或二次搜索调用搜索 API进行交叉验证。人工审核队列对于高风险或高价值内容引入人工审核环节。4.3 构建本地 AI 代理Agent的初步思路“AI 代理”指的是能够自主规划、使用工具、执行多步任务来达成目标的 AI 系统。Spring AI 提供了Agent相关的抽象但目前以 0.8.x 版本为例其高级 Agent 功能如 ReAct 模式仍处于快速演进中。一个更稳定且强大的实现方式是结合像LangChain4j这样的专门库。不过我们可以利用 Spring AI 的基础能力搭建一个简单的“工具使用”代理。概念模型工具Tool一个可供 AI 调用的函数例如“获取天气”、“查询数据库”、“发送邮件”。在 Spring AI 中你可以将一个Bean方法暴露为工具。提示词Prompt告诉 AI 它可以使用哪些工具以及在什么情况下使用。执行循环AI 分析用户请求 - 决定调用哪个工具并生成调用参数- 系统执行工具 - 将工具结果返回给 AI - AI 生成最终回答或决定下一步行动。简单示例创建一个计算器工具首先定义一个工具接口和实现package com.example.springaidemo.tools; import org.springframework.ai.tool.Tool; import org.springframework.stereotype.Component; Component public class CalculatorTool { Tool(name calculator, description 用于执行数学计算。输入一个数学表达式如 2 3 * 4返回计算结果。) public String calculate(String expression) { try { // 警告这里使用简单的脚本引擎仅为示例生产环境需要更安全、强大的表达式求值库。 // 此处仅作演示实际应使用如 exp4j、JEval 等库并做好沙箱隔离。 javax.script.ScriptEngineManager mgr new javax.script.ScriptEngineManager(); javax.script.ScriptEngine engine mgr.getEngineByName(JavaScript); Object result engine.eval(expression); return String.format(表达式 %s 的计算结果是: %s, expression, result.toString()); } catch (Exception e) { return String.format(计算表达式 %s 时出错: %s, expression, e.getMessage()); } } }然后在配置中启用工具支持并创建一个使用工具的 Servicepackage com.example.springaidemo.service; import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; Service public class AgentService { private final ChatClient chatClient; private final ToolCallbackProvider toolCallbackProvider; // 用于提供工具调用能力 Autowired public AgentService(ChatClient chatClient, ToolCallbackProvider toolCallbackProvider) { this.chatClient chatClient; this.toolCallbackProvider toolCallbackProvider; } public String askWithTools(String userQuestion) { // 构建一个提示词告诉 AI 可用的工具和任务 String systemPrompt 你是一个智能助手可以回答问题和使用工具。 你可以使用的工具有 - calculator: 用于执行数学计算。 当用户的问题涉及数学计算时你应该调用 calculator 工具。 调用工具时请提供完整的表达式。 在得到工具的结果后将其整合到你对用户的最终回复中。 ; String fullPrompt systemPrompt \n\n用户问题 userQuestion; // 创建 Prompt并关联工具调用能力 Prompt prompt new Prompt(fullPrompt); // 注意此处是简化演示。Spring AI 更完整的工具调用需要结合 ChatClient 的特殊调用方式或使用 ChatModel。 // 实际开发请参考最新官方文档的 Tool 和 ToolCalling 相关示例。 ChatResponse response chatClient.call(prompt); // 检查 response 中是否包含工具调用请求并执行... (此处省略复杂的工具调用循环逻辑) // 简化返回 return response.getResult().getOutput().getContent(); } }重要提示Spring AI 的 Agent 和工具调用 API 仍在快速发展中上述代码仅为概念演示。生产环境若要构建复杂 Agent建议密切关注 Spring AI 官方文档中关于Agent、Tool、Function Calling的最新示例。评估是否引入更成熟的 Agent 框架如 LangChain4j作为底层而 Spring AI 作为模型交互层。5. 生产环境部署考量与最佳实践将集成 Spring AI 的应用部署到生产环境需要超越功能实现关注稳定性、可观测性、安全性和成本。5.1 配置外部化与安全管理绝对不要将 API Key 提交到代码仓库。必须使用外部化配置。开发环境使用本地application-local.yml或环境变量该文件被.gitignore忽略。测试/生产环境环境变量在容器或服务器环境中设置OPENAI_API_KEY。配置中心使用 Spring Cloud Config、Apollo、Nacos 等。密钥管理服务使用云服务商提供的 KMS如 AWS Secrets Manager, Azure Key Vault或 HashiCorp Vault。Spring Cloud Vault 可以方便地集成。多环境配置示例application.yml(通用配置)spring: ai: openai: chat: options: model: ${AI_MODEL:gpt-3.5-turbo} client: read-timeout: ${AI_READ_TIMEOUT:60s}application-prod.yml(生产环境特定配置)# 生产环境使用更稳定的模型和更长的超时 spring: ai: openai: chat: options: model: gpt-4 temperature: 0.3 client: read-timeout: 120s通过启动参数-Dspring.profiles.activeprod激活生产配置而 API Key 通过环境变量OPENAI_API_KEY注入。5.2 监控、日志与熔断日志记录记录所有 AI 调用的请求和响应注意脱敏便于问题排查和审计。import org.slf4j.Logger; import org.slf4j.LoggerFactory; Service public class AIServiceWithLogging { private static final Logger log LoggerFactory.getLogger(AIServiceWithLogging.class); private final ChatClient chatClient; public String callWithLogging(String prompt) { log.info(Sending request to AI model. Prompt: {}, prompt); long startTime System.currentTimeMillis(); try { String response chatClient.call(prompt); long duration System.currentTimeMillis() - startTime; log.info(AI response received in {} ms. Response: {}, duration, response); return response; } catch (Exception e) { log.error(AI call failed after {} ms. Error: {}, System.currentTimeMillis() - startTime, e.getMessage(), e); throw e; // 或返回降级结果 } } }监控指标使用 Micrometer 集成监控系统如 Prometheus暴露关键指标。ai.calls.total调用总次数。ai.calls.duration调用耗时直方图。ai.calls.errors调用错误次数。ai.tokens.prompt,ai.tokens.completionToken 使用量如果 API 返回。熔断与降级当 AI 服务不稳定或超时时快速失败并返回降级内容如缓存答案、默认文案避免拖垮整个应用。可以使用 Resilience4j 或 Spring Cloud Circuit Breaker 实现。# 假设使用 Resilience4j resilience4j.circuitbreaker: instances: aiService: sliding-window-size: 10 failure-rate-threshold: 50 wait-duration-in-open-state: 10s5.3 性能优化与成本控制缓存对于重复性或变化不大的问题如“公司介绍”、“产品FAQ”可以将 AI 的回答缓存起来使用 Redis 或 Caffeine。设置合理的 TTL生存时间。异步处理对于非实时性要求高的任务如生成报告、内容摘要使用Async或消息队列进行异步处理避免阻塞用户请求。批处理如果有大量独立的文本需要处理如情感分析、分类可以考虑将请求批量发送但需注意模型是否有批处理 API 以及其限制。模型选型根据场景选择性价比合适的模型。例如简单的文本分类可能不需要gpt-4gpt-3.5-turbo甚至更小的专用模型就能满足成本大幅降低。Token 管理监控 Token 使用量。对于长文本考虑在调用前进行智能截断或分片总结。设置预算告警。5.4 常见问题排查清单当 AI 功能出现问题时可以按照以下清单进行排查问题现象可能原因检查步骤解决方案应用启动失败报BeanCreationException1. Spring AI 版本与 Spring Boot 不兼容。2. 缺少必要的依赖。3. 配置属性错误。1. 检查pom.xml中 BOM 和 Starter 版本。2. 检查依赖是否下载成功。3. 检查application.yml中spring.ai.openai.api-key等配置项拼写是否正确。1. 对照官方文档调整版本。2. 执行mvn clean compile。3. 修正配置属性名。调用接口返回 401 错误API Key 无效或未正确设置。1. 检查环境变量OPENAI_API_KEY是否已设置且正确。2. 检查配置文件中是否有硬编码的错误 Key 覆盖了环境变量。1. 使用echo $OPENAI_API_KEY验证。2. 确保配置优先级正确环境变量 配置文件。调用超时 (ReadTimeoutException)1. 网络问题。2. 模型服务响应慢。3. 请求内容Prompt过长或复杂。1. 检查网络连通性。2. 查看模型服务状态页如有。3. 检查日志中的请求大小和max-tokens设置。1. 增加spring.ai.openai.client.read-timeout。2. 优化 Prompt减少不必要的上下文。3. 实现重试和熔断机制。AI 回复内容被截断max-tokens参数设置过小。查看响应日志确认是否达到 token 限制。适当增加max-tokens的值但要权衡成本。AI 回复不符合预期“幻觉”1. Prompt 指令不清晰。2.temperature参数过高。3. 模型本身局限性。1. 审查 Prompt是否明确了角色、任务和约束。2. 检查temperature配置。1. 优化 Prompt 工程。2. 降低temperature如设为 0.2。3. 考虑使用更高级的模型或后处理验证。本地模型如 Ollama连接失败1. Ollama 服务未启动。2. 配置的 base URL 或模型名错误。1. 运行ollama serve并检查状态。2. 确认spring.ai.ollama.base-url和chat.options.model正确。1. 启动 Ollama 服务。2. 使用ollama list确认模型已拉取并正确命名。6. 扩展方向与进阶学习掌握了 Spring AI 的基础集成后你可以根据项目需求向以下几个方向深入多模型路由与降级实现一个ChatClient封装根据请求特征成本、时延要求、内容类型或主用模型的健康状态动态选择不同的底层模型如 OpenAI, Azure OpenAI, 本地 Ollama进行调用并在主模型失败时自动降级。向量数据库与 RAG结合 Spring AI 的EmbeddingClient和向量数据库如 Pinecone, Weaviate, pgvector构建检索增强生成RAG系统。将内部知识库向量化在回答问题时先检索相关文档再将文档作为上下文提供给 AI从而生成更准确、基于内部知识的回答。复杂工作流与 Agent 框架深入研究 Spring AI 的Agent、Chain和Tool抽象或集成 LangChain4j构建能够执行多步骤任务、使用多种工具搜索、数据库、API的智能代理。微服务集成在微服务架构中将 AI 能力封装成独立的服务通过 Feign 或 gRPC 对外提供。重点考虑该服务的弹性设计、限流、监控和版本管理。领域定制化针对特定业务领域如客服、代码生成、法律文书收集高质量的对话数据对开源基础模型进行微调Fine-tuning或构建精心的 Prompt 模板库以提升在该领域的表现。Spring AI 降低了在 Spring 生态中集成 AI 能力的门槛但构建健壮、可靠、有价值的 AI 应用仍然需要扎实的软件工程实践和对 AI 模型特性的深入理解。从明确的需求出发从小而精的功能试点开始逐步完善监控、安全、成本控制和用户体验是稳妥的落地路径。