深度剖析Spring AI源码(十):终章,从理论到实践的企业级AI应用
“In theory, there is no difference between theory and practice. In practice, there is.” —— Yogi Berra
经过前面九章的深入分析,我们已经掌握了Spring AI的核心原理和设计思想。但真正的考验在于实践——如何将这些知识转化为生产级的AI应用?今天,让我们通过一个完整的企业级案例,展示Spring AI的最佳实践。
实战案例:智能客服系统
我们将构建一个完整的智能客服系统,它具备以下功能:
- 多轮对话:支持上下文记忆的对话
- 知识检索:基于企业知识库的RAG问答
- 工具调用:查询订单、处理退款等业务操作
- 多模态支持:处理文本和图片输入
- 实时监控:完整的可观测性体系
系统架构设计
核心服务实现
1. 智能对话服务
@Service
@Transactional
public class IntelligentChatService {
private final ChatClient chatClient;
private final ConversationMemoryService memoryService;
private final UserContextService userContextService;
private final ChatMetricsCollector metricsCollector;
public IntelligentChatService(ChatModel chatModel,
VectorStore vectorStore,
ConversationMemoryService memoryService,
UserContextService userContextService,
List<ToolCallback> toolCallbacks) {
this.memoryService = memoryService;
this.userContextService = userContextService;
this.metricsCollector = new ChatMetricsCollector();
// 构建增强的ChatClient
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem("""
你是一个专业的客服助手,名叫小智。你的任务是:
1. 友好、专业地回答用户问题
2. 基于知识库提供准确信息
3. 在需要时调用相关工具处理业务
4. 保护用户隐私和数据安全
5. 如果无法解决问题,及时转接人工客服
""")
.defaultAdvisors(
// 安全防护 - 最高优先级
SafeGuardAdvisor.builder()
.inputBlockList(loadBlockList("input-blocklist.txt"))
.outputBlockList(loadBlockList("output-blocklist.txt"))
.build(),
// 用户上下文增强
new UserContextAdvisor(userContextService),
// 对话记忆
new ConversationMemoryAdvisor(memoryService),
// RAG知识检索
RagAdvisor.builder()
.vectorStore(vectorStore)
.topK(5)
.similarityThreshold(0.7)
.build(),
// 工具调用
new ToolCallingAdvisor(toolCallbacks),
// 日志和监控
new LoggingAdvisor(),
new MetricsAdvisor(metricsCollector)
)
.defaultOptions(OpenAiChatOptions.builder()
.model("gpt-4")
.temperature(0.3) // 客服需要稳定的回答
.maxTokens(1000)
.build())
.build();
}
/**
* 处理用户消息
*/
public ChatResponse handleUserMessage(ChatRequest request) {
String userId = request.getUserId();
String sessionId = request.getSessionId();
String message = request.getMessage();
try {
// 记录用户上下文
UserContext userContext = userContextService.getUserContext(userId);
// 构建对话请求
String response = chatClient
.prompt()
.user(userSpec -> userSpec
.text(message)
.metadata("user_id", userId)
.metadata("session_id", sessionId)
.metadata("timestamp", Instant.now().toString()))
.advisors(advisorSpec -> advisorSpec
.param("user_context", userContext)
.param("session_id", sessionId))
.call()
.content();
// 构建响应
return ChatResponse.builder()
.sessionId(sessionId)
.message(response)
.timestamp(Instant.now())
.sources(extractSources(response))
.suggestions(generateSuggestions(message, response))
.build();
} catch (Exception e) {
logger.error("Chat processing failed for user: {}", userId, e);
return createErrorResponse(sessionId, "抱歉,服务暂时不可用,请稍后重试。");
}
}
/**
* 流式对话处理
*/
public Flux<ChatResponse> handleUserMessageStream(ChatRequest request) {
return chatClient
.prompt()
.user(request.getMessage())
.advisors(advisorSpec -> advisorSpec
.param("user_context", userContextService.getUserContext(request.getUserId()))
.param("session_id", request.getSessionId()))
.stream()
.content()
.map(chunk -> ChatResponse.builder()
.sessionId(request.getSessionId())
.message(chunk)
.timestamp(Instant.now())
.isStreaming(true)
.build());
}
/**
* 多模态消息处理
*/
public ChatResponse handleMultimodalMessage(MultimodalChatRequest request) {
return chatClient
.prompt()
.user(userSpec -> userSpec
.text(request.getText())
.media(request.getImages().toArray(new Media[0])))
.advisors(advisorSpec -> advisorSpec
.param("user_context", userContextService.getUserContext(request.getUserId())))
.call()
.entity(ChatResponse.class);
}
}
2. 企业知识库服务
@Service
public class EnterpriseKnowledgeService {
private final VectorStore vectorStore;
private final EtlPipeline etlPipeline;
private final KnowledgeMetricsCollector metricsCollector;
/**
* 批量导入企业文档
*/
@Async
public CompletableFuture<ImportResult> importDocuments(List<Resource> resources) {
ImportResult.Builder resultBuilder = ImportResult.builder()
.startTime(Instant.now());
try {
// 构建ETL管道
EtlPipeline pipeline = EtlPipeline.builder()
// 多种文档读取器
.reader(new PdfDocumentReader())
.reader(new TikaDocumentReader())
.reader(new JsoupDocumentReader())
// 文档转换器链
.transformer(new ContentCleaningTransformer())
.transformer(new MetadataEnhancementTransformer())
.transformer(new RecursiveCharacterTextSplitter(1000, 200))
.transformer(new DuplicateRemovalTransformer())
// 向量存储写入器
.writer(vectorStore)
// 配置
.config(EtlPipelineConfig.builder()
.batchSize(100)
.failOnError(false)
.enableMetrics(true)
.build())
.build();
// 执行ETL
EtlResult etlResult = pipeline.execute();
resultBuilder
.documentsProcessed(etlResult.getDocumentsRead())
.documentsStored(etlResult.getDocumentsWritten())
.success(etlResult.isSuccess());
// 更新知识库索引
updateKnowledgeIndex();
} catch (Exception e) {
resultBuilder.success(false).error(e.getMessage());
logger.error("Document import failed", e);
} finally {
resultBuilder.endTime(Instant.now());
}
return CompletableFuture.completedFuture(resultBuilder.build());
}
/**
* 智能知识检索
*/
public KnowledgeSearchResult searchKnowledge(KnowledgeSearchRequest request) {
long startTime = System.currentTimeMillis();
try {
// 查询重写
List<String> rewrittenQueries = rewriteQuery(request.getQuery());
// 多查询检索
List<Document> allResults = new ArrayList<>();
for (String query : rewrittenQueries) {
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query(query)
.topK(request.getTopK())
.similarityThreshold(request.getSimilarityThreshold())
.filterExpression(request.getFilterExpression())
.build()
);
allResults.addAll(results);
}
// 结果去重和重排序
List<Document> deduplicatedResults = deduplicateDocuments(allResults);
List<Document> rerankedResults = rerank(request.getQuery(), deduplicatedResults);
// 限制结果数量
List<Document> finalResults = rerankedResults.stream()
.limit(request.getTopK())
.toList();
return KnowledgeSearchResult.builder()
.query(request.getQuery())
.results(finalResults)
.totalFound(allResults.size())
.responseTime(System.currentTimeMillis() - startTime)
.build();
} catch (Exception e) {
logger.error("Knowledge search failed", e);
throw new KnowledgeSearchException("搜索失败", e);
}
}
/**
* 知识库质量评估
*/
public KnowledgeQualityReport assessKnowledgeQuality() {
// 统计知识库基本信息
long totalDocuments = countTotalDocuments();
Map<String, Long> documentsByType = countDocumentsByType();
Map<String, Long> documentsBySource = countDocumentsBySource();
// 评估覆盖度
double coverageScore = assessCoverage();
// 评估质量
double qualityScore = assessQuality();
// 评估时效性
double freshnessScore = assessFreshness();
return KnowledgeQualityReport.builder()
.totalDocuments(totalDocuments)
.documentsByType(documentsByType)
.documentsBySource(documentsBySource)
.coverageScore(coverageScore)
.qualityScore(qualityScore)
.freshnessScore(freshnessScore)
.overallScore((coverageScore + qualityScore + freshnessScore) / 3)
.assessmentTime(Instant.now())
.build();
}
}
3. 业务工具集成
@Component
public class CustomerServiceTools {
private final OrderService orderService;
private final UserService userService;
private final RefundService refundService;
private final LogisticsService logisticsService;
/**
* 查询订单信息
*/
@ToolFunction(
name = "query_order",
description = "查询用户的订单信息,包括订单状态、商品详情、物流信息等"
)
public OrderInfo queryOrder(OrderQueryRequest request, ToolContext context) {
String userId = (String) context.get("user_id");
// 权限检查
if (!hasOrderAccess(userId, request.getOrderId())) {
throw new ToolExecutionException("无权访问该订单信息");
}
try {
Order order = orderService.findById(request.getOrderId());
if (order == null) {
return OrderInfo.notFound(request.getOrderId());
}
// 获取物流信息
LogisticsInfo logistics = logisticsService.getLogisticsInfo(order.getLogisticsNumber());
return OrderInfo.builder()
.orderId(order.getId())
.status(order.getStatus())
.items(order.getItems())
.totalAmount(order.getTotalAmount())
.createTime(order.getCreateTime())
.logistics(logistics)
.build();
} catch (Exception e) {
throw new ToolExecutionException("查询订单失败", e);
}
}
/**
* 处理退款申请
*/
@ToolFunction(
name = "process_refund",
description = "处理用户的退款申请,需要验证订单状态和退款条件"
)
public RefundResult processRefund(RefundRequest request, ToolContext context) {
String userId = (String) context.get("user_id");
try {
// 验证订单
Order order = orderService.findById(request.getOrderId());
if (order == null || !order.getUserId().equals(userId)) {
return RefundResult.failed("订单不存在或无权操作");
}
// 检查退款条件
RefundEligibility eligibility = refundService.checkEligibility(order);
if (!eligibility.isEligible()) {
return RefundResult.failed(eligibility.getReason());
}
// 创建退款申请
RefundApplication application = RefundApplication.builder()
.orderId(request.getOrderId())
.userId(userId)
.amount(request.getAmount())
.reason(request.getReason())
.type(request.getType())
.build();
RefundApplication savedApplication = refundService.createApplication(application);
// 自动审核(小额退款)
if (request.getAmount().compareTo(new BigDecimal("100")) <= 0) {
refundService.autoApprove(savedApplication.getId());
return RefundResult.success("退款申请已自动通过,预计3-5个工作日到账");
} else {
return RefundResult.pending("退款申请已提交,将在24小时内审核");
}
} catch (Exception e) {
logger.error("Refund processing failed", e);
return RefundResult.failed("退款处理失败,请联系人工客服");
}
}
/**
* 更新用户信息
*/
@ToolFunction(
name = "update_user_profile",
description = "更新用户的个人信息,如地址、电话等"
)
public UpdateResult updateUserProfile(UserUpdateRequest request, ToolContext context) {
String userId = (String) context.get("user_id");
try {
// 数据验证
validateUserUpdateRequest(request);
// 更新用户信息
User user = userService.findById(userId);
if (user == null) {
return UpdateResult.failed("用户不存在");
}
// 应用更新
if (request.getPhone() != null) {
user.setPhone(request.getPhone());
}
if (request.getAddress() != null) {
user.setAddress(request.getAddress());
}
if (request.getEmail() != null) {
user.setEmail(request.getEmail());
}
userService.save(user);
return UpdateResult.success("用户信息更新成功");
} catch (ValidationException e) {
return UpdateResult.failed("输入信息格式错误:" + e.getMessage());
} catch (Exception e) {
logger.error("User profile update failed", e);
return UpdateResult.failed("更新失败,请稍后重试");
}
}
/**
* 智能推荐商品
*/
@ToolFunction(
name = "recommend_products",
description = "基于用户历史和偏好推荐相关商品"
)
public RecommendationResult recommendProducts(RecommendationRequest request, ToolContext context) {
String userId = (String) context.get("user_id");
try {
// 获取用户画像
UserProfile profile = userService.getUserProfile(userId);
// 获取推荐商品
List<Product> recommendations = recommendationService.getRecommendations(
RecommendationQuery.builder()
.userId(userId)
.category(request.getCategory())
.priceRange(request.getPriceRange())
.limit(request.getLimit())
.userProfile(profile)
.build()
);
return RecommendationResult.builder()
.products(recommendations)
.reason("基于您的购买历史和偏好推荐")
.confidence(0.85)
.build();
} catch (Exception e) {
logger.error("Product recommendation failed", e);
return RecommendationResult.empty("暂时无法提供推荐");
}
}
}
安全与合规实现
1. 内容安全防护
@Component
public class ContentSecurityService {
private final SensitiveWordDetector sensitiveWordDetector;
private final PersonalInfoDetector personalInfoDetector;
private final ToxicityClassifier toxicityClassifier;
/**
* 输入内容安全检查
*/
public SecurityCheckResult checkInputSecurity(String content, String userId) {
SecurityCheckResult.Builder resultBuilder = SecurityCheckResult.builder()
.content(content)
.userId(userId);
// 1. 敏感词检测
SensitiveWordResult sensitiveResult = sensitiveWordDetector.detect(content);
if (sensitiveResult.hasSensitiveWords()) {
return resultBuilder
.safe(false)
.reason("包含敏感词汇")
.sensitiveWords(sensitiveResult.getWords())
.build();
}
// 2. 个人信息检测
PersonalInfoResult personalInfoResult = personalInfoDetector.detect(content);
if (personalInfoResult.hasPersonalInfo()) {
// 记录但不阻止,用于脱敏处理
resultBuilder.personalInfo(personalInfoResult.getInfoTypes());
}
// 3. 毒性内容检测
ToxicityResult toxicityResult = toxicityClassifier.classify(content);
if (toxicityResult.getToxicityScore() > 0.7) {
return resultBuilder
.safe(false)
.reason("内容可能包含不当信息")
.toxicityScore(toxicityResult.getToxicityScore())
.build();
}
return resultBuilder.safe(true).build();
}
/**
* 输出内容安全处理
*/
public String sanitizeOutput(String content) {
String sanitized = content;
// 1. 个人信息脱敏
sanitized = personalInfoDetector.mask(sanitized);
// 2. 敏感信息过滤
sanitized = sensitiveWordDetector.filter(sanitized);
// 3. 格式化处理
sanitized = formatOutput(sanitized);
return sanitized;
}
/**
* 用户行为风险评估
*/
public RiskAssessmentResult assessUserRisk(String userId, String content) {
// 获取用户历史行为
UserBehaviorHistory history = getUserBehaviorHistory(userId);
// 计算风险分数
double riskScore = calculateRiskScore(history, content);
RiskLevel riskLevel;
if (riskScore < 0.3) {
riskLevel = RiskLevel.LOW;
} else if (riskScore < 0.7) {
riskLevel = RiskLevel.MEDIUM;
} else {
riskLevel = RiskLevel.HIGH;
}
return RiskAssessmentResult.builder()
.userId(userId)
.riskScore(riskScore)
.riskLevel(riskLevel)
.factors(analyzeRiskFactors(history, content))
.recommendations(generateSecurityRecommendations(riskLevel))
.build();
}
}
2. 数据隐私保护
@Component
public class PrivacyProtectionService {
private final EncryptionService encryptionService;
private final AuditLogService auditLogService;
/**
* 敏感数据加密存储
*/
public void storeSensitiveData(String userId, String data, DataType dataType) {
try {
// 加密数据
String encryptedData = encryptionService.encrypt(data);
// 存储加密数据
SensitiveDataRecord record = SensitiveDataRecord.builder()
.userId(userId)
.encryptedData(encryptedData)
.dataType(dataType)
.createdAt(Instant.now())
.build();
sensitiveDataRepository.save(record);
// 记录审计日志
auditLogService.logDataAccess(
AuditEvent.builder()
.userId(userId)
.action("STORE_SENSITIVE_DATA")
.dataType(dataType.name())
.timestamp(Instant.now())
.build()
);
} catch (Exception e) {
logger.error("Failed to store sensitive data", e);
throw new PrivacyProtectionException("数据存储失败", e);
}
}
/**
* 用户数据删除(GDPR合规)
*/
@Transactional
public void deleteUserData(String userId, DataDeletionRequest request) {
try {
// 验证删除权限
if (!hasDataDeletionPermission(userId, request)) {
throw new UnauthorizedException("无权删除数据");
}
// 删除各类数据
if (request.isDeleteConversations()) {
conversationRepository.deleteByUserId(userId);
}
if (request.isDeleteProfile()) {
userProfileRepository.deleteByUserId(userId);
}
if (request.isDeleteSensitiveData()) {
sensitiveDataRepository.deleteByUserId(userId);
}
// 记录删除操作
auditLogService.logDataDeletion(
AuditEvent.builder()
.userId(userId)
.action("DELETE_USER_DATA")
.details(request.toString())
.timestamp(Instant.now())
.build()
);
} catch (Exception e) {
logger.error("User data deletion failed", e);
throw new PrivacyProtectionException("数据删除失败", e);
}
}
/**
* 数据访问日志记录
*/
@EventListener
public void handleDataAccessEvent(DataAccessEvent event) {
auditLogService.logDataAccess(
AuditEvent.builder()
.userId(event.getUserId())
.action("DATA_ACCESS")
.resourceType(event.getResourceType())
.resourceId(event.getResourceId())
.accessType(event.getAccessType())
.ipAddress(event.getIpAddress())
.userAgent(event.getUserAgent())
.timestamp(event.getTimestamp())
.build()
);
}
}
性能优化策略
1. 缓存策略
@Configuration
@EnableCaching
public class CacheConfiguration {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
// 对话缓存 - 短期缓存
cacheManager.registerCustomCache("conversations",
Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(Duration.ofMinutes(30))
.recordStats()
.build());
// 知识检索缓存 - 中期缓存
cacheManager.registerCustomCache("knowledge-search",
Caffeine.newBuilder()
.maximumSize(5000)
.expireAfterWrite(Duration.ofHours(2))
.recordStats()
.build());
// 用户上下文缓存 - 长期缓存
cacheManager.registerCustomCache("user-context",
Caffeine.newBuilder()
.maximumSize(50000)
.expireAfterWrite(Duration.ofHours(24))
.recordStats()
.build());
return cacheManager;
}
@Bean
public CacheMetricsRegistrar cacheMetricsRegistrar(MeterRegistry meterRegistry) {
return new CacheMetricsRegistrar(meterRegistry);
}
}
@Service
public class CachedKnowledgeService {
@Cacheable(value = "knowledge-search", key = "#query + '_' + #topK")
public List<Document> searchKnowledge(String query, int topK) {
return vectorStore.similaritySearch(query, topK);
}
@Cacheable(value = "user-context", key = "#userId")
public UserContext getUserContext(String userId) {
return userContextService.loadUserContext(userId);
}
@CacheEvict(value = "user-context", key = "#userId")
public void invalidateUserContext(String userId) {
// 缓存失效
}
}
2. 异步处理
@Configuration
@EnableAsync
public class AsyncConfiguration {
@Bean(name = "chatTaskExecutor")
public TaskExecutor chatTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("chat-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Bean(name = "knowledgeTaskExecutor")
public TaskExecutor knowledgeTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("knowledge-");
executor.initialize();
return executor;
}
}
@Service
public class AsyncChatService {
@Async("chatTaskExecutor")
public CompletableFuture<String> processMessageAsync(String message, String userId) {
// 异步处理消息
String response = chatClient.prompt(message).call().content();
// 异步保存对话历史
saveConversationAsync(userId, message, response);
return CompletableFuture.completedFuture(response);
}
@Async("knowledgeTaskExecutor")
public CompletableFuture<Void> updateKnowledgeAsync(List<Document> documents) {
// 异步更新知识库
vectorStore.add(documents);
return CompletableFuture.completedFuture(null);
}
}
3. 连接池优化
@Configuration
public class HttpClientConfiguration {
@Bean
public RestClient restClient() {
return RestClient.builder()
.requestFactory(clientHttpRequestFactory())
.build();
}
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
// 连接池配置
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(50);
// HTTP客户端配置
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(30000)
.build())
.build();
factory.setHttpClient(httpClient);
return factory;
}
}
监控与运维
1. 健康检查
@Component
public class AiHealthIndicator implements HealthIndicator {
private final ChatModel chatModel;
private final VectorStore vectorStore;
private final MeterRegistry meterRegistry;
@Override
public Health health() {
Health.Builder builder = Health.up();
try {
// 检查AI模型连接
checkChatModel(builder);
// 检查向量数据库
checkVectorStore(builder);
// 检查系统指标
checkSystemMetrics(builder);
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
return builder.build();
}
private void checkChatModel(Health.Builder builder) {
try {
long startTime = System.currentTimeMillis();
String response = chatModel.call(new Prompt("Health check")).getResult().getOutput().getContent();
long responseTime = System.currentTimeMillis() - startTime;
builder.withDetail("chatModel", Map.of(
"status", "UP",
"responseTime", responseTime + "ms",
"lastCheck", Instant.now()
));
} catch (Exception e) {
builder.withDetail("chatModel", Map.of(
"status", "DOWN",
"error", e.getMessage()
));
}
}
private void checkVectorStore(Health.Builder builder) {
try {
List<Document> results = vectorStore.similaritySearch("health check", 1);
builder.withDetail("vectorStore", Map.of(
"status", "UP",
"documentCount", results.size(),
"lastCheck", Instant.now()
));
} catch (Exception e) {
builder.withDetail("vectorStore", Map.of(
"status", "DOWN",
"error", e.getMessage()
));
}
}
}
2. 自定义指标
@Component
public class BusinessMetrics {
private final Counter conversationCounter;
private final Timer responseTimer;
private final Gauge activeUsersGauge;
private final DistributionSummary satisfactionScore;
public BusinessMetrics(MeterRegistry meterRegistry) {
this.conversationCounter = Counter.builder("business.conversations.total")
.description("Total number of conversations")
.register(meterRegistry);
this.responseTimer = Timer.builder("business.response.time")
.description("AI response time")
.register(meterRegistry);
this.activeUsersGauge = Gauge.builder("business.users.active")
.description("Number of active users")
.register(meterRegistry, this, BusinessMetrics::getActiveUserCount);
this.satisfactionScore = DistributionSummary.builder("business.satisfaction.score")
.description("User satisfaction scores")
.register(meterRegistry);
}
public void recordConversation(String userId, String channel) {
conversationCounter.increment(
Tags.of(
"user_type", getUserType(userId),
"channel", channel
)
);
}
public void recordResponseTime(Duration duration, String model) {
responseTimer.record(duration, Tags.of("model", model));
}
public void recordSatisfactionScore(double score) {
satisfactionScore.record(score);
}
private double getActiveUserCount() {
// 实现活跃用户统计逻辑
return activeUserService.getActiveUserCount();
}
}
部署与运维最佳实践
1. 容器化部署
# Dockerfile
FROM openjdk:17-jdk-slim
# 安装必要工具
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# 创建应用目录
WORKDIR /app
# 复制应用文件
COPY target/intelligent-customer-service-*.jar app.jar
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- OPENAI_API_KEY=${OPENAI_API_KEY}
- DATABASE_URL=jdbc:postgresql://postgres:5432/customerservice
- REDIS_URL=redis://redis:6379
depends_on:
- postgres
- redis
- pgvector
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
postgres:
image: postgres:15
environment:
POSTGRES_DB: customerservice
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
pgvector:
image: pgvector/pgvector:pg15
environment:
POSTGRES_DB: vectorstore
POSTGRES_USER: ${VECTOR_DB_USER}
POSTGRES_PASSWORD: ${VECTOR_DB_PASSWORD}
volumes:
- vector_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
volumes:
postgres_data:
vector_data:
redis_data:
2. Kubernetes部署
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: intelligent-customer-service
labels:
app: intelligent-customer-service
spec:
replicas: 3
selector:
matchLabels:
app: intelligent-customer-service
template:
metadata:
labels:
app: intelligent-customer-service
spec:
containers:
- name: app
image: intelligent-customer-service:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "kubernetes"
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: ai-secrets
key: openai-api-key
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: intelligent-customer-service
spec:
selector:
app: intelligent-customer-service
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: intelligent-customer-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: intelligent-customer-service
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
总结与展望
通过这个完整的企业级智能客服系统案例,我们展示了Spring AI在实际项目中的应用:
核心价值
- 开发效率:通过Spring AI的抽象和自动配置,大大简化了AI应用的开发
- 企业级特性:内置的安全、监控、缓存等特性满足生产环境需求
- 可扩展性:模块化的设计让系统易于扩展和维护
- 技术栈统一:与Spring生态无缝集成,降低学习成本
最佳实践总结
- 分层架构:清晰的分层设计,职责分离
- 安全第一:多层次的安全防护机制
- 性能优化:缓存、异步、连接池等优化策略
- 可观测性:全方位的监控和指标收集
- 容器化部署:现代化的部署和运维方式
未来展望
Spring AI作为一个快速发展的框架,未来可能会在以下方面继续演进:
- 多模态能力增强:更好的图像、音频处理支持
- 边缘计算支持:本地模型部署和推理
- 更多AI模型集成:支持更多的开源和商业模型
- 智能化运维:基于AI的自动化运维能力
系列文章结语
经过十章的深入剖析,我们完整地探索了Spring AI的设计哲学、核心架构和实践应用。从最初的项目概览,到最后的企业级实战,我们见证了一个优秀框架的诞生和成长。
Spring AI不仅仅是一个技术框架,更是Java生态拥抱AI时代的重要里程碑。它让Java开发者能够用熟悉的方式构建AI应用,让企业能够更容易地将AI能力集成到现有系统中。
希望这个系列能够帮助你:
- 深入理解Spring AI的设计思想
- 掌握企业级AI应用的开发技巧
- 建立完整的AI应用架构思维
- 在实际项目中应用这些知识

2880

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



