前言
今天介绍一下LangChain怎么玩。本人学AI Agent不超过一个月,如有错误,欢迎批评指正。了解我的人都知道,最近三年,本人都在打磨产品,没有涉足AI领域。最近才开始杀入AI领域的开发。除了Java后端有些基础外,我基础不比新人强多少。
LangChain是什么?
LangChain是一个开源的大语言模型(LLM)应用开发框架,作用是把大模型、文档、向量库、各类工具API组装起来,快速搭建AI应用。
开始开发(基础使用)
由于本人不会Python,所以只介绍Java的开发。老规矩,在pom.xml中配置依赖。
xml
<!-- 核心包,必须 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<!-- 兼容openai协议的都可以使用它 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!-- 也可以用具体的模型的SDK的,比如千问的 -->
创建OpenAiChatModel
先创建OpenAiChatModel对象,我这里举三个例子。
阿里云百炼
scss
val model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey("sk-xxx") // 阿里云dashscope api key
.modelName("qwen-turbo") // qwen-plus / qwen-max
.temperature(0.7)
.build();
DeepSeek
scss
val model = OpenAiChatModel.builder()
.baseUrl("https://api.deepseek.com")
.apiKey("sk-xxx") // deepseek api key
.modelName("deepseek-chat")
.temperature(0.7)
.returnThinking(true) // 开启reasoning_content思考内容解析
.build();
火山方舟
scss
val model = OpenAiChatModel.builder()
.baseUrl("https://ark.cn-beijing.volces.com/api/v3")
.apiKey("sk-xxx") //火山方舟api key
.modelName("ep-xxxxxx") //火山方舟是endpoint id,不是模型名!
.temperature(0.7)
.build();
生成内容
ini
String resp = model.chat("你好");
没错,就是这么一行代码,完成了。
RAG
在完成基础使用后,我们对Demo进行加强,使用到RAG。
什么是RAG?
RAG,Retrieval-Augmented Generation,检索增强生成。给大模型外接一个知识库,提问时先检索相关资料,再把资料连同问题一起交给大模型,让模型基于查到的材料来回答,而不是只靠模型自身预训练记忆。
为什么需要RAG?
使用RAG的目的是为了避免大模型出现幻觉,免得豆包等大模型一本正经的胡说八道。有人要问了,那我为什么不把知识库直接训练给大模型?好问题。原因如下:
-
模型训练需要时间,最新的知识无法实时更新
-
使用RAG就相当于外接一本书,回答可以附带引用原文片段,便于溯源与合规
-
解耦合,方便更新与更换
写一个RAG的Demo
创建Embedding模型
创建一个Embedding模型,这里以阿里的千问为例。
csharp
// Embedding模型(同样OpenAI兼容)
private static EmbeddingModel createEmbeddingModel() {
// 千问embedding
return OpenAiEmbeddingModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey("sk-你的dashscope-key")
.modelName("text-embedding-v1")
.build();
}
在RAG里,Embedding起什么作用?
回忆 RAG 流程:文档切分成 chunk → Embedding → 存入向量库。 用户提问时:问题文本 → Embedding → 在向量库计算向量距离,召回最相似的文档片段。
文档切分,向量化
ini
String docText = """
Langchain4j 是Java版大模型应用开发框架。
Langchain4j支持RAG检索增强生成,可以把私有文档内容交给大模型。
Langchain4j支持对话记忆,可以记住多轮聊天上下文。
作者:langchain4j社区。
""";
Document document = Document.from(docText);
var splitter = DocumentSplitters.recursive(300, 30);
var segments = splitter.split(document);
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
embeddingStore.addAll(embeddingModel.embedAll(segments).content(), segments);
先将文档拆分成很多Chunk ,这里使用的是DocumentSplitters拆分器,按300个字一组拆分,实际项目不会这么用。先使用InMemoryEmbeddingStore存到内存中,用Map保存,实际项目一般会存到Redis或Database。
定义Assistant接口
arduino
interface Assistant {
String chat(String userMessage);
}
召回记忆
ini
// 对话记忆:消息窗口,最多保存10条消息
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
创建检索增强器
scss
var contentRetriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(2) //最多召回2条
.minScore(0.6)
.build();
RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
.contentRetriever(contentRetriever)
.build();
Assistant发起对话
ini
// 创建AI服务实例,绑定记忆+RAG
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(createChatModel())
.chatMemory(chatMemory)
.retrievalAugmentor(retrievalAugmentor)
.build();
// ====== 测试对话 ======
System.out.println("【第一轮提问】Langchain4j是什么?");
String resp1 = assistant.chat("Langchain4j是什么?");
System.out.println(resp1);
System.out.println("\n【第二轮提问】它支持哪些能力?");
String resp2 = assistant.chat("它支持哪些能力?");
System.out.println(resp2);
System.out.println("\n【第三轮提问】刚才我们聊的框架是谁开发的?");
String resp3 = assistant.chat("刚才我们聊的框架是谁开发的?");
System.out.println(resp3);
RAG的会话隔离
前面的Demo有什么问题?记忆是所有会话共享的。这样,无论什么信息你都写入长期记忆了,那会话多了是不是会爆炸💥。人的大脑还要睡眠处理信息,然后选择性遗忘呢!
定义使用MemoryId隔离记忆的Assistant
less
interface AssistantUnique {
/**
* @param memoryId 会话唯一ID(userId / sessionId),不同id自动隔离记忆
* @param userMessage 用户提问
* @return LLM回答
*/
String chat(@MemoryId String memoryId, @UserMessage String userMessage);
}
多个String参数,需要使用@UserMessage手动标注哪个是UserMessage。
使用ChatMemoryProvider提供记忆(关键)
ini
ChatMemoryProvider memoryProvider = memoryId ->
MessageWindowChatMemory.withMaxMessages(10);
完整实现流程
java
package com.dora.agent.llm;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.RetrievalAugmentor;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
public class RagUniqueMemoryDemo {
private static OpenAiChatModel createChatModel() {
// 千问 dashscope
return OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey("sk-xxx")
.modelName("qwen-turbo")
.temperature(0.7)
.build();
}
private static EmbeddingModel createEmbeddingModel() {
return OpenAiEmbeddingModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey("sk-xxx")
.modelName("text-embedding-v1")
.build();
}
interface AssistantUnique {
/**
* @param memoryId 会话唯一ID(userId / sessionId),不同id自动隔离记忆
* @param userMessage 用户提问
* @return LLM回答
*/
String chat(@MemoryId String memoryId, @UserMessage String userMessage);
}
public static void main(String[] args) {
// 1. 向量库、文档向量化(全局知识库,所有会话共用)
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
EmbeddingModel embeddingModel = createEmbeddingModel();
String docText = """
Langchain4j 是Java版大模型应用开发框架。
Langchain4j支持RAG检索增强生成,可以把私有文档内容交给大模型。
Langchain4j支持对话记忆,可以记住多轮聊天上下文。
""";
Document document = Document.from(docText);
var splitter = DocumentSplitters.recursive(300, 30);
var segments = splitter.split(document);
embeddingStore.addAll(embeddingModel.embedAll(segments).content(), segments);
// 2. RAG检索器,全局共用
var retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(2)
.minScore(0.6)
.build();
RetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
.contentRetriever(retriever)
.build();
// 3.ChatMemoryProvider:根据memoryId自动创建独立记忆
ChatMemoryProvider memoryProvider = memoryId ->
MessageWindowChatMemory.withMaxMessages(10);
// 4. 构建AiService,只构建1个实例,供所有会话复用
AssistantUnique assistant = AiServices.builder(AssistantUnique.class)
.chatModel(createChatModel())
.chatMemoryProvider(memoryProvider) // 按id动态生成记忆
.retrievalAugmentor(augmentor)
.build();
// ========== 测试:两个独立会话,记忆互不串 ==========
String sessionA = "session_001";
String sessionB = "session_002";
System.out.println("==== 会话A(session_001) ====");
System.out.println(assistant.chat(sessionA, "Langchain4j是什么?"));
System.out.println(assistant.chat(sessionA, "它支持什么能力?"));
System.out.println("\n==== 会话B(session_002) ====");
System.out.println(assistant.chat(sessionB, "刚才我问了你什么?")); // B看不到A的对话,回答不知道
}
}
总结
本文面向Java后端开发新手,从零完成了LangChain4j框架的入门学习与实操开发,完整讲解了Java体系下大模型应用的基础搭建与RAG核心能力落地。首先介绍了LangChain4j的核心定位,作为轻量化开源LLM开发框架,它可快速整合各类大模型、知识库与工具接口,适配Java技术栈的AI应用开发场景。
在基础开发部分,详细演示了核心依赖引入方式,并适配阿里云百炼、DeepSeek、火山方舟三大主流兼容OpenAI协议的大模型,提供了可直接复用的模型初始化代码,极简实现了大模型基础对话能力,降低了新手接入大模型的开发门槛。
同时,文章重点拆解了RAG检索增强生成技术的核心原理与应用价值,明确了RAG解决大模型幻觉、知识滞后、无法私有化部署等核心痛点的优势,并完整落地了RAG入门Demo,涵盖Embedding模型创建、文档切片、文本向量化、向量内存存储、检索增强器配置、对话记忆绑定等全流程核心步骤,清晰阐释了Embedding在语义检索中的关键作用。
最后针对基础RAG Demo的缺陷,优化实现了会话记忆隔离能力,通过MemoryId、ChatMemoryProvider实现多用户、多会话的记忆独立隔离,解决了全局记忆共享导致的信息混乱、内存溢出等线上问题,让RAG应用具备了初步生产可用能力。
整体教程从理论到实操、从基础功能到生产优化,循序渐进,无需深厚AI基础即可上手,完整覆盖了LangChain4j+RAG的核心入门知识点,为后续开发复杂AI Agent、私有化知识库问答、智能对话系统等高阶应用打下了扎实的基础。后续可基于本文案例,进一步替换Redis、数据库等持久化向量存储,优化文档切片规则与检索权重,适配正式项目开发场景。