1. LangChain4j与SpringBoot集成概述

在当今AI技术快速发展的背景下,如何高效地将大模型能力集成到Java应用中成为了开发者关注的重点。LangChain4j作为Java生态中的AI集成框架,为开发者提供了统一、便捷的API来对接多种大模型服务。

我最初接触LangChain4j是在一个需要同时调用OpenAI和DeepSeek的项目中。当时面临的最大痛点就是不同模型的API差异导致代码难以维护。LangChain4j的标准化接口完美解决了这个问题,让我可以在不修改业务逻辑的情况下自由切换模型。

SpringBoot作为Java领域最流行的微服务框架,与LangChain4j的结合堪称完美。这种组合特别适合以下场景:

  • 需要快速构建AI功能的企业应用
  • 要求支持多模型动态切换的智能系统
  • 希望保持代码简洁性的中小型项目

2. 环境准备与基础配置

2.1 创建SpringBoot项目

首先使用Spring Initializr创建一个基础项目。我推荐使用IDEA的向导功能,勾选以下依赖:

  • Spring Web
  • Lombok(简化代码)
  • Spring Boot DevTools(开发热加载)
<!-- pom.xml基础配置 -->
<properties>
    <java.version>17</java.version>
    <langchain4j.version>1.0.0-beta3</langchain4j.version>
</properties>

2.2 添加LangChain4j依赖

根据项目需求选择具体模块。对于OpenAI和DeepSeek集成,需要添加以下依赖:

<dependencies>
    <!-- LangChain4j核心库 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
    
    <!-- OpenAI兼容接口 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
</dependencies>

2.3 配置API密钥管理

安全地管理API密钥是生产环境的基本要求。我推荐采用环境变量方式:

// 在application.properties中配置
openai.api-key=${OPENAI_API_KEY}
deepseek.api-key=${DEEPSEEK_API_KEY}

// 或者使用Spring的@ConfigurationProperties
@ConfigurationProperties(prefix = "ai")
@Data
public class AiConfig {
    private String openaiKey;
    private String deepseekKey;
}

3. 多模型动态切换实现

3.1 基础模型配置类

创建配置类来初始化不同模型实例。这里演示OpenAI和DeepSeek的配置:

@Configuration
public class ModelConfig {
    
    @Bean
    @Primary
    public ChatModel openAiChatModel(AiConfig aiConfig) {
        return OpenAiChatModel.builder()
                .apiKey(aiConfig.getOpenaiKey())
                .modelName("gpt-4")
                .temperature(0.7)
                .build();
    }
    
    @Bean
    public ChatModel deepSeekChatModel(AiConfig aiConfig) {
        return OpenAiChatModel.builder()
                .apiKey(aiConfig.getDeepseekKey())
                .baseUrl("https://api.deepseek.com/v1")
                .modelName("deepseek-chat")
                .build();
    }
}

3.2 动态路由策略

实现模型动态切换的核心是创建路由策略。这里分享我项目中验证过的两种方案:

方案一:基于注解的切换

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ModelRoute {
    String value() default "openai";
}

@Aspect
@Component
public class ModelRoutingAspect {
    @Autowired
    private Map<String, ChatModel> modelMap;
    
    @Around("@annotation(modelRoute)")
    public Object routeModel(ProceedingJoinPoint joinPoint, ModelRoute modelRoute) {
        ChatModelContext.setCurrentModel(modelRoute.value());
        try {
            return joinPoint.proceed();
        } finally {
            ChatModelContext.clear();
        }
    }
}

方案二:请求参数动态切换

@RestController
@RequestMapping("/api/chat")
public class ChatController {
    
    @Autowired
    private ModelRouter modelRouter;
    
    @PostMapping
    public String chat(@RequestParam String modelType, 
                      @RequestBody String prompt) {
        ChatModel model = modelRouter.getModel(modelType);
        return model.generate(prompt);
    }
}

3.3 模型性能监控

在生产环境中,监控各模型的响应时间和成功率很有必要:

@Bean
public ChatModel monitoredOpenAiModel(AiConfig config, MeterRegistry registry) {
    OpenAiChatModel original = OpenAiChatModel.builder()
            .apiKey(config.getOpenaiKey())
            .build();
    
    return new ChatModel() {
        @Override
        public Response<AiMessage> generate(List<ChatMessage> messages) {
            Timer.Sample sample = Timer.start(registry);
            try {
                Response<AiMessage> response = original.generate(messages);
                sample.stop(registry.timer("openai.response.time"));
                return response;
            } catch (Exception e) {
                registry.counter("openai.errors").increment();
                throw e;
            }
        }
    };
}

4. 高级功能实现

4.1 对话记忆管理

多轮对话是AI应用的核心需求。LangChain4j提供了完善的记忆管理机制:

