【Langchain4j-Java AI开发】10-框架集成(Spring Boot & Quarkus)

LangChain4j 框架集成(Spring Boot & Quarkus)

概述

LangChain4j 提供了与主流 Java 框架的无缝集成,让你可以在生产环境中轻松构建 AI 应用。本教程将介绍如何在 Spring Boot 和 Quarkus 中使用 LangChain4j。

Spring Boot 集成

Maven 依赖

xml 复制代码
<dependencies>
    <!-- LangChain4j Spring Boot Starter -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-spring-boot-starter</artifactId>
        <version>1.9.1</version>
    </dependency>

    <!-- OpenAI 集成 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
        <version>1.9.1</version>
    </dependency>

    <!-- 内存向量存储 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId>
        <version>1.9.1</version>
    </dependency>
</dependencies>

配置文件

application.properties

properties 复制代码
# OpenAI 配置
langchain4j.open-ai.chat-model.api-key=${OPENAI_API_KEY}
langchain4j.open-ai.chat-model.model-name=gpt-4o-mini
langchain4j.open-ai.chat-model.temperature=0.7
langchain4j.open-ai.chat-model.max-tokens=2000
langchain4j.open-ai.chat-model.timeout=60s
langchain4j.open-ai.chat-model.log-requests=true
langchain4j.open-ai.chat-model.log-responses=true

# Embedding 模型配置
langchain4j.open-ai.embedding-model.api-key=${OPENAI_API_KEY}
langchain4j.open-ai.embedding-model.model-name=text-embedding-3-small

# 应用配置
spring.application.name=langchain4j-demo
server.port=8080

基础 AI Service

java 复制代码
package com.example.demo;

import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;

@AiService
public interface Assistant {

    @SystemMessage("你是一位友好的 AI 助手,请用中文回答问题。")
    String chat(String message);

    @SystemMessage("你是一位专业的{{profession}}。")
    @UserMessage("请回答:{{question}}")
    String askExpert(
            @UserVariable("profession") String profession,
            @UserVariable("question") String question
    );
}

Controller 使用

java 复制代码
package com.example.demo;

import org.springframework.web.bind.annotation.*;

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

    private final Assistant assistant;

    public ChatController(Assistant assistant) {
        this.assistant = assistant;
    }

    @PostMapping
    public ChatResponse chat(@RequestBody ChatRequest request) {
        String answer = assistant.chat(request.message());
        return new ChatResponse(answer);
    }

    @PostMapping("/expert")
    public ChatResponse askExpert(@RequestBody ExpertRequest request) {
        String answer = assistant.askExpert(
                request.profession(),
                request.question()
        );
        return new ChatResponse(answer);
    }

    record ChatRequest(String message) {}
    record ExpertRequest(String profession, String question) {}
    record ChatResponse(String answer) {}
}

启动类

java 复制代码
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

测试

bash 复制代码
# 启动应用
mvn spring-boot:run

# 测试基础对话
curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "你好,介绍一下自己"}'

# 测试专家咨询
curl -X POST http://localhost:8080/api/chat/expert \
  -H "Content-Type: application/json" \
  -d '{"profession": "Java架构师", "question": "如何设计高并发系统?"}'

Spring Boot + 工具集成

定义工具

java 复制代码
package com.example.demo.tools;

import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;

@Component
public class WeatherTools {

    @Tool("获取指定城市的天气预报")
    public String getWeather(String city) {
        // 实际应用中调用天气 API
        return city + "的天气:晴天,温度 15-25°C";
    }

    @Tool("获取未来N天的天气预报")
    public String getWeatherForecast(String city, int days) {
        return city + "未来" + days + "天:晴转多云";
    }
}

AI Service 配置

java 复制代码
package com.example.demo.config;

import com.example.demo.tools.WeatherTools;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;

@Configuration
public class AiConfiguration {

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public ChatMemory chatMemory() {
        return MessageWindowChatMemory.withMaxMessages(10);
    }
}

使用工具的 AI Service

java 复制代码
@AiService(tools = WeatherTools.class)
public interface WeatherAssistant {

    @SystemMessage("你是一个天气查询助手,可以查询天气信息。")
    String chat(String message);
}

