一次性读懂读透 LangChain4j:Java 开发者的 LLM 应用开发终极指南

适用版本:LangChain4j 1.x(截至 1.15.1,2026 年 5 月)
阅读时间:约 60 分钟
定位:从零基础到生产级实战,一篇文章打通 LangChain4j 全脉络


目录


第一部分:为什么需要 LangChain4j

章节导读:在深入技术细节之前,我们先理解 LangChain4j 为什么存在——它解决了什么痛点,填补了什么空白,以及为什么 Java 开发者应该关注它。

1.1 Java 开发者的 AI 困境

2023 年,大语言模型(LLM)的爆发式增长让几乎所有开发者都开始思考如何将 AI 能力集成到自己的应用中。对于 Python 开发者来说,这是一段顺畅的旅程——LangChain、LlamaIndex 等框架提供了开箱即用的抽象层,几行代码就能完成从模型调用到 RAG 管道搭建的全部工作。

然而,对于全球数以百万计的 Java 开发者而言,情况却截然不同。企业级后端系统大多运行在 JVM 上,银行、保险、电商、物流等核心业务系统用 Java 或 Kotlin 构建。当这些系统需要接入 LLM 能力时,开发者面临着尴尬的选择:要么用 HttpClient 手写 HTTP 请求来调用 OpenAI 的 API(处理认证、重试、流式解析、错误恢复等大量胶水代码),要么切换到 Python 生态(引入跨语言调用的复杂度和运维成本)。

这种困境的本质是缺乏一个为 Java 生态量身打造的 LLM 应用开发框架。Python 的 LangChain 虽然优秀,但它是 Pythonic 的——大量使用动态类型、装饰器、异步生成器等语言特性,无法直接移植到 Java 的静态类型世界中。Java 开发者需要的不是一个 Python 框架的翻译版,而是一个从骨子里就为 Java 设计的原生方案。

1.2 LangChain4j 的诞生与定位

LangChain4j(LangChain for Java)正是在这样的背景下诞生的。它是一个开源的 Java 库,旨在简化将大语言模型集成到 Java 应用程序中的全过程。需要特别强调的是:LangChain4j 不是 Python LangChain 的 Java 移植版。它从第一行代码开始就为 Java 生态量身设计,充分利用了 Java 的语言特性——接口、注解、泛型、Builder 模式、动态代理等——来创造一种真正"Java 味"的 AI 开发体验。

项目托管在 GitHub(langchain4j/langchain4j),采用 Apache-2.0 开源协议。截至 2026 年 5 月,项目已积累超过 12,200 颗 Star 和 2,300 次 Fork,最新版本为 1.15.1,保持着活跃的开发节奏。

LangChain4j 的定位可以用一句话概括:它是 Java 生态中将 LLM 能力从"能用"提升到"好用"的桥梁层。它不做模型训练,不做推理优化,而是专注于解决应用层面的集成问题——如何优雅地与模型对话、如何管理上下文记忆、如何构建 RAG 管道、如何让模型安全地调用外部工具。

1.3 核心价值主张

LangChain4j 的价值可以从四个维度来理解:

统一抽象,屏蔽差异。不同的 LLM 提供商(OpenAI、Anthropic、Google Gemini、通义千问、本地 Ollama 等)各有各的 API 风格、认证方式和数据格式。LangChain4j 通过统一的 ChatModelEmbeddingModel 等接口,让你只需编写一次代码,就能在不同模型之间自由切换。目前支持 20+ 家模型提供商和 30+ 种向量存储。

双层 API,各取所需。对于需要完全掌控的开发者,LangChain4j 提供低层 API(Low-Level API),直接操作 ChatModelChatMessageEmbeddingStore 等基础构件。对于追求效率的开发者,高层 API(High-Level API)即 AI Services,通过 Java 接口加注解的方式,用声明式编程隐藏所有复杂性。

框架无关,自由集成。LangChain4j 不绑定任何特定的 Java 框架。无论你使用 Spring Boot、Quarkus、Micronaut 还是 Helidon,甚至是一个纯 Java 应用,都能无缝集成。它提供了一流的框架集成模块(如 langchain4j-spring-boot-starter),但核心库本身是框架无关的。

生产就绪,企业可用。LangChain4j 不只是一个玩具项目。它内置了对聊天记忆持久化、流式输出、结构化输出、Guardrails 安全护栏、可观测性等生产级特性的支持,能够直接用于企业级系统的构建。

本节要点:LangChain4j 是 Java 生态的原生 LLM 应用开发框架,不是 Python LangChain 的移植版。它通过统一抽象、双层 API、框架无关的设计,解决了 Java 开发者接入大模型的核心痛点。


第二部分:架构全景与设计哲学

章节导读:理解架构是掌握一个框架的捷径。这一部分我们将深入 LangChain4j 的分层设计、模块组织和核心设计模式,帮你建立全局认知。

2.1 分层架构总览

LangChain4j 采用清晰的三层架构设计,从底向上依次为:核心抽象层、高层组合层和具体实现层。

具体实现层(集成模块)

核心抽象层(langchain4j-core)

高层 API(AI Services)

AI Services 声明式接口

@SystemMessage / @UserMessage

@Tool / @MemoryId

结构化输出 / Guardrails

ChatModel / StreamingChatModel

EmbeddingModel / EmbeddingStore

ChatMemory / ChatMemoryStore

Document / DocumentSplitter

Tool Specification / Tool Executor

RetrievalAugmentor / ContentRetriever

langchain4j-open-ai

langchain4j-anthropic

langchain4j-ollama

langchain4j-pinecone

langchain4j-pgvector

langchain4j-milvus

langchain4j-... (30+ 模块)

核心抽象层langchain4j-core)是整个框架的基石。它定义了所有核心接口和数据模型,但不包含任何具体实现。这意味着你可以只依赖 langchain4j-core,然后自行实现其中的任何接口。这一层的关键抽象包括:ChatModel(对话模型)、EmbeddingModel(嵌入模型)、EmbeddingStore(向量存储)、ChatMemory(聊天记忆)、Document(文档)和 DocumentSplitter(文档分割器)等。

高层组合层langchain4j)在核心抽象之上提供了 AI Services 这一高级抽象,以及各种开箱即用的组件实现(如 MessageWindowChatMemoryDefaultRetrievalAugmentor 等)。AI Services 通过 Java 动态代理,将你定义的接口自动转化为可执行的 AI 服务,极大地降低了使用门槛。

具体实现层由数十个独立的集成模块组成,每个模块负责对接一个特定的外部服务。例如 langchain4j-open-ai 实现了 OpenAI 的 ChatModelEmbeddingModellangchain4j-pinecone 实现了 Pinecone 的 EmbeddingStore。这种设计让你可以按需引入依赖,避免不必要的传递依赖。

2.2 模块地图

LangChain4j 的模块组织遵循"核心+卫星"的模式。核心模块只有一个,卫星模块按功能分为几大类:

模型集成模块负责对接各类 LLM 和嵌入模型提供商。主要包括:langchain4j-open-ai(OpenAI / Azure OpenAI)、langchain4j-anthropic(Claude 系列)、langchain4j-google-ai-gemini(Gemini 系列)、langchain4j-vertex-ai(Google Vertex AI)、langchain4j-ollama(本地模型)、langchain4j-mistral-ai(Mistral 系列)、langchain4j-hugging-face(HuggingFace 推理端点)、langchain4j-cohere(Cohere 嵌入模型)、langchain4j-qianfan(百度文心一言)、langchain4j-dashscope(阿里通义千问)等。

