Spring AI实战指南:在Java项目中集成大语言模型

Spring AI实战指南:在Java项目中集成大语言模型

前言

作为Java开发者,在AI浪潮中我们常常面临一个尴尬的问题:Python生态的AI工具链极其丰富,而Java似乎被边缘化了。但实际上,Spring团队推出的Spring AI正在改变这一局面。

本文基于我在实际项目中的使用经验,分享如何在Spring Boot应用中集成大语言模型,包括踩过的坑和最佳实践。


一、Spring AI是什么

Spring AI是Spring官方推出的AI应用开发框架,目标是让Java开发者能够以Spring的方式使用AI能力。

1.1 核心定位

ini 复制代码
Spring AI = Spring的简洁性 + AI的强大能力

它解决了Java开发者在AI集成中的几个痛点:

  • 统一API:不同厂商的模型(OpenAI、Claude、通义等)使用相同的调用方式
  • 与Spring生态无缝集成:自动配置、依赖注入、AOP等特性全部可用
  • 类型安全:告别Python的动态类型,享受Java的编译期检查
  • 企业级特性:内置重试、熔断、监控等企业级能力

1.2 版本说明

目前Spring AI最新稳定版是1.1.0,基于Spring Boot 3.3+,需要JDK 17+。


二、环境准备

2.1 创建项目

使用Spring Initializr创建项目,选择以下依赖:

xml 复制代码
<dependencies>
    <!-- Spring AI核心 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    </dependency>
    
    <!-- 如果使用阿里通义 -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter</artifactId>
        <version>1.0.0-M3</version>
    </dependency>
</dependencies>

<!-- 添加Spring AI的Maven仓库 -->
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

2.2 配置API密钥

yaml 复制代码
# application.yml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.openai.com/v1
      chat:
        options:
          model: gpt-4o
          temperature: 0.7

如果使用阿里通义:

yaml 复制代码
spring:
  ai:
    alibaba:
      api-key: ${ALI_API_KEY}
      chat:
        options:
          model: qwen-plus

三、基础使用:ChatClient

3.1 最简单的对话

java 复制代码
@Service
public class ChatService {
    
    private final ChatClient chatClient;
    
    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }
    
    public String chat(String message) {
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

3.2 带系统提示的对话

java 复制代码
public String chatWithSystemPrompt(String message) {
    return chatClient.prompt()
            .system("你是一个专业的Java技术顾问,回答要简洁准确。")
            .user(message)
            .call()
            .content();
}

3.3 流式输出(SSE)

对于长文本回复,流式输出能提升用户体验:

java 复制代码
public Flux<String> chatStream(String message) {
    return chatClient.prompt()
            .user(message)
            .stream()
            .content();
}

Controller层配合SSE:

java 复制代码
@RestController
@RequestMapping("/api/chat")
public class ChatController {
    
    private final ChatService chatService;
    
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> stream(@RequestParam String message) {
        return chatService.chatStream(message);
    }
}

四、结构化输出:从字符串到对象

实际开发中,我们往往需要AI返回结构化数据,而不是纯文本。

4.1 定义输出结构

java 复制代码
public record CodeReviewResult(
    int score,
    List<String> issues,
    List<String> suggestions,
    String summary
) {}

4.2 调用并解析

java 复制代码
public CodeReviewResult reviewCode(String code) {
    String prompt = """
        请对以下Java代码进行审查,按JSON格式返回结果:
        
        代码:
        ```java
        %s
        ```
        
        返回格式:
        {
            "score": 分数(1-100),
            "issues": ["问题1", "问题2"],
            "suggestions": ["建议1", "建议2"],
            "summary": "总体评价"
        }
        """.formatted(code);
    
    String response = chatClient.prompt()
            .user(prompt)
            .call()
            .content();
    
    // 提取JSON并解析
    String json = extractJson(response);
    return new ObjectMapper().readValue(json, CodeReviewResult.class);
}

4.3 更优雅的Bean输出

Spring AI 1.1支持直接输出Bean:

java 复制代码
public CodeReviewResult reviewCodeV2(String code) {
    return chatClient.prompt()
            .user("请审查以下代码:" + code)
            .call()
            .entity(CodeReviewResult.class);
}

五、RAG:让AI读懂你的数据

RAG(检索增强生成)是生产环境最常用的AI应用模式。

5.1 核心流程

rust 复制代码
用户提问 -> 向量检索 -> 获取相关文档 -> 构建Prompt -> AI生成答案

5.2 添加向量存储依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-milvus-store-spring-boot-starter</artifactId>
</dependency>

5.3 文档加载与存储

java 复制代码
@Service
public class DocumentService {
    
    private final VectorStore vectorStore;
    
    public DocumentService(VectorStore vectorStore) {
        this.vectorStore = vectorStore;
    }
    
    public void addDocuments(List<String> texts) {
        List<Document> documents = texts.stream()
            .map(text -> new Document(text))
            .toList();
        
        vectorStore.add(documents);
    }
}

5.4 RAG问答实现

java 复制代码
@Service
public class RagService {
    
    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    
    public RagService(ChatClient chatClient, VectorStore vectorStore) {
        this.chatClient = chatClient;
        this.vectorStore = vectorStore;
    }
    
    public String answer(String question) {
        // 1. 检索相关文档
        List<Document> relevantDocs = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(question)
                .topK(5)
                .build()
        );
        
        // 2. 构建上下文
        String context = relevantDocs.stream()
            .map(Document::getText)
            .collect(Collectors.joining("\n\n"));
        
        // 3. 构建Prompt
        String prompt = """
            基于以下上下文回答问题。如果上下文中没有相关信息,请明确说明。
            
            上下文:
            %s
            
            问题:%s
            """.formatted(context, question);
        
        // 4. 调用AI
        return chatClient.prompt()
            .user(prompt)
            .call()
            .content();
    }
}