Spring Boot + RAG 集成

RAG 配置

java 复制代码
package com.example.demo.config;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.nio.file.Path;
import java.util.List;

import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocuments;

@Configuration
public class RagConfiguration {

    @Bean
    public EmbeddingModel embeddingModel() {
        return new AllMiniLmL6V2QuantizedEmbeddingModel();
    }

    @Bean
    public EmbeddingStore<TextSegment> embeddingStore(EmbeddingModel embeddingModel) {
        // 创建向量存储
        InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        // 加载文档
        List<Document> documents = loadDocuments(
                Path.of("src/main/resources/documents"),
                "*.txt"
        );

        // 摄取文档
        EmbeddingStoreIngestor.ingest(documents, embeddingStore);

        return embeddingStore;
    }

    @Bean
    public ContentRetriever contentRetriever(
            EmbeddingStore<TextSegment> embeddingStore,
            EmbeddingModel embeddingModel
    ) {
        return EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .maxResults(3)
                .minScore(0.6)
                .build();
    }
}

RAG AI Service

java 复制代码
@AiService
public interface DocumentAssistant {

    @SystemMessage("你是一个文档问答助手,根据提供的文档内容回答问题。")
    String chat(String question);
}

Controller

java 复制代码
@RestController
@RequestMapping("/api/documents")
public class DocumentController {

    private final DocumentAssistant assistant;

    public DocumentController(DocumentAssistant assistant) {
        this.assistant = assistant;
    }

    @PostMapping("/ask")
    public ChatResponse ask(@RequestBody QuestionRequest request) {
        String answer = assistant.chat(request.question());
        return new ChatResponse(answer);
    }

    record QuestionRequest(String question) {}
    record ChatResponse(String answer) {}
}

Spring Boot + 多用户会话管理

会话管理配置

java 复制代码
package com.example.demo.config;

import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MemoryConfiguration {

    @Bean
    public ChatMemoryStore chatMemoryStore() {
        return new InMemoryChatMemoryStore();
    }

    @Bean
    public ChatMemoryProvider chatMemoryProvider(
            ChatMemoryStore store,
            TokenCountEstimator tokenCountEstimator
    ) {
        return memoryId -> TokenWindowChatMemory.builder()
                .id(memoryId)
                .maxTokens(1000)
                .chatMemoryStore(store)
                .tokenCountEstimator(tokenCountEstimator)
                .build();
    }
}

多用户 AI Service

java 复制代码
@AiService
public interface UserAssistant {

    String chat(@MemoryId String userId, @UserMessage String message);
}

REST API

java 复制代码
@RestController
@RequestMapping("/api/users/{userId}/chat")
public class UserChatController {

    private final UserAssistant assistant;

    public UserChatController(UserAssistant assistant) {
        this.assistant = assistant;
    }

    @PostMapping
    public ChatResponse chat(
            @PathVariable String userId,
            @RequestBody ChatRequest request
    ) {
        String answer = assistant.chat(userId, request.message());
        return new ChatResponse(answer);
    }

    record ChatRequest(String message) {}
    record ChatResponse(String answer) {}
}

Quarkus 集成

Maven 依赖

xml 复制代码
<dependencies>
    <!-- Quarkus LangChain4j -->
    <dependency>
        <groupId>io.quarkiverse.langchain4j</groupId>
        <artifactId>quarkus-langchain4j-openai</artifactId>
        <version>1.9.1</version>
    </dependency>

    <!-- RESTEasy Reactive -->
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
    </dependency>
</dependencies>

配置文件

application.properties

properties 复制代码
# OpenAI 配置
quarkus.langchain4j.openai.api-key=${OPENAI_API_KEY}
quarkus.langchain4j.openai.chat-model.model-name=gpt-4o-mini
quarkus.langchain4j.openai.chat-model.temperature=0.7
quarkus.langchain4j.openai.timeout=60s

# 应用配置
quarkus.http.port=8080

AI Service(Quarkus)

java 复制代码
package com.example.demo;

import dev.langchain4j.service.SystemMessage;
import io.quarkiverse.langchain4j.RegisterAiService;

@RegisterAiService
public interface QuarkusAssistant {