向量存储模块负责对接各类向量数据库:langchain4j-pineconelangchain4j-milvuslangchain4j-chromalangchain4j-weaviatelangchain4j-qdrantlangchain4j-pgvector(PostgreSQL 向量扩展)、langchain4j-elasticsearchlangchain4j-opensearchlangchain4j-cassandralangchain4j-mongodb-atlaslangchain4j-redislangchain4j-couchbaselangchain4j-azure-ai-search 等。

文档处理模块包括文档加载器和解析器:langchain4j-document-parser-apache-tika(基于 Apache Tika 的通用文档解析)、langchain4j-document-parser-apache-pdfbox(PDF 解析)等。

框架集成模块提供与主流 Java 框架的深度集成:langchain4j-spring-boot-starterlangchain4j-quarkus(Quarkus 扩展)、langchain4j-helidonlangchain4j-micronaut 等。

辅助模块包括:langchain4j-web-search-engine-google-custom(Google 搜索集成)、langchain4j-embeddings-all-minilm-l6-v2(本地嵌入模型)等。

2.3 核心设计模式

LangChain4j 的源码中大量运用了几种经典的设计模式,理解它们有助于你在使用框架时做到"心中有数"。

Builder 模式贯穿全框架。几乎所有核心对象都通过 Builder 创建,确保参数的可读性和不可变性。创建 ChatModelEmbeddingStoreChatMemory 等对象时,你都会使用 .builder() 方法链式配置参数:

OpenAiChatModel model = OpenAiChatModel.builder()
    .apiKey("your-api-key")
    .modelName("gpt-4o")
    .temperature(0.7)
    .maxTokens(2000)
    .build();

策略模式体现在核心接口的可替换实现上。ChatModel 是一个策略接口,OpenAiChatModelAnthropicChatModelOllamaChatModel 等都是它的不同策略实现。你可以在运行时切换策略,而不需要修改上层业务代码。同理,EmbeddingStoreChatMemoryStoreDocumentSplitter 等接口也都遵循这一模式。

动态代理模式是 AI Services 的核心机制。当你定义一个 Java 接口并用 AiServices.builder() 创建代理时,LangChain4j 在底层使用 java.lang.reflect.Proxy 生成接口的动态实现。每次方法调用都会被拦截,框架根据接口上的注解(@SystemMessage@UserMessage@Tool 等)自动构建 Prompt、调用模型、解析响应,并将结果映射回方法的返回类型。

模板方法模式在 RAG 流程中体现得最为明显。DefaultRetrievalAugmentor 定义了 RAG 的骨架流程(查询转换 → 内容检索 → 内容注入 → 模型调用),而每一步的具体行为都可以通过替换组件来自定义。

管道/责任链模式在 Guardrails 机制中得到应用。多个 Guardrail 可以按优先级组成链,依次验证输入或输出,任何一个环节失败都可以中断流程或提供替代响应。

2.4 双层 API 哲学

LangChain4j 最核心的设计理念之一是双层 API:同一套功能,提供两种使用方式,适应不同场景和偏好。

低层 API(Low-Level API) 让你直接操作基础构件。你手动构建 ChatMessage 列表,手动调用 ChatModel.chat(),手动处理响应解析。这种方式给你最大的灵活性和控制力,适合需要精细控制每个环节的场景:

// 低层 API:完全控制每一步
ChatModel model = OpenAiChatModel.builder()
    .apiKey(apiKey)
    .modelName("gpt-4o")
    .build();

List<ChatMessage> messages = new ArrayList<>();
messages.add(SystemMessage.from("你是一个专业的客服助手"));
messages.add(UserMessage.from("我的订单 #12345 什么时候能到?"));

ChatResponse response = model.chat(messages);
String answer = response.aiMessage().text();

高层 API(AI Services) 让你通过定义 Java 接口来声明 AI 服务的行为,框架自动生成实现。这种方式将模板代码降到最低,适合快速开发和标准化集成:

// 高层 API:声明式,简洁优雅
interface CustomerService {
    @SystemMessage("你是一个专业的客服助手")
    String handleInquiry(@UserMessage String userMessage);
}

CustomerService service = AiServices.builder(CustomerService.class)
    .chatLanguageModel(model)
    .build();

String answer = service.handleInquiry("我的订单 #12345 什么时候能到?");

两种方式本质上调用的是同一套底层引擎,但高层 API 通过约定优于配置的原则,把大量重复性的胶水代码隐藏了。你可以根据项目需要自由选择,甚至在同一个项目中混合使用。

本节要点:LangChain4j 的三层架构(核心抽象层 → 高层组合层 → 具体实现层)配合 Builder、策略、动态代理等设计模式,构建了一个既灵活又可扩展的框架。双层 API 让不同层次的开发者都能找到适合自己的使用方式。


第三部分:核心能力——从概念到代码

章节导读:这是本文最核心的部分。我们将逐一拆解 LangChain4j 的每一项核心能力,每个能力都包含概念解释、完整代码示例和关键注意事项。从快速上手到高级特性,渐进式深入。

3.1 五分钟快速上手

在深入各个核心概念之前,我们先跑通一个最小可用的例子,建立直观感受。

第一步:添加依赖。在 Maven 项目中引入核心库和 OpenAI 集成模块(langchain4j 版本 >= 1.0.0):

<!-- pom.xml -->
<dependencies>
    <!-- LangChain4j 核心库 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>1.15.1</version>
    </dependency>
    <!-- OpenAI 集成 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>1.15.1</version>
    </dependency>
</dependencies>

如果你使用 Gradle:

// build.gradle
dependencies {
    implementation 'dev.langchain4j:langchain4j:1.15.1'
    implementation 'dev.langchain4j:langchain4j-open-ai:1.15.1'
}

第二步:编写第一个 AI 对话程序

import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.chat.ChatModel;

public class FirstAiChat {
    public static void main(String[] args) {
        // 1. 创建模型实例
        ChatModel model = OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY")) // 从环境变量读取,避免硬编码
            .modelName("gpt-4o")
            .build();

        // 2. 发送消息并获取回复
        String answer = model.chat("用一句话解释什么是 LangChain4j");
        
        // 3. 输出结果
        System.out.println(answer);
    }
}

运行这段代码(确保 OPENAI_API_KEY 环境变量已设置),你将得到类似这样的输出:

LangChain4j 是一个为 Java 生态量身打造的开源框架,用于简化将大语言模型集成到 Java 应用程序中。

这就是最基础的 LangChain4j 用法——三行核心代码完成一次 AI 对话。接下来的各个小节,我们将逐步展开更高级的用法。

3.2 ChatModel:与大模型对话

ChatModel 是 LangChain4j 中最基础也最重要的接口,它代表了一个对话模型的交互能力。从 1.0.0 版本开始,它取代了旧版的 ChatLanguageModel 接口,成为与 LLM 交互的标准入口。

3.2.1 消息类型体系

ChatModel 接收 ChatMessage 列表作为输入,返回 ChatResponse 作为输出。ChatMessage 是一个抽象类型,有五种具体实现:

UserMessage 代表用户输入。它可以包含纯文本,也可以包含图片、音频、视频、PDF 等多模态内容(多模态详见 3.9 节)。

SystemMessage 代表系统指令。它用于设定模型的行为、角色和约束条件,通常在对话的最前面,且在整个对话过程中保持不变。

AiMessage 代表模型的回复。除了文本内容外,它还可能包含"思考过程"(thinking content)和工具调用请求(tool execution requests)。

ToolExecutionResultMessage 代表工具执行的结果。当模型请求调用某个工具后,你将工具的执行结果以此消息类型返回给模型。

CustomMessage 是一个扩展类型,允许携带任意属性键值对,用于适配某些模型的特殊需求(如 Ollama 的自定义参数)。

3.2.2 请求定制

对于简单的对话场景,直接传入字符串或 UserMessage 即可。但当你需要精细控制请求参数时,可以使用 ChatRequest