六、Function Calling:AI调用Java方法

这是Spring AI最强大的特性之一:让AI能够调用你的业务方法。

6.1 定义工具方法

java 复制代码
@Component
public class WeatherService {
    
    @Tool(description = "获取指定城市的天气信息")
    public String getWeather(@ToolParam(description = "城市名称,如北京") String city) {
        // 实际调用天气API
        return "北京今天晴,25°C";
    }
}

6.2 注册工具并调用

java 复制代码
@Service
public class AgentService {
    
    private final ChatClient chatClient;
    private final WeatherService weatherService;
    
    public AgentService(ChatClient.Builder builder, WeatherService weatherService) {
        this.chatClient = builder
            .defaultTools(weatherService)
            .build();
        this.weatherService = weatherService;
    }
    
    public String chat(String message) {
        return chatClient.prompt()
            .user(message)
            .call()
            .content();
    }
}

当用户问"北京今天天气怎么样"时,AI会自动调用getWeather方法获取数据。


七、踩坑记录与解决方案

7.1 API调用超时

问题:大模型响应慢,默认超时时间不够。

解决

java 复制代码
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
    return builder
        .defaultClientRequest(request -> request
            .timeout(Duration.ofSeconds(60))
        )
        .build();
}

7.2 中文乱码

问题:返回的中文显示乱码。

解决:确保请求头设置正确:

yaml 复制代码
spring:
  ai:
    alibaba:
      api-key: ${ALI_API_KEY}
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1

7.3 Token计算不准确

问题:超出模型上下文限制。

解决:手动估算并截断:

java 复制代码
private String truncate(String text, int maxTokens) {
    // 粗略估算:中文1字≈1.5token
    int estimatedTokens = (int) (text.length() * 1.5);
    if (estimatedTokens > maxTokens) {
        int maxChars = (int) (maxTokens / 1.5);
        return text.substring(0, maxChars);
    }
    return text;
}

7.4 向量维度不匹配

问题:Milvus报错维度不一致。

解决:确保嵌入模型和向量库配置一致:

yaml 复制代码
spring:
  ai:
    vectorstore:
      milvus:
        client:
          host: localhost
          port: 19530
        collection-name: document_store
        embedding-dimension: 1536  # 与模型输出维度一致

八、生产环境最佳实践

