如果你已经熟悉 Python 版的 LangChain,那 LangChain4j 的核心概念你基本都能对上号。但 Java 生态有它自己的玩法,尤其在 Spring Boot 整合、声明式 API 和工具调用方面,LangChain4j 的设计更贴合 Java 开发者的习惯。

一、为什么是 LangChain4j?

Java 调用大模型的主流框架有两个:LangChain4jSpring AI。如果你是 Spring 生态的重度用户,两者都可以选。LangChain4j 的优势在于:

  • 与 LangChain(Python)概念高度对应,迁移成本低
  • Spring Boot 起步依赖,配置即用
  • 声明式 @AiService 注解,代码极简
  • 内置 RAG、Tools、会话记忆等高阶能力

官网:https://docs.langchain4j.dev

二、快速入门:5 分钟跑通第一个对话

2.1 引入依赖

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

LangChain4j 使用 OpenAI 兼容协议,所以阿里云百炼、DeepSeek 等平台只需换 baseUrl 即可。

2.2 构建模型 & 发起对话

OpenAiChatModel model = OpenAiChatModel.builder()
    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
    .apiKey(System.getenv("API-KEY"))  // 推荐:从环境变量读取
    .modelName("qwen-plus")
    .logRequests(true)   // 开发阶段开启日志
    .logResponses(true)
    .build();

String result = model.chat("你好,介绍一下自己");
System.out.println(result);

对比 LangChain(Python):

操作 LangChain (Python) LangChain4j (Java)
构建模型 ChatOpenAI(model=..., api_key=...) OpenAiChatModel.builder()...build()
发起对话 model.invoke("...") model.chat("...")
日志调试 需手动配置 logging .logRequests(true).logResponses(true)

核心差异:LangChain4j 用 Builder 模式 替代 Python 的关键字参数,日志开关是内建的。

三、Spring Boot 整合:配置驱动

纯 Java 方式能用,但实际项目必然要和 Spring 结合。LangChain4j 提供了起步依赖,做到配置即注入。

3.1 引入起步依赖

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

3.2 application.yml 配置

langchain4j:
  open-ai:
    chat-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}
      model-name: qwen-plus
      log-requests: true
      log-responses: true
logging:
  level:
    dev.langchain4j: debug

配置完成后,IOC 容器自动注入 OpenAiChatModel 对象,直接 @Autowired 使用。

3.3 接口开发

@RestController
public class ChatController {
    @Autowired
    private OpenAiChatModel model;

    @RequestMapping("/chat")
    public String chat(String message) {
        return model.chat(message);
    }
}

到这里,一个可用的 AI 对话接口就完成了。但直接用 model.chat() 做高阶功能(会话记忆、RAG、Tools)会很麻烦——所以 LangChain4j 提供了 AiServices

四、AiServices:LangChain4j 的灵魂(原理:动态代理)

LangChain4j 中,AiServices 是对 LangChain(Python)中 Chain 的替代方案。它把模型、记忆、检索、工具等能力封装到一个接口的动态代理中,用起来像调用普通方法一样简单。

4.1 编程式使用

// 1. 声明接口
public interface ConsultantService {
    String chat(String message);
}

// 2. 用 AiServices 创建代理对象
@Configuration
public class CommonConfig {
    @Autowired
    private OpenAiChatModel model;

    @Bean
    public ConsultantService consultantService() {
        return AiServices.builder(ConsultantService.class)
            .chatModel(model)
            .build();
    }
}

4.2 声明式使用(推荐)

更简洁的方式——直接在接口上加 @AiService 注解,LangChain4j 自动扫描创建代理:

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,  // 手动装配
    chatModel = "openAiChatModel"
)
public interface ConsultantService {
    String chat(String message);
}

不需要写 @Configuration,不需要手动构建 Bean,一个注解搞定。

对比 LangChain(Python):

概念 LangChain (Python) LangChain4j (Java)
链式调用 chain = LLMChain | prompt | memory @AiService 注解 + 属性配置
装配方式 代码串联 声明式注解,Spring 自动注入
扩展能力 传参给 Chain 构造函数 @AiService 的属性指定 Bean 名

