2025 最新版 · v1.0+

LangChain4j 完全指南
从零开始构建 AI 驱动的 Java 应用

这是一份面向零基础开发者的交互式教程。你将学会如何使用 LangChain4j 这个强大的 Java 库,把大语言模型(LLM)集成到你的应用中——从简单的对话聊天,到工具调用、RAG 检索增强生成、多模态处理,再到完整的 AI Agent 构建。

一、开篇概览

LangChain4j 是一个开源 Java 库,它的使命很简单:让 Java 开发者能够轻松地将大语言模型(LLM)集成到自己的应用中

想象一下,你想在自己的 Java 项目里加入"AI 对话"功能、让 AI 帮你查询数据库、或者基于公司内部文档自动回答用户问题——这些以前要写大量胶水代码的事情,LangChain4j 帮你用几行代码就搞定了。

💡 一句话总结
LangChain4j = 统一的 LLM API + 丰富的工具箱(Prompt 模板、对话记忆、RAG、Tool 调用、Agent 等),专为 Java 生态设计。

与同类库对比

LangChain4j ✦

  • 原生 Java,与 Spring Boot 深度集成
  • 支持 20+ LLM 提供商,30+ 向量数据库
  • 统一 API,一行代码切换模型
  • 完善的类型安全与注解驱动
  • 活跃社区,持续更新

Spring AI

  • Spring 官方出品,配置驱动
  • 深度融合 Spring 生态
  • 相对较新,API 仍在演进
  • 功能覆盖面略窄于 LangChain4j

LangChain (Python)

  • Python 生态最成熟的 LLM 框架
  • 社区最大,教程最多
  • Java 开发者无法直接使用
  • LangChain4j 从中汲取了大量灵感

Semantic Kernel (Java)

  • 微软出品,侧重 Azure 生态
  • Java 版功能不如 C# 版完善
  • 适合重度 Azure 用户

学完本教程,你将掌握

调用各种 LLM(OpenAI / Ollama 等) Prompt 模板设计 流式响应处理 对话记忆管理 AI Services 声明式开发 Tool / 函数调用 RAG 检索增强生成 文档加载与解析 图像与多模态 MCP 协议集成 完整 AI Agent 构建

✅ 本节小结

  • LangChain4j 是 Java 世界最流行的 LLM 集成框架
  • 它提供统一 API,屏蔽底层 LLM 差异
  • 适合所有 Java 开发者,零 AI 基础也能上手

二、环境搭建

开始之前,请确保你的环境满足以下条件:

⚙️ 环境要求
JDK 17+(LangChain4j 最低要求 JDK 17)
Maven 3.8+Gradle 7+
一个 LLM API Key(推荐先用 OpenAI,也可以用免费的 Ollama 本地模型)

添加依赖

LangChain4j 采用模块化设计——你只需引入用到的模块。最常见的组合是「核心库 + OpenAI 集成」:

Maven(推荐)
pom.xml
<!-- 使用 BOM 统一管理版本 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- 核心库(AI Services 等高级 API 需要) -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
    </dependency>

    <!-- OpenAI 集成 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
    </dependency>
</dependencies>
Gradle
build.gradle
dependencies {
    implementation platform('dev.langchain4j:langchain4j-bom:1.0.0')
    implementation 'dev.langchain4j:langchain4j'
    implementation 'dev.langchain4j:langchain4j-open-ai'
}
想用 Ollama(本地免费模型)?

如果你不想花钱买 API Key,可以用 Ollama 在本地运行开源模型。先安装 Ollama(ollama.com),然后拉取一个模型:

# 安装后,拉取模型
ollama pull llama3.2

Maven 依赖改用:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-ollama</artifactId>
</dependency>

最小可运行 Demo

下面这段代码不到 10 行,让你 30 秒看到 AI 回复:

HelloLangChain4j.java
import dev.langchain4j.model.openai.OpenAiChatModel;

public class HelloLangChain4j {
    public static void main(String[] args) {
        // 1. 创建模型实例(替换成你的 API Key)
        var model = OpenAiChatModel.builder()
                .apiKey(System.getenv("OPENAI_API_KEY")) // 从环境变量读取
                .modelName("gpt-4o-mini")
                .build();

        // 2. 发送消息并获取回复
        String answer = model.chat("用一句话解释什么是 Java?");

        // 3. 输出结果
        System.out.println(answer);
    }
}
🎉 运行一下!
在终端设置环境变量 export OPENAI_API_KEY="sk-...",然后运行。如果看到 AI 的回复,恭喜你——环境搭建成功!

