这是一篇风格化很重的LangChain4j实践教程。我不想给你看一个标准的技术文档模板,我想给你看一个真实的、会踩坑、会骂街、最终又能解决问题的Java开发者的实战记录。

LangChain4j,顾名思义,是LangChain的Java移植版。它的目标很明确:让Java开发者也能像Python开发者一样丝滑地构建大模型应用。目前它已经支持接入OpenAI、Azure、Ollama等超过20家模型提供商,还有内存管理、RAG、函数调用等一整套工具链。

我会从搭建环境开始,中间穿插我踩过的坑和学到的教训,然后重点讲RAG和Tool Calling这两个核心功能,最后聊几句LangChain4j和Spring AI到底怎么选。


1. 环境准备:先别急着写代码,选对版本很重要

LangChain4j的版本迭代挺快的,写这篇文章时最新稳定版是1.0.0-beta1。注意这个beta后缀——很多功能还在打磨,你用的版本可能和我用的不太一样。

如果你是Spring Boot项目,Maven里加上这些:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j</artifactId>
    <version>1.0.0-beta1</version>
</dependency>
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai</artifactId>
    <version>1.0.0-beta1</version>
</dependency>

如果你是纯Java项目不用Spring,也可以,只是多写几行配置代码的事。

API Key别硬编码到代码里,这是血的教训。用环境变量或者配置文件管理。


2. 别用Low-Level API,AI Services才是正解

刚上手时我犯过一个错误:直接用ChatLanguageModel来调大模型。代码大概长这样:

ChatLanguageModel model = OpenAiChatModel.builder()
    .apiKey(apiKey)
    .modelName("gpt-3.5-turbo")
    .build();
String response = model.generate("Hello, world!");

能跑,但问题很快就来了:每次都要手动处理对话历史,想加个RAG还得自己拼Prompt,代码越写越乱。后来才发现LangChain4j的设计精髓根本不在这里,而是在AI Services——你只需要定义一个接口,框架帮你生成实现。

public interface Assistant {
    String chat(String message);
}

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

这叫什么?这叫“声明式AI开发”。你声明你想要什么,框架帮你搞定怎么做到。


3. 第一个坑:对话记忆存MySQL,我踩过的雷

说实话,LangChain4j的官方文档现在确实还不够完善。有个开发者朋友在掘金上吐槽说,他想把对话记录存到MySQL,结果从下午一直折腾到晚上11点半。

问题出在哪?他把模型从阿里百炼换成OpenAI后,所有问题竟然都消失了。这说明什么?LangChain4j对不同模型提供商的适配程度是不一样的,有些SDK还藏着bug。如果你也遇到莫名其妙的持久化问题,不妨先换个模型试试,先确认是框架问题还是模型适配问题。

如果要用ChatMemory持久化到数据库,建议用框架官方支持的ChatMemoryStore实现,别自己瞎折腾。目前比较靠谱的方案是用MongoDB或Redis存对话记录。


4. RAG:从“极简版”到“实战版”的进化

RAG(检索增强生成)是LangChain4j最亮眼的功能之一。说白了就是给大模型配一个“小抄本”,让它回答前先查一下你的私有知识库。

4.1 极简版:三分钟跑通RAG

先跑通再说,别一上来就追求完美。引入langchain4j-easy-rag依赖:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-easy-rag</artifactId>
    <version>1.0.0-beta1</version>
</dependency>

然后几行代码就能跑起来:

// 1. 加载文档
List<Document> documents = FileSystemDocumentLoader
    .loadDocuments("src/main/resources/docs");

// 2. 转换成向量并存到内存
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor.ingest(documents, embeddingStore);

// 3. 构建AI Service并绑定检索器
Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore))
    .build();

极简版的特点是“一切皆默认”——内置Embedding模型、内存向量存储、默认分块策略。很适合快速验证想法。

4.2 实战版:换掉默认,优化效果

极简版跑通后,你会发现几个问题:内存存储重启就没了,默认的Embedding模型效果一般,文档分块策略太粗暴。

向量数据库的选择

生产环境别用内存存储。我推荐两个方向:

  • PgVector:如果你的项目已经在用PostgreSQL,这是最省事的选择,直接用现有数据库存向量。
  • MongoDB Atlas:如果你需要的是开箱即用的云服务,MongoDB的Vector Search功能很成熟,而且和LangChain4j有官方集成模块。

以PgVector为例,配置大概这样:

EmbeddingStore<TextSegment> embeddingStore = PgVectorEmbeddingStore.builder()
    .host("localhost")
    .port(5432)
    .database("rag_db")
    .user("postgres")
    .password("password")
    .table("embeddings")
    .dimension(1536)  // OpenAI embedding的维度
    .build();

Embedding模型的选择

默认的Embedding模型效果一般。生产环境建议换成OpenAI的text-embedding-3-small或Cohere的embed模型,中文场景可以试试阿里的通义千问Embedding。


5. Tool Calling:让AI学会调用你的Java方法