LangChain4j 的声明式风格对 Java 开发者更友好——不需要记住 Chain 的嵌套顺序,在注解里指明用哪个组件就行。

五、流式调用:从阻塞到实时

阻塞式调用一次性返回完整结果,用户体验差。流式调用逐 Token 推送,类似打字机效果。

5.1 配置流式模型

langchain4j:
  open-ai:
    streaming-chat-model:  # 流式模型配置
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}
      model-name: qwen-plus

5.2 引入 WebFlux 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
    <version>1.0.1-beta6</version>
</dependency>

5.3 接口返回 Flux

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel"
)
public interface ConsultantService {
    Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}

Controller 返回 Flux<String>,前端通过 SSE 接收实时推送。

六、消息注解:SystemMessage 与 UserMessage

大模型的行为由消息类型决定。SystemMessage 设定 AI 角色和规则,UserMessage 携带用户输入。

6.1 SystemMessage:设定 AI 人设

// 方式一:直接写在注解里
@SystemMessage("你是志愿填报顾问,只回答高考志愿相关问题")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);

// 方式二:从外部文件加载(推荐,方便管理长提示词)
@SystemMessage(fromResource = "system.txt")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);

6.2 UserMessage:模板化用户消息

可以在用户消息前后拼接预设内容,通过 {{it}}@V 注解引用参数:

// 使用默认占位符 {{it}}
@UserMessage("你是AI助手。{{it}}")
Flux<String> chat(String message);

// 自定义占位符名称
@UserMessage("你是AI助手。{{msg}}")
Flux<String> chat(@V("msg") String message);

七、会话记忆:从无状态到有上下文

大模型本身没有记忆,每次对话都是独立的。会话记忆的原理是把历史消息一起发给模型,让它"看到"之前的对话。

7.1 基本实现

@Bean
public ChatMemory chatMemory() {
    return MessageWindowChatMemory.builder()
        .maxMessages(20)  // 最多保留 20 条,超出淘汰最早的
        .build();
}
@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    chatMemory = "chatMemory"  // 注入会话记忆
)

为什么要限制条数?两个原因:大模型上下文有上限(约 10 万 Token);消息越多,Token 消耗越大,费用越高。

7.2 会话隔离

不同用户不能共享同一个记忆对象。通过 ChatMemoryProvider + @MemoryId 实现:

@Bean
public ChatMemoryProvider chatMemoryProvider() {
    return memoryId -> MessageWindowChatMemory.builder()
        .id(memoryId)
        .maxMessages(20)
        .build();
}
@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    chatMemoryProvider = "chatMemoryProvider"
)
public interface ConsultantService {
    @SystemMessage(fromResource = "system.txt")
    Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}

LangChain4j 根据 memoryId 查找或创建对应的 ChatMemory 对象,实现用户间记忆隔离。

对比 LangChain(Python):

操作 LangChain (Python) LangChain4j (Java)
记忆管理 ConversationBufferMemory MessageWindowChatMemory
消息窗口 ConversationBufferWindowMemory(k=20) .maxMessages(20)
会话隔离 手动管理 session_id ChatMemoryProvider + @MemoryId

7.3 持久化:记忆存到 Redis

默认的 MessageWindowChatMemory 使用内存存储,重启即丢失。实现 ChatMemoryStore 接口即可持久化:

@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        String json = redisTemplate.opsForValue().get(memoryId);
        return ChatMessageDeserializer.messagesFromJson(json);
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> list) {
        String json = ChatMessageSerializer.messagesToJson(list);
        redisTemplate.opsForValue().set(memoryId.toString(), json, Duration.ofDays(1));
    }

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

然后在 ChatMemoryProvider 中指定使用:

@Bean
public ChatMemoryProvider chatMemoryProvider() {
    return memoryId -> MessageWindowChatMemory.builder()
        .id(memoryId)
        .maxMessages(20)
        .chatMemoryStore(redisChatMemoryStore)  // 使用 Redis 存储
        .build();
}

八、RAG 知识库:让 AI 拥有专属知识

RAG(Retrieval Augmented Generation)的本质:先检索相关知识,再让模型结合知识生成答案

