初识LangChain4j
- 官网:LangChain4j 中文文档 | LangChain4j 中文文档
- LangChain4j 的目标是简化将 LLM 集成到 Java 应用程序中的过程。
快速上手
1.引入依赖
xml
<properties>
<langchain4j.version>1.0.0-beta1</langchain4j.version>
</properties>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
</dependencies>
如果出现依赖下载不了请检查Maven的远程仓库中是否存在langchain4j依赖, 本人用的远程仓库:repo1.maven.org/maven2/
2.示例
使用OpenAi
ini
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("http://langchain4j.dev/demo/openai/v1")
.apiKey("demo")
.modelName("gpt-4o-mini")
.build();
String answer = model.chat("Say 'Hello World'");
System.out.println(answer); // Hello World
使用Deepseek
ini
// DeepSeek使用的接口和OpenAI的接口一样,所以可以直接使用OpenAiChatModel
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("https://api.deepseek.com")
.apiKey("api key")
.modelName("deepseek-chat")
.build();
String answer = model.chat("你是谁");
System.out.println(answer);
使用通义千问
引入通义千问的依赖
xml
<!--通义千问-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope</artifactId>
<version>${langchain4j.version}</version>
</dependency>
测试通义千问
java
/**
* 描述:测试通义千问
*
* @author xuzili
* @date 2025/05/22
*/
@Test
public void testQw() {
QwenChatModel model = QwenChatModel.builder()
.apiKey("sk-62f684f1658144a4b3b6f7e9bee9497b")
.modelName("qwen-max")
.build();
String answer = model.chat("你是谁");
System.out.println(answer);
}
ollama
Ollama 是一个开源的本地大语言模型运行框架,专为在本地机器上便捷部署和运行大型语言模型(LLM)而设计。 Ollama 支持多种操作系统,包括 macOS、Windows、Linux 以及通过 Docker 容器运行。 Ollama 提供对模型量化的支持,可以显著降低显存要求,使得在普通家用计算机上运行大型模型成为可能。
安装部署
ollama国内加速镜像: ollama | newbe
使用
以安装deepseek-r1:1.5b模型为例,在官网中找到对应模型名称
使用ollama run deepseek-r1:1.5b命令安装到本地

在Java程序中使用Ollama
引入Ollama依赖
xml
<!-- ollama-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
测试Ollama
ollama默认端口为11434
java
/**
* 描述:测试ollama
*
* @author xuzili
* @date 2025/05/22
*/
@Test
public void testOllama() {
OllamaChatModel model = OllamaChatModel.builder()
.baseUrl("https://127.0.0.1:11434")
.modelName("deepseek-r1:1.5b")
.build();
String answer = model.chat("你是谁");
System.out.println(answer);
}
文生图
需要选择支持文生图的模型,这里使用wanx2.1-t2i-plus模型
java
/**
* 描述:测试通义千问的图片生成
*
* @author xuzili
* @date 2025/05/22
*/
@Test
public void testQwImage() {
WanxImageModel wanxImageModel = WanxImageModel.builder()
.modelName("wanx2.1-t2i-plus")
.apiKey("api key")
.build();
Response<Image> response = wanxImageModel.generate("美女");
System.out.println(response.content().url());
}


Spring Boot集成Langchain4j和通义千问百炼平台
1、创建Spring Boot项目
这里就不记录项目的创建过程了,贴一下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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xzl</groupId>
<artifactId>langchain4j_springboot_2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>langchain4j_springboot_2</name>
<description>langchain4j_springboot_2</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.0.2</spring-boot.version>
<langchain4j.version>1.0.0-beta2</langchain4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-bom</artifactId>
<version>${langchain4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.xzl.Langchain4jSpringboot2Application</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2、 使用普通对话
使用前需要在application.properties中配置对话的模型和api key,这里使用的是qwen-max模型
ini
langchain4j.community.dashscope.chat-model.api-key = api key
langchain4j.community.dashscope.chat-model.model-name=qwen-max
具体使用
less
/**
* 描述:
*
* @author: xuzili
* @date: 2025/05/22
*/
@RequestMapping("/ai")
@RestController
public class ChatController {
private static final Logger log = LogManager.getLogger(ChatController.class);
@Autowired
private QwenChatModel qwenChatModel;
@Autowired
private QwenStreamingChatModel qwenStreamingChatModel;
@RequestMapping("chat")
public String chat(@RequestParam String question) {
return qwenChatModel.chat(question);
}
}
测试普通对话
http://localhost:8080/ai/chat?question=你是谁

3、使用流式对话
需要在application.properties中配置流式对话的模型和api key,这里使用的是qwen3-32b模型
ini
langchain4j.community.dashscope.chat-model.api-key = api key
langchain4j.community.dashscope.chat-model.model-name=qwen3-32b
还需要使用Web Flux,在pom 文件中添加此依赖
xml
<!--使用ai的流式对话需要使用webflux接收响应并返回给前端 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
具体使用
typescript
@RequestMapping(value = "streamChat",produces = "text/stream;charset=UTF-8")
public Flux<String> streamChat(@RequestParam(defaultValue = "你是谁") String question) {
// http://localhost:8080/ai/streamChat
Flux<String> result = Flux.create(sink -> {
qwenStreamingChatModel.chat(question, new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String s) {
sink.next(s);
}
@Override
public void onCompleteResponse(ChatResponse chatResponse) {
sink.complete();
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
sink.error(throwable);
}
});
});
return result;
}
测试流式对话
访问:http://localhost:8080/ai/streamCha, 结果会持续不断的输出,然后直到结束

