参考资料:

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如何通过ChatModelEmbeddingModel等统一接口抽象不同的大模型服务商(如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的逐词输出体验。详细讲解StreamingResponseHandlerTokenStream以及如何与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 灵活性提升
  • 支持将 ChatRequestParameters 作为方法参数传递 #4226
  • 流式 AI Services 也支持传递 ChatRequestParameters #4264

5.其他重要变更 (Other Changes)
Agentic 相关改进
  • Agentic 作用域支持配置默认值 #4153
  • 修复 Supervisor 作为子代理使用的问题 #4161
  • Agent 支持通过 Map 定义工具 #4169
  • 修复条件规划器无匹配条件时的问题 #4202
  • 修复默认对话记忆在 Agent 中的使用问题 #4234
  • 新增 maxSequentialToolsInvocations 处理 #4204
RAG 与检索增强
  • 新增混合检索 (Hybrid Retrieval) 支持 #4124
  • 确保查询转换器始终能访问记忆中的系统消息 #4126
  • 增强用户消息后的对话记忆存储 #4272
向量存储与数据库
  • Infinispan 更新至 16.0.3 #4171 和 16.0.5 #4259
  • 新增 Jvector 文档 #4163
工具与 MCP (Model Context Protocol)
  • MCP HTTP & WebSocket 传输层支持自定义 HttpClient #4189
  • 修复 MCP 客户端在网络暂时故障后永久断开的问题 #4249
  • 修复 MCP 响应新增字段时的反序列化失败问题 #4283
安全与防护
  • 新增 MessageModeratorInputGuardrail 输入防护栏 #4160
提示词模板
  • PromptTemplate 支持 Fill name 功能 #4180
  • 修复单参数检测逻辑 #4186
缺陷修复
  • 修复 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. 首次模型调用
  • 原理:初始化 ChatLanguageModel Bean 后,可以直接调用其 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();
    }
}
总结
  1. 依赖管理核心:通过BOM统一版本,按场景选择核心依赖/社区依赖/SpringBoot Starter,避免版本冲突;
  2. 模型配置最佳实践:APIKey从环境变量获取,通过Builder模式配置超时、重试、日志等参数,多模型用@Qualifier区分;
  3. 开发模式选择:SpringBoot环境优先用@AiService声明式开发,非Spring环境用AiServices.create手动创建;
  4. 扩展能力:通过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. 项目初始化与配置
  • 步骤描述
    1. 创建 SpringBoot 项目:建议使用 SpringBoot 3.x 和 JDK 17+。
    2. 引入依赖:如上一节所示,引入 langchain4j-spring-boot-starter 及具体模型 starter。
    3. 配置密钥与模型参数:在 application.yml 中配置,支持多个模型 Bean 的配置。
    4. 创建启动类:标准的 SpringBoot 启动类即可。
  • 优势与局限
    • 优势:自动配置、依赖注入、与 Spring 生态无缝集成(如 @ConfigurationProperties 绑定配置)。
    • 局限:对非 Spring 的 Java 项目支持需要手动配置。
2. 自动配置的 Bean
  • 关键 Bean:引入 starter 后,Spring 会自动根据配置创建 ChatLanguageModelEmbeddingModelChatMemory 等 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 类,手动定义一个 ChatMemory Bean 以覆盖默认配置。

4. LangChain4j之低阶和高阶API

一、 基本信息
  • 学习主题:LangChain4j 的两层 API 设计
  • 核心目标:理解并区分低阶 ChatLanguageModel API 和高阶 AIService API 的使用场景与优劣。
  • 学习日期: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 等,无需手动组装组件。
    • 代码简洁:极大减少模板代码,使业务逻辑更清晰。
  • 代码示例
    // 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秒,会触发超时异常
  • 修改 timeout10s 后,请求可正常返回
2. 重试机制测试
  • 关闭网络(WiFi/有线)后访问上述接口
  • 查看后台日志,会打印 2次重试(对应配置 max-retries: 2)+ 1次原始请求,共3次请求记录
3. 日志验证
  • 启动工程后,控制台会输出 DEBUG 级别的 LangChain4j 日志
  • 包含请求的完整参数、响应内容、耗时等信息
4. 监控验证
  • 每次请求都会触发 ChatModelMonitorListener 的回调方法
  • 控制台打印请求开始/成功/失败的日志,包含请求耗时等监控指标
五、 总结
  1. 核心参数:temperature 控制随机性、max-tokens 控制响应长度,可通过 yml 全局配置或代码手动配置。
  2. 可靠性配置:timeout 防止请求阻塞,max-retries 实现失败重试,默认重试3次可自定义。
  3. 可观测性:日志需开启 DEBUG 级别 + log-requests/log-responses;监控通过实现 ChatModelListener 监听请求生命周期。
  4. 工程结构: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)、AudioContentVideoContentPdfFileContent 等。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 的注解方式支持多模态输入。

