Spring AI 框架实战:Java 后端集成大模型的架构设计与工程落地

1. 引言:为什么选择 Spring AI?

在人工智能浪潮席卷全球的今天,大语言模型(LLM)已成为企业数字化转型的核心驱动力。然而,对于 Java 后端开发者而言,如何将大模型能力无缝集成到现有系统中,面临着诸多挑战:API 调用复杂、模型切换困难、提示工程繁琐、成本控制不易等。

Spring AI 应运而生------这是 Spring 官方推出的 AI 集成框架,旨在为 Java 开发者提供统一、声明式的 AI 应用开发体验。它基于 Spring 生态的成熟设计理念,将大模型能力抽象为可插拔的组件,让开发者能够像使用数据库、消息队列一样轻松集成 AI 能力。

本文将深入探讨 Spring AI 的架构设计、核心组件、工程实践,并通过完整案例展示如何在企业级 Java 后端系统中落地大模型集成。

2. Spring AI 核心架构解析

2.1 分层架构设计

Spring AI 采用经典的分层架构,从上到下分为:

  1. 应用层:业务逻辑与 AI 能力的结合点
  2. 服务层AiClient 接口与具体实现
  3. 适配层:模型提供商适配器(OpenAI、Azure、Anthropic 等)
  4. 传输层:HTTP/REST 或 SDK 调用

#mermaid-svg-Pi2yvJcVA9nYjPBx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Pi2yvJcVA9nYjPBx .error-icon{fill:#552222;}#mermaid-svg-Pi2yvJcVA9nYjPBx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Pi2yvJcVA9nYjPBx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .marker.cross{stroke:#333333;}#mermaid-svg-Pi2yvJcVA9nYjPBx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Pi2yvJcVA9nYjPBx p{margin:0;}#mermaid-svg-Pi2yvJcVA9nYjPBx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .cluster-label text{fill:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .cluster-label span{color:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .cluster-label span p{background-color:transparent;}#mermaid-svg-Pi2yvJcVA9nYjPBx .label text,#mermaid-svg-Pi2yvJcVA9nYjPBx span{fill:#333;color:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .node rect,#mermaid-svg-Pi2yvJcVA9nYjPBx .node circle,#mermaid-svg-Pi2yvJcVA9nYjPBx .node ellipse,#mermaid-svg-Pi2yvJcVA9nYjPBx .node polygon,#mermaid-svg-Pi2yvJcVA9nYjPBx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .rough-node .label text,#mermaid-svg-Pi2yvJcVA9nYjPBx .node .label text,#mermaid-svg-Pi2yvJcVA9nYjPBx .image-shape .label,#mermaid-svg-Pi2yvJcVA9nYjPBx .icon-shape .label{text-anchor:middle;}#mermaid-svg-Pi2yvJcVA9nYjPBx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .rough-node .label,#mermaid-svg-Pi2yvJcVA9nYjPBx .node .label,#mermaid-svg-Pi2yvJcVA9nYjPBx .image-shape .label,#mermaid-svg-Pi2yvJcVA9nYjPBx .icon-shape .label{text-align:center;}#mermaid-svg-Pi2yvJcVA9nYjPBx .node.clickable{cursor:pointer;}#mermaid-svg-Pi2yvJcVA9nYjPBx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .arrowheadPath{fill:#333333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Pi2yvJcVA9nYjPBx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Pi2yvJcVA9nYjPBx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Pi2yvJcVA9nYjPBx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Pi2yvJcVA9nYjPBx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .cluster text{fill:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx .cluster span{color:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Pi2yvJcVA9nYjPBx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Pi2yvJcVA9nYjPBx rect.text{fill:none;stroke-width:0;}#mermaid-svg-Pi2yvJcVA9nYjPBx .icon-shape,#mermaid-svg-Pi2yvJcVA9nYjPBx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Pi2yvJcVA9nYjPBx .icon-shape p,#mermaid-svg-Pi2yvJcVA9nYjPBx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Pi2yvJcVA9nYjPBx .icon-shape .label rect,#mermaid-svg-Pi2yvJcVA9nYjPBx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Pi2yvJcVA9nYjPBx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Pi2yvJcVA9nYjPBx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Pi2yvJcVA9nYjPBx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 传输层
HTTP/REST
WebSocket
gRPC
适配层
OpenAI Adapter
Azure AI Adapter
Anthropic Adapter
Local Model Adapter
服务层
AiClient Interface
ChatClient
EmbeddingClient
应用层
Controller
Service
Prompt Templates

2.2 核心组件详解