如果你用 Ollama,代码改为:

import dev.langchain4j.model.ollama.OllamaChatModel;

var model = OllamaChatModel.builder()
        .baseUrl("http://localhost:11434")
        .modelName("llama3.2")
        .build();

String answer = model.chat("用一句话解释什么是 Java?");
System.out.println(answer);

✅ 本节小结

  • 使用 BOM 统一管理 LangChain4j 版本
  • 核心依赖 = langchain4j(高级 API)+ 具体模型集成包
  • 10 行代码就能完成第一次 AI 对话

三、核心概念

在正式动手之前,让我们先建立 LangChain4j 的心智模型。别担心,我会用生活中的类比来解释。

🏠 总体类比:LangChain4j 就像一个「AI 翻译公司」
想象你要跟来自不同国家的人通信。ChatLanguageModel 就是翻译员(可以换人),Message 是你写的信和收到的回信,Chat Memory 是翻译员的笔记本(记住上下文),AI Services 是一个全自动的翻译服务台(你只要说需求,它帮你安排一切)。

ChatLanguageModel — 翻译员

ChatLanguageModel 是你与 LLM 交互的核心接口。不管底层是 OpenAI、Anthropic 还是 Ollama,它们都实现这个接口。这就是"统一 API"的含义——换模型不需要改业务代码。

// OpenAI 翻译员
ChatLanguageModel openai = OpenAiChatModel.builder()
        .apiKey("sk-...")
        .modelName("gpt-4o-mini")
        .build();

// Ollama 翻译员(本地免费)
ChatLanguageModel ollama = OllamaChatModel.builder()
        .baseUrl("http://localhost:11434")
        .modelName("llama3.2")
        .build();

// 完全相同的调用方式!
String reply = openai.chat("你好");
String reply2 = ollama.chat("你好");

Message 体系 — 信件

LLM 交互的基本单位是消息(Message)。LangChain4j 定义了四种消息类型:

消息类型类比作用
SystemMessage给翻译员的工作说明书设定 AI 的角色和行为规则
UserMessage你写的信用户发给 AI 的消息
AiMessage翻译员的回信AI 的回复
ToolExecutionResultMessage翻译员查资料后的结果工具调用的返回结果
import dev.langchain4j.data.message.*;

// 构建一组消息
SystemMessage system = SystemMessage.from("你是一个友好的 Java 助手");
UserMessage user = UserMessage.from("什么是 Spring Boot?");

// 发送多条消息给模型
ChatResponse response = model.chat(system, user);
AiMessage aiReply = response.aiMessage();
System.out.println(aiReply.text());

AI Services — 全自动服务台

这是 LangChain4j 最强大的高级抽象。你只需定义一个 Java 接口,LangChain4j 帮你生成完整实现——包括消息构建、记忆管理、工具调用等。就像你去银行柜台,只说需求,柜员帮你搞定一切。

// 1. 定义接口(声明式,像写 MyBatis Mapper 一样自然)
interface Assistant {
    String chat(String userMessage);
}

// 2. 让 LangChain4j 生成实现
Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .build();

// 3. 像调用普通 Java 方法一样使用 AI
String answer = assistant.chat("Java 和 Kotlin 有什么区别?");

Chat Memory — 笔记本

LLM 本身是无状态的——每次请求它都"失忆"了。Chat Memory 就是给 AI 配的笔记本,帮它记住之前的对话,这样才能实现连贯的多轮对话。

// MessageWindowChatMemory:只记住最近 N 条消息(滑动窗口)
ChatMemory memory = MessageWindowChatMemory.withMaxMessages(20);

Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .chatMemory(memory) // 装上笔记本
        .build();

assistant.chat("我叫小明");        // AI 记住了
assistant.chat("我叫什么名字?");   // AI: "你叫小明!"

✅ 本节小结

  • ChatLanguageModel:统一的 LLM 调用接口,切换模型零成本
  • Message:四种消息类型构成对话的基本单位
  • AI Services:声明式接口,自动生成 AI 调用逻辑
  • Chat Memory:让 AI 拥有对话记忆能力

四、Prompt 模板

场景:你需要让 AI 根据不同的输入执行相似的任务——比如"翻译成不同语言"、"总结不同的文章"。每次手动拼字符串太累了,而且容易出错。

Prompt 模板就像 Java 的 String.format() 的 AI 版本——你定义一个带占位符的模板,运行时填入变量。

基础用法:PromptTemplate
import dev.langchain4j.model.input.PromptTemplate;

