Echo
发布于 2026-03-17 / 5 阅读
0
0

LangChain4j逐步整合

#AI

LangChain4j Spring Boot学习与实践方案

目标:掌握LangChain4j的核心功能,并能在Spring Boot应用中构建各种基于LLM的智能应用。

前置知识

  • Java 17+

  • Spring Boot 3.5+ 基础

  • Maven 或 Gradle 构建工具

  • 对LLM(大型语言模型)的基本理解(例如知道OpenAI或Google Vertex AI是什么)

学习资源


阶段一:初识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.propertiesapplication.yml配置LLM提供商的API Key和模型名称。

实践步骤

  1. 项目初始化

    • 使用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
      
  2. 第一个简单的聊天应用 (Low-Level API)

    • 创建一个Spring RestController

    • 注入LangChain4j自动配置的ChatModel bean(例如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具有记忆能力。

实践步骤

  1. 创建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); // 定义一个聊天方法
    }
    
  2. 集成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提供的会话记忆抽象,有多种实现(如MessageWindowChatMemoryTokenWindowChatMemory)。

  • @WithChatMemory:注解在AI Service方法上,启用会话记忆功能。

  • @ClearChatMemory:注解在方法上,用于清除当前会话记忆。

实践步骤

  1. 在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);
    }
    
  2. 更新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时注册工具对象。

实践步骤

  1. 定义工具类

    • 创建一个普通的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;
        }
    }
    
  2. 配置工具并注入AI Service

    • 在Spring Application类或配置类中,手动构建AssistantWithTools Bean,并注册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是多少?

    • 观察控制台输出,看addmultiply方法是否被调用。

案例:构建一个可以进行数学计算的智能助手,或者一个可以查询实时股票价格(需要自己实现模拟数据)的代理。

阶段五:检索增强生成 (RAG - Retrieval Augmented Generation)

核心概念

  • RAG:结合外部知识库来增强LLM的回答能力,解决LLM知识时效性或私有数据问题。

  • EmbeddingModel:将文本转换为向量(embedding)。

  • EmbeddingStore:存储文本的embedding及其原始内容,用于检索。常见的有InMemoryEmbeddingStorePineconeWeaviateRedis等。

  • ContentRetriever:从EmbeddingStore中检索与用户查询相关的文本片段。

  • DocumentSplitter:将大文档分割成小块。

  • DocumentLoader:从各种源(文件、URL等)加载文档。

实践步骤

  1. 添加RAG相关依赖

    • pom.xml中添加langchain4j-embeddingslangchain4j-document以及你选择的EmbeddingStoreEmbeddingModel依赖(例如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
      
  2. 构建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,支持查询转换、路由、重排等。

实践步骤(选择性)

  1. 流式响应 (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,观察响应是逐字或逐句返回。

  2. 高级RAG (RetrievalAugmentor)

    • 替换ContentRetrieverRetrievalAugmentor,并配置查询转换、内容聚合等。这涉及到更复杂的RAG管道。

  3. 多模态输入 (Multimodality)

    • 使用@UserMessage Content content@UserMessage ImageContent image来接收图像或其他类型的内容作为输入。需要确保LLM提供商支持多模态(如GPT-4o)。

  4. 自定义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:


评论