2.2.1 AiClient 接口

AiClient 是 Spring AI 的核心抽象,定义了统一的 AI 操作接口:

java 复制代码
public interface AiClient {
    String generate(String prompt);
    AiResponse generate(AiRequest request);
    // 流式响应支持
    Flux<String> stream(String prompt);
}
2.2.2 Prompt 模板引擎

Spring AI 内置强大的提示模板引擎,支持变量替换、条件逻辑和函数调用:

java 复制代码
@Bean
public PromptTemplate promptTemplate() {
    return new PromptTemplate("""
        你是一个专业的{role}助手。
        请根据以下上下文回答问题:
        上下文:{context}
        问题:{question}
        要求:{requirement}
        """);
}
2.2.3 向量存储集成

Spring AI 与主流向量数据库(Redis、PgVector、Milvus 等)深度集成:

java 复制代码
@Bean
public VectorStore vectorStore(EmbeddingClient embeddingClient) {
    return new RedisVectorStore(embeddingClient);
}

3. 环境搭建与项目初始化

3.1 依赖配置

xml 复制代码
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

3.2 配置文件

yaml 复制代码
# application.yml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4-turbo
          temperature: 0.7
          max-tokens: 2000
    
    vectorstore:
      pgvector:
        enabled: true
        host: localhost
        port: 5432
        database: ai_db
        username: postgres
        password: ${DB_PASSWORD}

3.3 基础配置类

java 复制代码
@Configuration
@EnableAiClients
public class AiConfig {
    
    @Bean
    public ChatClient chatClient(OpenAiChatClient openAiClient) {
        return openAiClient;
    }
    
    @Bean
    public EmbeddingClient embeddingClient(OpenAiEmbeddingClient openAiEmbeddingClient) {
        return openAiEmbeddingClient;
    }
    
    @Bean
    public PromptTemplate systemPromptTemplate() {
        return new PromptTemplate("""
            系统角色:{systemRole}
            当前任务:{task}
            用户输入:{userInput}
            请按照以下格式回复:
            {format}
            """);
    }
}

4. 核心功能实现

4.1 智能问答系统

java 复制代码
@Service
@Slf4j
public class QaService {
    
    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    private final PromptTemplate qaPromptTemplate;
    
    public QaService(ChatClient chatClient, 
                    VectorStore vectorStore,
                    @Qualifier("qaPromptTemplate") PromptTemplate qaPromptTemplate) {
        this.chatClient = chatClient;
        this.vectorStore = vectorStore;
        this.qaPromptTemplate = qaPromptTemplate;
    }
    
    public AiResponse answerQuestion(String question, String context) {
        // 1. 构建提示词
        Map<String, Object> promptVariables = Map.of(
            "question", question,
            "context", context,
            "currentTime", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        );
        
        Prompt prompt = qaPromptTemplate.create(promptVariables);
        
        // 2. 调用 AI 服务
        AiResponse response = chatClient.call(prompt);
        
        // 3. 记录日志
        log.info("QA request - Question: {}, Context length: {}, Response tokens: {}", 
                question, context.length(), response.getGeneration().getText().length());
        
        return response;
    }
    
    public Flux<String> streamAnswer(String question) {
        return chatClient.stream(question)
            .doOnNext(chunk -> log.debug("Received chunk: {}", chunk))
            .doOnError(error -> log.error("Stream error: ", error))
            .doOnComplete(() -> log.info("Stream completed"));
    }
}

4.2 文档智能处理

java 复制代码
@Service
public class DocumentService {
    
    private final EmbeddingClient embeddingClient;
    private final VectorStore vectorStore;
    
    public void processDocument(MultipartFile file) {
        try {
            // 1. 提取文本内容
            String content = extractText(file);
            
            // 2. 分块处理
            List<TextChunk> chunks = chunkText(content, 1000);
            
            // 3. 生成向量
            List<Embedding> embeddings = embeddingClient.embed(chunks.stream()
                .map(TextChunk::getText)
                .collect(Collectors.toList()));
            
            // 4. 存储到向量数据库
            List<Document> documents = new ArrayList<>();
            for (int i = 0; i < chunks.size(); i++) {
                Document doc = new Document(
                    chunks.get(i).getText(),
                    Map.of(
                        "filename", file.getOriginalFilename(),
                        "chunkIndex", i,
                        "timestamp", System.currentTimeMillis()
                    )
                );
                doc.setEmbedding(embeddings.get(i));
                documents.add(doc);
            }
            
            vectorStore.add(documents);
            
        } catch (IOException e) {
            throw new RuntimeException("文档处理失败", e);
        }
    }
    
