news 2026/5/10 15:07:10

深入浅出LangChain4J

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入浅出LangChain4J

1.走进LangChain

1.1.什么是LangChain4J?

The goal of LangChain4J is to simplify integrating LLMs into Java applications.

​ -- 《LangChain4J Doc》

LangChain4J就像Java的Spring框架一样,为LLM的接入提供了一套标准的接入能力。LangChain4J是LangChain在Java生态下的具体实现,用于构建基于LLM的应用和Agent系统。

LangChain4J为不同的LLM提供了一个统一的API,屏蔽了底层API供应商的实现和调用差异,开发者可以使用LangChain无缝切换不同的LLM。

2.Architecture of LangChain4J

LangChain4J的架构可以分为两层,分别为高层和底层。

高层AI服务屏蔽了底层实现的细节,开发者可以实现一些业务服务的API和LLM进行交互。

低层具有更高的自由度,你可以任意定义组件的具体实现,控制组件的组合方式等等。

下面,就LangChain4J的核心组件,一一详细介绍。

2.1.Chat and Language Model

一般地,LLMs的API可以分为两类,

  • LanguageModel:输入输出都为String类型,现在使用的越来越少了
  • ChatModel:应用广泛的一类API,接收多个ChatMessage作为输入,输出一个AiMessage,除了文本类型之外,还支持图片、音频、视频等其他模式。

ChatModel是LangChain4J的低层API,提供强大的灵活性和可扩展性。

根据消息来源进行分类,LangChain4J支持以下五种消息类型:

消息类型描述主要方法
UserMessage用户输入的消息数据content(), name(), attributes()
AiMessageAI根据输入数据生成的消息text(), thinking(), toolExceptionRequests(), attributes()
ToolExecutionResultMessage工具执行结果消息
SystemMessage系统发送的消息,可以由开发者自定义
CustomMessage自定义消息
2.2.Chat Memory

我们知道,大模型是无状态的,模型本身并不会记录对话上下文。因此,如果你想要在对话中使用上下文的内容,就必须主动维护管理ChatMessage。但是手动维护比较麻烦,而LangChain4J提供了ChatMemory用来维护管理chatMessage.

2.2.1.History VS Memory

历史记录和记忆听起来似乎是同一种东西,但是对于LLM Agent来说,history和memory具有两种截然不同的语义:

  • history保留了用户和AI的所有会话记录,用户可以在界面中看到
  • memory记录的是专门呈现给大模型使用的信息,使其表现得好像是“记住了”对话的内容,实际底层实现是截然不同的算法。

LangChain4J目前只提供Memroy,而不提供History

下面介绍关于Memory的几点高级特性。

2.2.2.Eviction Policy 淘汰策略

为什么要使用淘汰策略?

  • 存储空间受限:Memory组件可以理解为缓存,当存放的内容超过容量大小的时候,需要使用一定的策略淘汰一些记忆;
  • Token成本昂贵:更多的上下文记忆就代表使用更多的Token,而token的增加会增加每次调用LLM的成本;
  • 控制延迟:发送的LLM的token越多,处理他们所需要的时长越长,则用户等待输出的时间越长

LangChain4J目前支持两种开箱即用的记忆淘汰策略:

  1. 基于消息滑动窗口:使用MessageWindowChatMemory作为滑动窗口,仅保留最近的N条信息,淘汰窗口之外的旧消息;
  2. 基于token的滑动窗口:TokenWindowChatMemory只保留最近的N个token。但是消息是不可再分的,因此如果消息不合适的话,整条消息会直接被丢弃。
2.2.3.Persistence 持久化

默认情况下Memory是存放在内存中的,如果需要保留消息,可以自定义实现MessageStore,将chatMessage存储在数据库中。

class PersistentChatMemroyStore implements ChatMemoryStore { @Override public List<ChatMessage> getMessages(Object memoryId) { } @Override public void updateMessages(Object memoryId, List<ChatMessage> messages) { } @Override public void deleteMessages(Object memoryId) { // TODO: Implement deleting all messages in the persistent store by memory ID. } }
2.2.4.SystemMessage

SystemMessage是一种特殊的消息,具有如下的特性:

  • 一旦添加,就会一直被保留,不会被淘汰策略淘汰
  • 一次只能持有一个SystemMessage
  • SystemMessage具有唯一性,重复的SystemMessage会被忽略,如果不一致,则会覆盖掉之前的SystemMessage
2.2.5.Tool 消息配对

AIMessage 中的ToolExecutionRequestToolExecutionResponse总是成对出现的。如果ToolExecutionRequest被淘汰了,则其对应的ToolExecutionResponse消息也会被自动淘汰。

2.3.Tools(Function Calling)

工具(Tools)允许LLM在必要的时候调用开发者定义的一个或者多个可用工具,工具是一个泛称,可以表示任何东西,例如网页搜索、外部API、或者执行特定的代码等等。

实际上LLM并不会去主动调用工具,而是通过开发人员在业务层接收LLM的回复,根据LLM的意愿进行工具的调用并将执行结果反馈给LLM。

一个良好的工具应当具有以下几个属性:

  1. 清晰明确的工具名称
  2. 工具的具体描述,以及应该何时使用工具;
  3. 每个工具的具体参数;

如果这个工具对于人来说一眼就能理解应该如何使用,那么这个工具对于LLM也是易于使用的。

Tools的定义和使用可以参考文档:LangChain4J Documents

2.4.Agent

3.实战

3.1.ChatModel
3.1.1.基本聊天
public static void main(String[] args) { // 1.创建 chatModel OpenAiChatModel chatModel = OpenAiChatModel.builder() .apiKey(System.getenv("OPENAI_API_KEY")) .baseUrl(System.getenv("OPENAI_BASE_URL")) .modelName(System.getenv("OPENAI_MODEL")) .build(); // 2.使用 chat 方法发起对话 ChatResponse response = chatModel.chat(ChatRequest.builder() .messages(UserMessage.from("Hello, could you introduce yourself ?")) .build()); // 3.控制台打印 System.out.println(response.aiMessage().text()); }
3.1.2.多轮对话

多轮对话和基本对话的实现方式相同,只不过构建对话请求的时候,需要将前文传入到messages中,LLM会参考message得出合理的响应。

private static void chatWithMultipleMessages() { // 1.构建 User 和AI 的多轮对话 UserMessage firstUserMessage = UserMessage.from("Hello, My name is shepi, could you introduce yourself ?"); AiMessage firstAiMessage = CHAT_MODEL.chat( ChatRequest.builder() .messages(firstUserMessage) .build()) .aiMessage(); UserMessage secondUserMessage = UserMessage.from("Please tell me my name"); AiMessage secondAiMessage = CHAT_MODEL.chat( ChatRequest.builder() .messages(firstUserMessage, firstAiMessage, secondUserMessage) .build()).aiMessage(); // 2.控制台打印 System.out.println(secondAiMessage.text()); }
3.2.ChatMemory

ChatMemory可以帮助我们维护上下文,LangChain4J提供了两种开箱即用的窗口聊天记忆

  • MessageWindowChatMemory
  • TokenWindowChatMemory

下面是一个基于消息数量的窗口对话记忆:

public static void main(String[] args) { // 1.新建 messageWindow,滑动窗口最大长度设置为 3 MessageWindowChatMemory chatWindow = MessageWindowChatMemory.builder() .maxMessages(4) .build(); // tryChatWithCommonMessages(chatWindow); // 测试特殊的系统消息 systemMessage tryChatWithSystemMessage(chatWindow); } /** * 系统消息永远不会被驱逐 * @param chatWindow */ private static void tryChatWithSystemMessage(MessageWindowChatMemory chatWindow) { // 创建系统消息 SystemMessage systemMessage = SystemMessage.from("The user talking with you is shepi"); chatWindow.add(systemMessage); System.out.println(systemMessage.text()); for (int i = 0; i < 4; i++) { UserMessage userMessage = null; if (i == 3) { userMessage = UserMessage.from("Please tell me my name"); } else { userMessage = UserMessage.from("let's talk about something interesting"); } System.out.println(userMessage.contents()); chatWindow.add(userMessage); // 使用 chatMemory 对话 AiMessage aiMessage = CHAT_MODEL.chat(ChatRequest.builder().messages(chatWindow.messages()).build()).aiMessage(); System.out.println(aiMessage.text()); chatWindow.add(aiMessage); } } private static void tryChatWithCommonMessages(MessageWindowChatMemory chatWindow) { // 2.模拟进行多轮对话 // 第一轮给出自己的名字,第四轮询问AI我的名字,其他两轮随便聊点什么 for (int i = 0; i < 4; i++) { UserMessage userMessage = null; if (i == 0) { userMessage = UserMessage.from("Hello, My name is shepi, could you introduce yourself ?"); } else if (i == 3) { userMessage = UserMessage.from("Please tell me my name"); } else { userMessage = UserMessage.from("let's talk about something interesting"); } System.out.println(userMessage.contents()); chatWindow.add(userMessage); // 使用 chatMemory 对话 AiMessage aiMessage = CHAT_MODEL.chat(ChatRequest.builder().messages(chatWindow.messages()).build()).aiMessage(); System.out.println(aiMessage.text()); chatWindow.add(aiMessage); } }
3.3.Tools

LangChain中定义Tool非常简单,只需要在工具接口方法上使用注解@Tool("Tool description")即可,下面是一个简答的例子。

public class WeatherService { @Tool("获取指定城市的天气情况") public String getWeather(String city) { // 模拟天气数据 return MessageFormat. format("Today's weather in {0} is sunny with a temperature of 22 degrees.", city); } }
3.4.AiService (Agent 封装)

AiService 是什么?

AiService 是 LangChain4J 提供的高层 API,用于快速构建 Agent 应用。它屏蔽了工具调用的底层细节(如检测 LLM 返回的函数调用请求、执行工具、将结果反馈给 LLM),让开发者可以专注于业务逻辑。

AiService 与 Agent 的关系:

  • AiService 是 LangChain4J 对 Agent 概念的具体实现
  • 它自动完成了 Agent Loop 中的:接收输入 → 判断是否需要 Tool → 调用 Tool → 观察结果 → 生成响应
  • 开发者只需定义接口和 Tool,AiService 会自动完成工具调用的编排

如果想要使用上面创建的 Tool,我们需要在定义AiService时,传入 Tool 对象。

private static final OpenAiChatModel CHAT_MODEL = OpenAiChatModel.builder() .apiKey(System.getenv("OPENAI_API_KEY")) .baseUrl(System.getenv("OPENAI_BASE_URL")) .modelName(System.getenv("OPENAI_MODEL")) .build(); public static void main(String[] args) { // 根据CHAT_MODEL创建一个 chatService ChatAssistant chatService = AiServices.builder(ChatAssistant.class) .chatLanguageModel(CHAT_MODEL) .tools(new WeatherService()) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build(); // 问题 String question = "今天北京什么天气?"; String answer = chatService.chat(question); System.out.println(answer); }

4.流式响应 (Streaming)

LangChain4J 支持流式响应,即 LLM 在生成内容时实时返回每个 token,而不是等待完整响应后再返回。

使用场景
  • 需要实时显示生成过程的场景(如 ChatGPT 的打字机效果)
  • 生成较长内容时提升用户体验
  • 需要提前终止不满意的输出
实现方式

使用StreamingAiServices代替AiServices

private static final OpenAiChatModel CHAT_MODEL = OpenAiChatModel.builder() .apiKey(System.getenv("OPENAI_API_KEY")) .baseUrl(System.getenv("OPENAI_BASE_URL")) .modelName(System.getenv("OPENAI_MODEL")) .build(); public static void main(String[] args) { // 根据CHAT_MODEL创建一个 chatService ChatAssistant chatService = AiServices.builder(ChatAssistant.class) .chatLanguageModel(CHAT_MODEL) .tools(new WeatherService()) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build(); // 问题 String question = "今天北京什么天气?"; String answer = chatService.chat(question); System.out.println(answer); }
流式 vs 非流式
特性非流式 (AiServices)流式 (StreamingAiServices)
响应方式等待完整响应后返回实时返回每个 token
用户体验有等待感实时反馈,体验更好
实现复杂度简单稍复杂(需要处理回调)
适用场景短文本、后台任务长文本、交互式对话


学习资源推荐

如果你想更深入地学习大模型,以下是一些非常有价值的学习资源,这些资源将帮助你从不同角度学习大模型,提升你的实践能力。

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!​

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示

​因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

四、AI大模型商业化落地方案

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 12:34:27

别再瞎找了!千笔,抢手爆款的AI论文软件

你是否曾为论文选题发愁&#xff0c;绞尽脑汁却无从下手&#xff1f;是否在深夜面对空白文档&#xff0c;思绪枯竭、无从落笔&#xff1f;又或者反复修改却始终不满意表达效果&#xff1f;论文写作的每一步都充满挑战&#xff0c;而这些难题&#xff0c;正在被千笔AI一一化解。…

作者头像 李华
网站建设 2026/5/1 6:48:06

【电力系统】基于极限学习机的DC-DC转换器建模附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

作者头像 李华
网站建设 2026/5/4 9:53:07

Power BI Report Server 2026 v15.0.1120.113

Power BI 报表服务器是面向当前用户的本地报表解决方案&#xff0c;并可灵活迁移到云端。它包含在 Power BI Premium 中&#xff0c;因此您可以根据自身需求随时迁移到云端。Power BI 报表服务器是一款本地部署的报表解决方案&#xff0c;可满足您当前的报表需求&#xff0c;并…

作者头像 李华
网站建设 2026/5/4 16:58:56

模型剪枝大白话讲解:结构化 vs 非结构化

模型剪枝大白话讲解&#xff1a;结构化vs非结构化 先给核心结论&#xff1a;模型剪枝就是给训练好的模型“减肥”&#xff0c;删掉里面没用的部分&#xff0c;让模型变轻、计算变少&#xff1b;而结构化和非结构化剪枝的核心区别&#xff0c;就在于 “怎么剪”&#xff08;剪的…

作者头像 李华
网站建设 2026/5/9 14:07:17

指数期权指标分析未平仓量的市场信号

功能说明 本文实现的代码主要用于分析指数期权市场中未平仓量&#xff08;Open Interest&#xff09;的市场信号。通过获取期权交易数据&#xff0c;计算不同行权价和到期日的未平仓量&#xff0c;并结合标的资产价格、隐含波动率等指标&#xff0c;识别市场中的潜在趋势和反转…

作者头像 李华