前言

Spring AI让Java接入大模型变得简单,但简单不等于没有坑。本文从实际生产经验出发,总结五个最容易犯的错误,帮助大家避坑。

错误一:API Key写在配置文件里

错误做法

# ❌ 危险!API Key直接写在配置里
spring:
  ai:
    openai:
      api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxx

正确做法

# ✅ 使用环境变量
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: ${OPENAI_BASE_URL}

进阶方案:集成Spring Cloud Vault或AWS Secrets Manager,实现密钥的动态管理。

错误二:超时时间设置不当

问题:默认30秒超时,对于大模型远远不够。

正确配置

超时类型 推荐值 说明
connect-timeout 10秒 建立TCP连接
read-timeout 120秒 等待完整响应
流式模式 300秒 流式响应持续输出
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      timeout: 120s

错误三:流式响应没有背压控制

问题:模型输出速度 > 消费速度 → 内存溢出

正确做法

// ✅ 实现背压控制
return chatClient.prompt()
    .user(message)
    .stream()
    .content()
    .onBackpressureBuffer(100)  // 限制缓冲区大小
    .onBackpressureDrop(drop -> {
        log.warn("缓冲区溢出,丢弃数据");
    });

错误四:异常处理过于简单

错误做法

// ❌ 一个catch走天下
try {
    response = chatClient.call(prompt);
} catch (Exception e) {
    return "出错了";
}

正确做法

// ✅ 区分异常类型
try {
    response = chatClient.call(prompt);
} catch (ApiException e) {
    // API Key无效、额度耗尽 → 切换备用Key
    return fallbackToBackupKey(prompt);
} catch (TimeoutException e) {
    // 超时 → 指数退避重试
    return retryWithBackoff(prompt, 3);
} catch (RateLimitException e) {
    // 限流 → 等待后重试
    sleep(e.getRetryAfter());
    return retry(prompt);
}

错误五:Token消耗无监控

问题:一个简单请求可能因为返回过长,产生高额费用。

解决方案

  1. 设置max_tokens上限
@Bean
public ChatModel chatModel() {
    return OpenAiChatModel.builder()
        .apiKey(apiKey)
        .defaultOptions(
            ChatOptionsBuilder.builder()
                .withMaxTokens(2000)  // 限制单次响应长度
                .build()
        )
        .build();
}
  1. 实现消耗监控
@Component
public class TokenMonitor {
    
    @Autowired
    private ChatClient chatClient;
    
    public String chat(String prompt) {
        long startTime = System.currentTimeMillis();
        int inputTokens = countTokens(prompt);
        
        String response = chatClient.prompt()
            .user(prompt)
            .call()
            .content();
        
        int outputTokens = countTokens(response);
        long cost = calculateCost(inputTokens, outputTokens);
        
        // 记录到监控
        metrics.record("token.input", inputTokens);
        metrics.record("token.output", outputTokens);
        metrics.record("cost.total", cost);
        
        return response;
    }
}

错误六:同步调用大模型

错误做法

// ❌ 同步阻塞,前端等待30秒
@GetMapping("/chat")
public String chat(String message) {
    return chatClient.prompt()
        .user(message)
        .call()
        .content();
}

正确做法

// ✅ 异步化架构
@GetMapping("/chat")
public String chat(String message) {
    String taskId = taskService.submit(message);
    return "{\"taskId\": \"" + taskId + "\"}";
}

@GetMapping("/chat/result/{taskId}")
public SseEmitter result(@PathVariable String taskId) {
    SseEmitter emitter = new SseEmitter();
    taskService.subscribe(taskId, result -> {
        emitter.send(result);
        emitter.complete();
    });
    return emitter;
}

企业级建议

在实际生产环境中,建议通过API聚合平台(如weelinking等)统一管理多个模型供应商的接入,这类平台通常提供完善的限流策略、熔断机制和费用监控功能,能够有效降低AI集成的运维复杂度。

总结

错误 后果 解决方案
API Key硬编码 安全风险 环境变量/密钥管理服务
超时设置过短 请求失败 根据业务设置合理超时
无背压控制 内存溢出 实现背压策略
异常处理简单 无法定位问题 细分异常类型处理
Token无监控 费用失控 设置上限+监控告警
同步调用 用户体验差 异步化+SSE推送

#SpringAI #Java #避坑指南 #生产环境 #AI集成


📖 推荐阅读

如果这篇对你有帮助,以下文章你也会喜欢:

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