    public List<Document> searchSimilar(String query, int topK) {
        // 生成查询向量
        Embedding queryEmbedding = embeddingClient.embed(query);
        
        // 相似度搜索
        return vectorStore.similaritySearch(
            SimilaritySearchRequest.builder()
                .queryEmbedding(queryEmbedding)
                .topK(topK)
                .build()
        );
    }
}

4.3 函数调用与工具集成

java 复制代码
@Service
public class FunctionCallingService {
    
    @AiFunction(name = "getWeather", description = "获取指定城市的天气信息")
    public String getWeather(@AiParam("city") String city) {
        // 调用外部天气 API
        return weatherApiClient.getWeather(city);
    }
    
    @AiFunction(name = "calculate", description = "执行数学计算")
    public String calculate(
            @AiParam("expression") String expression,
            @AiParam("precision") int precision) {
        try {
            double result = evaluateExpression(expression);
            return String.format("%." + precision + "f", result);
        } catch (Exception e) {
            return "计算失败: " + e.getMessage();
        }
    }
    
    public AiResponse callWithFunctions(String userInput) {
        List<FunctionCallback> callbacks = List.of(
            FunctionCallbackWrapper.builder(new WeatherFunction())
                .withName("getWeather")
                .withDescription("获取天气信息")
                .withResponseConverter((response) -> response.toString())
                .build(),
            FunctionCallbackWrapper.builder(new CalculatorFunction())
                .withName("calculate")
                .withDescription("执行计算")
                .build()
        );
        
        return chatClient.call(
            new Prompt(userInput),
            ChatOptions.builder()
                .withFunctionCallbacks(callbacks)
                .build()
        );
    }
}

5. 企业级架构设计

5.1 微服务架构下的 AI 集成

#mermaid-svg-4GObQHNh8sl1Sb6e{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4GObQHNh8sl1Sb6e .error-icon{fill:#552222;}#mermaid-svg-4GObQHNh8sl1Sb6e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4GObQHNh8sl1Sb6e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4GObQHNh8sl1Sb6e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4GObQHNh8sl1Sb6e .marker.cross{stroke:#333333;}#mermaid-svg-4GObQHNh8sl1Sb6e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4GObQHNh8sl1Sb6e p{margin:0;}#mermaid-svg-4GObQHNh8sl1Sb6e .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e .cluster-label text{fill:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e .cluster-label span{color:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e .cluster-label span p{background-color:transparent;}#mermaid-svg-4GObQHNh8sl1Sb6e .label text,#mermaid-svg-4GObQHNh8sl1Sb6e span{fill:#333;color:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e .node rect,#mermaid-svg-4GObQHNh8sl1Sb6e .node circle,#mermaid-svg-4GObQHNh8sl1Sb6e .node ellipse,#mermaid-svg-4GObQHNh8sl1Sb6e .node polygon,#mermaid-svg-4GObQHNh8sl1Sb6e .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4GObQHNh8sl1Sb6e .rough-node .label text,#mermaid-svg-4GObQHNh8sl1Sb6e .node .label text,#mermaid-svg-4GObQHNh8sl1Sb6e .image-shape .label,#mermaid-svg-4GObQHNh8sl1Sb6e .icon-shape .label{text-anchor:middle;}#mermaid-svg-4GObQHNh8sl1Sb6e .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4GObQHNh8sl1Sb6e .rough-node .label,#mermaid-svg-4GObQHNh8sl1Sb6e .node .label,#mermaid-svg-4GObQHNh8sl1Sb6e .image-shape .label,#mermaid-svg-4GObQHNh8sl1Sb6e .icon-shape .label{text-align:center;}#mermaid-svg-4GObQHNh8sl1Sb6e .node.clickable{cursor:pointer;}#mermaid-svg-4GObQHNh8sl1Sb6e .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4GObQHNh8sl1Sb6e .arrowheadPath{fill:#333333;}#mermaid-svg-4GObQHNh8sl1Sb6e .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4GObQHNh8sl1Sb6e .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4GObQHNh8sl1Sb6e .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4GObQHNh8sl1Sb6e .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4GObQHNh8sl1Sb6e .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4GObQHNh8sl1Sb6e .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4GObQHNh8sl1Sb6e .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4GObQHNh8sl1Sb6e .cluster text{fill:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e .cluster span{color:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4GObQHNh8sl1Sb6e .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4GObQHNh8sl1Sb6e rect.text{fill:none;stroke-width:0;}#mermaid-svg-4GObQHNh8sl1Sb6e .icon-shape,#mermaid-svg-4GObQHNh8sl1Sb6e .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4GObQHNh8sl1Sb6e .icon-shape p,#mermaid-svg-4GObQHNh8sl1Sb6e .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4GObQHNh8sl1Sb6e .icon-shape .label rect,#mermaid-svg-4GObQHNh8sl1Sb6e .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4GObQHNh8sl1Sb6e .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4GObQHNh8sl1Sb6e .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4GObQHNh8sl1Sb6e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 模型服务层
数据服务层
AI 核心服务
AI 网关服务
API Gateway
负载均衡
限流熔断
Prompt 管理服务
模型路由服务
向量检索服务
缓存服务
向量数据库
关系数据库
缓存集群
OpenAI
Azure AI
本地模型
备用模型

5.2 配置中心与动态切换

java 复制代码
@Configuration
@RefreshScope
public class DynamicAiConfig {
    
    @Value("${spring.ai.provider:openai}")
    private String aiProvider;
    
    @Bean
    @Primary
    public ChatClient chatClient(
            OpenAiChatClient openAiClient,
            AzureOpenAiChatClient azureClient,
            AnthropicChatClient anthropicClient) {
        
        return switch (aiProvider.toLowerCase()) {
            case "azure" -> azureClient;
            case "anthropic" -> anthropicClient;
            case "openai", default -> openAiClient;
        };
    }
    
    @Bean
    public ModelRouter modelRouter() {
        return new ModelRouter(Map.of(
            "gpt-4", openAiChatClient,
            "claude-3", anthropicChatClient,
            "llama-3", localModelClient
        ));
    }
}

5.3 监控与可观测性

java 复制代码
@Configuration
public class MonitoringConfig {
    
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> aiMetrics() {
        return registry -> {
            Timer.builder("ai.request.duration")
                .description("AI 请求耗时")
                .tag("provider", "openai")
                .register(registry);
            
            Counter.builder("ai.request.total")
                .description("AI 请求总数")
                .tag("status", "success")
                .register(registry);
        };
    }
    
    @Bean
    public AiClientInterceptor metricsInterceptor(MeterRegistry meterRegistry) {
        return new AiClientInterceptor() {
            @Override
            public AiResponse intercept(AiRequest request, AiClientExecution execution) {
                Timer.Sample sample = Timer.start(meterRegistry);
                try {
                    AiResponse response = execution.execute(request);
                    sample.stop(Timer.builder("ai.request.duration")
                        .tag("status", "success")
                        .register(meterRegistry));
                    meterRegistry.counter("ai.request.total", 
                        "status", "success").increment();
                    return response;
                } catch (Exception e) {
                    sample.stop(Timer.builder("ai.request.duration")
                        .tag("status", "error")
                        .register(meterRegistry));
                    meterRegistry.counter("ai.request.total", 
                        "status", "error").increment();
                    throw e;
                }
            }
        };
    }
}

6. 性能优化与最佳实践

6.1 缓存策略

java 复制代码
@Service
@CacheConfig(cacheNames = "aiResponses")
public class CachedAiService {
    
    private final ChatClient chatClient;
    
    @Cacheable(key = "#prompt + '|' + #options.hashCode()", 
               unless = "#result == null")
    public AiResponse getCachedResponse(String prompt, ChatOptions options) {
        return chatClient.call(new Prompt(prompt, options));
    }
    
    @CacheEvict(allEntries = true)
    public void clearCache() {
        // 清理所有缓存
    }
    
    @Scheduled(fixedRate = 3600000) // 每小时清理一次
    public void scheduledCacheEviction() {
        clearCache();
    }
}

6.2 批量处理与并发控制

java 复制代码
@Service
public class BatchAiService {
    
    private final ChatClient chatClient;
    private final ExecutorService executorService;
    
    @Async("aiTaskExecutor")
    public CompletableFuture<List<AiResponse>> batchProcess(
            List<String> prompts, 
            int batchSize) {
        
        List<CompletableFuture<AiResponse>> futures = new ArrayList<>();
        
        // 分批处理
        for (int i = 0; i < prompts.size(); i += batchSize) {
            int end = Math.min(i + batchSize, prompts.size());
            List<String> batch = prompts.subList(i, end);
            
            CompletableFuture<AiResponse> future = CompletableFuture.supplyAsync(() -> {
                // 合并提示词
                String combinedPrompt = String.join("\n---\n", batch);
                return chatClient.call(combinedPrompt);
            }, executorService);
            
            futures.add(future);
        }
        
        // 等待所有任务完成
        return CompletableFuture.allOf(
            futures.toArray(new CompletableFuture[0])
        ).thenApply(v -> futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toList()));
    }
}