ChatRequest request = ChatRequest.builder()
    .messages(
        SystemMessage.from("你是一个专业的技术顾问,回答简洁且包含代码示例"),
        UserMessage.from("如何在 Java 中实现单例模式?")
    )
    .modelName("gpt-4o")        // 指定模型名称
    .temperature(0.3)            // 低温度,输出更确定性
    .maxTokens(1000)             // 限制输出长度
    .toolSpecifications(...)     // 提供可用工具列表
    .build();

ChatResponse response = chatModel.chat(request);

// 解析响应
AiMessage aiMessage = response.aiMessage();
String text = aiMessage.text();                    // 文本内容
TokenUsage tokenUsage = response.tokenUsage();      // Token 使用统计
FinishReason finishReason = response.finishReason(); // 结束原因

ChatResponse 不仅包含模型的文本回复,还携带了 Token 使用统计(inputTokenCountoutputTokenCounttotalTokenCount)和结束原因(STOPLENGTHTOOL_EXECUTION 等),这些信息对于成本控制和调试非常重要。

3.2.3 多轮对话管理

ChatModel 本身是无状态的——它不会自动记住之前的对话内容。每次调用都需要你把完整的对话历史传进去:

UserMessage firstUser = UserMessage.from("你好,我叫小明");
AiMessage firstAi = model.chat(firstUser).aiMessage();

UserMessage secondUser = UserMessage.from("我叫什么名字?");
// 必须把之前的对话历史都带上
AiMessage secondAi = model.chat(firstUser, firstAi, secondUser).aiMessage();
// 模型能正确回答"你叫小明"

这种无状态设计让你对上下文窗口有完全的控制权,但手动管理消息列表很快就会变得繁琐。这就是 ChatMemory(3.5 节)和 AI Services(3.3 节)存在的意义——它们自动帮你管理对话历史。

3.3 AI Services:声明式 AI 编程

如果说 ChatModel 是 LangChain4j 的"手动挡",那么 AI Services 就是它的"自动挡"。AI Services 是 LangChain4j 最具特色的高层抽象,它让你像定义普通的 Java Service 接口一样定义 AI 服务,框架在运行时自动生成实现。

3.3.1 基本用法
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

// 1. 定义接口
interface Translator {
    @SystemMessage("你是一个专业翻译,将用户输入翻译为{{language}}")
    String translate(@UserMessage String text, @V("language") String targetLanguage);
}

// 2. 构建代理
ChatModel model = OpenAiChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("gpt-4o")
    .build();

Translator translator = AiServices.builder(Translator.class)
    .chatLanguageModel(model)
    .build();

// 3. 像普通 Java 方法一样调用
String result = translator.translate("你好世界", "English");
// 输出: "Hello, World"

这个例子展示了 AI Services 的三个核心注解:

@SystemMessage 标注在方法上,定义系统指令模板。支持 {{variable}} 占位符。

@UserMessage 标注在方法参数上,将该参数的值作为用户消息发送给模型。同样支持 {{variable}} 模板语法。

@V 标注在方法参数上,将参数值注入到 @SystemMessage@UserMessage 的模板变量中。

3.3.2 注解体系详解

AI Services 的注解体系是整个框架最精巧的设计之一。以下是完整的注解清单:

注解 位置 作用
@SystemMessage 方法 定义系统指令,支持模板变量
@UserMessage 方法/参数 定义用户消息模板
@V 参数 注入模板变量值
@MemoryId 参数 指定用户标识,用于多用户记忆隔离
@UserName 参数 指定用户名称,注入到消息中
@Tool 方法 将方法注册为 AI 可调用的工具

其中 @MemoryId 在多租户场景中尤为关键。通过它,LangChain4j 可以为每个用户维护独立的对话记忆:

interface Assistant {
    @SystemMessage("你是一个友好的助手")
    String chat(@MemoryId int userId, @UserMessage String message);
}

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .chatMemory(MessageWindowChatMemory.withMaxMessages(20))
    .build();

// 不同 userId 的对话记忆是隔离的
assistant.chat(1, "我叫小明");  // 用户1的记忆
assistant.chat(2, "我叫小红");  // 用户2的记忆
assistant.chat(1, "我叫什么?"); // 回答"小明"
assistant.chat(2, "我叫什么?"); // 回答"小红"
3.3.3 工作原理:动态代理揭秘

理解 AI Services 的底层原理,有助于你在遇到问题时快速定位。当你调用 AiServices.builder(Translator.class).build() 时,框架内部做了这些事情:

首先,使用 java.lang.reflect.Proxy.newProxyInstance()Translator 接口生成一个动态代理对象。然后,当代理对象的方法被调用时,InvocationHandler 拦截调用,执行以下步骤:

  1. 解析注解:读取方法上的 @SystemMessage@UserMessage 注解,提取模板。
  2. 填充变量:用 @V 标注的参数值替换模板中的 {{variable}} 占位符。
  3. 组装消息:构建 SystemMessageUserMessage 列表。
  4. 注入记忆:如果配置了 ChatMemory,从记忆中加载历史消息并合并。
  5. 调用模型:将完整的消息列表发送给 ChatModel
  6. 解析响应:根据方法的返回类型,将模型的回复转换为相应的 Java 类型(String、POJO、List 等)。
  7. 更新记忆:将本轮对话写入记忆。

整个过程对你完全透明——你只需要定义接口、调用方法,剩下的交给框架。

3.4 Tool Calling:让模型调用你的代码

Tool Calling(也叫 Function Calling)是现代 LLM 最强大的能力之一。它允许模型在生成回复的过程中,请求调用你预定义的外部工具(函数),从而获取实时数据、执行计算或操作外部系统。LangChain4j 对 Tool Calling 提供了完善的支持。

3.4.1 定义工具

在 LangChain4j 中,定义一个工具非常简单——只需要一个普通的 Java 方法加上 @Tool 注解:

import dev.langchain4j.agent.tool.Tool;

class WeatherTools {
    
    @Tool("查询指定城市的当前天气信息,包括温度、湿度和天气状况")
    String getWeather(@P("城市名称") String city) {
        // 调用真实的天气 API
        return String.format("%s:晴,25°C,湿度 60%%", city);
    }
    
    @Tool("查询未来几天的天气预报")
    String getForecast(@P("城市名称") String city, @P("天数") int days) {
        return String.format("%s 未来 %d 天:多云转晴,22-28°C", city, days);
    }
}

@Tool 注解的字符串参数是工具的描述,模型会根据这个描述来决定何时调用该工具。@P 注解用于描述工具参数的含义,帮助模型理解如何传参。

3.4.2 注册工具并使用

定义好工具后,需要将工具实例注册到 AI Services 或 ChatModel 中:

// 方式一:通过 AI Services 注册
interface WeatherAssistant {
    @SystemMessage("你是一个天气助手,可以查询天气和预报")
    String chat(@UserMessage String message);
}

WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
    .chatLanguageModel(model)
    .tools(new WeatherTools()) // 注册工具实例
    .build();

// 模型会自动判断何时调用工具
String answer = assistant.chat("北京今天天气怎么样?");
// 模型会调用 getWeather("北京"),然后基于返回结果生成自然语言回复
// 方式二:通过低层 API 手动处理 Tool Calling
ChatModel model = OpenAiChatModel.builder()
    .apiKey(apiKey)
    .modelName("gpt-4o")
    .build();

// 注册工具规格
ToolSpecification toolSpec = ToolSpecification.builder()
    .name("getWeather")
    .description("查询指定城市的天气")
    .parameters(JsonObjectSchema.builder()
        .addStringProperty("city", "城市名称")
        .required("city")
        .build())
    .build();