4、记忆对话(多轮对话)
之前的测试,ai只能知道单次对话的内容,不知道之前的对话内容,所以ai并没有结合上下文去思考问题。比如第一次对话,给ai说我叫张三,第二次对话,问ai我叫什么,ai不会正确回答出你叫张三。所以就需要使用记忆对话功能。
具体使用
主要是通过qwenChatModel.chat()方法将第一次和AI对话的消息和回答,在第二次对话中设置,这样ai就知道第一次对话的内容了,就可以结合上下文进行回答。
ini
/**
* 描述:记忆对话
*
* @return {@link String }
* @author xuzili
* @date 2025/05/25
*/
@RequestMapping("memoryChat")
public String memoryChat() {
// http://localhost:8080/ai/memoryChat
UserMessage userMessage1 = UserMessage.userMessage( "你好,我是张三");
ChatResponse response1 = qwenChatModel.chat(userMessage1);
AiMessage aiMessage1 =response1.aiMessage();// 大模型的第一次响应
System.out.println(aiMessage1.text());
System.out.println("----");
//下面一行代码是重点
ChatResponse response2 = qwenChatModel.chat(userMessage1, aiMessage1, UserMessage.userMessage("我叫什么"));
AiMessage aiMessage2 = response2.aiMessage();// 大模型的第二次响应
System.out.println(aiMessage2.text());
return aiMessage2.text();
}
测试记忆对话
http://localhost:8080/ai/memoryChat

