Spring Boot 3 + AI大模型整合全攻略

技术架构

2026年,Java开发者必须拥抱AI大模型

Python训练模型,Java应用模型——这是2026年AI工程化的黄金分工。

一个事实:全球500强企业中,72%的后端系统运行在JVM上,但AI应用的原型开发90%用Python。问题来了——模型训练完了,谁来扛生产流量? 答案是Java。

为什么Java是AI应用的最佳载体

维度 Python Java (Spring Boot)
并发处理 GIL限制,单线程 多线程 + 虚拟线程(Loom),万级并发
企业集成 需大量胶水代码 Spring生态一站式集成
安全合规 动态类型,运行时才报错 强类型 + 编译期检查
运维成熟度 Gunicorn/uWSGI Spring Boot Actuator + K8s
团队技能 AI研究员 企业后端工程师
部署一致性 依赖地狱 Fat JAR,一次打包到处运行

Java + AI的三大场景

┌──────────────────────────────────────────────────────────┐
│                  Java + AI 应用全景                        │
├──────────────┬──────────────┬────────────────────────────┤
│   AI增强应用  │   AI原生应用  │      AI Agent              │
│              │              │                            │
│ 智能客服     │ ChatBot      │ 自主决策Agent              │
│ 文档问答     │ Code Copilot │ Planner→Executor→Evaluator │
│ 数据分析助手 │ RAG知识库    │ 多工具编排Agent            │
│ 智能推荐     │ 内容生成     │ 工作流自动化Agent          │
├──────────────┴──────────────┴────────────────────────────┤
│              Spring Boot 3 + Spring AI                   │
│         统一编程模型 · 声明式配置 · 生产级可靠性          │
└──────────────────────────────────────────────────────────┘

Spring AI vs LangChain4j:框架选型

2026年Java AI生态两大主流框架,各有侧重。

核心定位对比

维度 Spring AI LangChain4j
设计哲学 Spring风格,声明式 LangChain移植,链式调用
核心团队 Spring官方(VMware) 独立开源社区
配置方式 application.yml + Bean Builder模式 + 代码配置
模型支持 OpenAI/Azure/Ollama/通义 OpenAI/Azure/Ollama/通义/智谱
向量库 PGVector/Chroma/Milvus PGVector/Chroma/Milvus/Weaviate
RAG支持 内置ETL Pipeline 内置RAG模块
Function Calling 自动注册Spring Bean 手动注册@Tool方法
Spring集成 原生,零配置 需spring-boot-starter
流式响应 Flux TokenStream
社区活跃度 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
学习曲线 Spring开发者零门槛 需学LangChain概念
版本(2026) 1.0.0 GA 1.0.0 GA

代码风格对比

// Spring AI — 声明式,Spring风格
@Configuration
public class AiConfig {
    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder
            .defaultSystem("你是一个专业的Java技术顾问")
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build();
    }
}

// 调用:一行搞定
String response = chatClient.prompt()
    .user("解释Spring Boot 3的虚拟线程")
    .call()
    .content();
// LangChain4j — 链式,Builder风格
ChatLanguageModel model = OpenAiChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("gpt-4o")
    .temperature(0.7)
    .build();

// 调用:显式构造
Response<AiMessage> response = model.generate(
    SystemMessage.from("你是一个专业的Java技术顾问"),
    UserMessage.from("解释Spring Boot 3的虚拟线程")
);

选型建议

场景 推荐 理由
Spring项目加AI能力 Spring AI 零学习成本,原生集成
全新AI原生项目 均可 看团队技术栈偏好
复杂Agent编排 LangChain4j Chain/Agent抽象更成熟
企业合规要求 Spring AI Actuator + Security集成
快速原型 LangChain4j Builder模式更直观

本文以Spring AI为主线,因为它与Spring Boot 3的整合最为自然,也是2026年企业级Java AI应用的主流选择。


Spring Boot 3 + Spring AI快速入门

第一步:Maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.0</version>
    </parent>

    <properties>
        <java.version>21</java.version>
        <spring-ai.version>1.0.0</spring-ai.version>
    </properties>

    <dependencies>
        <!-- Spring AI OpenAI -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        </dependency>

        <!-- Spring AI Vector Store (PGVector) -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
        </dependency>

        <!-- Redis for Chat Memory -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-chat-memory-redis</artifactId>
        </dependency>

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

        <!-- Spring Actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

第二步:YAML配置

spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.openai.com
      chat:
        options:
          model: gpt-4o
          temperature: 0.7
          max-tokens: 4096
          top-p: 0.9
      embedding:
        options:
          model: text-embedding-3-large

    vectorstore:
      pgvector:
        index-type: HNSW
        dimensions: 3072
        distance-type: COSINE

    chat:
      memory:
        redis:
          host: localhost
          port: 6379
          ttl: 3600

server:
  port: 8080

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

第三步:ChatController

@RestController
@RequestMapping("/api/chat")
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @PostMapping
    public String chat(@RequestBody ChatRequest request) {
        return chatClient.prompt()
            .user(request.message())
            .call()
            .content();
    }

    @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatStream(@RequestBody ChatRequest request) {
        return chatClient.prompt()
            .user(request.message())
            .stream()
            .content();
    }

    @PostMapping("/system")
    public String chatWithSystem(
            @RequestBody ChatRequest request,
            @RequestParam String role) {
        return chatClient.prompt()
            .system(role)
            .user(request.message())
            .call()
            .content();
    }

    public record ChatRequest(String message) {}
}