6.3 错误处理与重试机制

java 复制代码
@Configuration
public class RetryConfig {
    
    @Bean
    public RetryTemplate aiRetryTemplate() {
        return RetryTemplate.builder()
            .maxAttempts(3)
            .exponentialBackoff(1000, 2, 10000)
            .retryOn(OpenAiHttpException.class)
            .retryOn(SocketTimeoutException.class)
            .notRetryOn(IllegalArgumentException.class)
            .withListener(new RetryListener() {
                @Override
                public <T, E extends Throwable> void onError(
                        RetryContext context, 
                        RetryCallback<T, E> callback, 
                        Throwable throwable) {
                    log.warn("AI 调用失败,重试次数: {}", context.getRetryCount(), throwable);
                }
            })
            .build();
    }
    
    @Bean
    public CircuitBreakerFactory aiCircuitBreakerFactory() {
        return new Resilience4JCircuitBreakerFactory();
    }
}

7. 安全与合规考虑

7.1 敏感信息过滤

java 复制代码
@Component
public class SecurityFilter implements AiClientInterceptor {
    
    private final SensitiveDataFilter sensitiveDataFilter;
    
    @Override
    public AiResponse intercept(AiRequest request, AiClientExecution execution) {
        // 1. 过滤敏感信息
        String filteredPrompt = sensitiveDataFilter.filter(request.getPrompt());
        
        // 2. 记录审计日志
        auditLogger.logRequest(filteredPrompt, request.getOptions());
        
        // 3. 执行请求
        AiRequest filteredRequest = new AiRequest(filteredPrompt, request.getOptions());
        AiResponse response = execution.execute(filteredRequest);
        
        // 4. 过滤响应中的敏感信息
        String filteredResponse = sensitiveDataFilter.filter(response.getGeneration().getText());
        
        return new AiResponse(filteredResponse, response.getMetadata());
    }
}

7.2 访问控制与权限管理

java 复制代码
@RestController
@RequestMapping("/api/ai")
@PreAuthorize("hasRole('AI_USER')")
public class AiController {
    
    @PostMapping("/chat")
    @RateLimit(limit = 10, duration = 60) // 每分钟10次
    @CostLimit(maxCost = 10.0) // 单次调用成本限制
    public ResponseEntity<AiResponse> chat(
            @RequestBody ChatRequest request,
            @AuthenticationPrincipal User user) {
        
        // 检查用户权限
        if (!user.hasPermission("ai.chat")) {
            throw new AccessDeniedException("无权限访问AI聊天功能");
        }
        
        // 检查额度
        if (!quotaService.hasEnoughQuota(user.getId(), request.estimatedCost())) {
            throw new QuotaExceededException("额度不足");
        }
        
        AiResponse response = chatService.chat(request);
        
        // 扣减额度
        quotaService.deductQuota(user.getId(), response.actualCost());
        
        return ResponseEntity.ok(response);
    }
}
相关推荐
墨舟的AI笔记1 小时前
权威服务器下的反作弊:从输入校验到状态可重放审计
人工智能
芝士熊爱编程1 小时前
创建型模式-单例模式
java·单例模式·设计模式
JoyCong19981 小时前
手机变身“司令台”!ToDesk AI安卓版上线
网络·人工智能·科技·智能手机·电脑·远程工作·远程操作
HIT_Weston1 小时前
153、【Agent】【OpenCode】启动分析(completion)
人工智能·agent·opencode
哔哩哔哩技术1 小时前
CVPR 2026 Highlight 丨 用“几何感知”把扩散 Transformer 采样做成免训练加速器
人工智能
byte轻骑兵1 小时前
【AVDTP】规范精讲[6]: 打通全流程,蓝牙音频连接背后的12步信令博弈
人工智能·音视频·avrcp·蓝牙耳机·蓝牙车机
LCG米1 小时前
AI Agent 工具调用失效排查实战:从 Function Calling 幻觉到死循环的 12 类生产故障深度复盘
人工智能
@insist1231 小时前
信息系统管理工程师-数字化转型成熟度模型核心考点解析
大数据·人工智能·软考·软件水平考试·信息系统管理工程师·软考信管
海兰1 小时前
【高速缓存】RedisVL 高级查询(全文搜索、混合搜索和 多向量搜索)
数据库·人工智能·redis·缓存