5、ChatMemory方式实现记忆对话
在上面的例子中,会发现手动维护和管理ChatMessage
是很麻烦的。 因此,LangChain4j提供了ChatMemory
抽象以及多种开箱即用的实现。
引入Lanchain4j的核心依赖
xml
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
配置
封装自定义的对话助手,在其中设置ChatMemory用来保存对话记录
kotlin
package com.xzl.config;
import com.fasterxml.jackson.core.TokenStreamFactory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AiConfig {
/**
* 描述:
*
* @author: xuzili
* @date: 2025/05/25
*/
public interface Assistant {
String chat(String message);
TokenStream stream(String message);
}
@Bean
public Assistant assistant(ChatLanguageModel chatLanguageModel, StreamingChatLanguageModel streamingChatLanguageModel){
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
// 创建对话助手,
return AiServices.builder(Assistant.class)
.chatLanguageModel(chatLanguageModel)
.streamingChatLanguageModel(streamingChatLanguageModel)
.chatMemory(chatMemory)
.build();
}
}
具体使用对话助手
less
@Autowired
private AiConfig.Assistant assistant;
/**
* 描述:使用对话助手实现普通对话
*
* @param message 消息
* @return {@link String }
* @author xuzili
* @date 2025/05/25
*/
@RequestMapping("assistantChat")
public String assistantChat(@RequestParam(defaultValue = "我叫张三") String message) {
// http://localhost:8080/ai/assistantChat
return assistant.chat(message);
}
/**
* 描述:使用对话助手实现流式对话
*
* @param message 消息
* @return {@link Flux }<{@link String }>
* @author xuzili
* @date 2025/05/25
*/
@RequestMapping(value = "assistantStreamChat",produces = "text/stream;charset=UTF-8")
public Flux<String> assistantStreamChat(@RequestParam(defaultValue = "我是谁") String message) {
// http://localhost:8080/ai/assistantStreamChat
TokenStream stream = assistant.stream(message);
return Flux.create(sink -> {
stream.onPartialResponse(sink::next)
.onCompleteResponse(c -> sink.complete())
.onError(sink::error)
.start();
});
}
测试
首先访问localhost:8080/ai/assistantChat,告诉ai我叫张三:
然后访问localhost:8080/ai/assistantStreamChat,询问ai我叫什么:
可以看到ai知道我叫张三,说明记忆对话成功
6、function-call的使用
-
定义:
- 当用户提出一个需要具体数据或执行操作的请求时(例如查询天气、计算数学公式、翻译文本),模型会通过"函数调用"触发预定义的外部功能(如API),并将结果返回给用户。
-
工作原理:
- 意图识别:模型分析用户输入,判断是否需要调用外部功能。
- 函数匹配:从已注册的函数库中找到最匹配的工具(例如通过自然语言理解映射到特定API)。
- 参数解析:从用户输入中提取函数所需的参数。
- 执行与返回:调用工具获取结果,并将结果整合到回复中。
典型应用场景
-
数据查询:
- 调用政务API获取重名的人数。
- 示例:用户问"武汉有多少叫张三的?",模型调用政务API后返回结果。
创建ToolService
kotlin
package com.xzl.service;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Service;
/**
* 描述:
*
* @author: xuzili
* @date: 2025/05/27
*/
@Service
public class ToolService {
/**
* 描述:测试tool,
* @Tool告诉ai什么时候调用此方法
* @P("姓名") 告诉ai需要提取的参数
*
*
* @param name 名称
* @return {@link Integer }
* @author xuzili
* @date 2025/05/27
*/
@Tool("武汉有多少个名字")
public Integer getNameCount(@P("姓名") String name) {
return 10;
}
}
将ToolService注册到对话助手中
在之前定义的对话助手中增加红色部分内容
使用
less
/**
* 描述:测试function-call
*
* @param message 消息
* @return {@link String }
* @author xuzili
* @date 2025/05/27
*/
@RequestMapping(value = "tool")
public String assistantTool(@RequestParam String message) {
// http://localhost:8080/ai/tool?message=武汉有多少个叫张三的
return assistant.chat(message);
}
测试function-call
访问:http://localhost:8080/ai/tool?message=武汉有多少个叫张三的 可以看到我们询问ai武汉有多少个叫张三的,ai回答了10个
7、预设角色(系统消息SystemMessage)
基础大模型是没有目的性的,你聊什么给什么,所以在有些场景下我们需要给大模型预设一个角色,保证大模型基于预设角色回答问题;下面告诉ai他是一个叫做蔡徐坤的人,喜欢唱、跳、rap、篮球,在问他喜欢干什么;
使用@SystemMessage注解定义预设角色
在之前的Assistant接口中增加systemMessageChat接口
java
/**
* 描述:测试系统消息
*
* @param userMessage 用户消息
* @return {@link String }
* @author xuzili
* @date 2025/06/01
*/
@SystemMessage("你是一个叫做蔡徐坤的人,喜欢唱、跳、rap、篮球")
String systemMessageChat(String userMessage);
测试SystemMessageChat
localhost:8080/ai/systemMessageChat?message=你喜欢干什么?
可以看到ai希望预设的角色,并基于这个角色做出相应的回答。
8、使用SystemMessage实现智能票务助手
但是如果我们开发的是一个智能票务助手, 我需要他以一个票务助手的角色跟我对话,并且在我跟他说"退票"的时候,让大模型一定要告诉我"车次"和"姓舌",这样我才能去调用业务方法(假设有一个业务方法,需要根据车子和姓名才能查询具体车票),进行退票。
在之前的Assistant接口中增加customerServiceChat方法
less
/**
* 描述:航空公司客服
* 当接口方法中有两个或以上的参数,需要使用 @UserMessage注解标记告诉 langchain4j,该参数是用户消息,而不是一个参数。
*
* @param userMessage 用户消息
* @return {@link String }
* @author xuzili
* @date 2025/06/01
*/
@SystemMessage(""春秋"航空公司的客户聊天支持代理。请以友好、乐于助人且愉快的方式来回复。 您正在通过在线聊天系统与客户互动 " +
"在提供有关预订或取消预订的信息之前,您必须始终从用户处获取以下信息:预订号、客户姓名" +
"请讲中文。" +
"今天的日期是{{current_date}}")
TokenStream customerServiceChat(@UserMessage String userMessage, @V("current_date") String currentDate);
在之前的ToolService类中增加refundTicket方法
less
@Tool("退票")
public String refundTicket(@P("姓名") String name,@P("预订号") String number) {
System.out.println("退票申请已受理");
return name + "您好" + number + "的退票申请已受理";
}
在之前的ChatController中增加
less
/**
* 描述:测试system message
*
* @param message 消息
* @return {@link String }
* @author xuzili
* @date 2025/05/27
*/
@RequestMapping(value = "customerServiceChat",produces = "text/stream;charset=UTF-8")
public Flux<String> customerServiceChat(@RequestParam String message) {
// http://localhost:8080/ai/customerServiceChat?message=你好
TokenStream stream = assistant.customerServiceChat(message, String.valueOf(LocalDate.now()));
return Flux.create(sink -> {
stream.onPartialResponse(sink::next)
.onCompleteResponse(c -> sink.complete())
.onError(sink::error)
.start();
});
}
测试
先打招呼 询问退票