第四步:启动与验证

# 设置API Key
export OPENAI_API_KEY=sk-xxxxx

# 启动应用
mvn spring-boot:run

# 测试
curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "用Java写一个快速排序"}'

# 流式测试
curl -X POST http://localhost:8080/api/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "解释JVM内存模型"}'
┌──────────────────────────────────────────────────────┐
│              Spring Boot 3 + Spring AI 启动流程       │
├──────────────────────────────────────────────────────┤
│                                                      │
│  main() → @SpringBootApplication                     │
│    ├── 自动配置 spring-ai-auto-configuration         │
│    ├── 注册 OpenAiChatModel Bean                     │
│    ├── 注册 OpenAiEmbeddingModel Bean                │
│    ├── 注册 PgVectorStore Bean                       │
│    ├── 注册 ChatClient Bean                          │
│    └── 注册 ChatMemory Bean (Redis)                  │
│                                                      │
│  ChatClient.prompt()                                 │
│    ├── .user() → 构造UserMessage                     │
│    ├── .system() → 构造SystemMessage                 │
│    ├── .advisors() → 注入Advisor链                   │
│    ├── .call() → 同步调用 → String                   │
│    └── .stream() → 流式调用 → Flux<String>           │
│                                                      │
└──────────────────────────────────────────────────────┘

企业级Chat应用:多轮对话与Redis持久化记忆

没有记忆的AI就像金鱼——每轮对话都是全新的,无法理解上下文。企业级Chat应用必须有持久化记忆。

对话记忆架构

┌──────────────────────────────────────────────────────────┐
│                   多轮对话记忆架构                         │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  用户消息 ──→ ChatMemoryAdvisor ──→ ChatClient           │
│                  │                      │                │
│                  ▼                      ▼                │
│            ┌──────────┐          ┌──────────┐          │
│            │  Redis   │          │ OpenAI   │          │
│            │ ChatStore│          │  API     │          │
│            └──────────┘          └──────────┘          │
│                  ▲                      │                │
│                  │                      ▼                │
│            写回记忆 ←── AI响应 ←── 模型推理              │
│                                                          │
│  Memory结构:                                             │
│  conversation:{userId} → [                               │
│    {role: "system", content: "..."},                     │
│    {role: "user", content: "..."},                       │
│    {role: "assistant", content: "..."},                  │
│    ...                                                   │
│  ]                                                       │
└──────────────────────────────────────────────────────────┘

配置ChatMemory

@Configuration
public class ChatMemoryConfig {

    @Bean
    public ChatClient chatClientWithMemory(
            ChatClient.Builder builder,
            ChatMemoryRepository memoryRepository) {

        ChatMemory chatMemory = new RedisChatMemory(memoryRepository);

        return builder
            .defaultSystem("""
                你是工具库网站的AI助手,专注于Java和Spring技术。
                回答要专业、准确、有代码示例。
                如果不确定,请诚实说明。
                """)
            .defaultAdvisors(
                MessageChatMemoryAdvisor.builder(chatMemory)
                    .conversationIdExpression("userId")
                    .maxMessages(20)
                    .build(),
                new SimpleLoggerAdvisor()
            )
            .build();
    }
}

ChatController with Memory

@RestController
@RequestMapping("/api/chat")
public class EnterpriseChatController {

    private final ChatClient chatClient;

    public EnterpriseChatController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @PostMapping("/conversation")
    public ChatResponse conversation(
            @RequestBody ConversationRequest request,
            @RequestHeader("X-User-Id") String userId) {

        String content = chatClient.prompt()
            .user(request.message())
            .advisors(a -> a.param("userId", userId))
            .call()
            .content();

        return new ChatResponse(content, userId, Instant.now());
    }

    @PostMapping("/conversation/stream")
    public Flux<ServerSentEvent<String>> conversationStream(
            @RequestBody ConversationRequest request,
            @RequestHeader("X-User-Id") String userId) {

        return chatClient.prompt()
            .user(request.message())
            .advisors(a -> a.param("userId", userId))
            .stream()
            .content()
            .map(chunk -> ServerSentEvent.<String>builder()
                .data(chunk)
                .build());
    }

    @DeleteMapping("/conversation/{userId}")
    public ResponseEntity<Void> clearMemory(@PathVariable String userId) {
        // 清除用户对话记忆
        return ResponseEntity.noContent().build();
    }

    public record ConversationRequest(String message) {}
    public record ChatResponse(String content, String userId, Instant timestamp) {}
}

Redis记忆存储实现

@Component
public class RedisChatMemoryRepository implements ChatMemoryRepository {

    private final StringRedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    private static final String KEY_PREFIX = "chat:memory:";
    private static final Duration TTL = Duration.ofHours(2);

    public RedisChatMemoryRepository(
            StringRedisTemplate redisTemplate,
            ObjectMapper objectMapper) {
        this.redisTemplate = redisTemplate;
        this.objectMapper = objectMapper;
    }