// 发送请求
ChatRequest request = ChatRequest.builder()
    .messages(UserMessage.from("上海天气如何?"))
    .toolSpecifications(toolSpec)
    .build();

ChatResponse response = model.chat(request);
AiMessage aiMessage = response.aiMessage();

// 检查模型是否请求调用工具
if (aiMessage.hasToolExecutionRequests()) {
    ToolExecutionRequest req = aiMessage.toolExecutionRequests().get(0);
    String toolName = req.name();           // "getWeather"
    String arguments = req.arguments();      // {"city": "上海"}
    
    // 执行工具并返回结果
    String result = new WeatherTools().getWeather("上海");
    
    // 将工具结果发回模型
    ToolExecutionResultMessage resultMessage = 
        ToolExecutionResultMessage.from(req, result);
    
    ChatResponse finalResponse = model.chat(
        UserMessage.from("上海天气如何?"),
        aiMessage,
        resultMessage
    );
    System.out.println(finalResponse.aiMessage().text());
}
3.4.3 ToolProvider:动态工具发现

当工具集需要动态确定时(例如根据用户权限显示不同工具),可以使用 ToolProvider 接口:

ToolProvider dynamicProvider = (memoryId, messages) -> {
    // 根据用户身份动态决定可用工具
    if (isAdmin(memoryId)) {
        return List.of(adminTools, commonTools);
    } else {
        return List.of(commonTools);
    }
};

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .toolProvider(dynamicProvider)
    .build();

3.5 Chat Memory:让对话有记忆

在实际应用中,用户期望 AI 助手能够"记住"之前的对话内容。LangChain4j 的 ChatMemory 机制正是为此设计的。

3.5.1 核心接口

ChatMemory 接口定义了四个方法:id()(获取记忆 ID)、add(ChatMessage)(添加消息)、messages()(获取所有消息)和 clear()(清空记忆)。它的设计思路是:在每次对话前后,自动管理消息列表的增删。

3.5.2 两种内置实现

LangChain4j 提供了两种开箱即用的记忆实现,分别适用于不同场景:

MessageWindowChatMemory 基于消息数量进行淘汰。设置 maxMessages=20 表示最多保留 20 条消息,超出后最早的消息会被移除。实现简单,适合对话轮次相对固定的场景:

ChatMemory memory = MessageWindowChatMemory.builder()
    .id("user-123")
    .maxMessages(20)
    .build();

TokenWindowChatMemory 基于 Token 数量进行淘汰。设置 maxTokens=3000 表示保留的消息总 Token 数不超过 3000,需要配合 Tokenizer 使用。这种方式更精确,适合需要严格控制上下文窗口大小的场景:

ChatMemory memory = TokenWindowChatMemory.builder()
    .id("user-123")
    .maxTokens(3000)
    .tokenizer(new OpenAiTokenizer())
    .build();
3.5.3 持久化存储

默认情况下,ChatMemory 将消息保存在内存中,应用重启后记忆会丢失。对于生产环境,你需要实现 ChatMemoryStore 接口来提供持久化存储:

class DatabaseChatMemoryStore implements ChatMemoryStore {
    
    private final JdbcTemplate jdbc; // 或使用你喜欢的 ORM
    
    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        // 从数据库加载消息
        return jdbc.query(
            "SELECT message_json FROM chat_messages WHERE memory_id = ? ORDER BY created_at",
            (rs, i) -> ChatMessageDeserializer.messageFromJson(rs.getString(1)),
            memoryId.toString()
        );
    }
    
    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> messages) {
        // 全量更新(先删后插)
        jdbc.update("DELETE FROM chat_messages WHERE memory_id = ?", memoryId.toString());
        for (ChatMessage msg : messages) {
            jdbc.update(
                "INSERT INTO chat_messages (memory_id, message_json, created_at) VALUES (?, ?, ?)",
                memoryId.toString(),
                ChatMessageSerializer.messageToJson(msg),
                LocalDateTime.now()
            );
        }
    }
    
    @Override
    public void deleteMessages(Object memoryId) {
        jdbc.update("DELETE FROM chat_messages WHERE memory_id = ?", memoryId.toString());
    }
}

// 使用持久化存储
ChatMemory memory = MessageWindowChatMemory.builder()
    .id("user-123")
    .maxMessages(50)
    .chatMemoryStore(new DatabaseChatMemoryStore(dataSource))
    .build();
3.5.4 记忆的特殊处理

ChatMemory 在处理不同类型的消息时有一些需要注意的细节。SystemMessage 始终保留在消息列表的最前面,不会被淘汰策略移除。ToolExecutionRequestMessageToolExecutionResultMessage 成对出现,如果被截断会导致模型报错,框架会自动处理这种边界情况以确保消息对的完整性。

3.6 RAG:检索增强生成

RAG(Retrieval Augmented Generation,检索增强生成)是当前 LLM 应用中最核心的模式之一。它通过在生成回复前先从外部知识库中检索相关信息,解决了模型"知识过时"和"幻觉"两大问题。LangChain4j 对 RAG 提供了完整的管道式支持。

3.6.1 RAG 全流程架构
ChatModel ContentInjector EmbeddingModel EmbeddingStore ContentRetriever QueryTransformer RetrievalAugmentor 用户 ChatModel ContentInjector EmbeddingModel EmbeddingStore ContentRetriever QueryTransformer RetrievalAugmentor 用户 用户提问 1. 查询转换(可选) 2. 转换后的查询 3. 文本 → 向量 4. 返回嵌入向量 5. 向量相似度检索 6. 返回相关文档片段 7. 检索到的内容 8. 将内容注入 Prompt 9. 增强后的 Prompt 10. 发送增强请求 11. 生成回答 12. 返回回答

整个 RAG 流程可以概括为四个阶段:预处理(文档加载与分割)、索引(嵌入并存储)、检索(根据查询找到相关内容)和生成(将检索结果注入 Prompt 让模型生成回答)。

3.6.2 文档加载与分割

RAG 的第一步是将原始文档转化为可被嵌入模型处理的文本片段。LangChain4j 提供了 DocumentLoaderDocumentSplitter 两个核心接口。

// 1. 加载文档
Document document = FileSystemDocumentLoader.loadDocument(
    Path.of("docs/company-handbook.pdf"),
    new ApachePdfBoxDocumentParser()
);

// 2. 分割文档
DocumentSplitter splitter = DocumentSplitters.recursive(
    500,    // 每个片段的最大 Token 数
    50      // 相邻片段的重叠 Token 数(保证语义连续性)
);

List<TextSegment> segments = splitter.split(document);
// 例如一份 50 页的 PDF 可能被分割为 200+ 个 TextSegment

DocumentSplitters.recursive() 是最常用的分割器,它采用递归策略:先尝试按段落分割,如果片段仍然太长,则按句子分割,最后按字符分割。重叠参数(overlap)确保相邻片段之间有一定的上下文延续性,避免关键信息被截断在片段边界。

LangChain4j 还支持多种文档格式的加载:通过 ApachePdfBoxDocumentParser 解析 PDF,通过 ApacheTikaDocumentParser 解析 Word、Excel、HTML 等格式,通过 TextDocumentParser 处理纯文本和 Markdown。

3.6.3 嵌入与存储

分割后的文本片段需要转化为向量(嵌入)并存入向量数据库:

// 创建嵌入模型(以 OpenAI 为例)
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("text-embedding-3-small")
    .build();

// 创建向量存储(以内存存储为例,生产环境应使用 Pinecone/Milvus 等)
EmbeddingStore<TextSegment> embeddingStore = InMemoryEmbeddingStore.fromExisting(
    embeddingModel.embed(segments).content(),
    segments
);