// 定义模板,{{variable}} 是占位符
PromptTemplate template = PromptTemplate.from(
    "请将以下文本翻译成{{language}}:\n\n{{text}}"
);

// 填入变量
Prompt prompt = template.apply(Map.of(
    "language", "日语",
    "text", "今天天气真好"
));

// 发送给模型
String result = model.chat(prompt.text());
System.out.println(result); // 今日はとても良い天気ですね
在 AI Services 中使用模板注解

更优雅的方式是用 @UserMessage 注解直接在接口上定义模板:

import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

interface Translator {

    @UserMessage("请将以下文本翻译成{{language}}:\n\n{{text}}")
    String translate(@V("language") String language,
                     @V("text") String text);
}

Translator translator = AiServices.create(Translator.class, model);
String japanese = translator.translate("日语", "今天天气真好");
String french = translator.translate("法语", "今天天气真好");
系统消息模板 @SystemMessage

你也可以通过 @SystemMessage 注解给 AI 设定角色:

interface Chef {

    @SystemMessage("你是一位米其林三星厨师。用专业但友好的口吻回答关于烹饪的问题。"
        + "如果问题与烹饪无关,礼貌地拒绝。")
    @UserMessage("{{question}}")
    String ask(@V("question") String question);
}

Chef chef = AiServices.create(Chef.class, model);
System.out.println(chef.ask("如何做一道完美的意大利面?"));
System.out.println(chef.ask("请帮我写一段 Python 代码")); // 会被礼貌拒绝
⚠️ 常见坑
占位符拼写错误:模板中的 {{language}} 必须和 @V("language") 完全一致,大小写敏感。
忘记转义:如果你的模板里需要出现双大括号 {{,需要用 \{{ 转义。

✅ 本节小结

  • PromptTemplate.from() 创建带变量的 Prompt 模板
  • @UserMessage + @V 注解让模板写在接口上,更加优雅
  • @SystemMessage 用于设定 AI 的角色和行为边界

五、流式响应

场景:AI 的回复通常需要好几秒。如果等全部生成完再显示,用户体验很差。流式响应(Streaming)让你能一个 token 一个 token 地接收——就像 ChatGPT 那种"打字机"效果。

import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;

// 1. 创建流式模型
StreamingChatLanguageModel streamingModel = OpenAiStreamingChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("gpt-4o-mini")
        .build();

// 2. 使用回调处理流式响应
streamingModel.chat("写一首关于 Java 的短诗", new StreamingChatResponseHandler() {
    @Override
    public void onPartialResponse(String partialResponse) {
        // 每收到一小段文字就触发
        System.out.print(partialResponse);
    }

    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        // 完整响应结束
        System.out.println("\n\n--- 生成完毕 ---");
    }

    @Override
    public void onError(Throwable error) {
        System.err.println("出错了: " + error.getMessage());
    }
});
在 AI Services 中使用流式响应

AI Services 也支持流式。返回类型改为 TokenStream

interface StreamingAssistant {
    TokenStream chat(String message);
}

StreamingAssistant assistant = AiServices.builder(StreamingAssistant.class)
        .streamingChatLanguageModel(streamingModel)
        .build();

TokenStream stream = assistant.chat("讲一个关于程序员的笑话");
stream.onPartialResponse(token -> System.out.print(token))
      .onCompleteResponse(resp -> System.out.println("\n完毕"))
      .onError(err -> err.printStackTrace())
      .start(); // 别忘了调用 start()!
⚠️ 常见坑
忘记调用 .start():TokenStream 是懒加载的,必须调用 start() 才会开始请求。
线程问题:流式回调在单独的线程中执行。如果在 main 方法中使用,需要阻塞主线程等待完成(比如用 CountDownLatch)。

✅ 本节小结

  • 流式模型使用 StreamingChatLanguageModel 接口
  • 通过回调函数逐步接收 AI 的回复
  • AI Services 通过 TokenStream 返回流式数据

六、Chat Memory 实战

场景:你要构建一个多轮对话聊天机器人,用户可以追问,AI 能记住上下文。

LangChain4j 提供两种内置的 Chat Memory 实现:

实现策略适用场景
MessageWindowChatMemory 滑动窗口,保留最近 N 条消息 大多数场景,简单高效
TokenWindowChatMemory 按 Token 数量保留,精确控制成本 需要精确控制 Token 消耗时
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiTokenCountEstimator;

// 方式 1:消息窗口(推荐入门使用)
ChatMemory messageMemory = MessageWindowChatMemory.builder()
        .maxMessages(20) // 保留最近 20 条
        .build();

// 方式 2:Token 窗口(精确控制)
ChatMemory tokenMemory = TokenWindowChatMemory.builder()
        .maxTokens(2000)
        .tokenCountEstimator(new OpenAiTokenCountEstimator("gpt-4o-mini"))
        .build();
多用户隔离:ChatMemoryProvider

实际应用中,每个用户需要独立的记忆空间。使用 chatMemoryProvider 为每个用户创建独立记忆:

interface Assistant {
    String chat(@MemoryId String oderId, @UserMessage String message);
}

Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .chatMemoryProvider(userId ->
            MessageWindowChatMemory.builder()
                .id(userId)
                .maxMessages(20)
                .build()
        )
        .build();

// 不同用户的对话互不干扰
assistant.chat("user-001", "我叫张三");
assistant.chat("user-002", "我叫李四");
assistant.chat("user-001", "我叫什么?"); // AI: "你叫张三"
assistant.chat("user-002", "我叫什么?"); // AI: "你叫李四"
持久化 Chat Memory

默认的记忆存在内存中,重启就丢失了。你可以实现 ChatMemoryStore 接口把记忆持久化到数据库:

import dev.langchain4j.store.memory.chat.ChatMemoryStore;

public class JdbcChatMemoryStore implements ChatMemoryStore {

    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        // 从数据库加载消息
        return db.loadMessages(memoryId.toString());
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> messages) {
        // 保存到数据库
        db.saveMessages(memoryId.toString(), messages);
    }

    @Override
    public void deleteMessages(Object memoryId) {
        db.deleteMessages(memoryId.toString());
    }
}

// 使用自定义存储
ChatMemory memory = MessageWindowChatMemory.builder()
        .maxMessages(20)
        .chatMemoryStore(new JdbcChatMemoryStore())
        .build();

✅ 本节小结

  • 两种内存策略:消息窗口 vs Token 窗口
  • @MemoryId + chatMemoryProvider 实现多用户记忆隔离
  • 实现 ChatMemoryStore 接口可持久化对话记忆

七、AI Services 深入

场景:你希望 AI 不只返回纯文本,而是返回结构化数据(比如一个 Java 对象),或者根据情况返回不同类型的结果。

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

这是 LangChain4j 最"魔法"的功能之一。你只需把返回类型定义成 POJO,AI 会自动返回符合格式的 JSON 并解析成对象:

// 定义返回结构
record Recipe(
    String name,           // 菜名
    List<String> ingredients, // 食材列表
    String steps,          // 步骤
    int cookingTimeMinutes // 烹饪时间
) {}

// 定义 AI Service
interface ChefAI {
    @UserMessage("给我一个{{dish}}的食谱")
    Recipe getRecipe(@V("dish") String dish);
}

ChefAI chef = AiServices.create(ChefAI.class, model);
Recipe recipe = chef.getRecipe("宫保鸡丁");

System.out.println(recipe.name());        // 宫保鸡丁
System.out.println(recipe.ingredients()); // [鸡胸肉, 花生, ...]
System.out.println(recipe.cookingTimeMinutes()); // 25

情感分析:返回枚举

enum Sentiment { POSITIVE, NEGATIVE, NEUTRAL }

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

SentimentAnalyzer analyzer = AiServices.create(SentimentAnalyzer.class, model);
Sentiment result = analyzer.analyze("这个产品太棒了,我非常喜欢!");
// result == Sentiment.POSITIVE

返回 boolean / int 等基本类型

interface ContentModerator {
    @UserMessage("以下内容是否包含不当言论?回答 true 或 false:{{content}}")
    boolean isInappropriate(@V("content") String content);
}

interface Scorer {
    @UserMessage("请给以下文章的写作质量打分(1-10):{{article}}")
    int score(@V("article") String article);
}
💡 支持的返回类型
AI Services 支持的返回类型包括:Stringbooleanintdouble枚举POJO/RecordList<T>TokenStream(流式)等。几乎你能想到的类型都可以。

✅ 本节小结

  • AI Services 自动将 AI 回复解析成 Java 对象(JSON → POJO)
  • 支持返回枚举、Record、List 等丰富类型
  • 声明式接口让 AI 调用像调用普通 Java 方法一样简单

八、Tool / 函数调用

场景:AI 只会"说",不会"做"。当用户问"北京现在几点?"或"帮我查一下订单状态"时,AI 本身无法获取这些实时信息。Tool 调用(Function Calling)让 AI 能够在对话中调用你定义的 Java 方法,获取真实数据。

🔧 类比
AI 就像一个聪明但"宅"的顾问——它知识渊博,但无法出门买菜。Tool 就是你给它的一组"外卖 App",它可以决定什么时候下单、点什么菜。
import dev.langchain4j.agent.tool.Tool;

// 1. 定义工具类
public class WeatherTool {

    @Tool("查询指定城市的当前天气")
    public String getWeather(String city) {
        // 实际项目中调用天气 API
        return city + ":晴天,25°C,湿度 60%";
    }
}

// 2. 定义 AI Service
interface WeatherAssistant {
    String chat(String message);
}

// 3. 注册工具
WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
        .chatLanguageModel(model)
        .tools(new WeatherTool()) // 把工具交给 AI
        .build();

// 4. AI 会自动决定是否调用工具
System.out.println(assistant.chat("北京今天天气怎么样?"));
// AI 内部:识别需要天气信息 → 调用 getWeather("北京") → 组织回复
// 输出:根据查询,北京今天是晴天,温度 25°C,湿度 60%。
多参数工具 + @P 参数描述
import dev.langchain4j.agent.tool.P;

public class OrderTool {

    @Tool("根据订单号查询订单详情")
    public String queryOrder(
            @P("订单编号,格式如 ORD-12345") String orderId) {
        // 查数据库
        return "订单 " + orderId + ":已发货,预计明天送达";
    }

    @Tool("计算两个数的和")
    public double add(
            @P("第一个数") double a,
            @P("第二个数") double b) {
        return a + b;
    }
}

@P 注解为参数提供描述,帮助 AI 理解每个参数的含义和格式——这对准确调用工具至关重要。

动态工具:ToolProvider

有时候你需要根据上下文动态提供工具(比如不同用户有不同权限)。使用 ToolProvider

ToolProvider toolProvider = (toolProviderRequest) -> {
    // 根据用户角色动态决定提供哪些工具
    String userId = toolProviderRequest.userMessage().text();
    if (isAdmin(userId)) {
        return ToolProviderResult.builder()
                .add(new AdminTool())
                .add(new UserTool())
                .build();
    }
    return ToolProviderResult.builder()
            .add(new UserTool())
            .build();
};

Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .toolProvider(toolProvider)
        .build();
⚠️ 常见坑
Tool 描述写得太模糊@Tool 的描述是 AI 判断"是否调用"的依据。描述越精准,AI 调用越准确。
返回值太复杂:Tool 的返回值建议是简单的 String。AI 需要"读懂"返回值来组织回复。
不是所有模型都支持:Tool 调用需要模型支持 Function Calling(GPT-4o、Claude 3.5 等),一些小模型可能不支持。

✅ 本节小结

  • @Tool 注解将 Java 方法暴露给 AI 调用
  • @P 注解为参数提供描述
  • AI 自动判断何时调用哪个工具
  • ToolProvider 支持动态工具注册

九、RAG 检索增强生成

场景:你希望 AI 能回答关于你自己的数据的问题——比如公司内部文档、产品说明书、FAQ 等。但这些内容 LLM 训练时没有见过。

📚 什么是 RAG?
RAG(Retrieval-Augmented Generation,检索增强生成)的思路很直觉:先从你的知识库中检索出相关内容,再把这些内容作为上下文喂给 AI,让它基于这些内容来回答。就像开卷考试——AI 可以翻书查资料再作答。

RAG 的完整流程分两步:

1

摄入阶段(Ingestion):把文档切分成小块 → 将每块转换成向量(Embedding) → 存入向量数据库

2

检索阶段(Retrieval):用户提问 → 将问题也转成向量 → 在向量数据库中找最相关的文档块 → 连同问题一起发给 AI

简单 RAG(内存向量存储)

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;

// 1. 准备 Embedding 模型(把文本变成向量)
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("text-embedding-3-small")
        .build();

// 2. 创建内存向量存储
InMemoryEmbeddingStore<TextSegment> embeddingStore =
        new InMemoryEmbeddingStore<>();

// 3. 摄入文档
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingModel(embeddingModel)
        .embeddingStore(embeddingStore)
        .build();

// 假设我们有一些公司文档
Document doc = Document.from("我们公司成立于 2020 年,总部位于北京。"
        + "主要产品包括智能客服系统和数据分析平台。"
        + "目前员工人数超过 500 人。");
ingestor.ingest(doc);

// 4. 创建检索器
EmbeddingStoreContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(3)     // 最多返回 3 个相关片段
        .minScore(0.7)     // 最低相关度
        .build();

// 5. 创建带 RAG 能力的 Assistant
interface Assistant {
    String chat(String message);
}

Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .contentRetriever(retriever) // 接入 RAG
        .build();

// 6. 提问!AI 会先检索再回答
System.out.println(assistant.chat("公司有多少员工?"));
// AI: "根据公司资料,目前员工人数超过 500 人。"
使用 EasyRAG 极简版

如果你想用最少的代码体验 RAG,LangChain4j 还提供了 langchain4j-easy-rag 模块:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-easy-rag</artifactId>
</dependency>
// 一行代码加载文件夹里的所有文档
List<Document> documents = FileSystemDocumentLoader.loadDocuments("/path/to/docs");

// 使用 EasyRAG 内置的 Embedding 模型(无需 API Key)
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingStore(embeddingStore)
        .build(); // EasyRAG 自动使用内置 embedding 模型
ingestor.ingest(documents);

✅ 本节小结

  • RAG = 检索 + 生成,让 AI 能回答关于你自己数据的问题
  • 核心组件:EmbeddingModel、EmbeddingStore、ContentRetriever
  • 通过 contentRetriever 把 RAG 接入 AI Services

十、文档加载与解析

场景:你的知识库不只是纯文本,可能包含 PDF、Word、HTML 等多种格式。LangChain4j 内置了多种文档加载器。

import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;

// 1. 加载单个文件(自动识别格式)
Document doc = FileSystemDocumentLoader.loadDocument(
        "/path/to/report.pdf",
        new ApacheTikaDocumentParser()  // 支持 PDF、Word、PPT 等
);

// 2. 加载整个目录
List<Document> docs = FileSystemDocumentLoader.loadDocuments(
        "/path/to/docs/",
        new ApacheTikaDocumentParser()
);

// 3. 切分文档(RAG 必须步骤)
var splitter = DocumentSplitters.recursive(500, 50);
// 每块最多 500 字符,相邻块重叠 50 字符
List<TextSegment> segments = splitter.splitAll(docs);
📋 Apache Tika 依赖
使用 ApacheTikaDocumentParser 需要额外引入:
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-document-parser-apache-tika</artifactId>
</dependency>
从 URL 加载网页内容
import dev.langchain4j.data.document.loader.UrlDocumentLoader;

Document webDoc = UrlDocumentLoader.load(
    "https://example.com/article",
    new ApacheTikaDocumentParser()
);
文档元数据与过滤
// 每个文档段可以携带元数据
TextSegment segment = TextSegment.from("内容...",
        Metadata.from("source", "product-manual.pdf")
                .put("page", "5")
                .put("department", "engineering"));

// 检索时可以过滤
EmbeddingStoreContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .filter(metadataKey("department").isEqualTo("engineering"))
        .build();

✅ 本节小结

  • FileSystemDocumentLoader 支持从文件 / 目录加载文档
  • ApacheTikaDocumentParser 解析 PDF、Word 等多种格式
  • DocumentSplitters.recursive() 智能切分文档为小块
  • 元数据可用于检索时的精确过滤

十一、图像与多模态

场景:你想让 AI 看图说话——分析图片内容、提取信息、或生成图片。

图像理解(Vision)

import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;

// GPT-4o 等支持视觉的模型
var visionModel = OpenAiChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("gpt-4o")
        .build();

// 构建包含图片的消息
UserMessage message = UserMessage.from(
    ImageContent.from("https://example.com/photo.jpg"),  // 图片 URL
    TextContent.from("请详细描述这张图片中的内容")
);

ChatResponse response = visionModel.chat(message);
System.out.println(response.aiMessage().text());

图像生成

import dev.langchain4j.model.image.ImageModel;
import dev.langchain4j.model.openai.OpenAiImageModel;
import dev.langchain4j.data.image.Image;

ImageModel imageModel = OpenAiImageModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("dall-e-3")
        .quality("hd")
        .build();

Response<Image> response = imageModel.generate("一只戴着程序员帽子的猫咪,像素风格");
String imageUrl = response.content().url().toString();
System.out.println("生成的图片: " + imageUrl);
💰 注意成本
图像生成比文本生成贵得多(DALL-E 3 约 $0.04-$0.08/张)。开发调试时建议控制调用频率。

✅ 本节小结

  • 使用 ImageContent 向支持视觉的模型发送图片
  • ImageModel 接口用于生成图片
  • 多模态能力取决于底层模型的支持程度

十二、MCP 协议集成

MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 发起的开放协议,它标准化了 AI 应用与外部工具/数据源的连接方式。可以把它理解为"AI 的 USB 接口"——任何符合 MCP 标准的工具,都可以即插即用。

import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport;

// 1. 创建 MCP 传输层(以 stdio 方式启动本地 MCP 服务)
McpTransport transport = new StdioMcpTransport.Builder()
        .command(List.of("npx", "-y", "@modelcontextprotocol/server-filesystem",
                "/path/to/allowed/directory"))
        .build();

// 2. 创建 MCP 客户端
McpClient mcpClient = new McpClient.Builder()
        .transport(transport)
        .build();

// 3. 使用 McpToolProvider 把 MCP 工具注入 AI Service
ToolProvider toolProvider = McpToolProvider.builder()
        .mcpClients(List.of(mcpClient))
        .build();

interface FileAssistant {
    String chat(String message);
}

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

// AI 现在可以读写文件了!
System.out.println(assistant.chat("列出目录中的所有文件"));
🌐 MCP 的价值
MCP 让你不用自己写 @Tool 方法——社区已有大量现成的 MCP Server(文件系统、GitHub、数据库、Slack 等)。只要连上就能用。

✅ 本节小结

  • MCP 是标准化的 AI 工具协议
  • LangChain4j 通过 McpToolProvider 无缝集成 MCP 服务
  • 支持 stdio 和 HTTP SSE 两种传输方式

十三、综合实战项目

现在让我们把前面学到的所有知识串联起来,构建一个"智能客服助手"——它能回答公司产品问题(RAG)、查询订单状态(Tool 调用)、记住对话上下文(Chat Memory)、并返回结构化数据。

1

定义工具类——模拟订单查询和产品价格查询

public class CustomerServiceTools {

    @Tool("根据订单号查询订单状态")
    public String queryOrder(@P("订单号") String orderId) {
        // 模拟数据库查询
        Map<String, String> orders = Map.of(
            "ORD-001", "已发货,预计明天到达",
            "ORD-002", "待支付",
            "ORD-003", "已签收"
        );
        return orders.getOrDefault(orderId, "未找到订单 " + orderId);
    }

    @Tool("查询产品价格")
    public String queryPrice(@P("产品名称") String productName) {
        Map<String, String> prices = Map.of(
            "智能客服系统", "标准版 ¥9,800/年,企业版 ¥29,800/年",
            "数据分析平台", "基础版 ¥5,800/年,高级版 ¥19,800/年"
        );
        return prices.getOrDefault(productName, "暂无该产品信息");
    }
}
2

准备知识库——加载公司文档并建立向量索引

// 模拟公司文档
Document faqDoc = Document.from(
    "Q: 智能客服系统支持哪些渠道?\n"
  + "A: 支持微信、网页、APP、电话四大渠道,统一后台管理。\n\n"
  + "Q: 数据分析平台的技术栈?\n"
  + "A: 基于 Apache Flink 实时计算引擎,支持 SQL 和 Java API。\n\n"
  + "Q: 如何申请试用?\n"
  + "A: 访问官网填写试用申请表,24 小时内审核通过。"
);

InMemoryEmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor.builder()
        .embeddingModel(embeddingModel)
        .embeddingStore(store)
        .documentSplitter(DocumentSplitters.recursive(300, 30))
        .build()
        .ingest(faqDoc);
3

组装 AI Service——集成所有能力

interface CustomerServiceBot {

    @SystemMessage("""
        你是「极客科技」的智能客服助手。请遵守以下规则:
        1. 友好、专业地回答用户问题
        2. 优先使用知识库中的信息回答产品问题
        3. 需要查询订单时,使用查询工具
        4. 如果不确定,诚实说不知道,不要编造
        """)
    String chat(@MemoryId String userId, @UserMessage String message);
}

CustomerServiceBot bot = AiServices.builder(CustomerServiceBot.class)
        .chatLanguageModel(model)
        .chatMemoryProvider(userId ->
            MessageWindowChatMemory.builder()
                .id(userId)
                .maxMessages(30)
                .build())
        .contentRetriever(EmbeddingStoreContentRetriever.builder()
            .embeddingStore(store)
            .embeddingModel(embeddingModel)
            .maxResults(3)
            .build())
        .tools(new CustomerServiceTools())
        .build();
4

交互测试

String userId = "user-001";

// 测试产品问答(RAG)
System.out.println(bot.chat(userId, "你们的客服系统支持哪些渠道?"));
// → 支持微信、网页、APP、电话四大渠道...

// 测试订单查询(Tool 调用)
System.out.println(bot.chat(userId, "帮我查一下订单 ORD-001 的状态"));
// → 您的订单 ORD-001 已发货,预计明天到达。

// 测试价格咨询(Tool 调用)
System.out.println(bot.chat(userId, "数据分析平台多少钱?"));
// → 基础版 ¥5,800/年,高级版 ¥19,800/年。

// 测试上下文记忆(Chat Memory)
System.out.println(bot.chat(userId, "刚才那个产品怎么申请试用?"));
// → 访问官网填写试用申请表,24 小时内审核通过。

// 测试多用户隔离
System.out.println(bot.chat("user-002", "刚才我问了什么?"));
// → 这是我们的第一次对话...
🎉 恭喜你!
到这里你已经构建了一个具备知识检索、工具调用、多轮记忆、多用户隔离四大能力的 AI 客服助手。这就是 LangChain4j 的威力——把复杂的 AI 编排简化成了清晰的 Java 接口。

✅ 本节小结

  • 综合运用了 RAG、Tool、Chat Memory、AI Services
  • 一个接口 + 一个 builder 就能组装出强大的 AI 应用
  • 声明式开发让复杂的 AI 编排变得简单直观

十四、速查表 / Cheat Sheet

模型相关

API用途示例
OpenAiChatModel.builder()创建 OpenAI 聊天模型.apiKey("...").modelName("gpt-4o-mini").build()
OllamaChatModel.builder()创建 Ollama 本地模型.baseUrl("http://localhost:11434").modelName("llama3.2").build()
model.chat(String)简单文本问答model.chat("你好")
model.chat(Message...)发送多条消息model.chat(systemMsg, userMsg)
OpenAiStreamingChatModel流式响应模型同 ChatModel 配置,返回逐步响应
OpenAiEmbeddingModel文本向量化模型.modelName("text-embedding-3-small").build()
OpenAiImageModel图像生成.modelName("dall-e-3").build()

AI Services 注解

注解用途示例
@SystemMessage设定 AI 角色/系统提示@SystemMessage("你是一个翻译助手")
@UserMessage定义用户消息模板@UserMessage("翻译:{{text}}")
@V("name")绑定模板变量@V("text") String text
@MemoryId标记用户 ID 参数@MemoryId String oderId
@Tool暴露方法为 AI 工具@Tool("查询天气") String getWeather(...)
@P工具参数描述@P("城市名称") String city

RAG & 文档

API用途示例
InMemoryEmbeddingStore内存向量存储new InMemoryEmbeddingStore<>()
EmbeddingStoreIngestor文档摄入管道.embeddingModel(em).embeddingStore(es).build()
EmbeddingStoreContentRetriever向量检索器.maxResults(3).minScore(0.7).build()
FileSystemDocumentLoader文件系统加载文档.loadDocuments("/path/")
DocumentSplitters.recursive()递归切分文档.recursive(500, 50)
ApacheTikaDocumentParser解析 PDF/Word 等需单独引入 Tika 依赖

Chat Memory

API用途示例
MessageWindowChatMemory按消息数滑动窗口.maxMessages(20).build()
TokenWindowChatMemory按 Token 数滑动窗口.maxTokens(2000).build()
ChatMemoryStore持久化接口实现 get/update/deleteMessages

十五、进阶路线图

恭喜你完成了整个教程!接下来是一些进阶方向和资源:

高级用法探索

Agent 模式:让 AI 自主规划和执行多步骤任务,结合多个工具完成复杂目标

查询路由:根据用户问题类型自动路由到不同的处理管道

高级 RAG:查询压缩、重排序(Re-ranking)、混合检索(关键词 + 向量)

可观测性:使用 ChatModelListener 监控 Token 消耗、延迟、成功率

Guard Rails:输入/输出守卫,确保 AI 回复的安全性和合规性

Spring Boot 集成:使用 langchain4j-spring-boot-starter 实现自动配置

Quarkus 集成quarkus-langchain4j 提供原生 Quarkus 支持

推荐资源

资源链接说明
官方文档docs.langchain4j.dev最权威的参考,持续更新
GitHub 仓库github.com/langchain4j源码、Issue、讨论
示例代码库langchain4j-examples大量可运行的示例
Discord 社区LangChain4j Discord活跃的社区交流
🚀 学习建议
最好的学习方式是动手做项目。建议你找一个自己感兴趣的场景(比如个人知识库助手、代码评审机器人、智能客服),把本教程学到的知识应用上去。遇到问题去翻官方文档和 GitHub Issues,进步会非常快!

🎓 教程完成!

你已经掌握了 LangChain4j 的核心用法。现在去构建属于你的 AI 应用吧!