    @Override
    public List<Message> findByConversationId(String conversationId) {
        String json = redisTemplate.opsForValue().get(KEY_PREFIX + conversationId);
        if (json == null) {
            return new ArrayList<>();
        }
        try {
            return objectMapper.readValue(json,
                new TypeReference<List<Message>>() {});
        } catch (JsonProcessingException e) {
            throw new ChatMemoryException("Failed to read memory", e);
        }
    }

    @Override
    public void saveAll(String conversationId, List<Message> messages) {
        try {
            String json = objectMapper.writeValueAsString(messages);
            redisTemplate.opsForValue()
                .set(KEY_PREFIX + conversationId, json, TTL);
        } catch (JsonProcessingException e) {
            throw new ChatMemoryException("Failed to save memory", e);
        }
    }
}

记忆策略对比

策略 实现 优点 缺点 适用场景
窗口记忆 保留最近N轮 简单,token可控 丢失早期上下文 通用对话
摘要记忆 旧对话压缩为摘要 保留全局语义 摘要可能丢细节 长对话
混合记忆 摘要 + 最近N轮 兼顾全局与细节 实现复杂 企业客服
向量记忆 按语义检索相关片段 无限上下文 检索延迟 知识密集型

RAG实战:文档ETL Pipeline + 向量检索 + 上下文注入

RAG(检索增强生成)是让大模型拥有企业私有知识的核心技术。

RAG完整架构

┌──────────────────────────────────────────────────────────────┐
│                      RAG 完整 Pipeline                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────┐    ┌──────────┐    ┌──────────┐               │
│  │  文档源  │───→│  ETL     │───→│  向量库   │               │
│  │ PDF/MD  │    │ Pipeline │    │ PGVector │               │
│  │ DOCX    │    │          │    │          │               │
│  └─────────┘    └──────────┘    └──────────┘               │
│                      │              ▲                       │
│                      ▼              │                       │
│              ┌──────────────┐      │                       │
│              │  Embedding   │──────┘                       │
│              │  text-embed-3│                               │
│              └──────────────┘                               │
│                                                              │
│  ┌─────────┐    ┌──────────┐    ┌──────────┐               │
│  │ 用户提问 │───→│  检索    │───→│  生成    │               │
│  │          │    │ 相似度TopK│    │ 上下文+Q │               │
│  └─────────┘    └──────────┘    └──────────┘               │
│                      │              │                       │
│                      ▼              ▼                       │
│              ┌──────────────┐  ┌──────────────┐           │
│              │  RRF重排     │  │  答案+引用    │           │
│              └──────────────┘  └──────────────┘           │
└──────────────────────────────────────────────────────────────┘

文档ETL Pipeline

@Service
public class DocumentEtlService {

    private final VectorStore vectorStore;
    private final DocumentReader documentReader;
    private final DocumentTransformer documentTransformer;

    public DocumentEtlService(
            VectorStore vectorStore,
            DocumentReader documentReader,
            DocumentTransformer documentTransformer) {
        this.vectorStore = vectorStore;
        this.documentReader = documentReader;
        this.documentTransformer = documentTransformer;
    }

    public void ingestDocuments(String directoryPath) {
        // Step 1: Read — 读取文档
        List<Document> documents = documentReader.read(directoryPath);

        // Step 2: Transform — 分块 + 添加元数据
        List<Document> chunks = documentTransformer.apply(documents);

        // Step 3: Load — Embedding + 写入向量库
        vectorStore.add(chunks);

        log.info("Ingested {} documents, {} chunks into vector store",
            documents.size(), chunks.size());
    }
}

文档读取器

@Component
public class SmartDocumentReader implements DocumentReader {

    private final TikaDocumentReader tikaReader;

    @Override
    public List<Document> read(String path) {
        return switch (getFileExtension(path)) {
            case "pdf" -> readPdf(path);
            case "md"  -> readMarkdown(path);
            case "docx" -> readDocx(path);
            default -> throw new UnsupportedDocumentException(path);
        };
    }

    private List<Document> readPdf(String path) {
        var reader = new PagePdfDocumentReader(
            path,
            PdfDocumentReaderConfig.builder()
                .pagesPerDocument(1)
                .build()
        );
        return reader.get();
    }

    private List<Document> readMarkdown(String path) {
        var reader = new MarkdownDocumentReader(
            path,
            MarkdownDocumentReaderConfig.builder()
                .includeCodeBlocks(true)
                .build()
        );
        return reader.get();
    }
}

文档分块与元数据增强

@Component
public class SmartDocumentTransformer implements DocumentTransformer {

    private final TokenTextSplitter splitter;

    @Override
    public List<Document> apply(List<Document> documents) {
        return documents.stream()
            .flatMap(doc -> splitter.split(doc).stream())
            .peek(this::enrichMetadata)
            .toList();
    }

    private void enrichMetadata(Document chunk) {
        Map<String, Object> metadata = chunk.getMetadata();
        metadata.put("chunkId", UUID.randomUUID().toString());
        metadata.put("createdAt", Instant.now().toString());
        metadata.put("tokenCount", estimateTokenCount(chunk.getContent()));
        metadata.put("version", "2026-Q2");
    }