// 更常见的做法:先创建空存储,再批量添加
EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
store.addAll(
    embeddingModel.embedAll(segments).content(),
    segments
);

在生产环境中,你通常会使用专门的向量数据库而非内存存储。以 PostgreSQL + pgvector 为例:

EmbeddingStore<TextSegment> pgStore = PgVectorEmbeddingStore.builder()
    .host("localhost")
    .port(5432)
    .database("ai_app")
    .user("postgres")
    .password("secret")
    .table("embeddings")
    .dimension(1536) // 嵌入向量的维度,取决于所用模型
    .build();
3.6.4 构建 RAG 服务

有了嵌入存储,就可以构建完整的 RAG 服务了:

// 1. 创建内容检索器
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
    .embeddingStore(store)
    .embeddingModel(embeddingModel)
    .maxResults(5)          // 每次检索返回最相关的 5 个片段
    .minScore(0.7)          // 最低相似度阈值
    .build();

// 2. 创建 RAG 增强器
RetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
    .contentRetriever(retriever)
    .build();

// 3. 构建带 RAG 能力的 AI 服务
interface KnowledgeAssistant {
    @SystemMessage("""
        你是一个企业知识库助手。
        请基于提供的上下文信息回答用户问题。
        如果上下文中没有相关信息,请如实告知。
        """)
    String answer(@UserMessage String question);
}

KnowledgeAssistant assistant = AiServices.builder(KnowledgeAssistant.class)
    .chatLanguageModel(chatModel)
    .retrievalAugmentor(augmentor)
    .build();

String answer = assistant.answer("公司的年假政策是什么?");
// 框架自动从知识库检索相关文档,注入到 Prompt 中,模型基于文档回答
3.6.5 高级 RAG 特性

LangChain4j 的 RAG 管道在每个环节都支持自定义扩展:

查询转换(QueryTransformer) 可以在检索前对用户查询进行改写。例如 CompressingQueryTransformer 会先用 LLM 将多轮对话中的上下文依赖解析出来,把"它怎么用?"这样的模糊查询改写为"LangChain4j 的 RAG 怎么使用?"这样的明确查询。

多路检索 支持同时从多个 ContentRetriever 中检索内容并合并结果,适合知识库分布在多个来源的场景。

内容注入定制(ContentInjector) 可以控制检索到的内容如何被注入到 Prompt 中。默认实现将内容附加在用户消息之前,你可以自定义格式:

ContentInjector customInjector = DefaultContentInjector.builder()
    .promptTemplate("""
        用户问题:{{userMessage}}
        
        以下是相关的参考资料:
        {{contents}}
        
        请基于上述参考资料回答问题,并在回答中标注信息来源。
        """)
    .build();

3.7 结构化输出:让 AI 返回 Java 对象

在大多数实际应用中,你需要的不是自由文本,而是结构化的数据。例如,从一段用户评论中提取情感评分和关键词,或者将一个自然语言描述转化为数据库查询条件。LangChain4j 支持将模型的输出自动映射为 Java 对象。

3.7.1 返回 POJO

通过 AI Services,你只需要将方法的返回类型定义为你想要的 Java 类,框架会自动指导模型输出 JSON 并反序列化为对象:

// 定义目标类
class SentimentResult {
    private String sentiment;     // "positive", "negative", "neutral"
    private double confidence;    // 0.0 ~ 1.0
    private List<String> keywords;
    // getter/setter 省略
}

interface SentimentAnalyzer {
    @UserMessage("分析以下文本的情感倾向:{{it}}")
    SentimentResult analyze(String text);
}

SentimentAnalyzer analyzer = AiServices.builder(SentimentAnalyzer.class)
    .chatLanguageModel(model)
    .build();

SentimentResult result = analyzer.analyze("这个产品太棒了,我非常喜欢!");
// result.sentiment == "positive"
// result.confidence == 0.95
// result.keywords == ["产品", "喜欢"]

框架内部会根据返回类型的字段结构,自动生成 JSON Schema 并附加到 Prompt 中,指导模型输出符合格式的 JSON,然后使用 Jackson 进行反序列化。

3.7.2 返回集合与枚举

结构化输出不仅支持单个对象,还支持集合和枚举类型:

interface DataExtractor {
    @UserMessage("从以下文本中提取所有人名和职位:{{it}}")
    List<PersonInfo> extractPeople(String text);
    
    @UserMessage("判断以下邮件属于哪个类别:{{it}}")
    EmailCategory classifyEmail(String email);
}

class PersonInfo {
    private String name;
    private String position;
}

enum EmailCategory {
    SPAM, INQUIRY, COMPLAINT, FEEDBACK, OTHER
}

3.8 流式输出:逐字响应用户体验

在聊天机器人等交互场景中,等待模型生成完整回复再一次性返回会让用户感到焦虑。流式输出(Streaming)让模型的回复像打字一样逐字显示,大幅提升用户体验。

3.8.1 StreamingChatModel

LangChain4j 通过 StreamingChatModel 接口支持流式输出:

StreamingChatModel streamingModel = OpenAiStreamingChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("gpt-4o")
    .build();

streamingModel.chat("给我讲一个故事", new StreamingChatResponseHandler() {
    @Override
    public void onPartialResponse(String partialResponse) {
        // 每收到一个 Token 就触发一次,逐步输出
        System.out.print(partialResponse);
    }
    
    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        System.out.println("\n--- 生成完毕 ---");
        System.out.println("Token 使用: " + completeResponse.tokenUsage());
    }
    
    @Override
    public void onError(Throwable error) {
        System.err.println("生成出错: " + error.getMessage());
    }
});
3.8.2 AI Services 中的流式

在 AI Services 中,只需要将方法的返回类型声明为 TokenStream 即可获得流式能力:

interface StoryTeller {
    @UserMessage("给我讲一个关于{{it}}的故事")
    TokenStream tellStory(String topic);
}

StoryTeller storyTeller = AiServices.builder(StoryTeller.class)
    .streamingChatLanguageModel(streamingModel)
    .build();

TokenStream stream = storyTeller.tellStory("一只会编程的猫");

// 使用 TokenStream 处理流式响应
stream.onPartialResponse(token -> System.out.print(token))
      .onCompleteResponse(response -> System.out.println("\nDone!"))
      .onError(error -> error.printStackTrace())
      .start();

3.9 多模态:图片、音频与文档

从 1.0.0 版本开始,LangChain4j 全面支持多模态输入。UserMessage 可以携带多种类型的 Content

// 图片 + 文字
UserMessage imageMessage = UserMessage.from(
    TextContent.from("请描述这张图片的内容"),
    ImageContent.from("https://example.com/photo.jpg")
);

// Base64 编码的图片
UserMessage base64Message = UserMessage.from(
    TextContent.from("这张图片里有什么?"),
    ImageContent.from(base64EncodedBytes, "image/png")
);

// 音频输入
UserMessage audioMessage = UserMessage.from(
    TextContent.from("请转录这段音频"),
    AudioContent.from(audioBytes, "audio/wav")
);

// PDF 文档
UserMessage pdfMessage = UserMessage.from(
    TextContent.from("请总结这份文档的要点"),
    PdfFileContent.from(pdfBytes, "report.pdf")
);

// 发送给模型
ChatResponse response = model.chat(imageMessage);

需要注意的是,多模态能力取决于所使用的模型是否支持。GPT-4o、Claude 3、Gemini 等模型支持图片输入,而音频和 PDF 支持则因模型而异。

3.10 Guardrails:输入输出安全护栏

在生产环境中,你无法完全信任用户的输入,也不能完全依赖模型的输出。Guardrails 机制让你在 AI 交互的入口和出口设置安全检查点。

3.10.1 输入护栏
// 定义输入护栏
class InputGuardrail implements InputGuardrail {
    