*创建于: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)就立即回调,实现边生成边输出,显著减少用户等待的感知时间,尤其对于长文本生成场景体验更好。
  • 三种核心方式
    1. StreamingResponseHandler:最直接的原生接口,通过实现 ==onNext(String token) ==等方法监听每个token,适合控制台打印或自定义处理逻辑。
    2. TokenStream:LangChain4j 封装的流式响应对象,实现了 Iterable 接口,允许以==“拉取(Pull)”模式按需、按节奏处理token==,适合后端进行复杂的逐token业务逻辑(如翻译、缓存)。
    3. Flux (与Reactor集成):将流式响应转换为响应式编程中的 Flux<String>。这是与 Spring WebFluxSSE 无缝集成的“神器”,支持非阻塞、背压控制和丰富的流操作符(如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生成内容的场景。
    • 核心实现流程
      1. Controller层:定义接口,返回 Flux<String> 并设置 produces = MediaType.TEXT_EVENT_STREAM_VALUE
      2. Service层:创建 Sinks.Many<String> 作为响应式流的源头。调用 StreamingChatLanguageModel.generate() 并传入自定义的 StreamingResponseHandler,在 onNext 中将token通过 sink.tryEmitNext(token) 推入流,最终返回 sink.asFlux()
      3. 前端连接:使用 EventSource API 连接SSE端点,监听 onmessage 事件实时更新页面内容。
    • 关键配置与优化
      • 连接管理:为 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>),并在每次请求时将其作为上下文提供给模型,从而实现有状态的对话。
  • 两种管理方式
    1. 手动管理:开发者自行维护一个 List<ChatMessage>,在每次调用模型时,将历史消息和当前问题一起传入。这种方式灵活但繁琐,需要自行处理消息窗口、持久化等。
    2. 自动管理(推荐):通过 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
四、 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. 一旦添加始终保留,不会被淘汰
    2. 仅保留最新的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
四、 测试验证
  1. 用户隔离测试

    • 访问 http://localhost:9005/chat/memory/chat?userId=user001&message=你好,我是用户1
    • 访问 http://localhost:9005/chat/memory/chat?userId=user002&message=你好,我是用户2
    • 验证两个用户的聊天记忆相互隔离,互不干扰
  2. 持久化测试

    • 发送多条消息后重启应用
    • 再次调用接口,验证聊天记忆未丢失
  3. 淘汰策略测试

    • 向同一个userId发送超过20条消息
    • 查看Redis中的消息数,验证仅保留最近20条
  4. 系统消息测试

    • 修改@SystemMessage内容后重新调用
    • 验证系统消息被更新为最新内容
五、 总结
  1. 核心区别:ChatMemory(供LLM使用,可修改)≠ 对话历史(供用户查看,需完整),LangChain4j仅原生支持前者。
  2. 淘汰策略:MessageWindowChatMemory适合快速开发,TokenWindowChatMemory适合生产环境,可精准控制令牌数。
  3. 持久化实现:通过自定义ChatMemoryStore接口,可将ChatMemory存储到Redis/数据库等,核心是实现消息的序列化/反序列化。
  4. 用户隔离:通过memoryId(如用户ID)为每个用户创建独立的ChatMemory实例,实现会话隔离。
  5. 特殊消息: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、内部知识)转换为向量并存储,供后续语义检索使用。
  • 核心流程
    1. 文档加载与解析:使用 DocumentLoaderDocumentParser(如基于Apache Tika)处理各类格式文件。
    2. 文本分块:使用 DocumentSplitter(如 RecursiveCharacterTextSplitter)将长文档分割成适合嵌入模型处理的小片段(Chunk)。
    3. 向量化与存储:使用 EmbeddingModel 将文本块转换为向量,然后存入 EmbeddingStore(向量数据库),如 Redis StackMilvus、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. 核心概念与流程
  • 原理:大模型根据用户请求和工具描述,自主决定是否需要调用工具、调用哪个工具、传入什么参数。执行后,工具的结果会返回给模型,模型再整合信息生成最终回答。
  • 实现步骤
    1. 定义工具:创建一个包含 @Tool 注解的类或方法。@Tool 中的描述至关重要,用于让LLM理解工具用途。
      public class Calculator {
          @Tool(“计算两个数字的和”)
          public int add(@P(“第一个加数”) int a, @P(“第二个加数”) int b) {
              return a + b;
          }
      }
      
    2. 注册工具并创建AI服务:将工具实例绑定到 AiService
      Assistant assistant = AiServices.builder(Assistant.class)
              .chatLanguageModel(model)
              .tools(new Calculator()) // 可注册多个工具
              .build();
      
    3. 发起对话:当用户提问涉及工具能力时,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分为 索引(离线)检索与生成(在线) 两个阶段。

  1. 索引阶段(离线)
    • 文档加载:从文件、数据库等来源加载原始文档。
    • 解析与分块:提取文本并按语义分割。
    • 向量化与持久化:生成向量并存入向量数据库。
  2. 检索与生成阶段(在线)
    • 问题向量化:将用户问题转换为向量。
    • 语义检索:在向量库中做相似性搜索,找出最相关的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。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