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)
- 配置健康检查端点
- 实现优雅关闭
- 使用持久化的向量数据库和会话存储
下一步
- 查看完整示例:
spring-boot-example/ - 学习更多 RAG 技术: 07-RAG检索增强生成
- 构建智能体系统: 09-智能体工作流
参考资料
- Spring Boot 示例:
spring-boot-example/src/main/java/ - Quarkus 示例:
quarkus-example/src/main/java/ - 官方文档: https://docs.langchain4j.dev/integrations/frameworks/spring-boot