Spring AI 系列(一):Spring AI 基础概念与架构入门

探索Spring生态系统中的AI革命:从零开始构建智能应用

📖 技术背景介绍

在人工智能技术快速发展的今天,传统的Spring应用开发者面临着如何将AI能力集成到现有系统中的挑战。Spring AI作为Spring生态系统的重要组成部分,为Java开发者提供了一套完整的AI应用开发框架,让开发者能够以熟悉的Spring方式构建智能应用。

🎯 Spring AI的诞生背景

  • 🔄 技术融合需求:传统企业应用需要集成AI能力
  • 🛠️ 开发复杂性:AI模型集成涉及复杂的配置和管理
  • 📈 生态系统完整性:Spring需要在AI时代保持技术领先
  • 👥 开发者友好性:降低Java开发者使用AI的门槛

🧠 核心概念解析

🏗️ Spring AI 架构概览

🔑 核心组件详解

1. Chat Client(聊天客户端)

功能 :提供与大语言模型的对话接口
特点

  • 🎯 统一的API接口
  • 🔄 多模型支持
  • 📝 流式响应
  • 🛠️ 函数调用支持
2. Embedding Client(嵌入客户端)

功能 :将文本转换为向量表示
应用场景

  • 🔍 语义搜索
  • 📊 文档相似度计算
  • 🎯 推荐系统
3. Vector Stores(向量存储)

功能 :存储和检索向量数据
支持的存储

  • 🗄️ Chroma
  • 📊 Pinecone
  • 🔍 Weaviate
  • 💾 Redis

🛠️ 具体实现步骤

步骤1:项目初始化

Maven依赖配置
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>spring-ai-demo</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <name>Spring AI Demo</name>
    <description>Spring AI基础示例项目</description>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>0.8.1</spring-ai.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring AI Core -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-core</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        
        <!-- Spring AI OpenAI -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

步骤2:配置文件设置

application.yml配置
yaml 复制代码
# Spring AI 配置
spring:
  application:
    name: spring-ai-demo
  
  # AI模型配置
  ai:
    openai:
      api-key: ${OPENAI_API_KEY:your-api-key-here}
      base-url: https://api.openai.com
      chat:
        options:
          model: gpt-3.5-turbo
          temperature: 0.7
          max-tokens: 1000
      embedding:
        options:
          model: text-embedding-ada-002

# 服务器配置
server:
  port: 8080
  servlet:
    context-path: /api

# 日志配置
logging:
  level:
    org.springframework.ai: DEBUG
    com.example: DEBUG
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

步骤3:核心服务实现

AI服务接口定义
java 复制代码
package com.example.service;

import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.embedding.EmbeddingResponse;

/**
 * 🤖 AI服务接口
 * 定义基础的AI功能
 */
public interface AIService {
    
    /**
     * 💬 简单聊天
     * @param message 用户消息
     * @return AI回复
     */
    String simpleChat(String message);
    
    /**
     * 🎯 结构化聊天
     * @param message 用户消息
     * @return 完整的聊天响应
     */
    ChatResponse structuredChat(String message);
    
    /**
     * 📊 文本嵌入
     * @param text 输入文本
     * @return 嵌入向量响应
     */
    EmbeddingResponse generateEmbedding(String text);
    
    /**
     * 🔍 语义相似度计算
     * @param text1 文本1
     * @param text2 文本2
     * @return 相似度分数
     */
    double calculateSimilarity(String text1, String text2);
}

📋 完整代码展示

AI服务实现类

java 复制代码
package com.example.service.impl;

import com.example.service.AIService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 🤖 AI服务实现类
 * 提供基础的AI功能实现
 */
@Service
public class AIServiceImpl implements AIService {
    
    private static final Logger logger = LoggerFactory.getLogger(AIServiceImpl.class);
    
    private final ChatClient chatClient;
    private final EmbeddingClient embeddingClient;
    
    public AIServiceImpl(ChatClient chatClient, EmbeddingClient embeddingClient) {
        this.chatClient = chatClient;
        this.embeddingClient = embeddingClient;
        logger.info("🚀 AI服务初始化完成");
    }
    