如果说RAG是给AI配了本参考书,那Tool Calling就是给了AI一双能干活的手。当用户问“今天天气怎么样”时,AI知道自己答不上来,但可以调用你写的getWeather工具来获取实时数据。

5.1 基础用法

@Tool注解标记你想让AI调用的方法:

public class WeatherTools {
    
    @Tool("获取指定城市的当前天气")
    public String getWeather(@P("城市名称") String city) {
        // 这里调用真实的天气API
        return city + "今天晴朗,温度22°C";
    }
    
    @Tool("计算两个数的和")
    public double sum(@P("第一个数") double a, @P("第二个数") double b) {
        return a + b;
    }
}

然后在构建AI Service时注册这些工具:

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .tools(new WeatherTools())
    .build();

现在你可以问AI“北京天气怎么样”或者“帮我算一下156加243”,它会自动判断需要调用哪个工具。

5.2 第二个坑:工具调用无限循环

我遇到过一个问题:AI在一个对话里反复调用同一个工具,token烧得飞起。有开发者说他看着AI对话转了半个小时,花了将近100万token。

原因是什么?记忆窗口太小了。LangChain4j默认只保留最近几条对话记录,当工具调用次数多了之后,AI会“忘记”自己刚才已经调用过这个工具了,于是重复调用。

解决方案也很简单:调大MessageWindowChatMemory的容量:

MessageWindowChatMemory chatMemory = MessageWindowChatMemory
    .withMaxMessages(35);  // 默认是10,调到35

这个值需要根据你的实际场景调整,太小容易循环,太大token消耗多。

5.3 多个工具怎么让AI选对?

如果你的工具有很多,关键是把@Tool注解里的描述写清楚。AI是根据你的描述来判断该用哪个工具的。描述要写清楚“这个工具是干什么的”、“什么时候应该用”。写得好不好,直接影响AI选工具的准确率。


6. 流式输出:别把用户晾在那干等

LangChain4j的流式输出确实比Spring AI麻烦一些。Spring AI里call是全量,stream是流式,很直觉。但LangChain4j需要单独用StreamingChatLanguageModel,还要加langchain4j-reactor依赖。

如果用AI Services方式实现流式,代码是这样的:

public interface StreamingAssistant {
    TokenStream chat(String message);
}

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

TokenStream tokenStream = assistant.chat("讲个笑话");
tokenStream.onNext(token -> System.out.print(token))
    .onComplete(response -> System.out.println("\n完成"))
    .onError(Throwable::printStackTrace)
    .start();

返回类型用TokenStream,然后通过onNext逐个处理token。

如果你用Spring Boot + WebFlux,可以直接把TokenStream转成Flux<String>,然后通过Server-Sent Events推给前端,实现ChatGPT那种逐字输出的效果。


7. 本地模型部署:Ollama + DeepSeek

不想每次都调OpenAI的付费API?Ollama是你最好的朋友。

Ollama是一个本地大模型运行平台,支持CPU和GPU,能跑DeepSeek、Llama、Mistral等各种开源模型。

安装和运行很简单:

# 安装Ollama
curl -fsSL https://ollama.com/install.sh | sh

# 拉取DeepSeek-R1模型(14b参数,本地可跑)
ollama pull deepseek-r1:14b

# 启动服务
ollama serve

然后在LangChain4j里这样配置:

ChatLanguageModel model = OllamaChatModel.builder()
    .baseUrl("http://localhost:11434")
    .modelName("deepseek-r1:14b")
    .build();

这样就完全本地化了,不用API Key,不用联网,数据安全也更有保障。


8. LangChain4j vs Spring AI,我到底该怎么选?

这个问题我被问过很多次。简单说:

LangChain4j适合你,如果:

  • 你需要丰富的功能(RAG、Agent、工具调用都很成熟)
  • 你不一定要用Spring生态(纯Java、Quarkus都可以)
  • 你需要兼容多种模型提供商

Spring AI适合你,如果:

  • 你已经在用Spring Boot/Cloud全家桶
  • 你追求和Spring生态的无缝集成(依赖注入、配置管理、可观测性)
  • 你能接受功能相对较少但更稳定的状态

我的个人选择:如果是Spring项目,我会用LangChain4j做核心AI逻辑,因为它的功能确实更全;配置文件管理、依赖注入这些基础设施就交给Spring。两者不冲突,可以一起用。


写在最后

LangChain4j现在确实还有很多不完美的地方:官方文档不够详细,某些功能还带着beta标签,不同模型提供商的适配程度参差不齐。但它在快速迭代,而且社区活跃度很高。

如果你是一个想用Java做大模型应用的开发者,LangChain4j是目前最好的选择之一。不要被它的不完美吓到——Python的LangChain一开始也是这样的。技术都是在踩坑中成长的,LangChain4j在成长,我们也是。

希望这篇文章能帮你少踩几个坑。如果你在实践中遇到什么问题,欢迎留言交流。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