LangChain4j
LangChain4j
AI发展史
AI,人工智能(Artificial Intelligence),使机器能够像人类一样思考、学习和解决问题。其发展史经历了符号主义、连接主义、神经网络三个阶段。
符号主义:将现实抽象为符号然后设置规则最后执行。如将天晴记为A,打篮球记为B,打游戏记为C。设置执行规则 --> 如果A,执行B,否则执行C,和代码中的if else很像。其有一个致命问题就是不可能把世界上所有的事情抽象为符号。
连接主义:模仿大脑神经元(树突接收信息、轴突传递信息、突触输出)的工作机制,有人提出了感知机模型(输入、权重、激活函数-输出)来模拟神经元。单个感知机只能处理一些是或者不是的判断,并不能处理复杂的逻辑。多层感知机由多个感知机叠加而成,第一层感知机的输出作为第二层感知机的输入,层层传递从而得到最终输出。理论上感知机的层数只要足够深就能解决任何复杂性问题,这也是神经网络的由来。
神经网络:每个感知机都有输入和权重以及激活函数,结合用户的输入和权重以及激活函数再与阈值(专业术语叫偏置)比较得到最终输出。每个神经元上使用的权重和偏置专业术语叫参数。由此每个神经元的参数数量等于权重数量 + 1。整个神经网络参数数量数不胜数。幸运的是这些参数不需要手动设置,神经网络是数学意义上面的模型
,将来这些模型需要软件(代码)去实现,这种软件具有学习能力,我们只需把数据给它,它就会自主的根据我们提供的数据去学习,学习过程中就会自动设置好神经网络中成千上万的参数。由于这种软件(代码)本质上实现了数学模型所以在AI领域一般不把其叫做软件而是模型。
AI市场分析
智能应用:将大模型接入传统软件中从而制作出智能应用(Agent)。
核心算法:主要研究开发大模型需要的算法以及算法框架比如Transformers、TensorFlow、PyTorch。主要公司有OpenAI、深度求索、Meta、Google。
基础算力:顾名思义就是提供计算能力的,这个赛道都是一些超大公司比如(英伟达、超威、寒武纪、亚马逊、阿里云、微软)。算力强不强芯片是关键,英伟达、超威、寒武纪都是制作芯片的。亚马逊、阿里云、微软是玩云计算的,由于大模型对算力的要求很高,很多情况下单台计算机并不能满足大模型的算力要求,此时就得考虑分布式部署。这些是亚马逊、阿里云、微软这些公司的强项。
大模型使用
大模型部署
自己部署
云服务部署:前期成本低,维护简单但是数据不安全,长期使用成本高。
本地部署:数据安全,长期成本低但是初期成本高,维护困难。可以使用Ollama、LM Studio等一键下载运行大模型。
他人部署
使用阿里云百炼、百度智能云、硅基流动、火山引擎等部署好的大模型,需要去申请API接口。
大模型调用
本地部署大模型
Ollama 下载
Ollama官网:https://ollama.com/
Ollama 安装
默认安装路径是C盘。如果需要改变安装路径,找到下载的OllamaSetup.exe安装包,比如存放在D盘的temp文件夹中。以管理员身份打开CMD,输入cd /d D:\Temp定位到安装包目录,再执行命令OllamaSetup.exe /DIR="目标安装路径",将引号内内容替换为你想安装的路径即可,比如OllamaSetup.exe /DIR="D:\AI\Ollama"。下载时会自动配置环境变量,其中有OLLAMA_MODELS环境变量其是大模型存储目录,默认也是C盘,如果需要更改其位置,自行更改即可。
Ollama 安装大模型
# 安装命令格式
ollama run [大模型名称]
# 有哪些大模型名称可去官网查看
# 如qwen3:0.6b 其中:后面的0.6b表示qwen3这个大模型有6亿个参数
# 1b = 10亿,参数越多越强,当然对电脑性能要求也越高
# 可自行根据需求选择不同参数量的大模型下载
# 安装示例
ollama run qwen3:0.6b
# 退出对话命令
/bye
# 退出后又想与其对话的命令还是安装命令
# 如果你电脑上已经安装过则不会重新安装而是进入对话界面,没有安装过则会安装
ollama run qwen3:0.6b
Ollama API对话方式
如果你本地上下载了Ollama大模型,它会在你本机的11434端口开一个服务。那么除了CMD黑窗口的对话方式外,就可以调用接口(具体接口名称需要去官网查)与其对话。
URL: http://localhost:11434/api/chat
请求方式:POST
请求体:
{
"model": "qwen3:0.6b", // 模型名称,需要与你电脑上下载的模型名一致
"messages": [
{
"role": "user", // 角色名
"content": "你好呀!" // 你的问题
}
],
"think": true,
"stream": false
}
阿里云百炼
- 登录阿里云: https://www.aliyun.com/
- 开通大模型服务平台百炼
- 申请百炼平台API-KEY
- 选择模型并使用
Token简介
在大语言模型中Token是大模型处理文本的最小单位,可以理解为模型看得懂的最小文本片段。用户输入的内容都需要转换成token,才能让大模型更好的处理。不同大模型一个Token代表多少字并不相同,使用第三方大模型都是按照Token数收费的。
普通Maven工程应用大模型
引入依赖
<!-- langchain4j依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.1</version>
</dependency>
创建OpenAiChatModel
package com.tensoflow;
import dev.langchain4j.model.openai.OpenAiChatModel;
@SuppressWarnings({"all"})
public class App {
public static void main( String[] args ) {
// 构建OpenAiChatModel对象
OpenAiChatModel model = OpenAiChatModel.builder()
// 阿里云平台大模型API参考中查询
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
// 阿里云平台上面申请的API-KEY
// 直接写死不安全
// 推荐在环境变量中的用户变量中创建API-KEY的变量,在这里通过代码读取
.apiKey(System.getenv("API-KEY"))
// 模型名称
.modelName("qwen-plus")
.build();
// 调用chat方法与大模型交互
String result = model.chat("晚上好呀!");
System.out.println(result);
}
}
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tensoflow</groupId>
<artifactId>langchain</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>langchain</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- langchain4j依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
晚上好呀!🌙 今天的夜色真温柔呢~你吃晚饭了吗?希望你度过了愉快的一天!(✧ω✧)
Process finished with exit code 0
注意
如果是在打开IDEA的时候配置的环境变量,需要重启IDEA才能读取到API-KEY变量值
打印日志信息
package com.tensoflow;
import dev.langchain4j.model.openai.OpenAiChatModel;
@SuppressWarnings({"all"})
public class App {
public static void main( String[] args ) {
// 构建OpenAiChatModel对象
OpenAiChatModel model = OpenAiChatModel.builder()
// 阿里云平台大模型API参考中查询
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
// 阿里云平台上面申请的API-KEY
// 直接写死不安全
// 推荐在环境变量中的用户变量中创建API-KEY的变量,在这里通过代码读取
.apiKey(System.getenv("API-KEY"))
// 模型名称
.modelName("qwen-plus")
// 开启打印请求日志
.logRequests(true)
// 开启打印响应日志
.logResponses(true)
.build();
// 调用chat方法与大模型交互
String result = model.chat("晚上好呀!");
System.out.println(result);
}
}
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tensoflow</groupId>
<artifactId>langchain</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>langchain</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- langchain4j依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.1</version>
</dependency>
<!-- logback日志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
00:10:15.432 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP request:
- method: POST
- url: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
- headers: [Authorization: Beare...c0], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "qwen-plus",
"messages" : [ {
"role" : "user",
"content" : "晚上好呀!"
} ],
"stream" : false
}
00:10:17.986 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP response:
- status code: 200
- headers: [:status: 200], [content-length: 527], [content-type: application/json], [date: Tue, 13 Jan 2026 16:10:16 GMT], [req-arrive-time: 1768320614823], [req-cost-time: 2157], [resp-start-time: 1768320616980], [server: istio-envoy], [vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding], [x-dashscope-call-gateway: true], [x-envoy-upstream-service-time: 2155], [x-request-id: beec59b7-867b-90df-b48b-b895ea02c54c]
- body: {"choices":[{"message":{"role":"assistant","content":"晚上好呀!🌙 今天过得怎么样呀?希望你度过了愉快的一天~ 有什么想聊的或者需要帮忙的,都可以告诉我哦!(✧ω✧)"},"finish_reason":"stop","index":0,"logprobs":null}],"object":"chat.completion","usage":{"prompt_tokens":12,"completion_tokens":38,"total_tokens":50,"prompt_tokens_details":{"cached_tokens":0}},"created":1768320617,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-beec59b7-867b-90df-b48b-b895ea02c54c"}
晚上好呀!🌙 今天过得怎么样呀?希望你度过了愉快的一天~ 有什么想聊的或者需要帮忙的,都可以告诉我哦!(✧ω✧)
Process finished with exit code 0
SpringBoot项目应用大模型
引入依赖
<!-- 要注意SpringBoot版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<!-- langchain4j起步依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true # 请求日志显示
log-responses: true # 响应日志显示
logging:
level:
dev.langchain4j: info # 日志级别
初级使用
package com.tensoflow.controller;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description: 大模型
* @author: TenSoFlow
* @date: 2026-01-17
**/
@RestController
@RequestMapping(value = "user")
public class ChatController {
@Autowired
private OpenAiChatModel model;
@GetMapping("chat")
public String Chat(String message) {
String result = model.chat(message);
return result;
}
}
AiServices工具类
AiServices 是一个核心工具类,用于将普通Java接口动态代理为可直接调用的大模型AI服务。它的本质是:把 Prompt 工程、上下文拼装、模型调用这些复杂细节,全部封装到一个接口实现中。仅需定义一个简单的Java接口,就能快速创建出具备大模型调用、提示词管理、参数绑定等能力的 AI 服务实例。
<!-- 增加AiServices工具类依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
package com.tensoflow.service;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
/**
* @AiService 是 LangChain4j 提供的核心注解
* 用于将一个普通的 Java 接口声明为「AI 服务接口」
* 被该注解标注的接口不会有手写实现类
* 而是由 LangChain4j 在 Spring 容器启动阶段通过动态代理自动生成实现类
* 并自动注册为 Spring Bean
*/
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 创建对象时手动装配
chatModel = "openAiChatModel" // 模型名称
)
public interface MyAiService {
/**
* 用于和大模型聊天的方法
* @param message 用户问题
* @return 大模型的回答
*/
String chat(String message);
}
调用AiServices使用
package com.tensoflow.controller;
import com.tensoflow.service.MyAiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description: 大模型
* @author: TenSoFlow
* @date: 2026-01-17
**/
@RestController
@RequestMapping(value = "user")
public class ChatController {
@Autowired
private MyAiService myAiService;
@GetMapping("chat")
public String Chat(String message) {
String result = myAiService.chat(message);
return result;
}
}
流式调用
流式调用指大模型在生成回答时,不等待完整结果生成完毕,而是将内容按片段(token / 句子 / 段落)实时、持续地返回给调用方,调用方可以边接收边处理或者展示结果。
<!-- 增加流式调用相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.0.1-beta6</version>
</dependency>
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true # 请求日志显示
log-responses: true # 响应日志显示
streaming-chat-model: # 流式调用
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
logging:
level:
dev.langchain4j: info # 日志级别
package com.tensoflow.service;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
/**
* @AiService 是 LangChain4j 提供的核心注解
* 用于将一个普通的 Java 接口声明为「AI 服务接口」
* 被该注解标注的接口不会有手写实现类
* 而是由 LangChain4j 在 Spring 容器启动阶段通过动态代理自动生成实现类
* 并自动注册为 Spring Bean
*/
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 创建对象时手动装配
chatModel = "openAiChatModel", // 模型名称
streamingChatModel = "openAiStreamingChatModel" // 流式调用模型名称
)
public interface MyAiService {
/**
* 用于和大模型聊天的方法
* @param message 用户问题
* @return 大模型的回答
*/
Flux<String> chat(String message);
}
流式调用使用
package com.tensoflow.controller;
import com.tensoflow.service.MyAiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* @Description: 大模型
* @author: TenSoFlow
* @date: 2026-01-17
**/
@RestController
@RequestMapping(value = "user")
public class ChatController {
@Autowired
private MyAiService myAiService;
// 要加上produces = "text/html;charset=utf-8"不然会出现乱码
@GetMapping(value = "chat", produces = "text/html;charset=utf-8")
public Flux<String> Chat(String message) {
Flux<String> result = myAiService.chat(message);
return result;
}
}
会话功能 - 消息注解
@SystemMessage
定义并固定发送给大模型的 system role 提示词(系统提示),用于从系统层面约束或引导模型的整体行为和回答风格。可以让模型在整个接口生命周期内都扮演一个稳定角色。如:资深 Java 架构师、严谨的技术文档审查员、只用中文回答的企业助手等等。
package com.tensoflow.service;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 创建对象时手动装配
chatModel = "openAiChatModel", // 模型名称
streamingChatModel = "openAiStreamingChatModel" // 流式调用模型名称
)
public interface MyAiService {
// 方式一:直接为大模型定义角色
@SystemMessage("你是TenSoFlow的助手包豆,特别善长编程。")
Flux<String> chat(String message);
}
package com.tensoflow.service;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 创建对象时手动装配
chatModel = "openAiChatModel", // 模型名称
streamingChatModel = "openAiStreamingChatModel" // 流式调用模型名称
)
public interface MyAiService {
// 方式二:使用文件的方式为大模型定义角色
// fromResource会将类路径(resources)当做根路径
@SystemMessage(fromResource = "system.txt")
Flux<String> chat(String message);
}
@UserMessage
用于定义大模型交互中的用户消息,配合@AiService标记的接口使用,能快速绑定方法参数与大模型的用户提示词,无需手动拼接提示词字符串,是实现结构化提示词模板的关键注解。简单来说,这个注解的作用是告诉 LangChain4j该注解标记的内容是发送给大模型的用户输入,既可以直接写固定提示词,也可以通过占位符绑定方法参数实现动态提示词。@SystemMessage是写死的,不能实现动态化,而@UserMessage就能实现让用户自定义大模型角色。
package com.tensoflow.service;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 创建对象时手动装配
chatModel = "openAiChatModel", // 模型名称
streamingChatModel = "openAiStreamingChatModel" // 流式调用模型名称
)
public interface MyAiService {
// {{it}}只能这样写,不能写成别的
// 会将chat方法中的message参数替换掉{{it}}
@UserMessage("你是TenSoFlow的助手豆包,特别善长编程。{{it}}")
Flux<String> chat(String message);
}
package com.tensoflow.service;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 创建对象时手动装配
chatModel = "openAiChatModel", // 模型名称
streamingChatModel = "openAiStreamingChatModel" // 流式调用模型名称
)
public interface MyAiService {
// 不加注解只能写{{it}}
// 加上@V注解之后则可以自定义{{}}中的名称
@UserMessage("你是TenSoFlow的助手豆包,特别善长编程。{{msg}}")
Flux<String> chat(@V("msg") String message);
}
会话功能 - 会话记忆
大模型是不具备记忆功能的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与新的提示词一起发给大模型。
package com.tensoflow.config;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description: 配置类
* @author: TenSoFlow
* @date: 2026-01-22
**/
@Configuration
public class CommonConfig {
// 构建会话记忆对象
@Bean
public ChatMemory chatMemory () {
return MessageWindowChatMemory.builder()
.maxMessages(20) // 最多记忆条数
.build();
}
}
package com.tensoflow.service;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel",
chatMemory = "chatMemory" // 配置会话记忆对象
)
public interface MyAiService {
/**
* 用于和大模型聊天的方法
* @param message 用户问题
* @return 大模型的回答
*/
@SystemMessage("你是TenSoFlow的助手豆包,特别善长编程。")
Flux<String> chat(String message);
}
会话功能 - 会话记忆隔离
如果使用的是同一个记忆存储对象(ChatMemory),则不同对话之间的记忆不会隔离。
package com.tensoflow.config;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description: 配置类
* @author: TenSoFlow
* @date: 2026-01-22
**/
@Configuration
public class CommonConfig {
// // 构建会话记忆对象
// @Bean
// public ChatMemory chatMemory () {
// return MessageWindowChatMemory.builder()
// .maxMessages(20) // 最多记忆条数
// .build();
// }
// 构建会话记忆提供者对象
@Bean
public ChatMemoryProvider chatMemoryProvider () {
return new ChatMemoryProvider() {
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20) // 最多记忆条数
.build();
}
};
}
}
package com.tensoflow.service;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel",
// chatMemory = "chatMemory", // 会话记忆对象
chatMemoryProvider = "chatMemoryProvider" // 配置会话记忆提供者对象
)
public interface MyAiService {
// 需要传入memoryid
@SystemMessage("你是TenSoFlow的助手豆包,特别善长编程。")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
package com.tensoflow.controller;
import com.tensoflow.service.MyAiService;
import org.springframework.beans.factory.annotation.Autowired;
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;
import reactor.core.publisher.Flux;
/**
* @Description: 大模型
* @author: TenSoFlow
* @date: 2026-01-17
**/
@RestController
@RequestMapping(value = "user")
public class ChatController {
@Autowired
private MyAiService myAiService;
// 要加上produces = "text/html;charset=utf-8"不然会出现乱码
@GetMapping(value = "chat", produces = "text/html;charset=utf-8")
public Flux<String> Chat(
@RequestParam("memoryId") String memoryId,
@RequestParam("message") String message
) {
Flux<String> result = myAiService.chat(memoryId, message);
return result;
}
}
会话功能 - 会话记忆持久化
默认的 MessageWindowChatMemory 依赖内存中的 List 存储会话,重启即丢失,因此需要通过实现 ChatMemoryStore 接口(有获取聊天记录、删除聊天记录、更新聊天记录等方法)自定义持久化逻辑如可以存储到Redis中,再将其注入到 MessageWindowChatMemory 中,替换默认的内存存储方式。
<!-- Redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true # 请求日志显示
log-responses: true # 响应日志显示
streaming-chat-model: # 流式调用
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
logging:
level:
dev.langchain4j: info # 日志级别
# redis配置
spring:
data:
redis:
host: localhost
port: 6379
package com.tensoflow.repository;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.ChatMessageDeserializer;
import dev.langchain4j.data.message.ChatMessageSerializer;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import java.time.Duration;
import java.util.List;
/**
* @Description: 存储实现类
* @author: TenSoFlow
* @date: 2026-01-22
**/
@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
// 注入RedisTemplate
@Autowired
private StringRedisTemplate redisTemplate;
// 获取所有聊天记录
@Override
public List<ChatMessage> getMessages(Object memoryId) {
// 从redis中获取所有聊天记录
String json = redisTemplate.opsForValue().get(memoryId);
// 把Json字符串转为List<ChatMessage>
List<ChatMessage> list = ChatMessageDeserializer.messagesFromJson(json);
return list;
}
// 更新所有聊天记录
@Override
public void updateMessages(Object memoryId, List<ChatMessage> list) {
// 把List(所有聊天记录)转为Json数据
String json = ChatMessageSerializer.messagesToJson(list);
// 把Json数据存储到redis中 一天有效期
redisTemplate
.opsForValue()
.set(memoryId.toString(), json, Duration.ofDays(1));
}
// 删除所有聊天记录
@Override
public void deleteMessages(Object memoryId) {
redisTemplate.delete(memoryId.toString());
}
}
package com.tensoflow.config;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description: 配置类
* @author: TenSoFlow
* @date: 2026-01-22
**/
@Configuration
public class CommonConfig {
@Autowired
private ChatMemoryStore redisChatMemoryStore;
// 构建会话记忆提供者对象
@Bean
public ChatMemoryProvider chatMemoryProvider () {
return new ChatMemoryProvider() {
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.chatMemoryStore(redisChatMemoryStore) // 自定义存储实现
.maxMessages(20) // 最多记忆条数
.build();
}
};
}
}
RAG知识库 - 介绍
简介
RAG(Retrieval Augmented Generation)检索增强生成。通过检索外部知识库的方式增强大模型的生成能力。大模型的知识库叫向量数据库是一种特殊的数据库。
向量
数学和物理中表示大小和方向的量
- 几何表示:有向线段,可以用一条带箭头的线段表示,线段长度表示大小,箭头方向表示向量方向
- 坐标表示,在直角坐标系中,向量可以用一组坐标表示
向量余弦相似度
用于表示坐标系中两个点之间的距离远近,值越大说明向量方向越近,两点之间的距离越小
向量数据库使用流程
先对外部知识文档做预处理切片,用指定的向量模型将文本片段转化为向量并与原文绑定后存入向量数据库,同时建立向量索引。当用户提出问题时,使用同一向量模型将问题转化为向量,在向量数据库中通过余弦相似度等算法检索出语义最相似的若干文本片段,将这些片段与用户问题拼接成Prompt发送给大模型,最终由大模型结合检索到的外部知识生成精准答案并返回。
RAG知识库 - 快速入门
构建向量数据库操作对象与检索对象
<!-- 增加rag-easy依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
<version>1.0.1-beta6</version>
</dependency>
package com.tensoflow.config;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.ClassPathDocumentLoader;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @Description: 配置类
* @author: TenSoFlow
* @date: 2026-01-22
**/
@Configuration
public class CommonConfig {
@Autowired
private ChatMemoryStore redisChatMemoryStore;
// 构建会话记忆提供者对象
@Bean
public ChatMemoryProvider chatMemoryProvider () {
return new ChatMemoryProvider() {
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.chatMemoryStore(redisChatMemoryStore) // 自定义存储实现
.maxMessages(20) // 最多记忆条数
.build();
}
};
}
// 构建向量数据库操作对象
@Bean
public EmbeddingStore embeddingStore () {
/**
* 加载文档进入内存
* loadDocuments的方法参数是resources下的一个目录(不是文件)名称
* 目录下可存放多个markdown文件或者PDF文件作为外部知识文档
* loadDocuments会扫描目录下的所有文件
*/
List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
// 构建向量数据库操作对象
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
// 构建一个EmbeddingStoreIngestor对象,完成文本数据切片、向量化、存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.build();
ingestor.ingest(documents);
return store;
}
// 构建向量数据库检索对象
@Bean
public ContentRetriever contentRetriever (EmbeddingStore store) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.minScore(0.5) // 余弦相似度合格值(0 ~ 1)
.maxResults(3) // 检索最大条数
.build();
}
}
package com.tensoflow.service;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel",
// chatMemory = "chatMemory",
chatMemoryProvider = "chatMemoryProvider",
contentRetriever = "contentRetriever" // 配置向量数据库检索对象
)
public interface MyAiService {
/**
* 用于和大模型聊天的方法
* @param message 用户问题
* @return 大模型的回答
*/
@SystemMessage("你是TenSoFlow的助手豆包,特别善长编程。")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
RAG知识库 - 核心API
文档加载器
用于把磁盘或者网络中的数据加载进程序
- FileSystemDocumentLoader:根据本地磁盘绝对路径加载
- ClassPathDocumentLoader:相对于类路径加载
- UrlDocumentLoader:根据URL路径加载
文档解析器
用于解析使用文档加载器加载进内存的内容,把非纯文本数据转化成纯文本
- TextDocumentParser:解析纯文本格式的文件
- ApachePdfBoxDocumentParser:解析PDF格式文件
- ApachePoiDocumentParser:解析微软的office文件例如DOC、PPT、XLS
- ApacheTikaDocumentParser(默认):几乎可以解析所有格式的文件
<!-- 增加PDF解析器依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
<version>1.0.1-beta6</version>
</dependency>
// 构建向量数据库操作对象
@Bean
public EmbeddingStore embeddingStore () {
/**
* 加载文档进入内存
* loadDocuments的方法参数是resources下的一个目录(不是文件)名称
* 目录下可存放多个markdown文件或者PDF文件作为外部知识文档
* loadDocuments会扫描目录下的所有文件
*/
// List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
// 加载文档数据时指定解析器为PDF
List<Document> documents = ClassPathDocumentLoader
.loadDocuments("content", new ApachePdfBoxDocumentParser());
// 构建向量数据库操作对象
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
// 构建一个EmbeddingStoreIngestor对象,完成文本数据切片、向量化、存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.build();
ingestor.ingest(documents);
return store;
}
文档分割器
用于把一个大的文档,切割成一个一个的小片段
- DocuemntByParagraphSplitter:按照段落分割文本
- DocumentByLineSplitter:按照行分割文本
- DocumentBySentenceSplitter:按照句子分割文本
- DocumentByWordSplitter:按照词分割文本
- DocumentByCharacterSplitter:按照固定数量的字符分割文本
- DocumentByRegexSplitter:按照正则表达式分割文本
- DocumentSplitters.recursive(...)(默认):递归分割器,优先按段落分割,再按行分割,再按句子分割,再按词分割
向量模型
用于把文档分割后的片段向量化或者查询时把用户输入的内容向量化。LangChain4j中内置有默认的向量模型但是功能不是很强大,配置另外的向量模型需要手动配置。
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
streaming-chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
embedding-model: # 向量模型配置
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: text-embedding-v3
log-requests: true
log-responses: true
logging:
level:
dev.langchain4j: debug
spring:
data:
redis:
host: localhost
port: 6379
package com.tensoflow.config;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.ClassPathDocumentLoader;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @Description: 配置类
* @author: TenSoFlow
* @date: 2026-01-22
**/
@Configuration
public class CommonConfig {
@Autowired
private ChatMemoryStore redisChatMemoryStore;
// 注入向量模型
@Autowired
private EmbeddingModel embeddingModel;
// 构建会话记忆提供者对象
@Bean
public ChatMemoryProvider chatMemoryProvider () {
return new ChatMemoryProvider() {
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.chatMemoryStore(redisChatMemoryStore) // 自定义存储实现
.maxMessages(20) // 最多记忆条数
.build();
}
};
}
// 构建向量数据库操作对象
@Bean
public EmbeddingStore embeddingStore () {
/**
* 加载文档进入内存
* loadDocuments的方法参数是resources下的一个目录(不是文件)名称
* 目录下可存放多个markdown文件或者PDF文件作为外部知识文档
* loadDocuments会扫描目录下的所有文件
*/
List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
// 构建向量数据库操作对象
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
// 构建一个EmbeddingStoreIngestor对象,完成文本数据切片、向量化、存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.embeddingModel(embeddingModel) // 设置向量模型
.build();
ingestor.ingest(documents);
return store;
}
// 构建向量数据库检索对象
@Bean
public ContentRetriever contentRetriever (EmbeddingStore store) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.embeddingModel(embeddingModel) // 设置向量模型
.minScore(0.5) // 余弦相似度合格值(0 ~ 1)
.maxResults(3) // 检索最大条数
.build();
}
}
Tools工具
LangChain4j 的Tools工具本质是开发人员基于业务需求编写的、带专属注解(@Tool)的自定义方法,注解会清晰描述工具的用途和参数,当用户问题需要依赖外部能力(如预约门诊、查天气、查数据等)才能解答时,大模型会先理解用户需求,自主判断需要调用哪个工具方法、自动提取问题中的关键信息作为参数传入,执行方法获取结果后,再结合结果生成最终的自然语言回答。核心是让大模型借用开发人员提供的外部方法能力,突破自身仅能基于知识库回答的局限,实现与真实业务系统的联动。这是大模型扩展外部能力的核心组件,作为实现智能体(Agent)的基础,它能弥补大模型自身无实时计算、无法访问外部系统、不支持复杂逻辑操作的短板,让大模型可自主决策是否调用工具、自动从自然语言中提取参数并传递给工具,还能基于工具的返回结果整合生成贴合问题的最终答案,实现大模型与外部系统、自定义业务逻辑的联动,突破其自身知识库的限制。
package com.tensoflow.tools;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;
/**
* @Description: Ai工具类
* @author: TenSoFlow
* @date: 2026-01-25
**/
@Component
public class AiTools {
/**
* @Tool注解标识方法作用
* @P注解标识参数作用
*/
@Tool("加法")
public int add (
@P("加法的第一个数") int num1,
@P("加法的第二个数") int num2
) {
return num1 + num2;
}
}
package com.tensoflow.service;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel",
chatMemoryProvider = "chatMemoryProvider",
contentRetriever = "contentRetriever",
tools = "aiTools" // 配置工具类,值为工具类类名小驼峰
)
public interface MyAiService {
@SystemMessage("你是TenSoFlow的助手豆包,特别善长编程。")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