    @Override
    public Result validate(UserMessage userMessage) {
        String text = userMessage.singleText();
        
        // 检查是否包含敏感信息
        if (containsPII(text)) {
            return Result.failure("输入包含个人敏感信息,请脱敏后重试");
        }
        
        // 检查是否为 Prompt 注入攻击
        if (isPromptInjection(text)) {
            return Result.failure("检测到潜在的 Prompt 注入攻击");
        }
        
        return Result.success();
    }
}
3.10.2 输出护栏
class OutputGuardrail implements OutputGuardrail {
    
    @Override
    public Result validate(AiMessage aiMessage) {
        String text = aiMessage.text();
        
        // 检查是否泄露了系统指令
        if (leaksSystemPrompt(text)) {
            return Result.failure("输出包含系统指令信息");
        }
        
        // 检查是否包含不当内容
        if (containsInappropriateContent(text)) {
            return Result.successWithAlternate(
                AiMessage.from("抱歉,我无法提供该信息。请问有其他问题吗?")
            );
        }
        
        return Result.success();
    }
}
3.10.3 集成到 AI Services
Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .guardrails(new InputGuardrail(), new OutputGuardrail())
    .build();

Result 有四种状态:success()(通过)、successWithAlternate()(通过但使用替代响应)、failure()(失败,返回错误信息)和 fatal()(严重失败,立即中断)。多个 Guardrail 可以组成链,按优先级依次执行。

3.11 MCP 协议:标准化的工具集成

MCP(Model Context Protocol)是 Anthropic 主导的开放协议,旨在标准化 LLM 与外部工具和数据源的连接方式,可以类比为 AI 世界的"USB 接口"。LangChain4j 正在积极支持 MCP 协议,让你可以通过标准化的方式接入各种外部工具服务,而不需要为每个工具编写自定义的集成代码。

MCP 的核心思想是将工具提供方封装为 MCP Server,工具使用方(你的 AI 应用)作为 MCP Client。通过 MCP 协议,Client 可以发现 Server 提供的工具列表、调用工具并获取结果,整个过程遵循统一的通信规范。

// MCP 集成示例(概念性,API 仍在演进中)
McpClient mcpClient = McpClient.builder()
    .transport(new StdioTransport("npx", "-y", "@modelcontextprotocol/server-filesystem", "/data"))
    .build();

// 从 MCP Server 发现可用工具
List<ToolSpecification> tools = mcpClient.listTools();

// 将 MCP 工具注册到 AI Services
Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .toolProvider(mcpClient.toToolProvider())
    .build();

MCP 的价值在于,一次集成、处处可用。你只需要为你的 MCP Server 实现一次标准接口,就可以在任何支持 MCP 的 AI 框架中使用,包括 LangChain4j。

本节要点:LangChain4j 的核心能力覆盖了 LLM 应用开发的全部关键环节——对话(ChatModel)、声明式编程(AI Services)、工具调用(Tool Calling)、记忆管理(Chat Memory)、知识增强(RAG)、结构化输出、流式响应、多模态、安全护栏和标准化工具集成(MCP)。每项能力都有低层和高层两种使用方式。


第四部分:生产级实战模式

章节导读:能跑通 Demo 和能上线生产之间,隔着一道巨大的鸿沟。这一部分我们聚焦如何将 LangChain4j 应用到真实的生产环境中——框架集成、监控、容错、性能和安全。

4.1 与 Spring Boot 深度集成

Spring Boot 是 Java 生态中最主流的应用框架,LangChain4j 提供了专门的 Spring Boot Starter,让集成变得几乎零配置。

4.1.1 引入 Starter
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-spring-boot-starter</artifactId>
    <version>1.15.1</version>
</dependency>
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
    <version>1.15.1</version>
</dependency>
4.1.2 配置化

Spring Boot Starter 支持通过 application.yml 配置模型参数,无需手写 Bean:

langchain4j:
  open-ai:
    chat-model:
      api-key: ${OPENAI_API_KEY}
      model-name: gpt-4o
      temperature: 0.7
      max-tokens: 2000
    streaming-chat-model:
      api-key: ${OPENAI_API_KEY}
      model-name: gpt-4o
    embedding-model:
      api-key: ${OPENAI_API_KEY}
      model-name: text-embedding-3-small
4.1.3 声明式 AI Service Bean

在 Spring Boot 中,你可以将 AI Service 注册为 Spring Bean,享受依赖注入和 AOP 的能力:

@Configuration
public class AiConfig {
    
    @Bean
    CustomerService customerService(ChatModel chatModel, ChatMemory chatMemory) {
        return AiServices.builder(CustomerService.class)
            .chatLanguageModel(chatModel)
            .chatMemory(chatMemory)
            .tools(new OrderTools(), new ProductTools())
            .build();
    }
    
    @Bean
    ChatMemory chatMemory() {
        return MessageWindowChatMemory.builder()
            .maxMessages(30)
            .chatMemoryStore(new RedisChatMemoryStore(redisTemplate))
            .build();
    }
}

4.2 可观测性与监控

在生产环境中运行 AI 应用,你需要知道每次调用的延迟、Token 消耗、错误率和成本。LangChain4j 本身不内置 Dev UI,但提供了与标准可观测性工具集成的能力。

Token 使用追踪。每次 ChatModel 调用返回的 ChatResponse 都包含 TokenUsage 信息。你可以在拦截器或 AOP 切面中收集这些数据:

@Aspect
@Component
public class AiObservabilityAspect {
    
    private final MeterRegistry meterRegistry;
    
    @Around("execution(* dev.langchain4j.model.chat.ChatModel.chat(..))")
    public Object trackAiCall(ProceedingJoinPoint pjp) throws Throwable {
        Timer.Sample sample = Timer.start(meterRegistry);
        
        try {
            ChatResponse response = (ChatResponse) pjp.proceed();
            
            // 记录 Token 使用
            TokenUsage usage = response.tokenUsage();
            meterRegistry.counter("ai.tokens.input", "model", "gpt-4o")
                .increment(usage.inputTokenCount());
            meterRegistry.counter("ai.tokens.output", "model", "gpt-4o")
                .increment(usage.outputTokenCount());
            
            // 记录成本估算
            double cost = estimateCost(usage);
            meterRegistry.counter("ai.cost", "model", "gpt-4o")
                .increment(cost);
            
            sample.stop(meterRegistry.timer("ai.call.duration", "model", "gpt-4o"));
            return response;
        } catch (Exception e) {
            meterRegistry.counter("ai.call.errors", "model", "gpt-4o").increment();
            throw e;
        }
    }
}

在 Spring Boot 中,结合 Micrometer + Prometheus + Grafana,你可以构建一个完整的 AI 调用监控仪表盘,追踪 QPS、P99 延迟、Token 消耗趋势和成本曲线。

4.3 错误处理与弹性设计

LLM 调用天然具有不确定性——网络超时、速率限制、模型过载、输出格式异常等。生产级应用必须为此做好弹性设计。

重试策略。对于临时性错误(429 Too Many Requests、503 Service Unavailable),使用指数退避重试:

// 使用 Resilience4j 配合 LangChain4j
RetryConfig retryConfig = RetryConfig.custom()
    .maxAttempts(3)
    .waitDuration(Duration.ofSeconds(2))
    .retryExceptions(RateLimitException.class, ServiceUnavailableException.class)
    .build();

Retry retry = Retry.of("aiModelRetry", retryConfig);

ChatModel resilientModel = Retry.decorateCheckedSupplier(retry, 
    () -> chatModel.chat(messages)).unchecked();

超时控制。为每次模型调用设置超时时间,避免用户长时间等待:

ChatModel model = OpenAiChatModel.builder()
    .apiKey(apiKey)
    .modelName("gpt-4o")
    .timeout(Duration.ofSeconds(30)) // 30秒超时
    .build();

降级策略。当模型不可用时,提供合理的降级响应:

try {
    return assistant.chat(userMessage);
} catch (Exception e) {
    log.warn("AI 服务不可用,返回降级响应", e);
    return "抱歉,当前服务繁忙,请稍后重试。您也可以拨打客服热线 400-xxx-xxxx。";
}

4.4 性能优化策略

连接池管理。HTTP 客户端的连接池配置直接影响调用延迟。建议使用支持连接池的 HTTP 客户端,并合理配置最大连接数、空闲超时等参数。

缓存层。对于相似的查询,可以缓存模型的响应以减少 API 调用。这在 RAG 场景中尤其有用——对相似的查询,检索结果和模型响应往往是一样的:

// 使用 Caffeine 缓存
Cache<String, String> responseCache = Caffeine.newBuilder()
    .maximumSize(10000)
    .expireAfterWrite(Duration.ofHours(1))
    .build();

String cachedAnswer = responseCache.get(queryHash, key -> assistant.chat(key));

异步与并行。在 Spring Boot 中使用 @Async 或 CompletableFuture 实现异步 AI 调用,避免阻塞主线程。在 RAG 场景中,可以并行从多个数据源检索内容,然后合并结果。

上下文窗口优化。Token 数量直接影响调用成本和延迟。合理设置 ChatMemory 的窗口大小,只保留必要的上下文信息。使用 TokenWindowChatMemory 而非 MessageWindowChatMemory 可以更精确地控制 Token 消耗。

4.5 安全最佳实践

API Key 管理。永远不要在代码中硬编码 API Key。使用环境变量、配置中心(如 Spring Cloud Config、Vault)或云平台的密钥管理服务。

输入验证与清洗。在将用户输入发送给模型之前,进行基本的验证和清洗——限制输入长度、过滤特殊字符、检测 Prompt 注入攻击。

输出过滤。模型可能生成包含敏感信息、不当内容或有害建议的回复。使用 Guardrails 机制对输出进行过滤和审核。

速率限制。为每个用户设置调用频率限制,防止滥用和成本失控。可以使用令牌桶或滑动窗口算法。

审计日志。记录每次 AI 交互的输入、输出、模型版本和 Token 消耗,用于合规审计和问题追溯。

4.6 测试策略

AI 应用的测试比传统应用更具挑战性,因为模型的输出具有不确定性。推荐的测试策略分三层:

单元测试。使用 Mock 替换 ChatModel,验证 AI Services 的注解解析、记忆管理和工具调用流程是否正确:

@Test
void shouldCallWeatherTool() {
    ChatModel mockModel = mock(ChatModel.class);
    when(mockModel.chat(any(ChatRequest.class)))
        .thenReturn(ChatResponse.from(
            AiMessage.from("北京今天晴朗,25°C")
        ));
    
    WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
        .chatLanguageModel(mockModel)
        .tools(new WeatherTools())
        .build();
    
    String answer = assistant.chat("北京天气如何?");
    assertNotNull(answer);
}

集成测试。使用 Testcontainers 启动真实的向量数据库(如 pgvector),验证 RAG 管道的端到端流程。可以使用 OpenAI 的 Sandbox 环境或本地 Ollama 模型进行低成本集成测试。

评估测试(Eval)。定义一组标准的测试用例和评估指标(准确性、相关性、安全性等),定期运行评估套件,追踪模型表现的变化趋势。这通常需要在 CI/CD 流程中集成评估脚本。

本节要点:从 Demo 到生产,需要补齐框架集成(Spring Boot Starter)、可观测性(Token 追踪 + Micrometer)、弹性设计(重试 + 超时 + 降级)、性能优化(缓存 + 异步 + 上下文优化)、安全(密钥管理 + Guardrails)和测试(单元 + 集成 + 评估)这六个维度的能力。


第五部分:生态版图与未来展望

章节导读:技术选型不是只看单个框架的好坏,还要看它所在的生态。这一部分我们审视 LangChain4j 在 Java AI 生态中的位置,与竞争方案的对比,以及未来的发展方向。

5.1 框架集成全景图

LangChain4j 的框架集成覆盖了 Java 生态的主流选项:

框架 集成模块 成熟度 特点
Spring Boot langchain4j-spring-boot-starter 自动配置、属性绑定、Actuator 端点
Quarkus langchain4j-quarkus 原生镜像支持、Dev UI、构建时优化
Micronaut langchain4j-micronaut AOT 编译、低内存占用
Helidon langchain4j-helidon Oracle 生态、云原生

此外,LangChain4j 还可以与任何纯 Java 应用集成——它不依赖任何 IoC 容器,核心库的传递依赖极少。

5.2 LangChain4j vs Spring AI vs Python LangChain

这是 Java 开发者最常面对的技术选型问题。以下是三个框架的全方位对比:

维度 LangChain4j Spring AI Python LangChain
定位 框架无关的 LLM 应用库 Spring 生态原生 AI 框架 Python LLM 应用框架
设计理念 “Java 程序员不应被框架绑架” “让 AI 成为 Spring 的一等公民” “快速原型到生产”
API 风格 接口 + 注解 + Builder Bean + 自动配置 + Advisors 链式调用 + LCEL
框架绑定 无(可选集成 Spring/Quarkus 等) 强绑定 Spring Boot 无框架概念
高层抽象 AI Services(动态代理) Advisors API Chains / Agents
RAG 能力 完整管道,高度可定制 通过 Advisor 实现,较简洁 最丰富,生态最完善
Tool Calling @Tool 注解 + ToolProvider @Tool + FunctionCallback @tool 装饰器
结构化输出 自动映射返回类型 BeanOutputConverter with_structured_output
流式支持 StreamingChatModel + TokenStream Flux 响应式 Streaming 回调
MCP 支持 积极开发中 通过 Spring AI MCP 支持 完善
向量存储 30+ 集成模块 15+ 集成模块 40+ 集成模块
可观测性 需手动集成 OpenTelemetry Micrometer 开箱即用 LangSmith / LangFuse
社区规模 12k+ Stars 3k+ Stars 100k+ Stars
学习曲线 中等 低(如果熟悉 Spring) 低(如果熟悉 Python)
适合场景 复杂 AI 应用、多框架项目 Spring Boot 项目快速集成 快速原型、研究实验

选择建议

如果你的项目是 Spring Boot 单体应用,且 AI 需求相对简单(对话 + 基础 RAG),Spring AI 是更自然的选择——它与 Spring 生态的无缝集成体验无出其右。

如果你需要构建复杂的 AI 应用(多 Agent 协作、高级 RAG 管道、精细的 Tool Calling 控制),或者项目使用了非 Spring 框架,或者你需要在不同框架之间保持一致的 AI 开发体验,LangChain4j 是更合适的选择——它的框架无关设计和更深层的可定制性在复杂场景中优势明显。

如果你的团队以 Python 为主,或者需要最快的技术迭代速度和最丰富的生态,Python LangChain 仍然是当前最成熟的选择。

实际上,LangChain4j 和 Spring AI 并非完全互斥。LangChain4j 提供了 Spring Boot Starter,你可以在 Spring 项目中使用 LangChain4j 的能力。两者也可以在同一项目中共存——用 Spring AI 处理简单的 AI 任务,用 LangChain4j 处理需要更精细控制的复杂场景。

5.3 社区生态与插件

LangChain4j 的社区生态在快速成长中。官方维护的 langchain4j-examples 仓库包含了数十个覆盖各种使用场景的示例项目。在社区方面,中文开发者社区对 LangChain4j 的关注度持续增长,CSDN、掘金等平台上已有大量高质量的教程和实践文章。

