在实际 AI 应用开发中,很多团队面临一个共同困境:虽然大模型能力越来越强,但真正要把 AI 集成到生产系统时,却常常卡在工程化落地环节。从原型验证到稳定可用的 AI 功能,中间需要跨越模型部署、服务化、性能优化、监控告警等一系列工程挑战。
Spring AI 作为 Spring 生态中的 AI 应用开发框架,提供了一套相对完整的解决方案。特别是与阿里巴巴相关技术栈结合时,能在微服务架构下实现 AI 能力的平滑集成。本文将以实际项目经验为基础,详细介绍如何基于 Spring AI 和阿里云技术栈构建可投入生产的 AI 应用。
1. 理解 Spring AI 的核心价值与适用场景
Spring AI 并不是要替代现有的 AI 框架或大模型,而是为 Java 开发者提供一套统一的编程模型,让 AI 能力能够像数据库、消息队列一样成为应用的自然组成部分。
1.1 Spring AI 解决了哪些实际问题
在传统 AI 应用开发中,Java 开发者通常需要直接面对各种 AI 服务的 HTTP API,处理复杂的请求构建、响应解析、错误重试和限流控制。Spring AI 通过抽象层封装了这些技术细节,让开发者可以更关注业务逻辑。
主要解决痛点包括:
- 多模型适配 :同一套代码可以适配 OpenAI、Azure OpenAI、阿里云百炼等不同模型服务
- 统一接口 :Chat、Embedding、Image 等不同能力有统一的编程模型
- 生态集成 :与 Spring Boot、Spring Security、Spring Data 等现有技术栈无缝集成
- 生产就绪 :内置重试、降级、监控等企业级特性
1.2 什么场景适合使用 Spring AI
从实际项目经验看,Spring AI 特别适合以下场景:
- 已有 Spring 技术栈的企业需要快速引入 AI 能力
- 需要同时对接多个模型服务商的混合云场景
- AI 功能作为业务系统辅助能力而非核心算法的场景
- 团队主要技术栈为 Java,不希望引入过多 Python 技术债
对于需要极致性能或复杂模型训练的纯 AI 研发场景,可能还是需要直接使用 PyTorch、TensorFlow 等专业框架。
2. 环境准备与依赖配置
开始具体开发前,需要先搭建基础环境。这里以 Spring Boot 3.2+ 和 Spring AI 最新稳定版为例。
2.1 项目初始化与依赖管理
使用 Spring Initializr 创建项目时,除了常规的 Web 依赖,需要添加 Spring AI 相关依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI 核心依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 阿里云百炼 SDK -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-alibaba-bailian-spring-boot-starter</artifactId>
</dependency>
<!-- 监控和健康检查 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2.2 关键配置说明
在
application.yml
中配置模型连接信息:
spring:
ai:
alibaba:
bailian:
access-key-id: ${ALIBABA_ACCESS_KEY_ID}
access-key-secret: ${ALIBABA_ACCESS_KEY_SECRET}
region: cn-hangzhou
# 默认模型配置
chat:
options:
model: qwen-plus
temperature: 0.7
max-tokens: 2000
# 生产环境建议的监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
重要配置参数说明:
| 参数 | 说明 | 生产环境建议 |
|---|---|---|
| access-key-id | 阿里云访问密钥 | 通过环境变量注入,不要硬编码 |
| region | 服务地域 | 根据实际业务选择,国内业务通常用 cn-hangzhou |
| model | 默认模型 | 根据业务需求选择 qwen-turbo/qwen-plus/qwen-max |
| temperature | 创造性参数 | 对话场景 0.7-0.9,确定性场景 0.1-0.3 |
| max-tokens | 最大输出长度 | 根据业务需要设置,避免过长响应 |
2.3 安全配置最佳实践
在实际项目中,访问密钥等敏感信息必须通过安全方式管理:
@Configuration
public class SecurityConfig {
@Bean
public AlibabaBailianProperties alibabaBailianProperties() {
AlibabaBailianProperties properties = new AlibabaBailianProperties();
// 从安全配置中心获取,不要硬编码
properties.setAccessKeyId(getSecureConfig("alibaba.access-key-id"));
properties.setAccessKeySecret(getSecureConfig("alibaba.access-key-secret"));
properties.setRegion("cn-hangzhou");
return properties;
}
private String getSecureConfig(String key) {
// 实际项目中集成配置中心如 Nacos、Apollo
return System.getenv(key.toUpperCase().replace(".", "_"));
}
}
3. 核心功能实现与代码详解
有了基础环境后,开始实现具体的 AI 功能。这里以智能客服场景为例,展示完整的实现流程。
3.1 基础聊天服务实现
首先创建基础的聊天服务类:
@Service
public class ChatService {
private final ChatClient chatClient;
private final MeterRegistry meterRegistry;
public ChatService(ChatClient chatClient, MeterRegistry meterRegistry) {
this.chatClient = chatClient;
this.meterRegistry = meterRegistry;
}
public ChatResponse chat(String message) {
// 记录请求指标
Timer.Sample sample = Timer.start(meterRegistry);
try {
ChatResponse response = chatClient.call(
new Prompt(message,
ChatOptions.builder()
.withTemperature(0.7)
.withMaxTokens(1000)
.build()
)
);
// 记录成功指标
sample.stop(Timer.builder("ai.chat.duration")
.tag("status", "success")
.register(meterRegistry));
return response;
} catch (Exception e) {
// 记录失败指标
sample.stop(Timer.builder("ai.chat.duration")
.tag("status", "error")
.tag("error_type", e.getClass().getSimpleName())
.register(meterRegistry));
throw new ChatException("AI服务调用失败", e);
}
}
}
3.2 带上下文的多轮对话实现
实际客服场景需要支持多轮对话,需要维护对话上下文:
@Service
public class ConversationService {
private final ChatClient chatClient;
private final Map<String, List<Message>> conversationContexts = new ConcurrentHashMap<>();
public ConversationService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public ChatResponse continueConversation(String sessionId, String userMessage) {
// 获取或创建对话上下文
List<Message> messages = conversationContexts.computeIfAbsent(
sessionId, k -> new ArrayList<>()
);
// 添加用户消息
messages.add(new Message("user", userMessage));
// 保持合理的上下文长度,避免token超限
if (messages.size() > 10) {
messages = messages.subList(messages.size() - 10, messages.size());
conversationContexts.put(sessionId, messages);
}
// 构建对话提示
String conversationContext = buildConversationContext(messages);
String prompt = String.format("""
以下是当前的对话上下文:
%s
请根据以上对话历史,回复用户的最新消息。
""", conversationContext);
ChatResponse response = chatClient.call(new Prompt(prompt));
// 添加AI回复到上下文
messages.add(new Message("assistant", response.getResult().getOutput().getContent()));
return response;
}
private String buildConversationContext(List<Message> messages) {
return messages.stream()
.map(msg -> String.format("%s: %s", msg.getRole(), msg.getContent()))
.collect(Collectors.joining("\n"));
}
}
3.3 业务特定的提示词工程
针对客服场景,需要设计专门的系统提示词:
@Component
public class CustomerServicePromptTemplate {
private static final String SYSTEM_PROMPT = """
你是一名专业的客服助手,需要遵循以下规则:
1. 始终使用友好、专业的语气
2. 如果用户问题涉及具体订单,要求用户提供订单号
3. 对于技术问题,提供初步排查步骤后建议联系技术支持
4. 无法确认的信息不要猜测,如实告知需要进一步查询
5. 回复要简洁明了,重点突出
公司信息:
- 产品名称:智能云服务
- 技术支持电话:400-123-4567
- 工作时间:工作日 9:00-18:00
请根据以下用户问题提供帮助:
""";
public Prompt createCustomerServicePrompt(String userQuestion) {
String fullPrompt = SYSTEM_PROMPT + userQuestion;
return new Prompt(fullPrompt,
ChatOptions.builder()
.withTemperature(0.3) // 客服场景需要确定性
.withMaxTokens(500) // 控制回复长度
.build()
);
}
}
4. 高级特性与生产级优化
基础功能实现后,需要加入生产环境必需的高级特性。
4.1 重试机制与熔断降级
AI 服务调用可能因为网络或服务端问题失败,需要完善的容错机制:
@Configuration
public class ResilienceConfig {
@Bean
public RetryTemplate aiRetryTemplate() {
return RetryTemplate.builder()
.maxAttempts(3)
.exponentialBackoff(Duration.ofSeconds(1), 2, Duration.ofSeconds(10))
.retryOn(ResourceAccessException.class)
.retryOn(HttpServerErrorException.class)
.build();
}
@Bean
public CircuitBreakerFactory circuitBreakerFactory() {
return new CircuitBreakerFactory();
}
}
@Service
public class ResilientChatService {
private final ChatClient chatClient;
private final RetryTemplate retryTemplate;
private final CircuitBreaker circuitBreaker;
public ResilientChatService(ChatClient chatClient, RetryTemplate retryTemplate,
CircuitBreakerFactory circuitBreakerFactory) {
this.chatClient = chatClient;
this.retryTemplate = retryTemplate;
this.circuitBreaker = circuitBreakerFactory.create("ai-chat");
}
public ChatResponse callWithResilience(String message) {
return circuitBreaker.run(() ->
retryTemplate.execute(context -> {
return chatClient.call(new Prompt(message));
}),
throwable -> getFallbackResponse(message)
);
}
private ChatResponse getFallbackResponse(String message) {
// 降级策略:返回预设回复或缓存答案
return new ChatResponse("当前服务繁忙,请稍后重试");
}
}
4.2 性能优化与缓存策略
大模型调用成本较高,合理的缓存能显著提升性能和控制成本:
@Service
@CacheConfig(cacheNames = "aiResponses")
public class CachedChatService {
private final ChatClient chatClient;
public CachedChatService(ChatClient chatClient) {
this.chatClient = chatClient;
}
@Cacheable(key = "T(com.example.util.CacheKeyGenerator).generateKey(#message)",
unless = "#result == null")
public ChatResponse getCachedResponse(String message) {
return chatClient.call(new Prompt(message));
}
@CacheEvict(allEntries = true)
public void clearCache() {
// 定期清理缓存
}
}
@Component
public class CacheKeyGenerator {
public static String generateKey(String message) {
// 对消息内容进行标准化处理,避免因空格、标点差异导致缓存失效
String normalized = message.trim().toLowerCase()
.replaceAll("\\s+", " ")
.replaceAll("[^a-z0-9\\u4e00-\\u9fa5 ]", "");
return DigestUtils.md5DigestAsHex(normalized.getBytes());
}
}
4.3 监控与可观测性
生产环境必须要有完善的监控体系:
@Component
public class ChatMetrics {
private final Counter requestCounter;
private final Timer responseTimer;
private final DistributionSummary tokenUsageSummary;
public ChatMetrics(MeterRegistry meterRegistry) {
this.requestCounter = Counter.builder("ai.chat.requests")
.description("AI聊天请求计数")
.register(meterRegistry);
this.responseTimer = Timer.builder("ai.chat.response.time")
.description("AI响应时间")
.register(meterRegistry);
this.tokenUsageSummary = DistributionSummary.builder("ai.chat.tokens.used")
.description("Token使用量分布")
.register(meterRegistry);
}
public void recordRequest(String model) {
requestCounter.increment();
}
public Timer.Sample startTiming() {
return Timer.start();
}
public void recordResponse(Timer.Sample sample, String model, int tokensUsed) {
sample.stop(responseTimer);
tokenUsageSummary.record(tokensUsed);
}
}
5. 完整项目结构与配置示例
一个生产可用的 Spring AI 项目应该具备清晰的模块划分:
src/main/java/com/example/ai/
├── config/ # 配置类
│ ├── AiConfig.java # AI相关配置
│ ├── ResilienceConfig.java # 弹性配置
│ └── CacheConfig.java # 缓存配置
├── controller/ # 控制器层
│ ├── ChatController.java # 聊天接口
│ └── HealthController.java # 健康检查
├── service/ # 业务逻辑层
│ ├── ChatService.java # 基础聊天服务
│ ├── ConversationService.java # 对话服务
│ └── CustomerService.java # 客服专用服务
├── model/ # 数据模型
│ ├── request/ # 请求对象
│ └── response/ # 响应对象
├── util/ # 工具类
│ ├── PromptUtil.java # 提示词工具
│ └── ValidationUtil.java # 验证工具
└── exception/ # 异常处理
├── AiException.java # AI异常基类
└── GlobalExceptionHandler.java # 全局异常处理
对应的配置文件结构:
src/main/resources/
├── application.yml # 主配置
├── application-dev.yml # 开发环境配置
├── application-prod.yml # 生产环境配置
└── prompts/ # 提示词模板
├── customer-service.txt # 客服提示词
└── technical-support.txt # 技术支持提示词
6. 常见问题排查与解决方案
在实际部署和运行过程中,可能会遇到各种问题。以下是典型问题及解决方法:
6.1 连接与认证问题
| 问题现象 | 可能原因 | 检查方式 | 解决方案 |
|---|---|---|---|
| 连接超时 | 网络不通或代理配置问题 | 检查网络连通性,查看防火墙规则 | 配置正确的网络代理或直接连接 |
| 认证失败 | AccessKey 无效或过期 | 检查阿里云控制台密钥状态 | 更新有效的 AccessKey 对 |
| 区域错误 | 服务在不支持的Region调用 | 查看错误信息中的Region提示 | 修改配置到正确的Region |
6.2 性能与限流问题
@Component
public class RateLimitAspect {
private final RateLimiter rateLimiter;
public RateLimitAspect() {
// 根据实际业务量设置合适的限流阈值
this.rateLimiter = RateLimiter.create(100); // 每秒100个请求
}
@Around("@annotation(aiChatMethod)")
public Object rateLimit(ProceedingJoinPoint joinPoint) throws Throwable {
if (rateLimiter.tryAcquire()) {
return joinPoint.proceed();
} else {
throw new RateLimitExceededException("请求频率过高,请稍后重试");
}
}
}
6.3 内容安全与审核
在生产环境中,必须对输入输出进行安全审核:
@Service
public class ContentSafetyService {
public boolean validateInput(String input) {
// 检查输入长度
if (input.length() > 4000) {
throw new ValidationException("输入内容过长");
}
// 检查敏感词
if (containsSensitiveWords(input)) {
throw new SecurityException("输入包含违规内容");
}
return true;
}
public boolean validateOutput(String output) {
// 对AI输出进行安全审核
if (containsUnsafeContent(output)) {
// 记录审核日志并返回安全回复
log.warn("AI生成内容未通过安全审核: {}", output);
return false;
}
return true;
}
}
7. 生产环境部署 checklist
在将 Spring AI 应用部署到生产环境前,建议按以下清单进行检查:
7.1 安全配置检查
- [ ] 访问密钥通过环境变量或配置中心管理,不在代码中硬编码
- [ ] 启用 HTTPS 和网络传输加密
- [ ] 配置适当的内容安全策略(CSP)
- [ ] 实现输入输出内容安全审核
- [ ] 设置合理的 API 访问权限和认证机制
7.2 性能与稳定性检查
- [ ] 配置合适的连接超时和读取超时时间
- [ ] 实现重试机制和熔断降级策略
- [ ] 设置合理的限流规则防止滥用
- [ ] 配置监控指标和告警规则
- [ ] 实现日志记录和审计追踪
7.3 成本控制检查
- [ ] 设置 Token 使用上限和费用告警
- [ ] 实现响应缓存减少重复调用
- [ ] 监控异常调用和无效请求
- [ ] 定期优化提示词减少 Token 消耗
Spring AI 为 Java 开发者提供了将 AI 能力集成到现有系统的有效路径,但真正要在生产环境中稳定运行,还需要在工程化方面做大量工作。从配置管理、异常处理到监控告警,每个环节都需要根据实际业务需求进行精心设计和实现。特别是在与阿里巴巴技术栈结合时,可以充分利用阿里云在监控、安全、稳定性方面的成熟解决方案,构建真正可靠的企业级 AI 应用。

1980

被折叠的 条评论
为什么被折叠?



