☕ Java老兵学AI:Spring AI到底怎么用?

40 阅读2分钟

"都2026年了,Java程序员再不学AI就要被淘汰了?" —— 很多人在问,但真正动手的少。这篇是给想入门AI的Java老兵写的,用你熟悉的方式打开Spring AI。


一、为什么是Spring AI?

作为Java老兵,你肯定熟悉Spring Boot那一套:依赖注入、AOP、自动配置。Spring AI就是Spring生态里的AI集成框架,让你用Spring的思维方式接入大模型。

好处显而易见:

  • ✅ 你会Spring Boot,就能快速上手
  • ✅ 支持OpenAI、Azure、Ollama、HuggingFace等多种模型
  • ✅ 对接RAG、向量数据库这些AI热门技术
  • ✅ 测试友好,写单元测试不头疼

二、快速开始:5分钟跑通第一个例子

2.1 依赖引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>

2.2 配置application.yml

spring:
  application:
    name: spring-ai-demo
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      model: gpt-4o

2.3 写个最简单的对话

@RestController
@RequestMapping("/ai")
public class AiController {

    private final ChatClient chatClient;

    public AiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

访问 http://localhost:8080/ai/chat?message=你好,看看返回什么?


三、主流用法:Prompt模板

实际项目中,Prompt往往很复杂,这时候用PromptTemplate更灵活:

@GetMapping("/review")
public String codeReview(@RequestParam String code) {
    PromptTemplate template = new PromptTemplate("""
        你是一个资深代码审查员。请审查以下Java代码,指出问题:
        
        ```java
        {code}
        ```
        
        请从以下维度评审:
        1. 代码性能
        2. 潜在bug
        3. 代码规范
        4. 安全性
        """);

    Prompt prompt = template.create(Map.of("code", code));

    return chatClient.prompt(prompt)
            .call()
            .content();
}

四、结构化输出:让AI返回JSON

很多场景需要AI返回结构化数据,Spring AI提供了实体映射

定义返回对象

public class CodeReviewResult {
    private String performance;
    private String bugs;
    private String specification;
    private String security;
    private int score; // 1-10

    // getters and setters
}

使用OpenAI的结构化输出

@GetMapping("/review-json")
public CodeReviewResult codeReviewJson(@RequestParam String code) {
    return chatClient.prompt()
            .system("你是一个资深代码审查员。返回JSON格式。")
            .user(code)
            .call()
            .entity(CodeReviewResult.class);
}

返回示例:

{
  "performance": "建议使用StringBuilder替代字符串拼接",
  "bugs": "存在空指针风险,建议增加判空",
  "specification": "方法命名不符合驼峰规范",
  "security": "未做SQL注入防护",
  "score": 6
}

五、Embedding + 向量检索:实现RAG

RAG(检索增强生成)是现在最火的AI应用模式,Spring AI也支持:

5.1 配置向量存储

spring:
  ai:
    postgres:
      vector-store:
        distance-type: COSINE_DISTANCE
        dimension: 1536

5.2 文档切分入库

@Service
public class DocumentService {

    private final VectorStore vectorStore;
    private final ChatClient chatClient;

    // 文档入库
    public void loadDocuments(String content) {
        TextSplitter splitter = new TextSplitter(500, 100);
        List<Document> docs = splitter.split(content);
        vectorStore.add(docs);
    }

    // 检索相关文档
    public String retrieve(String query) {
        List<Document> results = vectorStore.similaritySearch(query);
        return results.stream()
                .map(Document::getContent)
                .collect(Collectors.joining("\n"));
    }
}

5.3 RAG完整示例

@GetMapping("/rag-chat")
public String ragChat(@RequestParam String question) {
    // 1. 检索相关文档
    String context = documentService.retrieve(question);

    // 2. 构建带上下文的Prompt
    PromptTemplate template = new PromptTemplate("""
        基于以下资料回答问题。如果资料不够,说"我没有足够信息"。

        资料:
        {context}

        问题:{question}
        """);

    Prompt prompt = template.create(Map.of(
        "context", context,
        "question", question
    ));

    // 3. 调用AI
    return chatClient.prompt(prompt).call().content();
}

六、Function Calling:让AI调用Java方法

这是Spring AI的杀手级功能——AI可以调用你写好的Java方法

6.1 定义一个Function

@Component
public class WeatherService {

    @Bean
    public ChatClient.ToolContext weatherTool() {
        return ChatClient.Builder.getObjectMapper(); // 简化示例
    }

    @Tool(name = "get_weather", description = "获取城市天气")
    public String getWeather(@P("city") String city) {
        // 实际项目中这里调天气API
        return city + "今天晴天,25度,适宜跑步🏃";
    }
}

6.2 Controller中使用

@GetMapping("/weather-chat")
public String weatherChat(@RequestParam String city) {
    return chatClient.prompt()
            .system("你是一个天气助手。可以调用工具获取实时天气。")
            .user(city + "今天天气怎么样?适合跑步吗?")
            .tools(new WeatherService().weatherTool())
            .call()
            .content();
}

AI会自动判断什么时候该调用get_weather方法!


七、实战项目结构推荐

spring-ai-demo/
├── src/main/java/com/example/ai/
│   ├── controller/
│   │   └── AiController.java
│   ├── service/
│   │   ├── ChatService.java
│   │   └── DocumentService.java
│   ├── tools/
│   │   └── WeatherService.java
│   ├── model/
│   │   └── CodeReviewResult.java
│   └── config/
│       └── AiConfig.java
├── src/main/resources/
│   ├── application.yml
│   └── prompts/
│       └── code-review.st
└── pom.xml

八、避坑指南

解决方案
API Key泄露用环境变量 ${OPENAI_API_KEY},别写死在代码里
Token超限限制输入长度,用TextSplitter切分长文本
响应慢加超时配置,开启流式响应(stream())
中文乱码确保Prompt和解析编码一致
费用暴增限制max_tokens,加调用次数限制

九、学习路线建议

第一周:跑通官方示例,理解ChatClient基本用法
第二周:Prompt模板、结构化输出
第三周:Embedding + 向量数据库
第四周:Function Calling + RAG实战

十、总结

Spring AI让Java程序员用熟悉的姿势进入AI时代:

  • ✅ 会Spring Boot → 就会Spring AI
  • ✅ 从简单对话到RAG到Function Calling,都能覆盖
  • ✅ 生态成熟,社区活跃,文档完善

关键是动手做。看完这篇文章,你的第一步应该是:建个项目,跑通第二章的第一个例子。


📚 参考资料


有问题欢迎留言探讨!我是Java老兵,也是AI小学生,一起进步 🚀