    private int estimateTokenCount(String text) {
        return text.length() / 4;
    }
}

RAG检索服务

@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 query(String question) {
        // Step 1: 向量检索
        List<Document> relevantDocs = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(question)
                .topK(5)
                .similarityThreshold(0.7)
                .build()
        );

        // Step 2: 构造上下文
        String context = relevantDocs.stream()
            .map(doc -> """
                [来源: %s]
                %s
                """.formatted(
                    doc.getMetadata().get("source"),
                    doc.getContent()))
            .collect(Collectors.joining("\n---\n"));

        // Step 3: 注入上下文生成回答
        return chatClient.prompt()
            .system("""
                基于以下参考文档回答用户问题。
                如果文档中没有相关信息,请说明"根据现有文档无法回答"。
                回答时请标注引用来源。

                参考文档:
                {context}
                """)
            .user(question)
            .call()
            .content();
    }
}

RAG检索增强Advisor

@Component
public class RetrievalAugmentationAdvisor implements CallAdvisor {

    private final VectorStore vectorStore;
    private final QueryExpander queryExpander;

    @Override
    public AdvisedResponse adviseCall(AdvisedRequest request, Map<String, Object> context) {
        String query = request.userText();

        // 查询扩展(HyDE)
        List<String> expandedQueries = queryExpander.expand(query);

        // 多查询检索
        List<Document> allDocs = expandedQueries.stream()
            .flatMap(q -> vectorStore.similaritySearch(
                SearchRequest.builder()
                    .query(q)
                    .topK(3)
                    .build()
            ).stream())
            .toList();

        // 去重 + 重排
        List<Document> ranked = rerank(allDocs, query, 5);

        // 注入上下文
        String augmentedUserText = """
            参考文档:
            %s

            用户问题:%s
            """.formatted(formatDocuments(ranked), query);

        return new AdvisedResponse(
            request.mutate().userText(augmentedUserText).build(),
            context
        );
    }
}

RAG性能优化清单

优化项 方法 效果
分块大小 512-1024 tokens,overlap 64-128 平衡语义完整性与检索精度
查询扩展 HyDE + 同义词扩展 召回率提升15-30%
混合检索 向量 + BM25关键词,RRF融合 精确匹配+语义匹配互补
重排序 Cross-Encoder / Cohere Rerank Top5精度提升20%
元数据过滤 按部门/版本/日期过滤 减少无关文档干扰
缓存 相似查询缓存结果 重复查询延迟降低90%

Function Calling:让大模型调用Java方法

Function Calling是大模型与外部世界交互的桥梁——模型决定"何时调用",你定义"调用什么"。

Function Calling工作流程

┌──────────────────────────────────────────────────────────┐
│              Function Calling 工作流程                     │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  用户: "查询订单ORD-20260601的物流状态"                    │
│    │                                                     │
│    ▼                                                     │
│  ┌──────────┐                                            │
│  │ 大模型   │ → 分析意图 → 选择函数: queryLogistics       │
│  └──────────┘   参数: {orderId: "ORD-20260601"}          │
│    │                                                     │
│    ▼                                                     │
│  ┌──────────┐                                            │
│  │ Java方法 │ → 调用queryLogistics("ORD-20260601")       │
│  └──────────┘   返回: {status: "运输中", location: "..."} │
│    │                                                     │
│    ▼                                                     │
│  ┌──────────┐                                            │
│  │ 大模型   │ → 结合函数结果生成自然语言回答               │
│  └──────────┘                                            │
│    │                                                     │
│    ▼                                                     │
│  "订单ORD-20260601目前正在运输中,预计明天到达..."        │
│                                                          │
└──────────────────────────────────────────────────────────┘

订单查询Function

@Configuration
public class OrderFunctions {

    @Bean
    @Description("根据订单号查询订单详情,包括商品、金额、状态")
    public Function<OrderQuery, OrderInfo> queryOrder(OrderService orderService) {
        return query -> orderService.getOrderInfo(query.orderId());
    }

    @Bean
    @Description("根据订单号查询物流状态,包括当前位置和预计到达时间")
    public Function<LogisticsQuery, LogisticsInfo> queryLogistics(
            LogisticsService logisticsService) {
        return query -> logisticsService.getLogisticsInfo(query.orderId());
    }

    @Bean
    @Description("为订单发起退款申请,需要提供订单号和退款原因")
    public Function<RefundRequest, RefundResult> requestRefund(
            RefundService refundService) {
        return request -> refundService.processRefund(
            request.orderId(), request.reason());
    }

    public record OrderQuery(String orderId) {}
    public record LogisticsQuery(String orderId) {}
    public record RefundRequest(String orderId, String reason) {}

    public record OrderInfo(
        String orderId,
        String productName,
        BigDecimal amount,
        String status,
        LocalDateTime orderTime
    ) {}

    public record LogisticsInfo(
        String orderId,
        String status,
        String currentLocation,
        LocalDateTime estimatedArrival
    ) {}

    public record RefundResult(
        String refundId,
        String orderId,
        BigDecimal refundAmount,
        String status
    ) {}
}

Function Calling Controller