    @Override
    public String simpleChat(String message) {
        logger.debug("💬 处理简单聊天请求: {}", message);
        
        try {
            // 🎯 创建用户消息
            UserMessage userMessage = new UserMessage(message);
            
            // 📤 发送请求并获取响应
            ChatResponse response = chatClient.call(new Prompt(userMessage));
            
            // 📥 提取回复内容
            String reply = response.getResult().getOutput().getContent();
            
            logger.debug("✅ 聊天响应: {}", reply);
            return reply;
            
        } catch (Exception e) {
            logger.error("❌ 聊天请求失败", e);
            return "抱歉,我现在无法回答您的问题。请稍后再试。";
        }
    }
    
    @Override
    public ChatResponse structuredChat(String message) {
        logger.debug("🎯 处理结构化聊天请求: {}", message);
        
        try {
            // 🎯 创建提示
            Prompt prompt = new Prompt(new UserMessage(message));
            
            // 📤 发送请求
            ChatResponse response = chatClient.call(prompt);
            
            logger.debug("✅ 结构化聊天完成,Token使用: {}", 
                response.getMetadata().getUsage());
            
            return response;
            
        } catch (Exception e) {
            logger.error("❌ 结构化聊天失败", e);
            throw new RuntimeException("聊天服务暂时不可用", e);
        }
    }
    
    @Override
    public EmbeddingResponse generateEmbedding(String text) {
        logger.debug("📊 生成文本嵌入: {}", text.substring(0, Math.min(text.length(), 50)));
        
        try {
            // 🎯 创建嵌入请求
            EmbeddingRequest request = new EmbeddingRequest(List.of(text));
            
            // 📤 发送请求
            EmbeddingResponse response = embeddingClient.call(request);
            
            logger.debug("✅ 嵌入生成完成,维度: {}", 
                response.getResults().get(0).getOutput().size());
            
            return response;
            
        } catch (Exception e) {
            logger.error("❌ 嵌入生成失败", e);
            throw new RuntimeException("嵌入服务暂时不可用", e);
        }
    }
    
    @Override
    public double calculateSimilarity(String text1, String text2) {
        logger.debug("🔍 计算文本相似度");
        
        try {
            // 📊 生成两个文本的嵌入
            EmbeddingResponse embedding1 = generateEmbedding(text1);
            EmbeddingResponse embedding2 = generateEmbedding(text2);
            
            // 📐 提取向量
            List<Double> vector1 = embedding1.getResults().get(0).getOutput();
            List<Double> vector2 = embedding2.getResults().get(0).getOutput();
            
            // 🧮 计算余弦相似度
            double similarity = cosineSimilarity(vector1, vector2);
            
            logger.debug("✅ 相似度计算完成: {}", similarity);
            return similarity;
            
        } catch (Exception e) {
            logger.error("❌ 相似度计算失败", e);
            return 0.0;
        }
    }
    
    /**
     * 🧮 计算余弦相似度
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 相似度分数
     */
    private double cosineSimilarity(List<Double> vector1, List<Double> vector2) {
        if (vector1.size() != vector2.size()) {
            throw new IllegalArgumentException("向量维度不匹配");
        }
        
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;
        
        for (int i = 0; i < vector1.size(); i++) {
            dotProduct += vector1.get(i) * vector2.get(i);
            norm1 += Math.pow(vector1.get(i), 2);
            norm2 += Math.pow(vector2.get(i), 2);
        }
        
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }
}

REST控制器

java 复制代码
package com.example.controller;

import com.example.service.AIService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * 🌐 AI API控制器
 * 提供RESTful API接口
 */
@RestController
@RequestMapping("/ai")
@CrossOrigin(origins = "*")
public class AIController {
    
    private static final Logger logger = LoggerFactory.getLogger(AIController.class);
    
    private final AIService aiService;
    
    public AIController(AIService aiService) {
        this.aiService = aiService;
    }
    