    @SystemMessage("你是一位友好的 AI 助手。")
    String chat(String message);
}

Resource(相当于 Controller)

java 复制代码
package com.example.demo;

import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;

@Path("/api/chat")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ChatResource {

    @Inject
    QuarkusAssistant assistant;

    @POST
    public ChatResponse chat(ChatRequest request) {
        String answer = assistant.chat(request.message());
        return new ChatResponse(answer);
    }

    public record ChatRequest(String message) {}
    public record ChatResponse(String answer) {}
}

启动应用

bash 复制代码
# 开发模式
mvn quarkus:dev

# 生产构建
mvn package
java -jar target/quarkus-app/quarkus-run.jar

生产环境最佳实践

1. 环境变量管理

properties 复制代码
# 使用环境变量
langchain4j.open-ai.chat-model.api-key=${OPENAI_API_KEY:}

# 或使用 Spring Cloud Config
spring.config.import=optional:configserver:http://localhost:8888

2. 日志配置

properties 复制代码
# 生产环境关闭详细日志
langchain4j.open-ai.chat-model.log-requests=false
langchain4j.open-ai.chat-model.log-responses=false

# 应用日志
logging.level.dev.langchain4j=INFO
logging.level.com.example=INFO

3. 超时和重试

java 复制代码
@Configuration
public class OpenAiConfiguration {

    @Bean
    public ChatLanguageModel chatModel() {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("OPENAI_API_KEY"))
                .modelName(GPT_4_O_MINI)
                .timeout(Duration.ofSeconds(60))
                .maxRetries(3)
                .build();
    }
}

4. 异常处理

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        return ResponseEntity
                .status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(new ErrorResponse("AI 服务暂时不可用: " + e.getMessage()));
    }

    record ErrorResponse(String error) {}
}

5. 监控和度量

java 复制代码
@Component
public class AiMetrics {

    private final MeterRegistry registry;

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

    public void recordRequest(String endpoint, long duration) {
        registry.timer("ai.request",
                "endpoint", endpoint
        ).record(Duration.ofMillis(duration));
    }

    public void recordTokenUsage(int tokens) {
        registry.counter("ai.tokens.used").increment(tokens);
    }
}

6. 缓存策略

java 复制代码
@Service
public class CachedAiService {

    private final Assistant assistant;
    private final Cache<String, String> cache;

    public CachedAiService(Assistant assistant) {
        this.assistant = assistant;
        this.cache = Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(Duration.ofHours(1))
                .build();
    }

    public String chat(String message) {
        return cache.get(message, key -> assistant.chat(key));
    }
}

7. 速率限制

java 复制代码
@Component
public class RateLimiter {

    private final RateLimiter limiter = RateLimiter.create(10.0); // 每秒10个请求

    public void checkLimit() {
        if (!limiter.tryAcquire(Duration.ofSeconds(5))) {
            throw new TooManyRequestsException("请求过于频繁");
        }
    }
}

@RestController
public class ChatController {

    private final RateLimiter rateLimiter;
    private final Assistant assistant;

    @PostMapping("/api/chat")
    public ChatResponse chat(@RequestBody ChatRequest request) {
        rateLimiter.checkLimit();
        String answer = assistant.chat(request.message());
        return new ChatResponse(answer);
    }
}

完整示例:客服系统

项目结构

复制代码
src/main/java/com/example/support/
├── SupportApplication.java
├── controller/
│   └── SupportController.java
├── service/
│   ├── CustomerSupportAssistant.java
│   └── TicketService.java
├── tools/
│   └── TicketTools.java
├── config/
│   ├── AiConfiguration.java
│   └── RagConfiguration.java
└── model/
    └── Ticket.java

工具类

java 复制代码
@Component
public class TicketTools {

    @Autowired
    private TicketService ticketService;

    @Tool("创建新的客服工单")
    public String createTicket(
            @P("客户ID") String customerId,
            @P("问题描述") String description
    ) {
        Ticket ticket = ticketService.create(customerId, description);
        return "工单已创建,编号:" + ticket.getId();
    }

    @Tool("查询工单状态")
    public String getTicketStatus(@P("工单编号") String ticketId) {
        Ticket ticket = ticketService.findById(ticketId);
        return "工单 " + ticketId + " 状态:" + ticket.getStatus();
    }
}