@RestController
@RequestMapping("/api/assistant")
public class AiAssistantController {

    private final ChatClient chatClient;

    public AiAssistantController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @PostMapping
    public String assist(@RequestBody AssistRequest request) {
        return chatClient.prompt()
            .system("""
                你是一个电商智能客服助手。你可以:
                1. 查询订单详情
                2. 查询物流状态
                3. 处理退款申请

                请根据用户问题选择合适的操作。
                回答要友好、专业,包含具体信息。
                """)
            .user(request.message())
            .functions("queryOrder", "queryLogistics", "requestRefund")
            .call()
            .content();
    }

    public record AssistRequest(String message) {}
}

实际对话示例

用户: "我的订单ORD-20260601到哪了?"

AI内部流程:
1. 意图识别 → 查询物流
2. 调用 queryLogistics({orderId: "ORD-20260601"})
3. 函数返回: {status: "运输中", currentLocation: "杭州转运中心", estimatedArrival: "2026-06-07"}
4. 生成回答:

AI: "您的订单ORD-20260601目前正在运输中,已到达杭州转运中心,预计2026年6月7日送达。"
用户: "这个订单我不想要了,帮我退款"

AI内部流程:
1. 意图识别 → 先查订单再退款
2. 调用 queryOrder({orderId: "ORD-20260601"})
3. 函数返回: {productName: "MacBook Pro", amount: 14999, status: "已发货"}
4. 调用 requestRefund({orderId: "ORD-20260601", reason: "用户不想要"})
5. 函数返回: {refundId: "REF-20260605", refundAmount: 14999, status: "处理中"}
6. 生成回答:

AI: "已为您提交退款申请。订单ORD-20260601(MacBook Pro,¥14,999)的退款正在处理中,
     退款编号REF-20260605。由于商品已发货,退款将在商品退回后3-5个工作日内到账。"

从Chat到Agent:构建Java版AI Agent

Chat是"你问我答",Agent是"你提目标,我自主完成"。

Agent核心循环

┌──────────────────────────────────────────────────────────┐
│                  AI Agent 核心循环                         │
│                                                          │
│   ┌──────────┐     ┌──────────┐     ┌──────────┐        │
│   │ Planner  │────→│ Executor │────→│Evaluator │        │
│   │ 规划器   │     │ 执行器   │     │ 评估器   │        │
│   └──────────┘     └──────────┘     └──────────┘        │
│        ▲                                   │             │
│        │           不满意                   │             │
│        └───────────────────────────────────┘             │
│                                                          │
│   Planner:  将目标分解为可执行的步骤列表                   │
│   Executor: 逐步执行,每步可调用工具(函数)                 │
│   Evaluator: 检查结果是否满足目标,决定是否重试             │
│                                                          │
│   终止条件: 评估通过 / 达到最大重试次数 / 用户确认         │
└──────────────────────────────────────────────────────────┘

Agent核心实现

@Service
public class AiAgentService {

    private final ChatClient chatClient;
    private final List<AgentTool> tools;

    public AiAgentService(ChatClient chatClient, List<AgentTool> tools) {
        this.chatClient = chatClient;
        this.tools = tools;
    }

    public AgentResult execute(String goal) {
        int maxIterations = 5;

        // Phase 1: Plan — 规划
        Plan plan = plan(goal);

        // Phase 2: Execute — 执行
        List<StepResult> results = new ArrayList<>();
        for (Step step : plan.steps()) {
            StepResult result = executeStep(step, results);
            results.add(result);
        }

        // Phase 3: Evaluate — 评估
        Evaluation evaluation = evaluate(goal, results);

        // 如果不满意,重新规划
        int iteration = 1;
        while (!evaluation.satisfied() && iteration < maxIterations) {
            plan = replan(goal, results, evaluation.feedback());
            results.clear();
            for (Step step : plan.steps()) {
                results.add(executeStep(step, results));
            }
            evaluation = evaluate(goal, results);
            iteration++;
        }

        return new AgentResult(results, evaluation, iteration);
    }

    private Plan plan(String goal) {
        String planJson = chatClient.prompt()
            .system("""
                你是一个任务规划器。将用户目标分解为可执行的步骤。
                每个步骤必须包含: action(动作), tool(使用的工具), params(参数)。

                可用工具: %s

                输出JSON格式的步骤列表。
                """.formatted(getToolDescriptions()))
            .user("目标: " + goal)
            .call()
            .content();

        return parsePlan(planJson);
    }

    private StepResult executeStep(Step step, List<StepResult> previousResults) {
        AgentTool tool = findTool(step.tool());
        Object result = tool.execute(step.params());
        return new StepResult(step, result, Instant.now());
    }

    private Evaluation evaluate(String goal, List<StepResult> results) {
        String evalJson = chatClient.prompt()
            .system("""
                评估执行结果是否满足目标。
                输出: { "satisfied": boolean, "score": 0-100, "feedback": "改进建议" }
                """)
            .user("""
                目标: %s

                执行结果:
                %s
                """.formatted(goal, formatResults(results)))
            .call()
            .content();

        return parseEvaluation(evalJson);
    }