办理退票
控制台也打印了退票日志

9、RAG向量检索增强
为什么需要RAG
传统的语言模型,比如 GPT-3,虽然在生成文本方面表现出色,但它们有一个显著的局限性:它们依赖于预训练的参数,无法动态访问外部知识。这意味着这些模型在处理实时信息、领域特定知识或罕见实体时表现不佳。举个例子,在问答任务中,模型可能会生成不准确或过时的答案,因为它无法访问最新的数据。就像你问一个朋友"今天天气怎么样?",但他只能告诉你去年的天气情况,显然这样的信息对你来说毫无用处。这种局限性在需要精确答案的场景中尤为明显。例如,在医疗领域,医生可能需要最新的研究数据来做出诊断,而传统的语言模型无法提供这些信息。
什么是 RAG?
RAG(Retrieval Augmented Generation)检索增强生成,即大模型LLM在回答问题或生成文本时,会先从大量的文档中检索出相关信息,然后基于这些检索出的信息进行回答或生成文本,从而可以提高回答的质量,而不是任由LLM来发挥。RAG技术使得开发者没有必要为每个特定的任务重新训练整个大模型,只需要外挂上相关知识库就可以,即可为模型提供额外的信息输入,提高回答的准确性。
简单来说,RAG 是一种在发送给 LLM 之前,从你的数据中找到并注入相关信息片段到提示中的方法。 这样 LLM 将获得相关信息,并能够使用这些信息回复, 这会降低产生幻觉的概率。
- 全文(关键词)搜索。这种方法使用 TF-IDF 和 BM25 等技术, 通过匹配查询(例如,用户提问的内容)中的关键词与文档数据库进行搜索。 它根据每个文档中这些关键词的频率和相关性对结果进行排名。
- 向量搜索,也称为"语义搜索"。 文本文档使用嵌入模型转换为数字向量。 然后根据查询向量和文档向量之间的余弦相似度 或其他相似度/距离度量找到并排序文档, 从而捕捉更深层次的语义含义。
- 混合搜索。结合多种搜索方法(例如,全文 + 向量)通常可以提高搜索的有效性。
文本向量化
简单来说就是将人类可读的文本转化为ai可读的信息,向量就是一组基于文本含义生成的特征值;
scss
/**
* 描述:测试文本向量化
*
* @author xuzili
* @date 2025/06/07
*/
@Test
void testTextVectorization() {
QwenEmbeddingModel embeddingModel = QwenEmbeddingModel.builder()
.apiKey("key")
.build();
Response<Embedding> embed = embeddingModel.embed("我叫真爱坤,喜欢唱、跳、篮球");
// 打印向量坐标
System.out.println(embed);
// 打印向量的坐标数量
System.out.println(embed.content().vector().length);
}
打印结果

向量检索
就是将需要查询的问题,转化为向量,然后使用这个查询向量到向量数据库中查询,会根据查询向量做相似性分析,并得到一个分数,分数越高说明相似性越高,也就代表对应的候选向量最满足检索需求;
ini
/**
* 描述:测试向量检索
*
* @author xuzili
* @date 2025/06/07
*/
@Test
void testVectorSearch() {
// 创建向量模型
QwenEmbeddingModel embeddingModel = QwenEmbeddingModel.builder()
.apiKey("sk-62f684f1658144a4b3b6f7e9bee9497b")
.build();
// 创建向量数据库
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
// 创建一个新的文本片段
TextSegment trueKunTextSegment = TextSegment.from("我叫真爱坤,喜欢唱、跳、篮球");
// 将文本向量化
Response<Embedding> trueKunEmbedding = embeddingModel.embed(trueKunTextSegment);
// 将向量添加到向量数据库中
embeddingStore.add(trueKunEmbedding.content(), trueKunTextSegment);
TextSegment falseKunTextSegment = TextSegment.from("我叫假爱坤,喜欢干饭、摸鱼");
Response<Embedding> falseKunEmbedding = embeddingModel.embed(falseKunTextSegment);
embeddingStore.add(falseKunEmbedding.content(),falseKunTextSegment);
Response<Embedding> queryEmbedding = embeddingModel.embed("真爱坤喜欢干什么?");
// 创建向量检索
EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding.content())
.maxResults(1)
.build();
// 执行向量检索
EmbeddingSearchResult<TextSegment> searchResult = embeddingStore.search(searchRequest);
// 输出结果
searchResult.matches()
.forEach(embeddingMatch -> {
// 输出分数
System.out.println(embeddingMatch.score());
// 输出向量
System.out.println(embeddingMatch.embedding());
// 输出文本
System.out.println(embeddingMatch.embedded().text());
});
}
打印结果