AI Service

java 复制代码
@AiService(tools = TicketTools.class)
public interface CustomerSupportAssistant {

    @SystemMessage({
            "你是一位专业的客服代表。",
            "你友好、耐心、乐于助人。",
            "你可以创建和查询工单。"
    })
    String chat(@MemoryId String customerId, @UserMessage String message);
}

Controller

java 复制代码
@RestController
@RequestMapping("/api/support")
public class SupportController {

    private final CustomerSupportAssistant assistant;

    @PostMapping("/customers/{customerId}/chat")
    public ChatResponse chat(
            @PathVariable String customerId,
            @RequestBody ChatRequest request
    ) {
        String answer = assistant.chat(customerId, request.message());
        return new ChatResponse(answer);
    }
}

测试

单元测试

java 复制代码
@SpringBootTest
class AssistantTest {

    @Autowired
    private Assistant assistant;

    @Test
    void testChat() {
        String answer = assistant.chat("你好");
        assertThat(answer).isNotEmpty();
    }
}

集成测试

java 复制代码
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ChatControllerTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void testChatEndpoint() {
        ChatRequest request = new ChatRequest("你好");

        ResponseEntity<ChatResponse> response = restTemplate.postForEntity(
                "/api/chat",
                request,
                ChatResponse.class
        );

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(response.getBody().answer()).isNotEmpty();
    }
}

部署

Docker 部署

Dockerfile

dockerfile 复制代码
FROM eclipse-temurin:21-jre
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

docker-compose.yml

yaml 复制代码
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - SPRING_PROFILES_ACTIVE=prod
    depends_on:
      - postgres

  postgres:
    image: pgvector/pgvector:latest
    environment:
      - POSTGRES_DB=vectordb
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    ports:
      - "5432:5432"

Kubernetes 部署

deployment.yaml

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: langchain4j-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: langchain4j-app
  template:
    metadata:
      labels:
        app: langchain4j-app
    spec:
      containers:
        - name: app
          image: my-registry/langchain4j-app:latest
          ports:
            - containerPort: 8080
          env:
            - name: OPENAI_API_KEY
              valueFrom:
                secretKeyRef:
                  name: openai-secret
                  key: api-key

常见问题

Q1: 如何在 Spring Boot 中使用多个 LLM 提供商?

A:

java 复制代码
@Configuration
public class MultiModelConfiguration {

    @Bean
    @Primary
    public ChatLanguageModel openAiModel() {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("OPENAI_API_KEY"))
                .build();
    }

    @Bean
    public ChatLanguageModel anthropicModel() {
        return AnthropicChatModel.builder()
                .apiKey(System.getenv("ANTHROPIC_API_KEY"))
                .build();
    }
}

Q2: 如何实现生产环境的高可用?

A:

  • 使用负载均衡(Kubernetes Service)
  • 配置健康检查端点
  • 实现优雅关闭
  • 使用持久化的向量数据库和会话存储

下一步

参考资料

相关推荐
爱编程的鱼2 小时前
Tokens是什么意思?Token在AI大模型中的含义
人工智能
好奇龙猫2 小时前
【AI学习-comfyUI学习-第二十二-DepthAnythingV2深度图工作流-各个部分学习】
人工智能·学习
小妖同学学AI2 小时前
告别无效提问:开源工具Prompt Optimizer让AI真正懂你心意
人工智能·prompt
bleuesprit2 小时前
模型加载时trust_remote_code 的作用
人工智能
啊阿狸不会拉杆2 小时前
《数字图像处理》实验2-空间域灰度变换与滤波处理
图像处理·人工智能·机器学习·计算机视觉·数字图像处理
EniacCheng2 小时前
贝叶斯定理
人工智能·机器学习·概率论
木头左2 小时前
多时间框架LSTM量化交易策略的实现与参数优化
人工智能·rnn·lstm
小雨下雨的雨2 小时前
ModelEngine的Aido智能体【娱乐生涯 AI 助手】升级计划——工作流编排精确制导AI应用
人工智能·ai·娱乐·智能体
2501_916766542 小时前
【Java】final关键字
java·开发语言