    /**
     * 💬 简单聊天接口
     */
    @PostMapping("/chat/simple")
    public ResponseEntity<Map<String, Object>> simpleChat(@RequestBody Map<String, String> request) {
        logger.info("📥 收到简单聊天请求");
        
        String message = request.get("message");
        if (message == null || message.trim().isEmpty()) {
            return ResponseEntity.badRequest()
                .body(Map.of("error", "消息不能为空"));
        }
        
        try {
            String response = aiService.simpleChat(message);
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "message", message,
                "response", response,
                "timestamp", System.currentTimeMillis()
            ));
            
        } catch (Exception e) {
            logger.error("❌ 聊天处理失败", e);
            return ResponseEntity.internalServerError()
                .body(Map.of("error", "服务暂时不可用"));
        }
    }
    
    /**
     * 🎯 结构化聊天接口
     */
    @PostMapping("/chat/structured")
    public ResponseEntity<Map<String, Object>> structuredChat(@RequestBody Map<String, String> request) {
        logger.info("📥 收到结构化聊天请求");
        
        String message = request.get("message");
        if (message == null || message.trim().isEmpty()) {
            return ResponseEntity.badRequest()
                .body(Map.of("error", "消息不能为空"));
        }
        
        try {
            ChatResponse response = aiService.structuredChat(message);
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "message", message,
                "response", response.getResult().getOutput().getContent(),
                "metadata", Map.of(
                    "model", response.getMetadata().getModel(),
                    "usage", response.getMetadata().getUsage()
                ),
                "timestamp", System.currentTimeMillis()
            ));
            
        } catch (Exception e) {
            logger.error("❌ 结构化聊天处理失败", e);
            return ResponseEntity.internalServerError()
                .body(Map.of("error", "服务暂时不可用"));
        }
    }
    
    /**
     * 📊 文本嵌入接口
     */
    @PostMapping("/embedding")
    public ResponseEntity<Map<String, Object>> generateEmbedding(@RequestBody Map<String, String> request) {
        logger.info("📥 收到嵌入生成请求");
        
        String text = request.get("text");
        if (text == null || text.trim().isEmpty()) {
            return ResponseEntity.badRequest()
                .body(Map.of("error", "文本不能为空"));
        }
        
        try {
            EmbeddingResponse response = aiService.generateEmbedding(text);
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "text", text,
                "embedding", response.getResults().get(0).getOutput(),
                "dimensions", response.getResults().get(0).getOutput().size(),
                "timestamp", System.currentTimeMillis()
            ));
            
        } catch (Exception e) {
            logger.error("❌ 嵌入生成失败", e);
            return ResponseEntity.internalServerError()
                .body(Map.of("error", "服务暂时不可用"));
        }
    }
    
    /**
     * 🔍 相似度计算接口
     */
    @PostMapping("/similarity")
    public ResponseEntity<Map<String, Object>> calculateSimilarity(@RequestBody Map<String, String> request) {
        logger.info("📥 收到相似度计算请求");
        
        String text1 = request.get("text1");
        String text2 = request.get("text2");
        
        if (text1 == null || text1.trim().isEmpty() || 
            text2 == null || text2.trim().isEmpty()) {
            return ResponseEntity.badRequest()
                .body(Map.of("error", "两个文本都不能为空"));
        }
        
        try {
            double similarity = aiService.calculateSimilarity(text1, text2);
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "text1", text1,
                "text2", text2,
                "similarity", similarity,
                "timestamp", System.currentTimeMillis()
            ));
            
        } catch (Exception e) {
            logger.error("❌ 相似度计算失败", e);
            return ResponseEntity.internalServerError()
                .body(Map.of("error", "服务暂时不可用"));
        }
    }
    
    /**
     * 🏥 健康检查接口
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        return ResponseEntity.ok(Map.of(
            "status", "UP",
            "service", "Spring AI Demo",
            "timestamp", System.currentTimeMillis()
        ));
    }
}

主应用类

java 复制代码
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * 🚀 Spring AI 演示应用
 * 主启动类
 */
@SpringBootApplication
public class SpringAiDemoApplication {
    
    private static final Logger logger = LoggerFactory.getLogger(SpringAiDemoApplication.class);
    
    public static void main(String[] args) {
        logger.info("🚀 启动 Spring AI 演示应用...");
        
        ConfigurableApplicationContext context = SpringApplication.run(SpringAiDemoApplication.class, args);
        
        logger.info("✅ Spring AI 演示应用启动成功!");
        logger.info("🌐 API文档: http://localhost:8080/api");
        logger.info("🏥 健康检查: http://localhost:8080/api/ai/health");
    }
}

🔄 时序图分析

简单聊天流程时序图