8.1 RAG 工作原理

用户提问 → 向量化 → 在向量数据库中检索相似片段
→ 把「问题 + 检索到的片段」一起发给大模型 → 生成答案

核心概念:
- 向量:文本的数学表示,多维坐标中的一个点
- 余弦相似度:衡量两个向量的方向接近程度,值越大越相似(0~1)
- 向量数据库:专门存储和检索向量的数据库(Milvus、Chroma、RedisSearch 等)

8.2 快速入门:内存版 RAG

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-easy-rag</artifactId>
    <version>1.0.1-beta6</version>
</dependency>
@Bean
public EmbeddingStore store() {
    // 1. 加载文档
    List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
    // 2. 构建内存向量数据库
    InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
    // 3. 分割 + 向量化 + 存储(一步搞定)
    EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingStore(store)
        .build();
    ingestor.ingest(documents);
    return store;
}

@Bean
public ContentRetriever contentRetriever(EmbeddingStore store) {
    return EmbeddingStoreContentRetriever.builder()
        .embeddingStore(store)
        .minScore(0.5)   // 最低相似度阈值
        .maxResults(3)    // 最多返回 3 个片段
        .build();
}
@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    chatMemoryProvider = "chatMemoryProvider",
    contentRetriever = "contentRetriever"  // 配置检索器
)

三步搞定:存文档 → 建检索器 → 配到 @AiService

8.3 核心组件详解

RAG 涉及五个核心 API,LangChain4j 把大部分细节封装到了 EmbeddingStoreIngestor 中:

① 文档加载器

加载器 用途
ClassPathDocumentLoader 从 classpath 加载
FileSystemDocumentLoader 从本地磁盘加载
UrlDocumentLoader 从 URL 加载

② 文档解析器

解析器 支持格式
ApacheTikaDocumentParser(默认) 几乎所有格式
ApachePdfBoxDocumentParser PDF
ApachePoiDocumentParser Office 文件
TextDocumentParser 纯文本

③ 文档分割器

分割器 策略
DocumentByParagraphSplitter 按段落
DocumentByLineSplitter 按行
DocumentBySentenceSplitter 按句子
DocumentSplitters.recursive()(默认) 段落 → 行 → 句子 → 词,逐级递归

递归分割器最实用,还支持配置片段重叠保持语义连贯:

DocumentSplitter ds = DocumentSplitters.recursive(500, 100);
// 500 = 每个片段最大字符数
// 100 = 相邻片段重叠字符数(防止语义断裂)

④ 向量模型

内存版向量模型功能有限,生产环境建议替换为百炼的 text-embedding-v3

langchain4j:
  open-ai:
    embedding-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY}
      model-name: text-embedding-v3

注入后交给 EmbeddingStoreIngestorEmbeddingStoreContentRetriever

@Autowired
private EmbeddingModel embeddingModel;

// 存储时用
EmbeddingStoreIngestor.builder()
    .embeddingStore(store)
    .embeddingModel(embeddingModel)
    .build();

// 检索时也用
EmbeddingStoreContentRetriever.builder()
    .embeddingStore(store)
    .embeddingModel(embeddingModel)
    .build();

⑤ 向量数据库

内存版 InMemoryEmbeddingStore 重启即丢,生产环境用 RedisSearch:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-redis-spring-boot-starter</artifactId>
    <version>1.0.1-beta6</version>
</dependency>
langchain4j:
  community:
    redis:
      host: localhost
      port: 6379

配置后自动注入 RedisEmbeddingStore,替换 InMemoryEmbeddingStore 即可。

8.4 LangChain vs LangChain4j RAG 对比

环节 LangChain (Python) LangChain4j (Java)
文档加载 PyPDFLoader / DirectoryLoader ClassPathDocumentLoader / FileSystemDocumentLoader
文本分割 RecursiveCharacterTextSplitter DocumentSplitters.recursive()
向量模型 OpenAIEmbeddings() EmbeddingModel(yml 配置注入)
向量数据库 FAISS / Chroma / Pinecone InMemoryEmbeddingStore / RedisEmbeddingStore
检索器 retriever = vectorstore.as_retriever() EmbeddingStoreContentRetriever
整合方式 RetrievalQA.from_chain_type() @AiService(contentRetriever=...)

关键差异:LangChain4j 用 @AiService 注解的 contentRetriever 属性挂载检索器,比 Python 的 Chain 组装更简洁。

九、Tools 工具:让 AI 调用你的代码

Tools(原 Function Calling)让大模型能调用你定义的 Java 方法。典型场景:AI 在对话中识别用户意图,自动调用预约接口写入数据库。

9.1 工作原理

用户提问 → 大模型判断是否需要调用工具
→ 返回工具名称 + 参数 → AI 应用执行工具方法
→ 把执行结果发回大模型 → 大模型生成最终回答

大模型不直接执行你的代码,它只是告诉你"该调用哪个方法、传什么参数",由你的程序执行后把结果回传。

9.2 定义工具方法

@Tool 描述方法作用,用 @P 描述参数含义:

@Component
public class ReservationTool {
    @Autowired
    private ReservationService reservationService;

    @Tool("预约志愿填报服务")
    public void addReservation(
        @P("考生姓名") String name,
        @P("考生性别") String gender,
        @P("考生手机号") String phone,
        @P("预约沟通时间,格式:yyyy-MM-dd'T'HH:mm") String communicationTime,
        @P("考生所在省份") String province,
        @P("考生预估分数") Integer estimatedScore
    ) {
        Reservation reservation = new Reservation(null, name, gender, phone,
            LocalDateTime.parse(communicationTime), province, estimatedScore);
        reservationService.insert(reservation);
    }

    @Tool("根据考生手机号查询预约单")
    public Reservation findReservation(@P("考生手机号") String phone) {
        return reservationService.findByPhone(phone);
    }
}

9.3 配置工具

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel",
    chatMemoryProvider = "chatMemoryProvider",
    contentRetriever = "contentRetriever",
    tools = "reservationTool"  // 挂载工具
)

用户说"我想预约,我叫张三,电话13800000001",大模型会自动解析出参数并调用 addReservation 方法。

对比 LangChain(Python):

操作 LangChain (Python) LangChain4j (Java)
工具定义 @tool 装饰器 或 StructuredTool @Tool + @P 注解
工具挂载 agent = Agent(tools=[...]) @AiService(tools="beanName")
参数描述 Pydantic BaseModel 的 Field @P("描述")
自动执行 Agent 自动调用 LangChain4j 自动调用

十、全能力配置:最终形态

把所有能力整合到一个 @AiService 接口上:

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",              // 对话模型
    streamingChatModel = "openAiStreamingChatModel", // 流式模型
    chatMemoryProvider = "chatMemoryProvider",   // 会话记忆(Redis 持久化)
    contentRetriever = "contentRetriever",       // RAG 知识库检索
    tools = "reservationTool"                    // Tools 工具
)
public interface ConsultantService {
    @SystemMessage(fromResource = "system.txt")  // 系统人设
    Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}

一个接口,五个注解属性,覆盖了 AI 应用开发的核心能力。

十一、总结:LangChain vs LangChain4j 核心映射

能力 LangChain (Python) LangChain4j (Java)
模型调用 ChatOpenAI() OpenAiChatModel.builder() 或 yml 配置
链式编排 LLMChain \| SequentialChain @AiService 声明式注解
会话记忆 ConversationBufferMemory MessageWindowChatMemory + ChatMemoryProvider
消息模板 ChatPromptTemplate @SystemMessage / @UserMessage 注解
RAG RetrievalQA + 各种 Loader EmbeddingStoreIngestor + ContentRetriever
工具调用 @tool + Agent @Tool + @P + tools="beanName"
流式输出 astream() Flux<String> + WebFlux
Spring 整合 不适用 起步依赖 + yml 配置即注入

LangChain4j 的核心设计哲学:用声明式注解替代编程式组装,用 Spring 生态替代手动管理。 如果你已经理解了 LangChain 的概念,迁移到 LangChain4j 只需要换一套 API 风格——底层原理完全一致。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