    public record Plan(List<Step> steps) {}
    public record Step(String action, String tool, Map<String, Object> params) {}
    public record StepResult(Step step, Object result, Instant timestamp) {}
    public record Evaluation(boolean satisfied, int score, String feedback) {}
    public record AgentResult(List<StepResult> results, Evaluation evaluation, int iterations) {}
}

Agent工具注册

public interface AgentTool {
    String name();
    String description();
    Object execute(Map<String, Object> params);
}

@Component
public class DatabaseQueryTool implements AgentTool {

    private final JdbcTemplate jdbcTemplate;

    @Override
    public String name() { return "database_query"; }

    @Override
    public String description() { return "执行SQL查询数据库,仅支持SELECT语句"; }

    @Override
    public Object execute(Map<String, Object> params) {
        String sql = (String) params.get("sql");
        if (!sql.trim().toUpperCase().startsWith("SELECT")) {
            throw new SecurityException("Only SELECT queries are allowed");
        }
        return jdbcTemplate.queryForList(sql);
    }
}

@Component
public class HttpApiTool implements AgentTool {

    private final RestClient restClient;

    @Override
    public String name() { return "http_api"; }

    @Override
    public String description() { return "调用外部HTTP API获取数据"; }

    @Override
    public Object execute(Map<String, Object> params) {
        String url = (String) params.get("url");
        String method = (String) params.getOrDefault("method", "GET");
        return restClient.get().uri(url).retrieve().body(String.class);
    }
}

@Component
public class FileWriteTool implements AgentTool {

    @Override
    public String name() { return "file_write"; }

    @Override
    public String description() { return "将内容写入指定文件"; }

    @Override
    public Object execute(Map<String, Object> params) {
        String path = (String) params.get("path");
        String content = (String) params.get("content");
        try {
            Files.writeString(Path.of(path), content);
            return "File written successfully: " + path;
        } catch (IOException e) {
            return "Failed to write file: " + e.getMessage();
        }
    }
}

Agent执行示例

用户目标: "分析Q1销售数据,生成报告并发送给管理层"

Agent执行过程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Planner] 分解目标为3个步骤:
  Step 1: 查询Q1销售数据 (tool: database_query)
  Step 2: 分析数据生成报告 (tool: llm_analyze)
  Step 3: 发送邮件 (tool: email_send)

[Executor] Step 1: 执行SQL...
  SELECT product, SUM(amount) as total, COUNT(*) as orders
  FROM sales WHERE quarter='Q1' GROUP BY product
  → 返回12条产品销售数据

[Executor] Step 2: 分析数据...
  "Q1总销售额¥2,340万,同比增长23%。Top3: MacBook(¥580万)..."

[Executor] Step 3: 发送邮件...
  → 发送至 management@company.com,附件: Q1-Sales-Report.pdf

[Evaluator] 评估: satisfied=true, score=95
  "目标完成,数据准确,报告已发送"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

多模型路由与Fallback策略

生产环境不能把所有鸡蛋放在一个篮子里——GPT-4o挂了,通义千问顶上。

多模型路由架构

┌──────────────────────────────────────────────────────────────┐
│                   多模型路由架构                               │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  请求 ──→ ModelRouter ──→ ┌─────────┐                       │
│                           │ 路由策略 │                       │
│                           └────┬────┘                       │
│                 ┌──────────────┼──────────────┐             │
│                 ▼              ▼              ▼             │
│          ┌──────────┐  ┌──────────┐  ┌──────────┐         │
│          │  GPT-4o  │  │ 通义千问  │  │ DeepSeek │         │
│          │ (高质量) │  │ (国产)   │  │ (高性价比)│         │
│          └──────────┘  └──────────┘  └──────────┘         │
│                 │              │              │             │
│                 ▼              ▼              ▼             │
│          ┌─────────────────────────────────────────┐       │
│          │          Fallback Chain                  │       │
│          │  GPT-4o → 通义千问 → DeepSeek → 本地Ollama│     │
│          └─────────────────────────────────────────┘       │
│                                                              │
└──────────────────────────────────────────────────────────────┘

路由策略实现

@Service
public class ModelRouterService {

    private final Map<String, ChatModel> models;
    private final CircuitBreakerRegistry breakerRegistry;

    public ModelRouterService(
            @Qualifier("openai") ChatModel openai,
            @Qualifier("tongyi") ChatModel tongyi,
            @Qualifier("deepseek") ChatModel deepseek,
            @Qualifier("ollama") ChatModel ollama,
            CircuitBreakerRegistry breakerRegistry) {
        this.models = Map.of(
            "gpt-4o", openai,
            "qwen-max", tongyi,
            "deepseek-v3", deepseek,
            "llama3", ollama
        );
        this.breakerRegistry = breakerRegistry;
    }

    public String chat(String prompt, RoutingStrategy strategy) {
        List<String> modelChain = strategy.resolveChain(prompt);

        for (String modelName : modelChain) {
            try {
                CircuitBreaker breaker = breakerRegistry.circuitBreaker(modelName);
                ChatModel model = models.get(modelName);

                String result = breaker.executeSupplier(() ->
                    model.call(new Prompt(prompt))
                        .getResult()
                        .getOutput()
                        .getText()
                );

                log.info("Model {} succeeded for prompt: {}",
                    modelName, truncate(prompt, 50));
                return result;

            } catch (CallNotPermittedException e) {
                log.warn("Model {} circuit breaker open, trying next",
                    modelName);
            } catch (Exception e) {
                log.error("Model {} failed: {}", modelName, e.getMessage());
            }
        }

        throw new AllModelsFailedException("All models in chain failed");
    }
}