🖥️ 客户端 🌐 AIController 🤖 AIService 💬 ChatClient 🧠 OpenAI API POST /ai/chat/simple {"message": "你好"} 📝 验证请求参数 simpleChat(message) 🎯 创建UserMessage call(Prompt) 📤 发送聊天请求 HTTP POST /v1/chat/completions 📥 返回AI响应 ChatResponse 📊 提取回复内容 String reply 📦 构建响应对象 200 OK {"success": true, "response": "你好!..."} 🖥️ 客户端 🌐 AIController 🤖 AIService 💬 ChatClient 🧠 OpenAI API

嵌入生成流程时序图

🖥️ 客户端 🌐 AIController 🤖 AIService 📊 EmbeddingClient 🧠 OpenAI API POST /ai/embedding {"text": "Spring AI很棒"} 📝 验证请求参数 generateEmbedding(text) 🎯 创建EmbeddingRequest call(EmbeddingRequest) 📤 发送嵌入请求 HTTP POST /v1/embeddings 📥 返回向量数据 EmbeddingResponse 📊 提取向量信息 EmbeddingResponse 📦 构建响应对象 200 OK {"success": true, "embedding": [0.1, 0.2, ...], "dimensions": 1536} 🖥️ 客户端 🌐 AIController 🤖 AIService 📊 EmbeddingClient 🧠 OpenAI API

📝 总结与扩展思考

🎯 本文核心要点

  1. 🏗️ 架构理解:Spring AI提供了统一的AI能力集成框架
  2. 🔧 配置简化:通过Spring Boot自动配置简化AI服务集成
  3. 🎯 接口统一:不同AI提供商的统一抽象接口
  4. 📊 功能丰富:支持聊天、嵌入、图像等多种AI能力

🚀 扩展思考

1. 性能优化方向
  • 💾 缓存策略:对频繁请求的结果进行缓存
  • 🔄 连接池:优化HTTP连接管理
  • 📊 批处理:支持批量嵌入生成
  • ⚡ 异步处理:使用响应式编程提升并发性能
2. 功能扩展方向
  • 🛠️ 函数调用:集成外部工具和API
  • 📝 提示模板:动态提示词管理
  • 💾 向量存储:集成向量数据库
  • 🔍 RAG系统:检索增强生成
3. 生产环境考虑
  • 🔒 安全性:API密钥管理和访问控制
  • 📊 监控告警:服务健康状态监控
  • 🔄 容错处理:优雅的错误处理和重试机制
  • 📈 扩展性:支持多实例部署和负载均衡

🔮 下期预告

在下一篇文章中,我们将深入探讨Spring AI的提示工程与模板管理,学习如何:

  • 🎯 设计高效的提示模板
  • 📝 实现动态提示词生成
  • 🔄 管理提示词版本和A/B测试
  • 🎨 构建领域特定的提示词库

标签#SpringAI #人工智能 #Java开发 #微服务架构 #OpenAI

相关推荐
阿杜杜不是阿木木21 分钟前
什么?OpenCV调用cv2.putText()乱码?寻找支持中文的方法之旅
人工智能·opencv·计算机视觉
赴33535 分钟前
图像边缘检测
人工智能·python·opencv·计算机视觉
机器视觉知识推荐、就业指导1 小时前
如何消除工业视觉检测中的反光问题
人工智能·计算机视觉·视觉检测
Xの哲學1 小时前
Linux PCI 子系统:工作原理与实现机制深度分析
linux·网络·算法·架构·边缘计算
周润发的弟弟2 小时前
2025年Java在中国开发语言排名分析报告
人工智能
杭州泽沃电子科技有限公司2 小时前
工业环境电缆火灾预防的分布式光纤在线监测
运维·人工智能·科技·安全
没有梦想的咸鱼185-1037-16632 小时前
AI大模型支持下的:CMIP6数据分析与可视化、降尺度技术与气候变化的区域影响、极端气候分析
人工智能·python·深度学习·机器学习·chatgpt·数据挖掘·数据分析
柠檬味拥抱2 小时前
基于自适应信号处理的AI Agent多任务协同控制方法研究
人工智能
唐丙斯城2 小时前
新能源汽车热管理仿真:蒙特卡洛助力神经网络训练
人工智能·神经网络·汽车
qb3 小时前
vue3.5.18源码:computed 在发布订阅者模式中的双重角色
前端·vue.js·架构