8.1 配置管理

使用Spring Cloud Config或环境变量管理API密钥,不要硬编码:

java 复制代码
@Configuration
@ConfigurationProperties(prefix = "spring.ai.alibaba")
public class AiProperties {
    private String apiKey;
    private String baseUrl;
    // getter/setter
}

8.2 错误处理

java 复制代码
@Service
public class RobustChatService {
    
    private final ChatClient chatClient;
    
    @Retryable(value = {AiApiException.class}, maxAttempts = 3)
    public String chatWithRetry(String message) {
        try {
            return chatClient.prompt()
                .user(message)
                .call()
                .content();
        } catch (Exception e) {
            log.error("AI调用失败", e);
            return "服务暂时不可用,请稍后重试";
        }
    }
}

8.3 成本监控

java 复制代码
@Component
public class TokenMetrics {
    
    private final MeterRegistry meterRegistry;
    
    public void record(int inputTokens, int outputTokens) {
        meterRegistry.counter("ai.tokens.input").increment(inputTokens);
        meterRegistry.counter("ai.tokens.output").increment(outputTokens);
    }
}

九、完整示例项目

9.1 项目结构

css 复制代码
spring-ai-demo/
├── src/main/java/com/example/demo/
│   ├── DemoApplication.java
│   ├── config/
│   │   └── AiConfig.java
│   ├── controller/
│   │   └── ChatController.java
│   ├── service/
│   │   ├── ChatService.java
│   │   └── RagService.java
│   └── model/
│       └── ChatRequest.java
└── src/main/resources/
    └── application.yml

9.2 可运行的完整代码

java 复制代码
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@RestController
@RequestMapping("/api")
public class ChatController {
    
    private final ChatService chatService;
    
    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }
    
    @PostMapping("/chat")
    public ResponseEntity<String> chat(@RequestBody ChatRequest request) {
        String response = chatService.chat(request.message());
        return ResponseEntity.ok(response);
    }
}

@Service
public class ChatService {
    
    private final ChatClient chatClient;
    
    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }
    
    public String chat(String message) {
        return chatClient.prompt()
            .user(message)
            .call()
            .content();
    }
}

public record ChatRequest(String message) {}

十、总结

Spring AI让Java开发者能够以熟悉的方式接入AI能力。核心要点:

  1. ChatClient是核心API,支持链式调用和流式输出
  2. RAG是生产环境最常用的模式,需要配合向量数据库
  3. Function Calling让AI能够调用业务方法,实现真正的智能代理
  4. 注意错误处理和成本控制,生产环境必须考虑这些

后续可以深入学习的方向:

  • Spring AI与LangChain4j的对比
  • 多模态AI(图像、语音)集成
  • AI Agent的自主决策能力

参考链接

相关推荐
暗夜猎手-大魔王1 小时前
转载--Karpathy 怎么看 AI Agent(三):怎么给 Agent 搭一个真正能用的上下文
人工智能
每日综合1 小时前
UKey Wallet 产品体系:移动端应用、硬件安全设备与助记词备份设备
人工智能
阿里云大数据AI技术1 小时前
基于 MaxCompute Delta Table 实现 SCD Type 2:Time Travel 驱动的维度变更追踪方案
人工智能
听麟2 小时前
HarmonyOS 6.0+ PC端离线翻译工具开发实战:端侧AI模型集成与多格式内容翻译落地
人工智能·华为·harmonyos
摆烂大大王2 小时前
AI 日报|2026年5月8日:xAI解散、DeepSeek融资450亿美元、苹果AI耳机入DVT尾声
人工智能
@不误正业2 小时前
AI-Agent安全性实战-提示注入防御与工具调用沙箱隔离
人工智能·华为·harmonyos
用户8356290780512 小时前
Python 操作 PowerPoint 表格的创建与格式化
后端·python
forestqq2 小时前
基于openeuler2403sp3的容器,打包django运行环境镜像
后端·python·django
AI学长2 小时前
数据集|西红柿番茄成熟度目标检测数据集-6类别800张图
人工智能·目标检测·水果西红柿番茄