智能路由策略

@Component
public class SmartRoutingStrategy implements RoutingStrategy {

    @Override
    public List<String> resolveChain(String prompt) {
        Complexity complexity = analyzeComplexity(prompt);

        return switch (complexity) {
            case HIGH -> List.of("gpt-4o", "qwen-max", "deepseek-v3", "llama3");
            case MEDIUM -> List.of("qwen-max", "deepseek-v3", "gpt-4o");
            case LOW -> List.of("deepseek-v3", "qwen-max", "llama3");
        };
    }

    private Complexity analyzeComplexity(String prompt) {
        if (prompt.length() > 500 || containsCodeRequest(prompt)) {
            return Complexity.HIGH;
        } else if (prompt.length() > 100 || containsReasoning(prompt)) {
            return Complexity.MEDIUM;
        }
        return Complexity.LOW;
    }

    private boolean containsCodeRequest(String prompt) {
        return prompt.toLowerCase().contains("代码") ||
               prompt.toLowerCase().contains("code") ||
               prompt.toLowerCase().contains("实现");
    }

    private boolean containsReasoning(String prompt) {
        return prompt.toLowerCase().contains("分析") ||
               prompt.toLowerCase().contains("比较") ||
               prompt.toLowerCase().contains("为什么");
    }

    enum Complexity { HIGH, MEDIUM, LOW }
}

熔断器配置

resilience4j:
  circuitbreaker:
    instances:
      gpt-4o:
        failure-rate-threshold: 50
        slow-call-rate-threshold: 80
        slow-call-duration-threshold: 10s
        wait-duration-in-open-state: 30s
        sliding-window-size: 10
      qwen-max:
        failure-rate-threshold: 50
        slow-call-rate-threshold: 80
        slow-call-duration-threshold: 8s
        wait-duration-in-open-state: 20s
        sliding-window-size: 10
      deepseek-v3:
        failure-rate-threshold: 60
        slow-call-duration-threshold: 5s
        wait-duration-in-open-state: 15s
        sliding-window-size: 10

多模型成本对比

模型 输入价格(/1M tokens) 输出价格(/1M tokens) 质量 延迟 适用场景
GPT-4o $2.50 $10.00 ⭐⭐⭐⭐⭐ 1-3s 复杂推理、代码生成
通义千问-Max ¥8.00 ¥32.00 ⭐⭐⭐⭐ 0.5-2s 中文场景、合规
DeepSeek-V3 ¥1.00 ¥2.00 ⭐⭐⭐⭐ 0.3-1s 日常对话、高并发
Llama3(本地) 免费 免费 ⭐⭐⭐ 2-5s 隐私敏感、离线

生产级部署与性能调优

从Demo到Production,差距就在这些细节里。

Docker部署

FROM eclipse-temurin:21-jre-alpine

WORKDIR /app

COPY target/app.jar app.jar

ENV JAVA_OPTS="-XX:+UseZGC \
  -XX:+ZGenerational \
  -XX:MaxRAMPercentage=75.0 \
  -XX:+EnableVirtualThreads \
  -Dspring.profiles.active=prod"