10、知识库RAG实战
创建知识库对话方法
在Assisant接口中增加knowledgeBaseChat方法
java
/**
* 描述:知识库问答
*
* @param message 消息
* @return {@link TokenStream }
* @author xuzili
* @date 2025/06/07
*/
TokenStream knowledgeBaseChat(String message);
创建一个向量数据库(EmbeddingStore)
java
/**
* 描述:创建一个基于内存的向量数据库
*
* @return {@link EmbeddingStore }<{@link TextSegment }>
* @author xuzili
* @date 2025/06/07
*/
@Bean
public EmbeddingStore<TextSegment> createEmbeddingStore(){
return new InMemoryEmbeddingStore<>();
}
创建向量检索器(EmbeddingStoreContentRetriever)
改造创建对话助手的方法
scss
/**
* 描述:创建ai助手
*
* @param chatLanguageModel 对话模型
* @param streamingChatLanguageModel 流式对话模型
* @param toolService function call工具服务
* @param embeddingModel 向量模型
* @param embeddingStore 向量数据库
* @return {@link Assistant }
* @author xuzili
* @date 2025/06/07
*/
@Bean
public Assistant assistant(ChatLanguageModel chatLanguageModel,
StreamingChatLanguageModel streamingChatLanguageModel,
ToolService toolService,
EmbeddingModel embeddingModel,
EmbeddingStore<TextSegment> embeddingStore
){
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
// 创建向量检索器
EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.maxResults(5)
.minScore(0.6)
.build();
// 创建对话助手,
return AiServices.builder(Assistant.class)
// 添加function call工具服务
.tools(toolService)
.chatLanguageModel(chatLanguageModel)
.streamingChatLanguageModel(streamingChatLanguageModel)
.chatMemory(chatMemory)
.contentRetriever(contentRetriever)
.build();
}
创建向量检索器EmbeddingStoreContentRetriever contentRetriever
scss
// 创建向量检索器
EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.maxResults(5)
.minScore(0.6)
.build();
将向量检索器注入到对话助手中
scss
.contentRetriever(contentRetriever)
初始化知识库数据
typescript
/**
* 描述:初始化知识库
*
* @param embeddingStore 向量数据库
* @param embeddingModel 向量模型
* @return {@link CommandLineRunner }
* @author xuzili
* @date 2025/06/07
*/
@Bean
public CommandLineRunner initKnowledgeBase(EmbeddingStore<TextSegment> embeddingStore,EmbeddingModel embeddingModel){
return args -> {
// 创建文档
Document document = ClassPathDocumentLoader.loadDocument("document/document.txt");
System.out.println(document.text());
// 文档分割
// 文本读取过来后还需要分成一段一段的片段(分块chunk),分块是为了更好地拆分语义单元,
// 这样在后面可以更精确地进行语义相似性检索,也可以避免LLM的Token限制。
DocumentBySentenceSplitter splitter = new DocumentBySentenceSplitter(
// 每个分块的长度
100,
// 重叠的长度
20);
// 分词器会先按照分词规则拆分,然后按照分块长度拆分,最后按照重叠长度进行重叠
List<TextSegment> textSegments = splitter.split(document);
System.out.println(textSegments);
// 将文档向量化
Response<List<Embedding>> listResponse = embeddingModel.embedAll(textSegments);
// 将向量添加到向量数据库中
embeddingStore.addAll(listResponse.content(), textSegments);
};
}
新增知识库对话接口
less
/**
* 描述:测试RAG应用知识库
*
* @param message 消息
* @return {@link String }
* @author xuzili
* @date 2025/05/27
*/
@RequestMapping(value = "knowledgeBaseChat",produces = "text/stream;charset=UTF-8")
public Flux<String> knowledgeBaseChat(@RequestParam String message) {
// http://localhost:8080/ai/knowledgeBaseChat?message=退费
TokenStream stream = assistant.knowledgeBaseChat(message);
return Flux.create(sink -> {
stream.onPartialResponse(sink::next)
.onCompleteResponse(c -> sink.complete())
.onError(sink::error)
.start();
});
}