@Bean
public ChatMemoryProvider chatMemoryProvider() {
    return memoryId -> MessageWindowChatMemory.builder()
            .id(memoryId)
            .maxMessages(20)
            .chatMemoryStore(new RedisChatMemoryStore(redisTemplate))
            .build();
}

@Service
public class ChatService {
    @Autowired
    private ChatMemoryProvider memoryProvider;
    
    public String chat(String sessionId, String message) {
        ChatMemory memory = memoryProvider.get(sessionId);
        memory.add(UserMessage.from(message));
        
        ChatModel model = getCurrentModel();
        AiMessage response = model.generate(memory.messages()).content();
        memory.add(response);
        
        return response.text();
    }
}

4.2 函数调用集成

函数调用可以让大模型执行具体操作,比如查询数据库:

@Bean
public Tool weatherTool() {
    return Tool.builder()
            .name("getWeather")
            .description("获取指定城市的天气")
            .callable(input -> weatherApi.get(input))
            .build();
}

@Bean
public AiServices<Assistant> aiServices(ChatModel model, List<Tool> tools) {
    return AiServices.builder(Assistant.class)
            .chatLanguageModel(model)
            .tools(tools)
            .build();
}

4.3 流式响应处理

对于需要实时显示响应的场景,流式API能显著提升用户体验:

@GetMapping("/stream")
public SseEmitter streamChat(@RequestParam String message) {
    SseEmitter emitter = new SseEmitter();
    
    model.generate(message, new StreamingResponseHandler() {
        @Override
        public void onNext(String token) {
            emitter.send(token);
        }
        
        @Override
        public void onComplete() {
            emitter.complete();
        }
        
        @Override
        public void onError(Throwable error) {
            emitter.completeWithError(error);
        }
    });
    
    return emitter;
}

5. 生产环境最佳实践

5.1 异常处理策略

大模型服务存在不稳定性,需要完善的容错机制:

@ControllerAdvice
public class AiExceptionHandler {
    
    @ExceptionHandler(AiException.class)
    public ResponseEntity<ErrorResponse> handleAiException(AiException e) {
        ErrorResponse response = new ErrorResponse(
            e.getErrorCode(),
            "AI服务处理失败: " + e.getMessage()
        );
        return ResponseEntity.status(502).body(response);
    }
    
    @Retryable(value = {TimeoutException.class}, 
               maxAttempts = 3,
               backoff = @Backoff(delay = 1000))
    public String reliableChat(String prompt) {
        return model.generate(prompt);
    }
}

5.2 性能优化技巧

经过多次压测验证的优化方案:

  1. 连接池配置
@Bean
public OpenAiClient openAiClient(AiConfig config) {
    return OpenAiClient.builder()
            .apiKey(config.getOpenaiKey())
            .callTimeout(Duration.ofSeconds(30))
            .connectTimeout(Duration.ofSeconds(10))
            .writeTimeout(Duration.ofSeconds(10))
            .readTimeout(Duration.ofSeconds(10))
            .build();
}
  1. 批量请求处理
public List<String> batchProcess(List<String> prompts) {
    return prompts.parallelStream()
            .map(prompt -> {
                try {
                    return model.generate(prompt);
                } catch (Exception e) {
                    return "处理失败";
                }
            })
            .collect(Collectors.toList());
}

5.3 安全防护措施

  1. 输入校验
@PostMapping("/safe-chat")
public String safeChat(@Valid @RequestBody ChatRequest request) {
    // 自动校验参数
    return model.generate(request.getMessage());
}

public class ChatRequest {
    @NotBlank
    @Size(max = 1000)
    private String message;
    
    @Pattern(regexp = "openai|deepseek")
    private String modelType;
}
  1. 敏感词过滤
public class SafeChatModel implements ChatModel {
    private final ChatModel delegate;
    private final SensitiveWordFilter filter;
    
    @Override
    public Response<AiMessage> generate(List<ChatMessage> messages) {
        List<ChatMessage> filtered = messages.stream()
                .map(msg -> filter.filter(msg.text()))
                .collect(Collectors.toList());
        return delegate.generate(filtered);
    }
}

6. 典型问题解决方案

在实际开发中,我遇到过几个典型问题及解决方案:

问题1:DeepSeek返回格式不一致

解决方案:自定义响应解析器

public class DeepSeekResponseAdapter implements ResponseAdapter {
    @Override
    public AiMessage adapt(Response response) {
        // 转换DeepSeek特有格式
        return AiMessage.from(response.getData().getText());
    }
}

问题2:多模型内存泄漏

解决方案:定期清理模型缓存

@Scheduled(fixedRate = 3600000)
public void cleanModelCache() {
    modelCache.cleanUp();
}

问题3:长文本处理超时

解决方案:分块处理

public String processLongText(String longText) {
    List<String> chunks = TextSplitter.split(longText, 2000);
    StringBuilder result = new StringBuilder();
    
    for (String chunk : chunks) {
        result.append(model.generate(chunk));
    }
    
    return result.toString();
}
Logo

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

更多推荐