LangChain4j Spring Boot学习与实践方案
目标:掌握LangChain4j的核心功能,并能在Spring Boot应用中构建各种基于LLM的智能应用。
前置知识:
Java 17+
Spring Boot 3.5+ 基础
Maven 或 Gradle 构建工具
对LLM(大型语言模型)的基本理解(例如知道OpenAI或Google Vertex AI是什么)
学习资源:
LangChain4j官方文档:https://docs.langchain4j.dev/
LangChain4j Spring Boot集成示例:https://github.com/langchain4j/langchain4j-spring
LangChain4j 示例仓库:https://github.com/langchain4j/langchain4j-examples
阶段一:初识LangChain4j与低层API (Low-Level API)
核心概念:
统一API:LangChain4j提供统一的API来集成不同的LLM提供商(如OpenAI, Google Vertex AI)和向量存储(如Pinecone, Milvus)。
ChatModel:这是与聊天模型交互的核心接口。UserMessage/AiMessage:表示聊天中的用户消息和AI消息。ChatResponse:LLM的响应结果。依赖管理:在Spring Boot项目中添加LangChain4j的Starter依赖。
配置:通过
application.properties或application.yml配置LLM提供商的API Key和模型名称。
实践步骤:
项目初始化:
使用Spring Initializr (start.spring.io) 创建一个新的Spring Boot项目,选择Java 17+ 和 Spring Web 依赖。
在
pom.xml(或build.gradle)中添加LangChain4j Spring Boot Starter依赖。<!-- Maven --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-spring-boot-starter</artifactId> <version>${langchain4j.version}</version> <!-- 使用最新版本 --> </dependency> <!-- 如果使用OpenAI,还需要额外添加其集成依赖 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>${langchain4j.version}</version> </dependency>在
application.properties中配置你的LLM提供商(以OpenAI为例):langchain4j.open-ai.chat-model.api-key=YOUR_OPENAI_API_KEY langchain4j.open-ai.chat-model.model-name=gpt-4o-mini # 或其他你选择的模型 langchain4j.open-ai.chat-model.temperature=0.7
第一个简单的聊天应用 (Low-Level API):
创建一个Spring
RestController。注入LangChain4j自动配置的
ChatModelbean(例如OpenAiChatModel)。创建一个端点,接收用户消息,然后使用
ChatModel.generate()方法与LLM交互,并返回AI的响应。
// src/main/java/com/example/demo/controller/SimpleChatController.java package com.example.demo.controller; import dev.langchain4j.data.message.AiMessage; import dev.langchain4j.data.message.UserMessage; import dev.langchain4j.model.chat.ChatModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class SimpleChatController { private final ChatModel chatModel; // Spring Boot会自动注入配置好的ChatModel实例 public SimpleChatController(ChatModel chatModel) { this.chatModel = chatModel; } @GetMapping("/chat/simple") public String chat(@RequestParam String message) { // 使用低层API发送用户消息并获取AI响应 AiMessage aiMessage = chatModel.generate(new UserMessage(message)).content(); return aiMessage.text(); } }运行项目,访问
http://localhost:8080/chat/simple?message=Hello。
案例:构建一个能回答简单问题的问答机器人。
阶段二:使用AI Services (High-Level API)
核心概念:
@AiService:LangChain4j提供的高级API,通过定义Java接口来声明LLM驱动的服务,大大减少了样板代码。@UserMessage:注解在接口方法参数上,表示用户输入。@SystemMessage:注解在接口或方法上,定义AI的角色或系统指令。ChatMemory:用于管理会话历史,使AI具有记忆能力。
实践步骤:
创建AI Service接口:
定义一个Java接口,用
@AiService注解。在接口方法上使用
@UserMessage和@SystemMessage。
// src/main/java/com/example/demo/service/Assistant.java package com.example.demo.service; import dev.langchain4j.service.AiService; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; @AiService // 声明这是一个AI服务 public interface Assistant { @SystemMessage("你是一个乐于助人的AI助手,请用中文简洁地回答问题。") // 定义AI的角色 String chat(@UserMessage String userMessage); // 定义一个聊天方法 }集成AI Service到Controller:
在Spring
RestController中注入Assistant接口的实例(Spring Boot会自动为@AiService接口创建代理实现)。
// src/main/java/com/example/demo/controller/AiServiceChatController.java package com.example.demo.controller; import com.example.demo.service.Assistant; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class AiServiceChatController { private final Assistant assistant; public AiServiceChatController(Assistant assistant) { this.assistant = assistant; } @GetMapping("/chat/aiservice") public String chatWithAiService(@RequestParam String message) { return assistant.chat(message); } }运行项目,访问
http://localhost:8080/chat/aiservice?message=你好。
案例:构建一个具备特定角色(如“幽默的AI”)的聊天机器人。
阶段三:引入会话记忆 (Chat Memory)
核心概念:
@MemoryId:用于区分不同用户的会话。ChatMemory:LangChain4j提供的会话记忆抽象,有多种实现(如MessageWindowChatMemory、TokenWindowChatMemory)。@WithChatMemory:注解在AI Service方法上,启用会话记忆功能。@ClearChatMemory:注解在方法上,用于清除当前会话记忆。
实践步骤:
在AI Service中启用记忆:
修改
Assistant接口,添加@WithChatMemory注解和@MemoryId参数。
// src/main/java/com/example/demo/service/AssistantWithMemory.java package com.example.demo.service; import dev.langchain4j.service.AiService; import dev.langchain4j.service.MemoryId; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.WithChatMemory; // 引入WithChatMemory注解 @AiService public interface AssistantWithMemory { // 默认使用 MessageWindowChatMemory @WithChatMemory // 为此方法启用会话记忆 @SystemMessage("你是一个乐于助人的AI助手,请记住我们的对话内容。") String chat(@UserMessage String userMessage, @MemoryId String memoryId); // memoryId用于区分不同会话 @ClearChatMemory // 添加一个清除记忆的方法 String clearChat(@MemoryId String memoryId); }更新Controller:
注入
AssistantWithMemory并提供memoryId(例如使用Session ID或简单的固定ID)。
// src/main/java/com/example/demo/controller/MemoryChatController.java package com.example.demo.controller; import com.example.demo.service.AssistantWithMemory; import jakarta.servlet.http.HttpSession; // 用于获取会话ID import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class MemoryChatController { private final AssistantWithMemory assistantWithMemory; public MemoryChatController(AssistantWithMemory assistantWithMemory) { this.assistantWithMemory = assistantWithMemory; } @GetMapping("/chat/memory") public String chatWithMemory(@RequestParam String message, HttpSession session) { // 使用HttpSession的ID作为memoryId return assistantWithMemory.chat(message, session.getId()); } @GetMapping("/chat/clear") public String clearMemory(HttpSession session) { assistantWithMemory.clearChat(session.getId()); return "Chat memory cleared for session: " + session.getId(); } }运行项目,多次访问
http://localhost:8080/chat/memory?message=...,观察AI是否能记住之前的对话。
案例:开发一个多轮对话的客服机器人,能够记住用户之前的问题。
阶段四:引入工具调用 (Tools / Function Calling)
核心概念:
@Tool:注解在Java方法上,将其暴露给LLM作为可调用的工具。@P:注解在工具方法的参数上,提供参数描述。AiServices.builder().tools(...):在构建AI Service时注册工具对象。
实践步骤:
定义工具类:
创建一个普通的Java类,包含用
@Tool注解的方法。
// src/main/java/com/example/demo/tools/Calculator.java package com.example.demo.tools; import dev.langchain4j.agent.tool.Tool; import dev.langchain4j.agent.tool.P; // 引入P注解 public class Calculator { @Tool("将两个整数相加") public int add(@P("第一个数字") int a, @P("第二个数字") int b) { System.out.println("Executing tool: add(" + a + ", " + b + ")"); return a + b; } @Tool("将两个整数相乘") public int multiply(@P("第一个数字") int a, @P("第二个数字") int b) { System.out.println("Executing tool: multiply(" + a + ", " + b + ")"); return a * b; } }配置工具并注入AI Service:
在Spring
Application类或配置类中,手动构建AssistantWithToolsBean,并注册Calculator实例。因为Spring Boot自动配置
@AiService的方式可能无法直接注入tools,所以这里需要手动构建。
// src/main/java/com/example/demo/service/AssistantWithTools.java package com.example.demo.service; import dev.langchain4j.service.AiService; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; @AiService // 这里仅作为标记,实际Bean的创建在配置类中手动完成 public interface AssistantWithTools { @SystemMessage("你是一个强大的助手,可以使用工具来完成计算。") String chat(@UserMessage String userMessage); }// src/main/java/com/example/demo/config/AiServiceConfig.java package com.example.demo.config; import com.example.demo.service.AssistantWithTools; import com.example.demo.tools.Calculator; import dev.langchain4j.model.chat.ChatModel; import dev.langchain4j.service.AiServices; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AiServiceConfig { @Bean // 手动配置AssistantWithTools Bean public AssistantWithTools assistantWithTools(ChatModel chatModel) { return AiServices.builder(AssistantWithTools.class) .chatModel(chatModel) .tools(new Calculator()) // 注册工具实例 .build(); } @Bean // Calculator工具类也需要被Spring管理,以便于在其他地方使用或测试 public Calculator calculator() { return new Calculator(); } }更新
RestController来使用AssistantWithTools。
// src/main/java/com/example/demo/controller/ToolChatController.java package com.example.demo.controller; import com.example.demo.service.AssistantWithTools; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ToolChatController { private final AssistantWithTools assistantWithTools; public ToolChatController(AssistantWithTools assistantWithTools) { this.assistantWithTools = assistantWithTools; } @GetMapping("/chat/tool") public String chatWithTool(@RequestParam String message) { return assistantWithTools.chat(message); } }运行项目,访问
http://localhost:8080/chat/tool?message=123乘以456是多少?。观察控制台输出,看
add或multiply方法是否被调用。
案例:构建一个可以进行数学计算的智能助手,或者一个可以查询实时股票价格(需要自己实现模拟数据)的代理。
阶段五:检索增强生成 (RAG - Retrieval Augmented Generation)
核心概念:
RAG:结合外部知识库来增强LLM的回答能力,解决LLM知识时效性或私有数据问题。
EmbeddingModel:将文本转换为向量(embedding)。EmbeddingStore:存储文本的embedding及其原始内容,用于检索。常见的有InMemoryEmbeddingStore、Pinecone、Weaviate、Redis等。ContentRetriever:从EmbeddingStore中检索与用户查询相关的文本片段。DocumentSplitter:将大文档分割成小块。DocumentLoader:从各种源(文件、URL等)加载文档。
实践步骤:
添加RAG相关依赖:
在
pom.xml中添加langchain4j-embeddings和langchain4j-document以及你选择的EmbeddingStore和EmbeddingModel依赖(例如OpenAI Embedding Model和InMemoryEmbeddingStore)。
<!-- OpenAI Embedding Model --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>${langchain4j.version}</version> </dependency> <!-- Embedding Stores (选择一个或多个) --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-milvus</artifactId> <!-- 例如使用Milvus,InMemoryEmbeddingStore不需要额外依赖 --> <version>${langchain4j.version}</version> </dependency> <!-- 文档处理相关 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-document</artifactId> <version>${langchain4j.version}</version> </dependency>配置
application.properties中的Embedding Model API Key。langchain4j.open-ai.embedding-model.api-key=YOUR_OPENAI_API_KEY langchain4j.open-ai.embedding-model.model-name=text-embedding-ada-002
构建RAG组件 (以InMemoryEmbeddingStore为例):
加载文档:从文件系统加载一个文本文件(例如
data.txt)。分割文档:使用
DocumentSplitter将文档分割成小块。生成Embedding并存储:使用
EmbeddingModel为每个文本块生成embedding,并存储到EmbeddingStore。创建
ContentRetriever:用于从EmbeddingStore检索相关内容。配置AI Service启用RAG:通过
AiServices.builder().contentRetriever(...)将ContentRetriever注入到AI Service。
// src/main/java/com/example/demo/rag/RagConfig.java package com.example.demo.rag; import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.loader.FileSystemDocumentLoader; import dev.langchain4j.data.document.parser.TextDocumentParser; import dev.langchain4j.data.document.splitter.DocumentSplitters; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.embedding.EmbeddingModel; import dev.langchain4j.model.chat.ChatModel; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; import com.example.demo.service.AssistantWithRAG; import dev.langchain4j.service.AiServices; import jakarta.annotation.PostConstruct; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @Configuration public class RagConfig { private final EmbeddingModel embeddingModel; private final ResourceLoader resourceLoader; public RagConfig(EmbeddingModel embeddingModel, ResourceLoader resourceLoader) { this.embeddingModel = embeddingModel; this.resourceLoader = resourceLoader; } // 1. 创建 EmbeddingStore @Bean public EmbeddingStore<TextSegment> embeddingStore() { return new InMemoryEmbeddingStore<>(); } // 2. 将文档加载、分割、嵌入、存储到EmbeddingStore @PostConstruct public void initRagPipeline() throws IOException { Path filePath = Paths.get(resourceLoader.getResource("classpath:data.txt").getURI()); if (!Files.exists(filePath)) { // 如果文件不存在,创建一个示例文件 Files.writeString(filePath, "LangChain4j 是一个用于将LLM集成到Java应用程序的库。\n" + "它提供统一的API,支持20多个LLM提供商和30多个向量存储。\n" + "LangChain4j 始于2023年初,旨在填补Java在LLM库方面的空白。\n" + "它的核心功能包括AI Services、工具调用、RAG、聊天记忆等。\n" + "Spring Boot 集成需要Java 17和Spring Boot 3.5。" ); } Document document = FileSystemDocumentLoader.loadDocument(filePath, new TextDocumentParser()); EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder() .documentSplitter(DocumentSplitters.recursive(50, 0)) // 分割成50个字符的块 .embeddingModel(embeddingModel) .embeddingStore(embeddingStore()) .build(); ingestor.ingest(document); System.out.println("Document ingested into EmbeddingStore."); } // 3. 创建 ContentRetriever @Bean public ContentRetriever contentRetriever(EmbeddingStore<TextSegment> embeddingStore) { return EmbeddingStoreContentRetriever.builder() .embeddingStore(embeddingStore) .embeddingModel(embeddingModel) .maxResults(3) // 最多检索3个相关片段 .minScore(0.7) // 最小相似度分数 .build(); } // 4. 配置AI Service启用RAG @Bean public AssistantWithRAG assistantWithRAG(ChatModel chatModel, ContentRetriever contentRetriever) { return AiServices.builder(AssistantWithRAG.class) .chatModel(chatModel) .contentRetriever(contentRetriever) // 注入ContentRetriever .build(); } }// src/main/java/com/example/demo/service/AssistantWithRAG.java package com.example.demo.service; import dev.langchain4j.service.AiService; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; @AiService public interface AssistantWithRAG { @SystemMessage("你是一个知识渊博的AI助手。请根据提供的上下文回答问题。如果信息不在上下文中,请说不知道。") String chat(@UserMessage String userMessage); }更新
RestController来使用AssistantWithRAG。
// src/main/java/com/example/demo/controller/RagChatController.java package com.example.demo.controller; import com.example.demo.service.AssistantWithRAG; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class RagChatController { private final AssistantWithRAG assistantWithRAG; public RagChatController(AssistantWithRAG assistantWithRAG) { this.assistantWithRAG = assistantWithRAG; } @GetMapping("/chat/rag") public String chatWithRag(@RequestParam String message) { return assistantWithRAG.chat(message); } }在
src/main/resources目录下创建data.txt文件,并写入一些内容(如上面RAG配置中的示例文本)。运行项目,访问
http://localhost:8080/chat/rag?message=LangChain4j是什么时候开始开发的?,观察它是否能从data.txt中检索信息并回答。
案例:构建一个基于内部文档(如公司规章制度、产品手册)的问答系统。
阶段六:复杂场景与进阶功能
核心概念:
ChatRequestParameters:精细控制每次LLM调用的参数(如温度、最大tokens)。StreamingChatModel/Flux<String>:实现流式响应,提供更好的用户体验。Agent:更复杂的AI行为,可以自主规划、执行一系列工具。
多模态:处理图像、音频等多种输入。
RetrievalAugmentor:高级RAG,支持查询转换、路由、重排等。
实践步骤(选择性):
流式响应 (Streaming):
将AI Service方法的返回类型改为
Flux<String>。
// src/main/java/com/example/demo/service/AssistantWithStreaming.java package com.example.demo.service; import dev.langchain4j.service.AiService; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; import reactor.core.publisher.Flux; // 引入Flux @AiService public interface AssistantWithStreaming { @SystemMessage("你是一个健谈的AI助手,请详细地回答问题。") Flux<String> chat(@UserMessage String userMessage); // 返回Flux实现流式响应 }在
RestController中处理Flux<String>,例如返回text/event-stream类型。
// src/main/java/com/example/demo/controller/StreamingChatController.java package com.example.demo.controller; import com.example.demo.service.AssistantWithStreaming; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RestController public class StreamingChatController { private final AssistantWithStreaming assistantWithStreaming; public StreamingChatController(AssistantWithStreaming assistantWithStreaming) { this.assistantWithStreaming = assistantWithStreaming; } @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> chatStream(@RequestParam String message) { return assistantWithStreaming.chat(message); } }运行项目,访问
http://localhost:8080/chat/stream?message=请详细解释一下LangChain4j,观察响应是逐字或逐句返回。
高级RAG (
RetrievalAugmentor):替换
ContentRetriever为RetrievalAugmentor,并配置查询转换、内容聚合等。这涉及到更复杂的RAG管道。
多模态输入 (Multimodality):
使用
@UserMessage Content content或@UserMessage ImageContent image来接收图像或其他类型的内容作为输入。需要确保LLM提供商支持多模态(如GPT-4o)。
自定义LLM参数 (
ChatRequestParameters):在AI Service方法中添加
ChatRequestParameters参数,在调用时传递自定义参数。
// 在AssistantWithMemory接口中添加一个方法 String chatWithCustomParams(@UserMessage String userMessage, @MemoryId String memoryId, ChatRequestParameters params);
案例:
智能排班系统:接收用户的排班需求(多模态),通过工具查询员工可用性,最终给出优化方案。
智能代码助手:结合RAG从项目文档中获取上下文,通过工具调用编译器、测试框架,帮助开发者编写、调试代码。
总结:
这个学习方案从LangChain4j最基础的LLM交互开始,逐步引入了Spring Boot的集成、高级AI Services、会话记忆、工具调用,最终深入到RAG和流式响应等复杂功能。每个阶段都提供了核心概念、详细的实践步骤和案例,帮助你一步步掌握LangChain4j。
在每个阶段,建议你:
动手实践:亲自敲代码,运行和调试,理解每个组件的作用。
查阅文档:LangChain4j的官方文档是最好的学习资源,深入了解每个API的细节。
参考示例:LangChain4j的
examples仓库提供了大量真实世界的示例,可以作为参考和灵感。探索不同集成:尝试切换不同的LLM提供商(如Google Vertex AI、Ollama)和
EmbeddingStore,理解LangChain4j的统一API优势。
祝你学习愉快,构建出色的AI应用!
ℹ️ This answer was generated using information from the following documentation pages: