《LangChain4j:从入门到企业级实战》全部内容
定义:LangChain4j 是一个专为 Java 开发者设计的 AI 集成框架,旨在简化大型语言模型(LLM)与 Java 应用程序的集成过程。其灵感来源于 Python 的 LangChain,但根据 Java 生态的特点(强类型、企业级库丰富)进行了重新设计和实现。核心价值:提供一套统一的 API 和预构建的组件,将 LLM 与外部数据、系统连接起来,从而让开发者能够以声明式、遵循 Java
参考资料:
1.LangChain4J框架速通实战(官网)
2.Langchain4j-0-基本概念与依赖导入
![[Pasted image 20260201115154.png]]
基于您提供的关于LangChain4j的搜索结果,我为您设计了一个逻辑清晰、循序渐进、覆盖从入门到精通全路径的13章节学习与实践框架。该框架综合了核心概念解析、实战开发流程、高级特性应用以及生产部署考量,旨在为构建系统性的学习材料或项目文档提供标题模板。
《LangChain4j:从入门到企业级实战》核心框架(1-13章)
第一章:启程:大模型时代与Java开发者的新机遇
本章将阐述大模型(LLM)如何重塑软件交互范式,并分析Java生态在集成AI能力时面临的挑战与机遇,引出LangChain4j作为“Java开发者大模型开发加速器”的定位与核心价值。
第二章:初识LangChain4j:框架概览与核心哲学
深入介绍LangChain4j的设计目标、核心特点(如多模型兼容、低代码、与Java生态深度融合)及其与Python版LangChain的异同,帮助读者建立对框架的整体认知。
第三章:基石:统一模型层(Model Layer)与环境搭建
详解LangChain4j如何通过ChatModel、EmbeddingModel等统一接口抽象不同的大模型服务商(如OpenAI、通义千问、本地Ollama)。本章将包含依赖引入、API密钥配置、首个模型Bean的创建等实战步骤。
第四章:灵魂对话:聊天模型、记忆管理与多轮对话
聚焦ChatLanguageModel的使用,深入讲解ChatMemory组件(如基于消息窗口或Token窗口的记忆策略)如何自动维护对话上下文,实现有状态的、连贯的多轮对话体验,这是智能聊天应用的基石。
第五章:智慧之源:提示工程与模板(Prompt Template)
探讨如何超越简单的字符串拼接,使用PromptTemplate进行结构化的提示词设计与管理。内容包括变量替换、模板复用以及如何通过精心设计的提示词来引导模型生成更高质量、更符合预期的输出。
第六章:流程引擎:链(Chain)与智能体(Agent)
解析LangChain4j得名的核心——Chain。阐述如何将多个组件(模型、记忆、工具)串联成复杂的工作流。进一步介绍Agent的概念,即能够自主规划、调用工具以完成复杂任务的智能系统。
第七章:赋予手脚:工具调用(Tools)与外部世界连接
详细讲解如何通过@Tool注解将任意Java方法(如查询数据库、调用API、执行计算)暴露给大模型,使模型获得与外部系统和实时信息交互的能力,突破纯文本生成的局限。
第八章:知识增强:检索增强生成(RAG)架构与实践
这是当前企业级应用的核心场景。本章系统介绍RAG的全流程:从文档加载、解析分块,到使用EmbeddingModel向量化、存入EmbeddingStore,最后在问答时进行相似性检索并将结果注入提示词,从而让模型基于私有知识库生成准确回答,减少“幻觉”。
第九章:高效开发:声明式AI服务(AiServices)
介绍LangChain4j提供的高级API——AiServices。通过类似Spring Data JPA的声明式接口和注解(如@SystemMessage, @UserMessage),极大简化集成代码,提升开发效率,快速实现包含记忆、工具等高级功能的服务。
第十章:实时交互:流式输出(Streaming)与Web集成
专章探讨如何实现类ChatGPT的逐词输出体验。详细讲解StreamingResponseHandler、TokenStream以及如何与Spring WebFlux的Flux结合,并通过SSE(Server-Sent Events)协议将流式响应实时推送到前端页面。
第十一章:企业级集成:与Spring Boot深度融合
展示如何将前述所有组件优雅地集成到Spring Boot应用中。包括使用Spring Boot Starter进行自动配置、将各种组件声明为Spring Bean、以及如何设计RESTful API或WebSocket端点来提供AI服务,满足企业级开发标准。
第十二章:走向生产:性能、安全与运维考量
讨论在生产环境中部署LangChain4j应用时必须关注的问题。包括异步调用与性能优化、API密钥与访问的安全管理、Token消耗与成本控制、日志监控、熔断限流策略,以及如何避免常见的陷阱。
第十三章:进阶与展望:行业趋势与未来探索
总结LangChain4j在Java AI生态中的关键地位,展望其未来发展方向(如与Spring AI生态的进一步融合)。并引导读者探索更前沿的主题,如多模态模型集成、复杂Agent系统设计,以及如何将AI能力深度融入现有业务架构。
1. LangChain4j 基础概念与架构
一、 基本信息
- 学习主题:LangChain4j 核心概念与整体架构
- 核心目标:理解 LangChain4j 的设计哲学、核心价值与核心组件。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 核心概念与原理
1. 什么是 LangChain4j
- 定义:LangChain4j 是一个专为 Java 开发者设计的 AI 集成框架,旨在简化大型语言模型(LLM)与 Java 应用程序的集成过程。其灵感来源于 Python 的 LangChain,但根据 Java 生态的特点(强类型、企业级库丰富)进行了重新设计和实现。
- 核心价值:提供一套统一的 API 和预构建的组件,将 LLM 与外部数据、系统连接起来,从而让开发者能够以声明式、遵循 Java 习惯的方式,构建功能强大、上下文感知的 AI 应用,大大降低了开发复杂度。
- 设计哲学:约定优于配置,通过模块化设计抽象 LLM 交互中的各个要素(如提示模板、记忆管理、工具调用),使开发者无需关心底层复杂细节。
![[Pasted image 20260201124814.png]]
2.Before、After、产品定位:
![[Pasted image 20260201124922.png]]
随着人工智能(AI)技术的迅猛发展,越来越多的开发者开始将目光投向AI应用的开发。然而,目前市场上大多数AI框架和工具如LangChain、PyTorch等主要支持Python,而Java开发者常常面临工具缺乏和学习门槛较高的问题,但是不用担心,
谁让Java/Spring群体强大那?任何一个框架/XXX云服务器,想要大面积推广,应该不会忘记庞大的Spring社区和Java程序员
Langchain4J官网:https://docs.langchain4j.dev/
![[Pasted image 20260201125351.png]]
![[Pasted image 20260201125420.png]]
大模型的分类:
![[Pasted image 20260201125526.png]]
产品定位:
![[Pasted image 20260201125610.png]]
3. 核心组件解析
理解 LangChain4j 的架构需要掌握几个关键概念,它们协同工作形成一个完整的链式处理流程:
- Model (模型):抽象了与各种 LLM 提供商(如 OpenAI, Google Gemini, Anthropic Claude, 本地 Ollama 等)的交互,通过统一接口调用,便于切换模型而无需重写业务逻辑。
- ChatMemory (聊天记忆):管理对话的上下文历史,是实现多轮对话的关键。支持多种策略,从简单的内存存储到基于 Redis 或数据库的持久化存储。
- Tools (工具):允许 LLM 按需执行外部动作或获取外部数据(如查询数据库、调用 API),是将 LLM 能力与现有系统连接起来的核心。
- PromptTemplates (提示模板):帮助动态生成高质量的提示(Prompt),将用户输入、上下文等变量注入预定义模板,提高提示词的一致性、可维护性和复用性。
- Embeddings (嵌入) & VectorStores (向量数据库):Embeddings 将文本转换为数值向量;VectorStores 存储和检索这些向量。这是实现检索增强生成(RAG) 的基础,让 LLM 能够基于自有知识库生成准确回答,避免“幻觉”。
- AI Services (AI 服务):一个非常强大且具有创新性的高级抽象。允许通过定义 Java 接口和注解(如
@SystemMessage,@UserMessage)来创建 AI 应用,框架在运行时自动生成代理实现,处理所有复杂细节,让代码变得极其简洁和声明式。
最新版本特性:
1.10.0 and 1.10.0-beta18 Latest
这是 LangChain4j 1.10.0 及 1.10.0-beta18 版本的发布说明总结,主要聚焦于模型目录支持、Agentic 可观测性、Anthropic 生态增强及 AI Services 灵活性提升。
4.核心变更 (Notable Changes)
1. 模型目录支持 (Model Catalog Support)
- 新增对 Anthropic、Gemini、OpenAI 和 Mistral 的模型目录支持 #4240
- 开发者可更便捷地浏览和选择各厂商提供的模型
2. Agentic 可观测性与监控
- 新增 Agentic 架构的可观测性和监控能力 #4181
- 提升 AI Agent 在生产环境的可调试性和运维能力
3. Anthropic 生态重大增强
- 支持最新 Tool 特性 #4211
- 支持结构化输出 (Structured Outputs) #4220
- 支持返回原始 HTTP 响应和 SSE 事件 #4225
- 支持通过 URL 输入 PDF #4216
- 新增 strictTools 支持 #4223
4. OpenAI 功能扩展
- 新增语音转录 (Transcription) 支持 #4101
5. AI Services 灵活性提升
5.其他重要变更 (Other Changes)
Agentic 相关改进
- Agentic 作用域支持配置默认值 #4153
- 修复 Supervisor 作为子代理使用的问题 #4161
- Agent 支持通过 Map 定义工具 #4169
- 修复条件规划器无匹配条件时的问题 #4202
- 修复默认对话记忆在 Agent 中的使用问题 #4234
- 新增
maxSequentialToolsInvocations处理 #4204
RAG 与检索增强
向量存储与数据库
工具与 MCP (Model Context Protocol)
- MCP HTTP & WebSocket 传输层支持自定义 HttpClient #4189
- 修复 MCP 客户端在网络暂时故障后永久断开的问题 #4249
- 修复 MCP 响应新增字段时的反序列化失败问题 #4283
安全与防护
- 新增
MessageModeratorInputGuardrail输入防护栏 #4160
提示词模板
缺陷修复
- 修复 Anthropic Token 计数器空消息问题 #3952
- 修复 AI Service 输出格式指令追加位置 #4184
- 修复 SupervisorPlanner NPE 问题 #4199
- 修复 SQL 过滤器解析器函数表达式处理 #4170
- 修复 Gemini Batch 响应映射 #4175
- 修复 Ollama 显式响应格式 NPE #4238
- 修复 PartsMapper 工具结果格式处理 #4244
依赖与模块调整
- 迁移进程内嵌入模块到主仓库 #4179
- 更新 Azure 和 OpenAI 依赖 #4203
- 废弃
langchain4j-github-models模块 #4243 - 更新 watsonx-ai 依赖至 0.16.0 #4251
事件与响应
AiServiceResponseReceivedEvent现包含ChatRequest#4215- 支持返回
behavior.immediate与动态工具 #4224 - 支持包含推理内容 (reasoning content) #4200
文档更新
- 更新版本号至 1.9.1 和 1.10.0-SNAPSHOT
- 添加 Jlama VM 选项文档 #4155
- 添加本地代码执行引擎文档 #4159
- 更新聊天消息类型数量 #4138
- Spring Boot 集成文档添加自动组件 ToolProvider #3075
- 改进特性列表间距 #4254
总结
1.10.0 版本是 LangChain4j 的重要里程碑,特别是在 Agentic 架构、Anthropic 生态完善 和 RAG 混合检索 方面有显著提升,同时增强了框架的可观测性和生产就绪能力。
2. LangChain4j之永远的HelloWorld
一、 基本信息
- 学习主题:第一个 LangChain4j 程序
- 核心目标:完成环境配置,实现最简单的 LLM 调用。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 核心概念与原理
1. 环境准备与依赖
- 核心依赖:使用 LangChain4j 需要引入核心库及对应模型提供商(如 OpenAI)的 starter 依赖。
<!-- LangChain4j 核心启动器 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-spring-boot-starter</artifactId> <version>${langchain4j.version}</version> </dependency> <!-- 以 OpenAI 为例 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId> <version>${langchain4j.version}</version> </dependency> - 密钥配置:安全地管理模型 API 密钥至关重要,建议通过环境变量或配置文件(如
application.yml)设置,避免硬编码。langchain4j: openai: chat-model: api-key: ${OPENAI_API_KEY} model-name: gpt-3.5-turbo
2. 首次模型调用
- 原理:初始化
ChatLanguageModelBean 后,可以直接调用其chat方法发送提示词。LangChain4j 在底层处理了网络通信、错误重试和结果解析等细节。 - 代码示例:
@SpringBootTest public class HelloWorldTest { @Autowired private ChatLanguageModel chatModel; // 由 starter 自动配置 @Test public void testFirstChat() { String answer = chatModel.chat("Hello, introduce yourself."); System.out.println(answer); } } - 易错点/注意事项:❗ 确保网络通畅,API 密钥有效且有额度。初次调用建议使用简单问题验证环境。
![[Pasted image 20260201131937.png]]
2. 解读
模型开发和常规开发层级对比
- Prompt:好比UI层,进行用户交互
- Langchain4j, Spring AI:好比Controller,调用AI大模型
- 各类AI大模型:好比Service,提供人工智能服务
- 向量数据库:好比Mapper,进行数据存储
![[Pasted image 20260201140107.png]]
你补充的这份笔记聚焦于LangChain4j的基础集成与核心配置,涵盖了依赖管理、多模型对接、SpringBoot整合等实战细节,我帮你将这部分内容系统化整合,并与之前的核心知识点衔接,形成完整的LangChain4j入门到实战体系。
2. LangChain4j之永远的HelloWorld(补充)
#整合补充:LangChain4j基础集成与核心配置
一、 核心概念类比(快速理解层级)
为了快速建立认知,可将LangChain4j开发与常规开发层级做对应:
| LangChain4j/AI领域 | 常规开发领域 | 核心作用 |
|---|---|---|
| Prompt(提示词) | UI层 | 定义用户与AI的交互规则 |
| LangChain4j/Spring AI | Controller层 | 封装LLM调用逻辑,衔接业务与模型 |
| 各类大模型(GPT/Qwen等) | Service层 | 提供AI生成能力 |
| 向量数据库 | Mapper层 | 存储/检索向量化的外部知识 |
二、 依赖管理(标准化配置)
LangChain4j采用BOM(物料清单)统一管理版本,避免依赖冲突,核心依赖分三类:
1. 基础核心依赖(OpenAI生态)
<properties>
<langchain4j.version>1.0.1</langchain4j.version>
</properties>
<!-- 导入BOM统一版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>${langchain4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 核心依赖(按需导入) -->
<!-- Low-Level API:底层模型调用 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!-- High-Level API:AI Service抽象 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
2. SpringBoot整合依赖(声明式开发)
<!-- OpenAI SpringBoot Starter -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.0.0-beta3</version>
</dependency>
<!-- 通用SpringBoot Starter -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.0.0-beta3</version>
</dependency>
3. 第三方模型集成(以通义千问为例)
<properties>
<langchain4j-community.version>1.0.1-beta6</langchain4j-community.version>
</properties>
<!-- 导入社区版BOM(对接非OpenAI模型) -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-bom</artifactId>
<version>${langchain4j-community.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 通义千问(阿里云百炼)Starter -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>
三、 核心配置与实战
1. 模型实例化(以通义千问为例)
通过Builder模式配置模型参数,支持多模型差异化配置:
@Configuration
public class LLMConfig {
// 文本模型(qwen-plus)
@Bean(name = "chatModelQwen")
public ChatModel chatModelQwen() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("ALIQWEN_API")) // 从环境变量取APIKey(安全最佳实践)
.modelName("qwen-plus") // 模型名称
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") // 阿里云兼容OpenAI接口
// 基础配置
.logRequests(true) // 打印请求日志(debug级别生效)
.logResponses(true) // 打印响应日志
.maxRetries(2) // 失败重试次数
.timeout(Duration.ofSeconds(5)) // 请求超时时间
// 扩展配置:事件监听(链路追踪/参数传递)
.listeners(List.of(new TestChatModelListener()))
.build();
}
// 多模态模型(qwen-vl-max,支持图片+文本)
@Bean(name = "imageModelQwen")
public ChatModel imageModelQwen() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("ALIQWEN_API"))
.modelName("qwen-vl-max") // 多模态模型
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
}
2. 事件监听器(链路追踪/参数传递)
通过ChatModelListener实现请求/响应全生命周期监控,支持上下文参数传递:
@Slf4j
public class TestChatModelListener implements ChatModelListener {
@Override
public void onRequest(ChatModelRequestContext requestContext) {
// 生成TraceID,存入上下文(跨阶段传递)
String traceId = IdUtil.simpleUUID();
requestContext.attributes().put("TraceID", traceId);
log.info("LLM请求-TraceID:{},参数:{}", traceId, requestContext);
}
@Override
public void onResponse(ChatModelResponseContext responseContext) {
// 获取请求阶段的TraceID,实现链路追踪
String traceId = (String) responseContext.attributes().get("TraceID");
log.info("LLM响应-TraceID:{},结果:{}", traceId, responseContext);
}
@Override
public void onError(ChatModelErrorContext errorContext) {
log.error("LLM调用异常-TraceID:{},错误:{}",
errorContext.attributes().get("TraceID"),
errorContext.error().getMessage());
}
}
3. AI Service两种创建方式
| 方式 | 实现方式 | 适用场景 |
|---|---|---|
| 原生手动创建 | AiServices.create(接口, 模型实例) | 非SpringBoot环境/灵活配置 |
| 声明式创建 | @AiService注解 | SpringBoot环境(推荐) |
方式1:原生手动创建
// 1. 定义AI Service接口
public interface ChatAssistant {
String chat(String prompt);
}
// 2. 配置类中创建Bean
@Bean
public ChatAssistant chatAssistant(@Qualifier("chatModelQwen") ChatModel chatModel) {
return AiServices.create(ChatAssistant.class, chatModel);
}
// 3. 控制器调用
@RestController
public class HighApiController {
@Resource
private ChatAssistant chatAssistant;
@GetMapping("/highapi/chat")
public String chat(@RequestParam String prompt) {
return chatAssistant.chat(prompt);
}
}
方式2:SpringBoot声明式创建(推荐)
// 1. 接口加@AiService注解,指定模型(可选)
@AiService(wiringMode = EXPLICIT, chatModel = "chatModelQwen")
public interface ChatAssistant {
String chat(String prompt);
}
// 2. 控制器直接注入调用
@RestController
public class DeclarativeController {
@Resource
private ChatAssistant chatAssistant;
@GetMapping("/lc4j/boot/chat")
public String chat(@RequestParam String prompt) {
return chatAssistant.chat(prompt);
}
}
4. 多模态模型实战(图片+文本交互)
通义千问qwen-vl-max支持图片解析,核心是将图片转Base64后构造ImageContent:
@RestController
public class ImageModelController {
@Autowired
@Qualifier("imageModelQwen")
private ChatModel imageModel;
@Value("classpath:static/images/mi.jpg")
private Resource imageResource;
@GetMapping("/image/analyze")
public String analyzeImage() throws IOException {
// 1. 图片转Base64
byte[] imageBytes = imageResource.getContentAsByteArray();
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
// 2. 构造多模态消息(文本+图片)
UserMessage userMessage = UserMessage.from(
TextContent.from("提取图片中的网站名称、股价走势、5月30号股价"),
ImageContent.from(base64Image, "image/jpg") // 图片内容+格式
);
// 3. 调用模型
ChatResponse response = imageModel.chat(userMessage);
return response.aiMessage().text();
}
}
总结
- 依赖管理核心:通过BOM统一版本,按场景选择核心依赖/社区依赖/SpringBoot Starter,避免版本冲突;
- 模型配置最佳实践:APIKey从环境变量获取,通过Builder模式配置超时、重试、日志等参数,多模型用
@Qualifier区分; - 开发模式选择:SpringBoot环境优先用
@AiService声明式开发,非Spring环境用AiServices.create手动创建; - 扩展能力:通过
ChatModelListener实现链路追踪,多模态模型需将图片转Base64后构造ImageContent。
这份补充整合了基础依赖、模型配置、AI Service开发、多模态交互等入门核心内容,与之前的流式输出、记忆、RAG等进阶知识点形成完整体系,覆盖了LangChain4j从入门配置到实战开发的全流程。
3. LangChain4j之整合SpringBoot
一、 基本信息
- 学习主题:LangChain4j 与 SpringBoot 深度集成
- 核心目标:掌握在 SpringBoot 项目中配置和使用 LangChain4j 的最佳实践。
- 学习日期:2026-02-01
- 技术版本:SpringBoot 3.x, LangChain4j 1.x
![[Pasted image 20260201163645.png]]
![[Pasted image 20260201164029.png]]
![[Pasted image 20260201164124.png]]
#Boot整合底阶API所需POM
popular integrations
![[Pasted image 20260201164312.png]]
#Boot整合高阶API所需POM
declarative Al Services
![[Pasted image 20260201164354.png]]
LangChain4J原生整合
![[Pasted image 20260201164600.png]]
LangChain4J-Boot整合
![[Pasted image 20260201164628.png]]
小总结
![[Pasted image 20260201170120.png]]
![[Pasted image 20260201170354.png]]
![[Pasted image 20260201170446.png]]
![[Pasted image 20260201170557.png]]
![[Pasted image 20260201170658.png]]
![[Pasted image 20260201171009.png]]
- AiService
- Tools
程序员自己定义接口,通过AiServices类里面的方法实现,优点是api封装度比较高,减少了代码的复杂性,但仍可以进行灵活的微调。
==官方总结
![[Pasted image 20260201171231.png]]
二、 方法、流程与实战
1. 项目初始化与配置
- 步骤描述:
- 创建 SpringBoot 项目:建议使用 SpringBoot 3.x 和 JDK 17+。
- 引入依赖:如上一节所示,引入
langchain4j-spring-boot-starter及具体模型 starter。 - 配置密钥与模型参数:在
application.yml中配置,支持多个模型 Bean 的配置。 - 创建启动类:标准的 SpringBoot 启动类即可。
- 优势与局限:
- 优势:自动配置、依赖注入、与 Spring 生态无缝集成(如
@ConfigurationProperties绑定配置)。 - 局限:对非 Spring 的 Java 项目支持需要手动配置。
- 优势:自动配置、依赖注入、与 Spring 生态无缝集成(如
2. 自动配置的 Bean
- 关键 Bean:引入 starter 后,Spring 会自动根据配置创建
ChatLanguageModel、EmbeddingModel、ChatMemory等 Bean,可直接@Autowired注入使用。 - 代码示例:
@Service public class MyAIService { @Autowired private ChatLanguageModel chatModel; // 默认模型 @Autowired @Qualifier("qwenChatModel") // 指定 Bean 名称,当配置多个模型时 private ChatLanguageModel qwenModel; }
三、 个人思考与关联
- 疑问与探索:❓ 如何在一个项目中同时配置和使用多个不同提供商(如 OpenAI 和 通义千问)的模型?
- 启发与联想:💡 LangChain4j 的 SpringBoot Starter 设计遵循了 Spring Boot 的“约定优于配置”原则,与
spring-boot-starter-data-redis等 starter 的设计理念一致。 - 行动项:
- 在配置文件中尝试配置两个不同 API Key 和模型的 Bean。
- 编写一个
@Configuration类,手动定义一个ChatMemoryBean 以覆盖默认配置。
4. LangChain4j之低阶和高阶API
一、 基本信息
- 学习主题:LangChain4j 的两层 API 设计
- 核心目标:理解并区分低阶
ChatLanguageModelAPI 和高阶AIServiceAPI 的使用场景与优劣。 - 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 核心概念与原理
1. 低阶 API:ChatLanguageModel
- 定义:直接与 LLM 交互的接口,提供了最基础和最灵活的调用方式。
- 特点/为什么:
- 灵活性高:开发者需要手动管理消息列表 (
List<ChatMessage>)、工具调用结果、对话历史等,适合需要精细控制的场景。 - 支持多模态:
UserMessage可以包含文本、图像、音频、PDF 文件等多种内容类型。 - 核心方法:
chat(String userMessage),chat(List<ChatMessage> messages),chat(ChatRequest request)。
- 灵活性高:开发者需要手动管理消息列表 (
- 代码示例:
List<ChatMessage> messages = new ArrayList<>(); messages.add(new SystemMessage("You are a helpful assistant.")); messages.add(new UserMessage("What is LangChain4j?")); AiMessage response = chatModel.chat(messages);
2. 高阶 API:AIService
- 定义:基于动态代理和接口注解的声明式编程模型,是 LangChain4j 的核心抽象,旨在简化开发。
- 特点/为什么:
- 声明式开发:通过定义 Java 接口和注解(如
@SystemMessage,@UserMessage,@MemoryId)来描述 AI 服务的行为,框架自动处理底层交互,类似 Spring Data JPA。 - 集成高级功能:天然支持聊天记忆、工具调用、RAG 等,无需手动组装组件。
- 代码简洁:极大减少模板代码,使业务逻辑更清晰。
- 声明式开发:通过定义 Java 接口和注解(如
- 代码示例:
// 1. 定义接口 @AiService public interface Assistant { @SystemMessage("You are a helpful assistant.") String chat(@UserMessage String userMessage); } // 2. 创建代理实例并调用 Assistant assistant = AiServices.create(Assistant.class, chatModel); String answer = assistant.chat("What is LangChain4j?");
三、 个人思考与关联
- 疑问与探索:❓ 在什么场景下应该选择低阶 API 而非高阶 AIService?例如,处理复杂的多模态输入流时。
- 启发与联想:💡 AIService 的注解式开发模式,与 JAX-RS (Java RESTful API) 或 Spring MVC 的注解控制器非常相似,都是通过元数据来描述行为。
- 行动项:
- 使用低阶 API 实现一个包含历史消息的手动多轮对话。
- 使用 AIService 实现同一个功能,对比代码复杂度。
*创建于:2026-02-01 | 标签:#知识类 #API设计 #AIService
5. LangChain4j之模型参数配置
https://docs.langchain4j.dev/tutorials/observability#chat-model-observability
https://docs.langchain4j.dev/tutorials/spring-boot-integration#observability
一、 基本信息
- 学习主题:调控 LLM 行为的核心参数 + 日志/监控/重试/超时配置
- 核心目标:
- 掌握温度(temperature)、最大令牌数(max tokens)等关键参数的作用及调优方法
- 配置 LangChain4j 日志输出、请求监控、重试机制和超时控制
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
- 工程名称:langchain4j-05model-parameters
- 访问端口:9005
![[Pasted image 20260201174229.png]]
二、 核心概念与原理
1. 核心参数解析
- 温度 (Temperature):
- 定义:控制输出随机性的参数,取值范围通常为 0.0 到 2.0。
- 影响:较低值(如 0.1) 使输出更确定、一致,适合事实问答、代码生成。较高值(如 0.8) 增加随机性和创造性,适合创意写作、头脑风暴。
- 最大令牌数 (Max Tokens):
- 定义:限制模型单次响应所能生成的最大令牌(可以粗略理解为词元)数量。
- 影响:控制响应长度。设置过低可能导致回答不完整,过高可能浪费资源。
- Top-p (核采样):
- 定义:另一种控制随机性的方法,模型仅从累积概率超过阈值 p 的令牌中采样。
- 影响:与温度配合使用,可以更精细地控制输出的多样性。
- 超时时间 (Timeout):
- 定义:设置请求大模型的最大等待时间。
- 影响:防止请求长时间阻塞,快速失败并释放资源。
- 重试机制 (Retry):
- 定义:请求失败时自动重试的次数配置。
- 默认值:LangChain4j 对 OpenAI 集成默认重试 3 次。
2. 日志与监控
- 日志配置:需将日志级别调整为
DEBUG并开启 LangChain4j 日志开关,才能看到请求/响应的详细日志。 - 监控 (Observability):通过实现
ChatModelListener接口,监听大模型请求的生命周期(开始、结束、失败),实现请求耗时、成功率等指标监控。
三、 工程实现步骤
1. 基础工程搭建
(1) 创建 Maven 模块(langchain4j-05model-parameters)
(2) 修改 POM.xml 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.2</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>langchain4j-05model-parameters</artifactId>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- LangChain4j OpenAI 集成 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>0.37.0</version>
</dependency>
<!-- Lombok(可选,简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
(3) 编写 application.yml 配置文件
server:
port: 9005 # 工程端口
# LangChain4j 核心配置
langchain4j:
openai:
chat-model:
api-key: ${OPENAI_API_KEY:你的OpenAI API Key} # 替换为实际API Key
model-name: gpt-3.5-turbo
# 模型核心参数
temperature: 0.7 # 随机性:0.0(确定)~2.0(创意)
max-tokens: 500 # 最大响应令牌数
top-p: 1.0 # 核采样阈值
# 超时与重试配置
timeout: 2s # 请求超时时间(2秒)
max-retries: 2 # 重试次数(默认3次,此处改为2次)
log-requests: true # 开启请求日志
log-responses: true # 开启响应日志
# 日志配置
logging:
level:
root: INFO
dev.langchain4j: DEBUG # LangChain4j 日志级别设为DEBUG
org.springframework.web: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
2. 代码开发
(1) 主启动类
package com.langchain4j.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ModelParametersApplication {
public static void main(String[] args) {
SpringApplication.run(ModelParametersApplication.class, args);
}
}
(2) 监控监听器(实现 ChatModelListener)
package com.langchain4j.demo.config;
import dev.langchain4j.model.chat.ChatModelListener;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.chat.StreamingChatModelListener;
import dev.langchain4j.model.StreamingResponseHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
/**
* 大模型请求监控监听器
*/
@Slf4j
@Component
public class ChatModelMonitorListener implements ChatModelListener {
/**
* 请求开始时触发
*/
@Override
public void onStart(Object request, Object configuration) {
Instant start = Instant.now();
log.info("===== 大模型请求开始 =====");
log.info("请求参数: {}", request);
log.info("配置信息: {}", configuration);
// 将开始时间存入线程上下文,用于计算耗时
Thread.currentThread().setContextClassLoader(Thread.currentThread().getContextClassLoader());
Thread.currentThread().setName("chat-request-" + start.toEpochMilli());
}
/**
* 请求成功时触发
*/
@Override
public void onSuccess(Object request, Object response, Object configuration) {
Instant end = Instant.now();
String threadName = Thread.currentThread().getName();
long startMs = Long.parseLong(threadName.split("-")[2]);
Duration duration = Duration.between(Instant.ofEpochMilli(startMs), end);
log.info("===== 大模型请求成功 =====");
log.info("响应结果: {}", response);
log.info("请求耗时: {} 毫秒", duration.toMillis());
}
/**
* 请求失败时触发
*/
@Override
public void onError(Object request, Throwable error, Object configuration) {
log.error("===== 大模型请求失败 =====", error);
log.error("失败请求: {}", request);
}
}
(3) LLMConfig 配置类(手动配置扩展,可选)
package com.langchain4j.demo.config;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
/**
* 手动配置大模型(补充yml配置,可覆盖默认配置)
*/
@Configuration
public class LLMConfig {
@Value("${langchain4j.openai.chat-model.api-key}")
private String apiKey;
@Value("${langchain4j.openai.chat-model.model-name}")
private String modelName;
@Value("${langchain4j.openai.chat-model.temperature}")
private Double temperature;
@Value("${langchain4j.openai.chat-model.max-tokens}")
private Integer maxTokens;
@Value("${langchain4j.openai.chat-model.timeout}")
private Duration timeout;
@Value("${langchain4j.openai.chat-model.max-retries}")
private Integer maxRetries;
/**
* 手动创建 OpenAiChatModel Bean(可选,yml配置已足够)
*/
@Bean
public OpenAiChatModel openAiChatModel() {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.temperature(temperature)
.maxTokens(maxTokens)
.timeout(timeout)
.maxRetries(maxRetries)
.logRequests(true)
.logResponses(true)
.build();
}
}
(4) 业务 Controller
package com.langchain4j.demo.controller;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 模型参数测试控制器
*/
@Slf4j
@RestController
@RequestMapping("/modelparam")
@RequiredArgsConstructor
public class ModelParamController {
// 注入 LangChain4j 自动配置的 ChatLanguageModel
private final ChatLanguageModel chatLanguageModel;
/**
* 测试模型参数配置
* 访问地址:http://localhost:9005/modelparam/config?prompt=介绍下三文鱼
*/
@GetMapping("/config")
public String testModelParam(@RequestParam String prompt) {
try {
// 调用大模型
String response = chatLanguageModel.generate(prompt);
return "请求成功:\n" + response;
} catch (Exception e) {
log.error("调用大模型失败", e);
return "请求失败:" + e.getMessage();
}
}
}
四、 测试验证
1. 核心参数测试
- 访问
http://localhost:9005/modelparam/config?prompt=介绍下三文鱼 - 由于配置了
timeout: 2s,而GPT回答三文鱼通常需要超过2秒,会触发超时异常 - 修改
timeout为10s后,请求可正常返回
2. 重试机制测试
- 关闭网络(WiFi/有线)后访问上述接口
- 查看后台日志,会打印 2次重试(对应配置
max-retries: 2)+ 1次原始请求,共3次请求记录
3. 日志验证
- 启动工程后,控制台会输出
DEBUG级别的 LangChain4j 日志 - 包含请求的完整参数、响应内容、耗时等信息
4. 监控验证
- 每次请求都会触发
ChatModelMonitorListener的回调方法 - 控制台打印请求开始/成功/失败的日志,包含请求耗时等监控指标
五、 总结
- 核心参数:temperature 控制随机性、max-tokens 控制响应长度,可通过 yml 全局配置或代码手动配置。
- 可靠性配置:timeout 防止请求阻塞,max-retries 实现失败重试,默认重试3次可自定义。
- 可观测性:日志需开启 DEBUG 级别 + log-requests/log-responses;监控通过实现 ChatModelListener 监听请求生命周期。
- 工程结构:Spring Boot 集成 LangChain4j 只需引入专用 starter,核心配置在 yml 中完成,监听器@Component 自动生效。
六、 个人思考与关联
- 疑问与探索:❓ “温度”和“Top-p”通常如何配合使用?是否有经验性的最佳实践组合?
- 启发与联想:💡 这类似于数据库查询中的“优化器提示”(Hints)或 JVM 调优参数,通过调整“旋钮”来使系统行为更符合特定场景的预期。
- 行动项:
- 对同一个问题,分别设置 temperature=0.2 和 temperature=0.9,观察并记录回答的差异。
- 尝试设置一个很小的 max-tokens(如 50),看模型如何截断回答。
*创建于:2026-02-01 | 标签:#知识类 #模型调优 #参数配置
6. LangChain4j之多模态视觉理解
一、 基本信息
- 学习主题:让 LLM 处理图像等非文本内容
- 核心目标:掌握如何使用
UserMessage上传并让模型理解图像信息。 - 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x (需模型支持,如 GPT-4V)
![[Pasted image 20260201181832.png]]
二、 方法、流程与实战
1. 多模态支持原理
- 原理:
UserMessage类可以包含多个Content对象。除了TextContent,还支持ImageContent(通过 URL 或 Base64)、AudioContent、VideoContent、PdfFileContent等。LangChain4j 会将这些内容按模型要求格式组装成请求。 - 前提:所使用的底层 LLM 必须具备多模态理解能力(如 OpenAI GPT-4V、Google Gemini Pro Vision)。
![[Pasted image 20260201184415.png]]
![[Pasted image 20260201184445.png]]
![[Pasted image 20260201184604.png]]
![[Pasted image 20260201184620.png]]
![[Pasted image 20260201184722.png]]
![[Pasted image 20260201185052.png]]
![[Pasted image 20260201221210.png]]
2. 实践案例:图像描述
- 背景与目的:上传一张图片,让模型描述图片内容。
- 关键代码与注释:
// 假设从本地文件读取图片并转为 Base64 String base64Image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."; // 构建包含图片和文本的 UserMessage UserMessage userMessage = UserMessage.from( ImageContent.from(base64Image), // 图片内容 TextContent.from("请描述这张图片里有什么。") // 文本指令 ); // 发送消息(使用低阶 API 示例) AiMessage response = chatModel.chat(userMessage); System.out.println(response.text());
三、 个人思考与关联
- 疑问与探索:❓ 如何处理包含多张图片和复杂文本指令的混合输入?
Content对象的顺序是否影响模型理解? - 启发与联想:💡 这为开发“智能图库管理”、“视觉问答机器人”、“文档(含图表)理解”等应用提供了可能。可以类比为为 LLM 装上了“眼睛”。
- 行动项:
- 尝试使用图片的 URL 而非 Base64 来创建
ImageContent。 - 探索是否可以通过 AIService 的注解方式支持多模态输入。
- 尝试使用图片的 URL 而非 Base64 来创建
*创建于:2026-02-01 | 标签:#实战类 #多模态 #图像理解
7、 LangChain4j之流式输出
一、 基本信息
- 学习主题:实时获取 LLM 生成的令牌流,并与Web技术栈集成。
- 核心目标:实现类似 ChatGPT 的逐字输出效果,并掌握将其应用于Web接口(如SSE、WebSocket)的完整方案,提升用户体验。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 方法、流程与实战
![[Pasted image 20260201221346.png]]
![[Pasted image 20260201221405.png]]
1. 流式输出原理与三种实现方式
- 原理:传统的
chat方法会等待模型生成完整响应后一次性返回。流式输出 API 则允许注册一个回调,模型每生成一个令牌(token)就立即回调,实现边生成边输出,显著减少用户等待的感知时间,尤其对于长文本生成场景体验更好。 - 三种核心方式:
StreamingResponseHandler:最直接的原生接口,通过实现 ==onNext(String token)==等方法监听每个token,适合控制台打印或自定义处理逻辑。TokenStream:LangChain4j 封装的流式响应对象,实现了Iterable接口,允许以==“拉取(Pull)”模式按需、按节奏处理token==,适合后端进行复杂的逐token业务逻辑(如翻译、缓存)。Flux(与Reactor集成):将流式响应转换为响应式编程中的Flux<String>流。这是与 Spring WebFlux 和 SSE 无缝集成的“神器”,支持非阻塞、背压控制和丰富的流操作符(如map、filter),是实现高并发Web流式接口的首选方式。
2. 实践案例:从控制台到Web接口
-
基础控制台流式打印:使用
StreamingResponseHandler在控制台模拟逐字输出效果。 -
关键代码与注释:
chatModel.generate("请用 Java 写一个快速排序算法。", new StreamingResponseHandler<AiMessage>() { @Override public void onNext(String token) { // 每收到一个令牌就打印,不换行 System.out.print(token); System.out.flush(); // 确保立即输出 } @Override public void onComplete(Response<AiMessage> response) { System.out.println("\n--- 生成完毕 ---"); } @Override public void onError(Throwable error) { System.err.println("生成出错: " + error); } }); // 注意:generate 方法可能是异步的,主线程可能需要等待 -
Spring WebFlux + SSE 集成实战:这是构建生产级流式API的核心模式。
- 技术选型:使用 Spring WebFlux 替代传统的Spring MVC,因其非阻塞IO模型天生适合处理长时间运行的流式响应。选择 SSE 协议,因其基于HTTP,实现简单且支持自动重连,非常适合服务器向客户端单向推送AI生成内容的场景。
- 核心实现流程:
- Controller层:定义接口,返回
Flux<String>并设置produces = MediaType.TEXT_EVENT_STREAM_VALUE。 - Service层:创建
Sinks.Many<String>作为响应式流的源头。调用StreamingChatLanguageModel.generate()并传入自定义的StreamingResponseHandler,在onNext中将token通过sink.tryEmitNext(token)推入流,最终返回sink.asFlux()。 - 前端连接:使用
EventSourceAPI 连接SSE端点,监听onmessage事件实时更新页面内容。
- Controller层:定义接口,返回
- 关键配置与优化:
- 连接管理:为
Flux设置.timeout()和.retryWhen()策略,防止僵尸连接并提升网络容错性。 - 性能优化:可考虑将多个token打包后发送,以减少SSE事件帧数量,提升前端渲染效率。
- 连接管理:为
-
WebSocket集成备选:对于需要全双工实时通信的更复杂场景(如多人协作、实时指令),可选择WebSocket。Spring Boot也提供了良好的支持,在
@OnMessage方法中调用流式模型,并通过session.getAsyncRemote().sendText(token)发送令牌。
三、 个人思考与关联
- 疑问与探索:❓ 在WebFlux项目中,如何优雅地处理流式生成过程中的业务逻辑(如对话记忆持久化、RAG检索)?
- 启发与联想:💡
Flux的响应式模型使得在流式生成前后插入其他异步操作(如查询数据库、调用向量检索)变得非常自然,可以通过操作符链式调用实现复杂的业务管道。 - 疑问与探索:❓ 如何将流式输出与 Spring WebFlux 或传统的 Servlet 异步响应结合,用于 Web 接口?
- 启发与联想:💡 这与服务器推送(Server-Sent Events, SSE)或 WebSocket 技术结合,可以轻松构建具有实时交互感的 AI 聊天前端。
- 行动项:
- 将上述流式输出逻辑封装成一个 REST API,使用 SSE 向浏览器客户端推送数据
- 掌握三种流式输出方式的核心区别与适用场景。
- 实现一个完整的Spring Boot + WebFlux + LangChain4j流式聊天接口,并集成对话记忆功能。
8、 LangChain4j之记忆(Memory)
一、 基本信息
- 学习主题:使大模型具备对话记忆能力,实现连贯的多轮对话。
- 核心目标:理解并应用
ChatMemory抽象,实现短期(会话内)和长期(持久化)记忆。 - 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
![[Pasted image 20260201222759.png]]
二、 方法、流程与实战
1. 记忆的核心概念与实现
- 原理:默认情况下,LLM每次请求都是独立的。
ChatMemory的核心作用是自动维护和管理用户与AI之间的对话历史(List<ChatMessage>),并在每次请求时将其作为上下文提供给模型,从而实现有状态的对话。 - 两种管理方式:
- 手动管理:开发者自行维护一个
List<ChatMessage>,在每次调用模型时,将历史消息和当前问题一起传入。这种方式灵活但繁琐,需要自行处理消息窗口、持久化等。 - 自动管理(推荐):通过
ChatMemory组件自动管理。在创建AiService时绑定一个ChatMemory实例(如MessageWindowChatMemory),框架会自动完成消息的存储、截断和注入。
- 手动管理:开发者自行维护一个
2. 实践案例:实现有记忆的AI服务
- 使用
MessageWindowChatMemory:这是最常用的内存记忆实现,可指定保留最近N条消息或N个token。ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10); Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .chatMemory(chatMemory) .build(); // 后续对话,assistant 会自动记住上下文 - 记忆持久化:默认的
ChatMemory仅在内存中,应用重启后记忆会丢失。为了实现持久化(支持分布式会话),需要提供ChatMemoryStore的实现。社区提供了如langchain4j-community-redis-spring-boot-starter等组件,配置后即可将记忆自动存储到Redis等外部存储中,并支持TTL过期。
三、 个人思考与关联
- 疑问与探索:❓ 在流式对话场景中,如何确保对话历史在生成开始前已加载,并在生成结束后被正确保存?
- 启发与联想:💡 记忆机制是构建智能体(Agent)的基础,它使Agent能够基于历史交互进行学习和决策。结合向量数据库,甚至可以实现长期、跨会话的“经验”记忆。
- 行动项:
- 在流式聊天服务中,集成基于Redis的持久化
ChatMemory。
- 在流式聊天服务中,集成基于Redis的持久化
四、 LangChain4j之聊天记忆(ChatMemory)
一、 基本信息
- 学习主题:LangChain4j 聊天记忆的核心概念、使用方式与扩展
- 核心目标:
- 理解记忆(Memory)与历史(History)的区别
- 掌握内置的聊天记忆实现(消息窗口/令牌窗口)
- 实现聊天记忆的持久化存储
- 了解系统消息、工具消息的特殊处理规则
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 核心概念与原理
1. 记忆(Memory)vs 历史(History)
| 维度 | 记忆(Memory) | 历史(History) |
|---|---|---|
| 定义 | 呈现给LLM的对话信息,用于让模型"记住"对话 | 用户和AI之间的完整消息记录,用于UI展示 |
| 特性 | 可被修改(淘汰、总结、注入信息) | 完整无缺,保留所有原始消息 |
| 用途 | 适配LLM上下文窗口、控制成本/延迟 | 展示完整对话、追溯历史 |
| LangChain4j支持 | 原生支持多种实现 | 需手动实现保存 |
2. 淘汰策略(Eviction Strategy)
淘汰策略是ChatMemory的核心能力,主要解决3个问题:
- 上下文窗口限制:LLM单次可处理的令牌数有上限,超过则需淘汰旧消息
- 成本控制:减少令牌数降低API调用费用
- 延迟控制:减少令牌数加快LLM处理速度
LangChain4j提供2种开箱即用的淘汰策略实现:
| 实现类 | 核心逻辑 | 适用场景 |
|---|---|---|
| MessageWindowChatMemory | 保留最近N条消息,淘汰超出的旧消息 | 快速原型开发、消息长度均匀 |
| TokenWindowChatMemory | 保留最近N个令牌,消息不可分割(整段淘汰) | 生产环境、精准控制令牌数 |
3. 特殊消息处理规则
- SystemMessage(系统消息):
- 一旦添加始终保留,不会被淘汰
- 仅保留最新的1条(内容不同则替换,相同则忽略)
- 工具消息(Tool Messages):
- 若包含ToolExecutionRequest的AiMessage被淘汰,其关联的ToolExecutionResultMessage会被自动淘汰
- 避免向OpenAI等提供商发送孤立的ToolExecutionResultMessage导致报错
4. 持久化机制
- 默认ChatMemory使用内存存储,重启后丢失
- 可通过实现
ChatMemoryStore接口自定义持久化存储(数据库、Redis、文件等) - 核心方法:
getMessages():通过memoryId获取消息列表updateMessages():更新指定memoryId的消息(淘汰/新增时触发)deleteMessages():删除指定memoryId的所有消息(调用clear()时触发)
三、 工程实现步骤
1. 依赖补充(若未引入)
<!-- 如需TokenWindowChatMemory,需引入令牌解析依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>0.37.0</version>
</dependency>
<!-- 如需Redis持久化,可引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 核心代码实现
(1) 持久化存储实现(Redis示例)
package com.langchain4j.demo.memory;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.data.message.ChatMessageDeserializer;
import dev.langchain4j.data.message.ChatMessageSerializer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 基于Redis的ChatMemory持久化存储实现
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class RedisChatMemoryStore implements ChatMemoryStore {
private final StringRedisTemplate redisTemplate;
// 过期时间:24小时(可根据业务调整)
private static final long EXPIRATION_TIME = 24;
private static final TimeUnit EXPIRATION_UNIT = TimeUnit.HOURS;
private static final String REDIS_KEY_PREFIX = "langchain4j:chat:memory:";
/**
* 构建Redis Key
*/
private String buildKey(Object memoryId) {
return REDIS_KEY_PREFIX + memoryId.toString();
}
/**
* 从Redis获取消息列表
*/
@Override
public List<ChatMessage> getMessages(Object memoryId) {
String key = buildKey(memoryId);
String json = redisTemplate.opsForValue().get(key);
if (json == null || json.isEmpty()) {
return List.of();
}
try {
return ChatMessageDeserializer.messagesFromJson(json);
} catch (Exception e) {
log.error("从Redis反序列化ChatMessage失败, memoryId={}", memoryId, e);
return List.of();
}
}
/**
* 更新Redis中的消息列表(淘汰/新增消息时触发)
*/
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
String key = buildKey(memoryId);
try {
String json = ChatMessageSerializer.messagesToJson(messages);
redisTemplate.opsForValue().set(key, json, EXPIRATION_TIME, EXPIRATION_UNIT);
log.debug("更新ChatMemory成功, memoryId={}, 消息数={}", memoryId, messages.size());
} catch (Exception e) {
log.error("序列化ChatMessage并保存到Redis失败, memoryId={}", memoryId, e);
}
}
/**
* 删除Redis中的消息列表(调用clear()时触发)
*/
@Override
public void deleteMessages(Object memoryId) {
String key = buildKey(memoryId);
redisTemplate.delete(key);
log.debug("删除ChatMemory成功, memoryId={}", memoryId);
}
}
(2) ChatMemory配置类
package com.langchain4j.demo.config;
import dev.langchain4j.model.openai.OpenAiTokenizer;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.store.memory.chat.TokenWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* ChatMemory配置
*/
@Configuration
public class ChatMemoryConfig {
/**
* 消息窗口ChatMemory(基于消息数淘汰)
*/
@Bean
public MessageWindowChatMemory messageWindowChatMemory(ChatMemoryStore chatMemoryStore) {
return MessageWindowChatMemory.builder()
.id("default-message-window") // 默认memoryId
.maxMessages(10) // 保留最近10条消息
.chatMemoryStore(chatMemoryStore) // 持久化存储
.build();
}
/**
* 令牌窗口ChatMemory(基于令牌数淘汰)
*/
@Bean
public TokenWindowChatMemory tokenWindowChatMemory(ChatMemoryStore chatMemoryStore) {
return TokenWindowChatMemory.builder()
.id("default-token-window") // 默认memoryId
.maxTokens(1000) // 保留最近1000个令牌
.tokenizer(new OpenAiTokenizer()) // 使用OpenAI的令牌解析器
.chatMemoryStore(chatMemoryStore) // 持久化存储
.build();
}
}
(3) 业务服务类(AiServices使用示例)
package com.langchain4j.demo.service;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.AiService;
/**
* 基于AiServices的对话服务(自动集成ChatMemory)
*/
@AiService(
chatMemoryProvider = CustomChatMemoryProvider.class, // 自定义ChatMemory提供器
chatMemoryId = "default" // 默认memoryId
)
public interface ConversationService {
/**
* 系统消息:仅保留最新1条
*/
@SystemMessage("你是一个专业的客服助手,回答简洁明了,使用中文。")
String chat(@MemoryId String userId, @UserMessage String userMessage);
}
(4) 自定义ChatMemory提供器(按用户ID隔离)
package com.langchain4j.demo.service;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.service.ChatMemoryProvider;
import dev.langchain4j.store.memory.chat.ChatMemory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 为每个用户提供独立的ChatMemory
*/
@Component
@RequiredArgsConstructor
public class CustomChatMemoryProvider implements ChatMemoryProvider {
private final ChatMemoryStore chatMemoryStore;
/**
* 根据memoryId(此处为用户ID)创建专属ChatMemory
*/
@Override
public ChatMemory get(Object memoryId) {
// 为每个用户创建独立的MessageWindowChatMemory
return MessageWindowChatMemory.builder()
.id(memoryId) // 使用用户ID作为memoryId
.maxMessages(20) // 每个用户保留最近20条消息
.chatMemoryStore(chatMemoryStore) // 持久化存储
.build();
}
}
(5) Controller测试类
package com.langchain4j.demo.controller;
import com.langchain4j.demo.service.ConversationService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 聊天记忆测试控制器
*/
@RestController
@RequestMapping("/chat/memory")
@RequiredArgsConstructor
public class ChatMemoryController {
private final ConversationService conversationService;
/**
* 测试用户专属聊天记忆
* 访问地址:http://localhost:9005/chat/memory/chat?userId=user001&message=你好
*/
@GetMapping("/chat")
public String chat(
@RequestParam String userId,
@RequestParam String message
) {
return conversationService.chat(userId, message);
}
}
(6) 传统Chain使用示例(可选)
package com.langchain4j.demo.chain;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.chain.ConversationalChain;
import dev.langchain4j.store.memory.chat.ChatMemory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 传统ConversationalChain使用ChatMemory示例
*/
@Component
@RequiredArgsConstructor
public class ConversationalChainService {
private final ChatLanguageModel chatLanguageModel;
private final ChatMemory chatMemory;
/**
* 使用ConversationalChain进行对话
*/
public String converse(String userMessage) {
ConversationalChain chain = ConversationalChain.builder()
.chatLanguageModel(chatLanguageModel)
.chatMemory(chatMemory)
.build();
return chain.execute(userMessage);
}
}
3. 配置文件补充(application.yml)
# Redis配置(持久化ChatMemory用)
spring:
redis:
host: localhost
port: 6379
database: 0
timeout: 2000ms
# LangChain4j配置(补充)
langchain4j:
openai:
chat-model:
# 需配置API Key
api-key: ${OPENAI_API_KEY:你的API Key}
model-name: gpt-3.5-turbo
四、 测试验证
-
用户隔离测试:
- 访问
http://localhost:9005/chat/memory/chat?userId=user001&message=你好,我是用户1 - 访问
http://localhost:9005/chat/memory/chat?userId=user002&message=你好,我是用户2 - 验证两个用户的聊天记忆相互隔离,互不干扰
- 访问
-
持久化测试:
- 发送多条消息后重启应用
- 再次调用接口,验证聊天记忆未丢失
-
淘汰策略测试:
- 向同一个userId发送超过20条消息
- 查看Redis中的消息数,验证仅保留最近20条
-
系统消息测试:
- 修改@SystemMessage内容后重新调用
- 验证系统消息被更新为最新内容
五、 总结
- 核心区别:ChatMemory(供LLM使用,可修改)≠ 对话历史(供用户查看,需完整),LangChain4j仅原生支持前者。
- 淘汰策略:MessageWindowChatMemory适合快速开发,TokenWindowChatMemory适合生产环境,可精准控制令牌数。
- 持久化实现:通过自定义
ChatMemoryStore接口,可将ChatMemory存储到Redis/数据库等,核心是实现消息的序列化/反序列化。 - 用户隔离:通过memoryId(如用户ID)为每个用户创建独立的ChatMemory实例,实现会话隔离。
- 特殊消息:SystemMessage始终保留且仅存1条,工具消息会关联淘汰,需遵循这些规则避免兼容性问题。
9、 LangChain4j之持久化存储
一、 基本信息
- 学习主题:对话记忆与知识向量的持久化存储。
- 核心目标:区分两种持久化需求,并掌握其实现方案:1) 支撑有状态的长期对话;2) 为RAG应用构建外部知识库。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 方法、流程与实战
1. 记忆持久化 (ChatMemoryStore)
- 目标:解决应用重启或分布式部署时对话历史丢失的问题。
- 方案:通过实现
ChatMemoryStore接口,将消息存储到外部数据库。例如,使用langchain4j-community-redis-spring-boot-starter,在application.yml中配置Redis连接后,ChatMemory的数据便会自动持久化到Redis,支持会话管理和TTL。
2. 向量存储持久化 (EmbeddingStore) - RAG基石
- 目标:将外部文档(如PDF、内部知识)转换为向量并存储,供后续语义检索使用。
- 核心流程:
- 文档加载与解析:使用
DocumentLoader和DocumentParser(如基于Apache Tika)处理各类格式文件。 - 文本分块:使用
DocumentSplitter(如RecursiveCharacterTextSplitter)将长文档分割成适合嵌入模型处理的小片段(Chunk)。 - 向量化与存储:使用
EmbeddingModel将文本块转换为向量,然后存入EmbeddingStore(向量数据库),如 Redis Stack、Milvus、Pinecone等。这些数据库负责高效存储和相似性搜索。
- 文档加载与解析:使用
三、 个人思考与关联
- 疑问与探索:❓ 向量数据库(如Milvus)和传统关系型数据库在存储对话历史时,应如何选择?
- 启发与联想:💡 记忆存储关注的是时序和会话结构,而向量存储关注的是语义和相似性。两者结合可以构建更强大的AI应用,例如,用向量搜索快速找到相关历史对话片段。
- 行动项:
- 配置并使用Milvus或Redis Stack作为项目的向量数据库。
10、 LangChain4j之提示词工程
一、 基本信息
- 学习主题:通过精心设计的提示词(Prompt)引导大模型生成高质量、可控的输出。
- 核心目标:掌握LangChain4j提供的声明式(注解)和编程式两种提示词管理方案。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 方法、流程与实战
1. 注解式提示词(高阶API)
- 原理:通过在
AiService接口的方法上添加注解来定义提示词模板,是最声明式、便捷的方式。 - 核心注解:
@SystemMessage:定义AI的固定角色或系统指令,优先级最高。例如:@SystemMessage("你是一名专业的翻译官...")。@UserMessage:定义用户消息的模板,支持{{variable}}语法进行变量替换。例如:@UserMessage("将{{text}}翻译成英文")。@V:将方法参数绑定到模板变量名。
@AiService public interface Translator { @SystemMessage("你是一名专业的翻译官") @UserMessage("将以下文本翻译成英文:{{text}}") String translate(@V("text") String text); }
2. 编程式提示词模板(低阶API)
- 原理:使用
PromptTemplate类进行动态的提示词构建,适用于更复杂的场景。 - 用法:
String template = "请用{style}风格总结:{content}"; PromptTemplate promptTemplate = PromptTemplate.from(template); String finalPrompt = promptTemplate.apply(“幽默”, “一篇长文...”).text();
3. 最佳实践
- 角色清晰:充分利用
@SystemMessage明确AI的能力边界,提高准确性和安全性。 - 模板外置:将提示词模板内容放在资源文件(如
.txt)中,通过@SystemMessage(fromResource = “/prompts/system.txt”)引用,便于管理和A/B测试。 - 结构化提示:对于复杂输入,可使用
@StructuredPrompt注解定义提示词类。
三、 个人思考与关联
- 疑问与探索:❓ 如何对不同的用户或场景动态切换
SystemMessage? - 启发与联想:💡 提示词工程是“对齐”模型行为的关键。可以设计一个“提示词版本库”,根据用户反馈和数据指标持续迭代优化提示词。
- 行动项:
- 将项目的系统提示词外置到配置文件中。
11、 LangChain4j之工具调用
一、 基本信息
- 学习主题:赋予大模型调用外部工具(函数)的能力。
- 核心目标:掌握通过
@Tool注解定义工具,并让模型自主决策调用的流程,这是构建智能体(Agent)的核心。 - 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 方法、流程与实战
1. 核心概念与流程
- 原理:大模型根据用户请求和工具描述,自主决定是否需要调用工具、调用哪个工具、传入什么参数。执行后,工具的结果会返回给模型,模型再整合信息生成最终回答。
- 实现步骤:
- 定义工具:创建一个包含
@Tool注解的类或方法。@Tool中的描述至关重要,用于让LLM理解工具用途。public class Calculator { @Tool(“计算两个数字的和”) public int add(@P(“第一个加数”) int a, @P(“第二个加数”) int b) { return a + b; } } - 注册工具并创建AI服务:将工具实例绑定到
AiService。Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(new Calculator()) // 可注册多个工具 .build(); - 发起对话:当用户提问涉及工具能力时,LLM会自动触发调用。
- 定义工具:创建一个包含
2. 高级考量与安全
- 复杂任务规划:LangChain4j支持ReAct(Reasoning + Acting)模式,模型通过“思考链”逐步推理并调用工具,适合复杂任务。
- 安全与权限:自定义工具(如数据库查询工具)必须内置严格的权限校验和参数过滤(如SQL注入防护),防止LLM被诱导执行危险操作。
- 错误处理:为工具调用配置超时和重试机制,并设计友好的降级策略。
三、 个人思考与关联
- 疑问与探索:❓ 如何让模型在流式生成过程中,动态地决定并调用工具?
- 启发与联想:💡 工具调用将LLM从“思考大脑”升级为“决策中枢”,使其能操作真实世界。结合记忆和RAG,可以构建出能查询知识库、执行操作、并记录结果的超级助手。
- 行动项:
- 实现一个能查询数据库或调用外部API的工具。
12、 LangChain4j之向量数据库
一、 基本信息
- 学习主题:专门用于存储、索引和搜索高维向量(嵌入)的数据库。
- 核心目标:理解向量数据库在RAG中的作用,并掌握LangChain4j与主流向量数据库的集成。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 方法、流程与实战
1. 为什么需要向量数据库?
- 解决LLM局限:大模型本身的知识存在滞后性和局限性。向量数据库允许我们将外部知识(公司文档、最新资料)转换成向量存储。当用户提问时,先进行语义检索找到最相关的知识片段,再将其作为上下文提供给LLM,从而生成更准确、更具时效性的回答。
2. LangChain4j集成方案
- 抽象接口:通过
EmbeddingStore<TextSegment>接口统一操作。 - 常用实现:
- 入门/测试:
InMemoryEmbeddingStore。 - 生产级:Redis Stack(适合已有Redis生态)、Milvus/Pinecone(专业的分布式向量数据库,为大规模向量搜索优化)。
- 入门/测试:
3. 核心操作流程(文档入库)
// 1. 准备嵌入模型和向量存储
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
// 2. 文档处理:加载 -> 分块 -> 向量化 -> 存储
Document document = loadDocument(“handbook.pdf”);
List<TextSegment> segments = splitter.split(document);
for (TextSegment segment : segments) {
Embedding embedding = embeddingModel.embed(segment.text()).content();
embeddingStore.add(embedding, segment); // 存储向量和对应的文本片段
}
三、 个人思考与关联
- 疑问与探索:❓ 如何评估和选择不同的向量数据库?指标有哪些(如QPS、召回率、成本)?
- 启发与联想:💡 向量搜索的本质是“以问找答”。未来可探索多模态向量数据库,支持图片、音频的联合语义检索。
- 行动项:
- 对比测试Redis Stack和Milvus在相同数据集上的检索性能与精度。
13、 LangChain4j之检索增强生成
一、 基本信息
- 学习主题:检索增强生成(RAG)的完整架构与实现。
- 核心目标:掌握利用外部知识库增强大模型生成能力的技术,构建企业级知识问答系统。
- 学习日期:2026-02-01
- 技术版本:LangChain4j 1.x
二、 方法、流程与实战
1. RAG核心流程
RAG分为 索引(离线) 和 检索与生成(在线) 两个阶段。
- 索引阶段(离线):
- 文档加载:从文件、数据库等来源加载原始文档。
- 解析与分块:提取文本并按语义分割。
- 向量化与持久化:生成向量并存入向量数据库。
- 检索与生成阶段(在线):
- 问题向量化:将用户问题转换为向量。
- 语义检索:在向量库中做相似性搜索,找出最相关的K个文本块。
- 提示词构建:将检索到的上下文与问题结合,构建增强提示词(如“基于以下信息回答:{context}。问题:{question}”)。
- 增强生成:将增强提示词发送给LLM,得到最终答案。
2.LangChain4j的RAG支持:
LangChain4j提供了不同层次的API来简化RAG开发:
- Easy RAG:零配置快速入门,自动完成文档加载、分块、嵌入和存储的全流程,适合原型验证。
- Naive RAG:通过
EmbeddingStoreContentRetriever等组件进行基础配置,如设置最大返回结果数、相似度分数阈值等。
代码示例(Naive RAG核心部分):
// 1. 创建检索器,连接到已有的向量存储
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(3) // 返回最相关的3个片段
.build();
// 2. 创建AI服务时注入检索器
interface KnowledgeBaseAssistant {
String answer(String question);
}
KnowledgeBaseAssistant assistant = AiServices.builder(KnowledgeBaseAssistant.class)
.chatLanguageModel(model)
.contentRetriever(retriever) // 关键:绑定检索器
.build();
// 3. 提问(将自动完成检索-增强-生成的全过程)
String answer = assistant.answer(“LangChain4j中如何实现流式输出?”);
本学习笔记基于《LangChain4J零基础速通实战》课程内容,并结合了社区技术文档进行整理与拓展,最后更新于2026-02-01。
3. 实践案例(Naive RAG核心)
// 1. 创建检索器
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(3) // 返回最相关的3个片段
.build();
// 2. 创建AI服务时注入检索器
interface KnowledgeBaseAssistant {
String answer(String question);
}
KnowledgeBaseAssistant assistant = AiServices.builder(KnowledgeBaseAssistant.class)
.chatLanguageModel(model)
.contentRetriever(retriever) // 关键:绑定检索器
.build();
// 3. 提问(自动完成检索-增强-生成)
String answer = assistant.answer(“LangChain4j中如何实现流式输出?”);
三、 个人思考与关联
- **疑问与探索
本学习笔记基于《LangChain4J零基础速通实战》课程内容,并结合了社区技术文档进行整理与拓展,最后更新于2026-02-01。
更多推荐


所有评论(0)