EXPOSE 8080

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
# docker-compose.yml
services:
  app:
    build: .
    ports: ["8080:8080"]
    environment:
      OPENAI_API_KEY: ${OPENAI_API_KEY}
      SPRING_AI_OPENAI_BASE-URL: https://api.openai.com
    depends_on:
      redis: { condition: service_healthy }
      postgres: { condition: service_healthy }
    deploy:
      resources:
        limits: { memory: 1G, cpus: "2.0" }
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/actuator/health"]
      interval: 10s
      timeout: 5s
      retries: 3

  redis:
    image: redis:7-alpine
    ports: ["6379:6379"]
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]

  postgres:
    image: pgvector/pgvector:pg16
    ports: ["5432:5432"]
    environment:
      POSTGRES_DB: ai_vectors
      POSTGRES_PASSWORD: ${PG_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

限流配置

@Configuration
public class RateLimitConfig {

    @Bean
    public RateLimiter aiApiRateLimiter() {
        return RateLimiter.builder()
            .name("ai-api")
            .limitForPeriod(50)
            .limitRefreshPeriod(Duration.ofSeconds(1))
            .timeoutDuration(Duration.ofSeconds(5))
            .build();
    }
}

@RestController
@RequestMapping("/api/chat")
public class RateLimitedChatController {

    private final ChatClient chatClient;
    private final RateLimiter rateLimiter;

    @PostMapping
    @RateLimiter(name = "ai-api", fallbackMethod = "rateLimitFallback")
    public String chat(@RequestBody ChatRequest request) {
        return chatClient.prompt()
            .user(request.message())
            .call()
            .content();
    }

    public String rateLimitFallback(ChatRequest request, Exception e) {
        return "当前请求过多,请稍后再试。";
    }
}

请求超时与重试

@Configuration
public class AiRetryConfig {

    @Bean
    public Retry aiRetry() {
        return Retry.builder()
            .name("ai-retry")
            .maxAttempts(3)
            .waitDuration(Duration.ofMillis(500))
            .retryOnException(e ->
                e instanceof ApiCallException ||
                e instanceof SocketTimeoutException)
            .build();
    }
}

监控指标

@Component
public class AiMetrics {

    private final MeterRegistry registry;

    public AiMetrics(MeterRegistry registry) {
        this.registry = registry;
    }

    public void recordApiCall(String model, boolean success, long latencyMs) {
        registry.counter("ai.api.calls",
            "model", model,
            "status", success ? "success" : "failure"
        ).increment();

        registry.timer("ai.api.latency",
            "model", model
        ).record(latencyMs, TimeUnit.MILLISECONDS);
    }

    public void recordTokenUsage(String model, int promptTokens, int completionTokens) {
        registry.counter("ai.tokens.prompt", "model", model)
            .increment(promptTokens);
        registry.counter("ai.tokens.completion", "model", model)
            .increment(completionTokens);
    }

    public void recordFunctionCall(String functionName, boolean success) {
        registry.counter("ai.function.calls",
            "function", functionName,
            "status", success ? "success" : "failure"
        ).increment();
    }
}

生产级性能清单

类别 检查项 目标 工具
延迟 P95 API响应时间 < 3s Actuator + Grafana
延迟 流式首Token时间 < 500ms 自定义Metrics
吞吐 并发请求处理能力 > 100 QPS JMeter/k6
可靠性 熔断器触发率 < 5% Resilience4j
可靠性 Fallback成功率 > 99% 自定义Metrics
成本 日均Token消耗 < 预算 Token计数器
成本 模型路由命中率 高复杂→GPT-4o >80% 路由Metrics
安全 API Key轮换 90天一次 Vault/KMS
安全 敏感信息过滤 100%拦截 输入/输出Guard
运维 滚动部署零中断 0 error K8s ReadinessProbe
运维 配置热更新 无需重启 Spring Cloud Config

总结与架构全景图

全景架构

┌──────────────────────────────────────────────────────────────────┐
│                  Spring Boot 3 + AI 全景架构                     │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌────────────────────────────────────────────────────────┐     │
│  │                    API Gateway / 负载均衡               │     │
│  └──────────────────────┬─────────────────────────────────┘     │
│                         │                                       │
│  ┌──────────────────────▼─────────────────────────────────┐     │
│  │              Spring Boot 3 Application                  │     │
│  │                                                        │     │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐            │     │
│  │  │ Chat     │  │ RAG      │  │ Agent    │            │     │
│  │  │ Controller│  │ Service  │  │ Service  │            │     │
│  │  └────┬─────┘  └────┬─────┘  └────┬─────┘            │     │
│  │       │             │             │                    │     │
│  │  ┌────▼─────────────▼─────────────▼─────┐            │     │
│  │  │         ChatClient (Spring AI)       │            │     │
│  │  │  ┌─────────────────────────────┐    │            │     │
│  │  │  │      Advisor Chain          │    │            │     │
│  │  │  │  Memory → RAG → Function   │    │            │     │
│  │  │  │  → Guard → Logging         │    │            │     │
│  │  │  └─────────────────────────────┘    │            │     │
│  │  └──────────────┬──────────────────────┘            │     │
│  │                  │                                    │     │
│  │  ┌──────────────▼──────────────────────┐            │     │
│  │  │         ModelRouter                 │            │     │
│  │  │  GPT-4o │ 通义千问 │ DeepSeek │ Ollama│         │     │
│  │  └─────────────────────────────────────┘            │     │
│  └──────────────────────────────────────────────────────┘     │
│                         │                                       │
│  ┌──────────────────────▼─────────────────────────────────┐     │
│  │              基础设施层                                │     │
│  │  Redis(记忆) │ PGVector(向量) │ MySQL(业务) │ K8s    │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

核心要点回顾

  1. Java是AI应用的最佳生产载体 — 并发、安全、运维三位一体,Python训练用,Java应用用
  2. Spring AI是2026年首选框架 — Spring官方出品,声明式配置,零学习成本
  3. 多轮对话必须有持久化记忆 — Redis ChatMemory,窗口/摘要/混合策略按场景选
  4. RAG是企业AI的基石 — ETL Pipeline + 向量检索 + 上下文注入,缺一不可
  5. Function Calling连接模型与世界 — 模型决策何时调用,你定义调用什么
  6. Agent = Planner + Executor + Evaluator — 从被动响应到主动执行
  7. 多模型路由是生产标配 — GPT-4o + 通义千问 + DeepSeek,Fallback链保可用性
  8. 生产级部署不能省 — Docker + 熔断 + 限流 + 监控,一个都不能少

Spring Boot 3 + AI大模型,不是"Java追赶AI",而是"AI终于找到了最可靠的生产运行时"。2026年,Java开发者的AI时代,已经到来。

本站提供浏览器本地工具,免注册即可试用 →

#Spring Boot#Spring AI#LangChain4j#AI大模型#RAG#Function Calling#Java Agent