LangChain4j 的 GitHub Discussions 和 Discord 频道是获取帮助和参与讨论的主要渠道。项目的贡献者群体在持续扩大,新的集成模块和功能 PR 保持着稳定的提交频率。

5.4 版本演进与路线图

LangChain4j 的版本演进经历了几个关键里程碑:

0.x 时代(2023-2024):快速迭代期。核心架构成型,AI Services 概念确立,大量集成模块上线。

1.0.0-beta 系列(2024):走向稳定。包结构统一为 dev.langchain4jLanguageModel 拆分为 ChatModelStreamingChatModel,新增 JSON Schema 结构化输出和多模态支持。

1.0.0 正式版(2025):API 稳定性承诺。标志着框架进入生产就绪状态,后续版本遵循语义化版本控制。

1.x 持续迭代(2025-2026):截至 1.15.1 版本,持续增加新的集成模块、性能优化和 MCP 支持等前沿特性。Agent 能力(langchain4j-agentic)作为独立模块正在积极开发中。

未来的发展方向预计将集中在以下几个方面:Agent 能力的成熟化(多 Agent 协作、Agent 编排)、MCP 协议的全面支持、更完善的可观测性集成、评估框架的内置化,以及对更多新兴模型提供商的快速适配。

本节要点:LangChain4j 在 Java AI 框架生态中占据着独特的"框架无关"定位,与 Spring AI 形成互补而非对立。选择哪个框架取决于你的项目架构和 AI 需求复杂度。框架本身保持着活跃的迭代节奏,社区生态在持续壮大。


附录

A:核心依赖速查表

功能需求 Maven ArtifactId 说明
核心库 langchain4j 包含 AI Services、ChatMemory、RAG 等核心功能
核心抽象 langchain4j-core 仅包含接口定义,不含实现
OpenAI langchain4j-open-ai GPT-4o、GPT-4、text-embedding-3 等
Anthropic langchain4j-anthropic Claude 3.5/3 系列
Google Gemini langchain4j-google-ai-gemini Gemini Pro/Ultra
Ollama langchain4j-ollama 本地模型(Llama、Mistral 等)
通义千问 langchain4j-dashscope 阿里云 DashScope
文心一言 langchain4j-qianfan 百度千帆平台
Pinecone langchain4j-pinecone 云端向量数据库
Milvus langchain4j-milvus 开源向量数据库
pgvector langchain4j-pgvector PostgreSQL 向量扩展
Chroma langchain4j-chroma 轻量级向量数据库
Spring Boot langchain4j-spring-boot-starter Spring Boot 自动配置
PDF 解析 langchain4j-document-parser-apache-pdfbox 基于 PDFBox
通用文档解析 langchain4j-document-parser-apache-tika 基于 Apache Tika
本地嵌入模型 langchain4j-embeddings-all-minilm-l6-v2 无需 API Key 的嵌入模型

B:常见问题与排错指南

Q:ChatLanguageModelChatModel 有什么区别?
ChatLanguageModel 是 0.x 版本的旧接口,从 1.0.0-beta 开始被 ChatModel 取代。如果你使用的是 1.x 版本,请统一使用 ChatModel。新接口设计更加简洁,并增加了对多模态和结构化输出的原生支持。

Q:AI Services 的方法返回类型支持哪些?
支持的返回类型包括:String(纯文本)、自定义 POJO(结构化输出)、List<T>(集合)、Enum(枚举值)、TokenStream(流式输出)和 Response<T>(包含元数据的完整响应)。

Q:Tool Calling 不生效怎么办?
首先检查 @Tool 注解的方法是否为 public;其次确认工具描述(@Tool 的字符串参数)足够清晰,模型需要根据描述来判断何时调用;最后确认你使用的模型支持 Tool Calling 功能(GPT-4o、Claude 3、Gemini 等主流模型均支持)。

Q:RAG 检索结果不相关怎么办?
调整 minScore 阈值(降低以获得更多结果,或升高以获得更精确的结果);检查 DocumentSplitter 的参数设置(片段过大可能包含太多噪声,过小可能丢失上下文);尝试使用 CompressingQueryTransformer 改写查询;考虑更换嵌入模型以获得更好的语义表示。

Q:如何在不使用 OpenAI 的情况下本地运行?
使用 Ollama 集成本地模型。安装 Ollama 后拉取模型(如 ollama pull llama3),然后使用 OllamaChatModel.builder().baseUrl("http://localhost:11434").modelName("llama3").build() 创建模型实例。本地模型无需 API Key,适合开发和测试。

Q:如何处理多用户并发场景?
AI Services 是线程安全的,可以安全地在多线程环境中使用。关键是使用 @MemoryId 注解为每个用户分配独立的记忆空间,并为 ChatMemoryStore 使用线程安全的存储实现(如数据库或 Redis)。

C:术语表

术语 说明
ChatModel LangChain4j 中与 LLM 进行对话交互的核心接口
StreamingChatModel 支持流式输出的对话模型接口
AI Services 通过 Java 接口 + 注解实现声明式 AI 编程的高层抽象
EmbeddingModel 将文本转化为向量(嵌入)的模型接口
EmbeddingStore 存储和检索向量的接口,对接各类向量数据库
ChatMemory 管理对话历史消息的接口
ChatMemoryStore ChatMemory 的持久化存储接口
Tool Calling 让 LLM 在生成过程中调用外部函数/工具的能力
RAG Retrieval Augmented Generation,检索增强生成
RetrievalAugmentor RAG 流程的核心编排器
ContentRetriever 从数据源检索相关内容的接口
DocumentSplitter 将文档分割为较小文本片段的接口
Guardrails 对 AI 输入/输出进行安全检查的护栏机制
TokenStream 流式输出的 Token 流对象
MCP Model Context Protocol,模型上下文协议,标准化工具集成
TextSegment 文本片段,文档分割后的最小单元
Tokenizer 将文本分解为 Token 的工具,用于计算 Token 数量
Prompt Template 带有占位符的 Prompt 模板,运行时动态填充变量

D:学习路线图

入门阶段

进阶阶段

高级阶段

专家阶段

理解 ChatModel 基本用法

完成第一个 AI 对话

使用 AI Services 简化代码

掌握 Tool Calling

实现 ChatMemory

构建基础 RAG 管道

结构化输出

高级 RAG 定制

多 Agent 协作

流式输出 + 多模态

生产级错误处理

自定义核心组件实现

可观测性体系搭建

评估框架设计

性能调优与成本控制

入门阶段(1-2 天):从本文的 3.1 和 3.2 节开始,跑通第一个 AI 对话示例,理解 ChatModelChatMessageChatResponse 的关系。然后学习 3.3 节的 AI Services,体会声明式编程的简洁。

进阶阶段(1-2 周):依次掌握 Tool Calling(3.4)、Chat Memory(3.5)、RAG(3.6)和结构化输出(3.7),能够独立构建一个带知识库的 AI 助手。

高级阶段(1-2 月):深入学习高级 RAG 定制(查询转换、多路检索)、流式输出(3.8)、多模态(3.9)、Guardrails(3.10),以及第四部分的所有生产模式。

专家阶段(持续精进):阅读 LangChain4j 源码,理解动态代理、RAG 管道等核心机制的实现细节。为社区贡献代码,参与新特性的设计和讨论。构建企业级的 AI 应用平台,沉淀可复用的 AI 组件库。


本文基于 LangChain4j 1.15.1 版本编写。框架在持续迭代中,部分 API 可能在后续版本中发生变化。建议始终以 官方文档GitHub 仓库 为准。

Logo

一座年轻的奋斗人之城,一个温馨的开发者之家。在这里,代码改变人生,开发创造未来!

更多推荐