SpringBoot集成LangChain4j玩转AI大模型(三)
让 AI 更懂行:一文读懂检索增强生成(RAG)
你有没有过这样的经历?问 AI 一个专业问题,比如 “2024 年最新的新能源汽车补贴政策”,它却给你一套 2022 年的答案;或者让它解释 “量子计算中的量子隧穿效应”,结果说出来的内容似是而非,甚至有明显错误。
这不是 AI “不努力”,而是大语言模型(LLM)天生有两个短板:知识有保质期(训练数据截止到某个时间点,之后的新信息不知道)、容易 “瞎编”(遇到不懂的问题可能硬凑答案)。
而今天要讲的检索增强生成(RAG),就是给 AI “装个外挂”,让它既能回答最新知识,又能说得更靠谱。
一、为什么需要RAG?专业知识的获取之道
大型语言模型(LLM)虽然强大,但它的知识仅限于训练数据。当需要处理专业领域知识或私有数据时,有三种主要解决方案:
-
RAG(检索增强生成)
-
实时从外部知识库检索信息
-
将检索结果与问题一起交给LLM生成答案
-
优势:知识实时更新,成本低
-
场景:客服系统、实时金融数据查询
-
-
模型微调(Fine-tuning)
-
使用专业数据重新训练模型
-
调整模型参数适应特定领域
-
优势:响应速度快(单次模型调用)
-
场景:自动驾驶系统、专业文档生成
-
-
混合策略
-
结合RAG和微调的优势
-
基础能力通过微调实现
-
实时知识通过RAG补充
-
选择指南:
✅ 优先微调:自动驾驶、实时翻译等毫秒级响应场景
✅ 优先RAG:客服机器人、股票咨询等知识频繁更新场景
✅ 混合方案:医疗诊断等复杂专业场景举个例子:
- 如果你做 “古诗生成” APP,用微调更合适(古诗知识几百年不变)。
- 如果你做 “电商客服机器人”,用 RAG 更合适(商品价格、库存天天变,改改知识库就行)。

二、什么是 RAG?给 AI 开 “卷” 考试的能力
检索增强生成(Retrieval-Augmented Generation),简单说就是:
在 AI 回答问题前,先让它从你的专属知识库(比如公司文档、行业报告、最新新闻)里 “搜资料”,再把搜到的信息和问题一起交给 AI,让它基于这些资料生成答案。
打个比方:
- 没有 RAG 的 AI,像闭卷考试的学生,全靠记忆答题,记不清就可能错。
- 有 RAG 的 AI,像开卷考试的学生,答题时可以翻书、查笔记,答案既准又新。
三、RAG vs 微调:两种让 AI “变专业” 的方法怎么选?
除了 RAG,还有一种让 AI 懂专业知识的方法叫 “微调”(Fine-tuning)。两者的区别,用生活例子一看就懂:
| 对比维度 | 微调(Fine-tuning) | RAG(检索增强生成) |
|---|---|---|
| 原理 | 用专业数据重新 “训练” AI,让它把知识 “背下来” | 不训练 AI,让它答题时 “临时查资料” |
| 知识更新 | 难(更新后需要重新 “背”,成本高) | 易(直接改知识库内容,AI 下次查就自动获取新信息) |
| 成本 | 高(需要大量数据和计算资源,像请老师一对一补课) | 低(只需准备知识库,像给学生配一本参考书) |
| 适用场景 | 知识稳定、少更新的领域: 比如古诗创作(唐诗宋词不会变)、法律条文解读(几年才修订一次) | 知识频繁更新的领域: 比如电商客服(商品价格天天变)、新闻问答(每天都有新事件)、股票咨询(实时行情更新) |
混合策略:复杂场景可以结合两者优势。比如先微调一个 “基础版” AI(让它熟悉行业术语),再用 RAG 接入实时数据(让它获取最新信息),像金融领域的 AI 助手,既懂金融术语,又能查当天股市行情。

三、RAG 的 “核心引擎”:向量搜索技术详解
RAG 能快速找到 “相关资料”,靠的是向量搜索(语义搜索)。它比传统的 “关键词搜索” 聪明得多,我们一步步拆解:
1. 向量:给文字编一串 “数字密码”
你可能会问:“文字怎么能被‘搜索’呢?” 向量搜索的第一步,是把文字转换成 “数字向量”。
-
什么是向量? 就是一串数字,用来描述文字的 “语义特征”。
比如:- “猫” 的向量:
[0.8, 0.2, -0.5, 0.3](这串数字代表 “动物、毛茸茸、会叫、小型” 等特征) - “狗” 的向量:
[0.7, 0.3, -0.4, 0.2](和 “猫” 的向量很像,因为都是宠物) - “汽车” 的向量:
[-0.6, 0.9, 0.2, -0.1](和 “猫” 的向量差别很大)
简单说:意思越接近的文字,向量越相似。
- “猫” 的向量:
2. 维度:描述 “语义特征” 的角度
向量的 “维度”,就是描述文字的 “特征角度”。维度越多,描述越精准。
-
比如描述 “一杯奶茶”,可以有这些维度(特征):
维度(特征) 数值(0-10 分) 甜度 8(全糖) 冰度 5(少冰) 是否加珍珠 1(是) 价格(元) 18 这杯奶茶的向量就是:
[8, 5, 1, 18]。 -
再比如描述 “一篇文章”,维度可能是 “主题(科技 / 娱乐)”“情感(正面 / 负面)”“篇幅(长 / 短)” 等,每个维度用数字表示,最终形成一个多维度向量。
3. 相似度计算:判断两句话 “像不像”
向量搜索的核心是 “找相似”。比如用户搜 “轿车”,我们希望返回 “汽车”“vehicle” 等相关内容,这就要靠 “相似度计算”。
最常用的是余弦相似度(不用记公式,理解逻辑即可):
- 两个向量 “方向越接近”,余弦相似度越高(比如 “轿车” 和 “汽车” 的向量,方向几乎一致,相似度≈0.9)。
- 两个向量 “方向越相反”,余弦相似度越低(比如 “热水” 和 “冰块” 的向量,方向相反,相似度≈-0.8)。
举个例子:
- 用户问 “什么车适合家庭用?”,向量是 A。
- 知识库中 “SUV 空间大,适合家庭出行” 的向量是 B,“跑车速度快,适合单人驾驶” 的向量是 C。
- 计算发现 A 和 B 的余弦相似度(0.8)远高于 A 和 C(0.2),所以优先返回 B 对应的内容。
相似度计算四大方法
| 方法 | 特点 | 适用场景 |
|---|---|---|
| 余弦相似度 | 专注方向差异 | 语义匹配 |
| 欧几里得距离 | 计算空间直线距离 | 简单数值匹配 |
| 点积 | 考虑方向和大小 | 综合匹配 |
| 曼哈顿距离 | 计算网格路径距离 | 分类特征匹配 |
4. 为什么向量搜索比关键词搜索强?
- 关键词搜索的局限:比如搜 “苹果”,只会返回带 “苹果” 二字的内容,可能漏掉 “iPhone”“Mac”(虽然都是苹果公司产品)。
- 向量搜索的优势:能 “理解语义”。搜 “苹果手机” 时,会找到向量相似的 “iPhone”“苹果 15” 等内容,哪怕文字里没直接出现 “苹果手机” 四个字。
四、RAG 完整工作流程:从 “喂资料” 到 “答问题”
RAG 的工作过程分两大阶段:索引阶段(提前准备知识库)和检索阶段(实时回答问题)。我们结合具体工具(以 LangChain4j 为例)拆解每一步:
阶段 1:索引阶段 —— 给 AI “喂资料”(离线准备)
这一步是提前处理知识库,让 AI 后续能快速查到资料。流程如下:

1. 加载文档:把你的资料 “搬进系统”
需要把各种格式的文档(TXT、PDF、Word、网页、Excel 等)加载到系统中。LangChain4j 提供了多种 “文档加载器”:
| 文档来源 | 工具类 | 用法示例 |
|---|---|---|
| 本地文件 | FileSystemDocumentLoader | 加载D:/知识库/产品手册.txt |
| 网页内容 | UrlDocumentLoader | 加载https://www.example.com/news的网页内容 |
| 阿里云 OSS | AliyunOssDocumentLoader | 加载阿里云 OSS 存储的文档 |
| 腾讯云 COS | TencentCosDocumentLoader | 加载腾讯云 COS 存储的文档 |
| GitHub 仓库 | GitHubDocumentLoader | 加载 GitHub 仓库里的代码或文档 |
代码示例(加载本地 TXT):
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class RAGTest {
@Test
public void testReadDocument() {
//使用FileSystemDocumentLoader读取指定目录下的知识库文档
// 加载本地TXT文档,默认用TextDocumentParser解析
Document document = FileSystemDocumentLoader.loadDocument("D:/知识库/产品手册.txt");
System.out.println("文档内容:" + document.text()); // 打印文档内容
}
}
如果是 PDF/Word,需要指定解析器:
比如解析 PDF,先添加依赖:
<!-- 解析PDF的依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
<version>${langchain4j.version}</version>
</dependency>
再用代码加载:
// 加载并解析PDF文档(指定ApachePdfBoxDocumentParser)
Document pdfDoc = FileSystemDocumentLoader.loadDocument(
"D:/知识库/医疗指南.pdf",
new ApachePdfBoxDocumentParser() // 专门解析PDF的工具
);
System.out.println("PDF文档内容:" + pdfDoc.text());
常见的文档加载器
- 来自 langchain4j 模块的文件系统文档加载器(FileSystemDocumentLoader)
- 来自 langchain4j 模块的类路径文档加载器(ClassPathDocumentLoader)
- 来自 langchain4j 模块的网址文档加载器(UrlDocumentLoader)
- 来自 langchain4j-document-loader-amazon-s3 模块的亚马逊 S3 文档加载器 (AmazonS3DocumentLoader)
- 来自 langchain4j-document-loader-azure-storage-blob 模块的 Azure Blob 存储文档加载器(AzureBlobStorageDocumentLoader)
- 来自 langchain4j-document-loader-github 模块的 GitHub 文档加载器(GitHubDocumentLoader)
- 来自 langchain4j-document-loader-google-cloud-storage 模块的谷歌云存储文档加载器 (GoogleCloudStorageDocumentLoader)
- 来自 langchain4j-document-loader-selenium 模块的 Selenium 文档加载器 (SeleniumDocumentLoader)
- 来自 langchain4j-document-loader-tencent-cos 模块的腾讯云对象存储文档加载器 (TencentCosDocumentLoader)
2. 文档分割:把长文档切成 “小片段”
为什么要分割?
- 大模型有 “上下文窗口限制”(比如 GPT-3.5 最多处理 4096 个 token,约 8000 汉字),太长的文档塞不进去。
- 片段越小,搜索越精准(比如查 “电池续航”,不用加载整本书,只需要相关的几小段)。
分割工具:LangChain4j 提供多种 “文档分割器”,常用的有:
| 分割器类型 | 特点 | 适用场景 |
|---|---|---|
| 按段落分割 | 按空行分割(适合散文、文档) | 结构松散的文本 |
| 按句子分割 | 按句号 / 感叹号分割(用 OpenNLP 库) | 短句多的文本(如新闻、对话) |
| 按 token 分割 | 按模型可识别的 token 数分割(最常用) | 所有类型,尤其是技术文档 |
| 递归分割(推荐) | 先按大单元(段落)分割,太大再切句子 | 复杂文档(混合段落、长句) |
关键参数:
maxSegmentSize:每个片段的最大长度(以 token 为单位,1token≈2 汉字)。overlapSize:相邻片段的重叠长度(保证上下文连贯)
代码示例(递归分割):
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-hugging-face</artifactId>
<version>${langchain4j.version}</version> <!-- 与核心版本一致:1.0.0-beta3 -->
</dependency>
// 定义分割规则:最大300token,重叠30token
DocumentSplitter splitter = DocumentSplitters.recursive(
300, // 每个片段最多300token(约600字)
30, // 相邻片段重叠30token(约60字)
new HuggingFaceTokenizer() // 用tokenizer计算长度
);
// 分割文档(把整个文档切成多个小片段)
List<TextSegment> segments = splitter.split(document);
System.out.println("分割后片段数:" + segments.size());
参数怎么设才合理?
maxSegmentSize:参考大模型的上下文窗口,比如模型支持 4096token,就设 300-800(给问题和指令留空间)。- 技术文档(如 API 手册):设大一点(600-800),避免公式 / 代码被切碎。
- 新闻 / 对话:设小一点(300-500),提高搜索精度。
overlapSize:20-50token 为宜。- 逻辑严密的文本(如论文):重叠大一点(40-50),避免分割断裂。
- 独立短句(如商品列表):重叠小一点(20-30),减少冗余。
- token和token计算:
- DeepSeek:Token 用量计算 | DeepSeek API Docs
- 阿里百炼:百炼控制台
-
@Test public void testTokenCount() { String text = "这是一个示例文本,用于测试 token 长度的计算。"; UserMessage userMessage = UserMessage.userMessage(text); //计算 token 长度 //QwenTokenizer tokenizer = new QwenTokenizer(System.getenv("DASH_SCOPE_API_KEY"),"qwen-max"); HuggingFaceTokenizer tokenizer = new HuggingFaceTokenizer(); int count = tokenizer.estimateTokenCountInMessage(userMessage); System.out.println("token长度:" + count); }
3. 文本嵌入:把片段转换成向量
用 “嵌入模型”(Embedding Model)把每个文本片段转换成向量。嵌入模型就像 “翻译器”,能把文字翻译成向量。
常用嵌入模型:
- 开源:Sentence-BERT(轻量,适合本地部署)、BGE(中文支持好)。
- 闭源:OpenAI Embedding(精度高,需 API 密钥)、阿里云百炼 Embedding。
// 创建向量数据库
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
// 把一个文本片段转换成向量
TextSegment segment = segments.get(0); // 取第一个片段
Embedding embedding = embeddingModel.embed(segment.text()).content();
System.out.println("向量维度:" + embedding.vector().length);
总代码:
/**
* 加载文档并存入向量数据库
*/
@Test
public void testReadDocumentAndStore() {
// 加载本地TXT文档,默认用TextDocumentParser解析
Document document = FileSystemDocumentLoader.loadDocument("F:/code/java-ai-langchain4j/src/main/resources/xiaozhi-prompt-template.txt");
System.out.println("文档内容:" + document.text()); // 打印文档内容
// 定义分割规则:最大300token,重叠30token
DocumentSplitter splitter = DocumentSplitters.recursive(
300, // 每个片段最多300token(约600字)
30, // 相邻片段重叠30token(约60字)
new HuggingFaceTokenizer() // 用tokenizer计算长度
);
// 分割文档(把整个文档切成多个小片段)
List<TextSegment> segments = splitter.split(document);
System.out.println("分割后片段数:" + segments.size());
// 创建向量数据库
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); // 直接使用预定义模型
// 把一个文本片段转换成向量
TextSegment segment = segments.get(0); // 取第一个片段
Embedding embedding = embeddingModel.embed(segment.text()).content();
System.out.println("向量维度:" + embedding.vector().length);
}
终极理解
其实文本向量(或者说 “文本的数字表示”)的核心作用很简单:把人类能看懂的文字,翻译成计算机能 “理解” 的数字。咱们结合代码,用生活化的例子一步步说清楚:
一、为什么需要 “文本向量”?
计算机天生不认识文字。比如 “苹果” 这两个字,对计算机来说就是一串字符,它不知道这是一种水果。但如果把 “苹果” 转换成一串数字(比如
[0.2, 0.5, -0.1, ...]),计算机就能通过比较这些数字的 “相似度”,判断两句话的意思是否相近。举个例子:
- “我想吃苹果” → 向量 A
- “我想吃香蕉” → 向量 B
- “我想买汽车” → 向量 C
向量 A 和向量 B 的数字差异会很小(因为都是 “想吃的水果”),而 A 和 C 的差异会很大(一个是水果,一个是交通工具)。
这就是向量的核心价值:用数字捕捉文字的 “语义含义”,让计算机能比较文字的相似性。二、代码里,向量是怎么来的?
代码做了三件关键的事,最终目的就是生成这些 “语义数字”:
1. 把文档切成小片段(
DocumentSplitter)为什么要分割?
如果把一篇长文档(比如 1000 字)转换成一个向量,这个向量很难精确表达文档里的每个细节(比如前面讲 “苹果”,后面讲 “香蕉”,向量会模糊两者的差异)。
就像把一本厚书浓缩成一句话,会丢失很多信息。
代码里把文档切成 “最多 300 个 token(约 600 字)、重叠 30 个 token” 的小片段,每个片段更聚焦一个局部主题,方便后续生成更精确的向量。2. 用模型把片段转换成向量(
AllMiniLmL6V2EmbeddingModel)这个模型就像一个 “翻译官”:输入文字,输出一串数字(向量)。
它是怎么 “翻译” 的?
这个模型是用海量文本训练出来的(比如互联网上的文章、书籍),训练过程中它会学习文字的 “上下文规律”。比如它会发现:
- “苹果” 经常和 “水果”“吃” 一起出现;
- “医生” 经常和 “医院”“看病” 一起出现。
所以当输入 “苹果是一种水果”,它会输出一串数字,这些数字综合了 “苹果”“水果” 的语义特征 —— 这串数字就是向量。
3. 向量的 “维度” 是什么意思?
代码里打印的 “向量维度:768”,意思是每个文本片段的向量由 768 个数字组成。
可以理解成:用 768 个 “角度” 来描述一个文本的特征。
比如:
- 第 1 个数字:描述 “是否和食物相关”;
- 第 2 个数字:描述 “是否和动物相关”;
- ...
- 第 768 个数字:描述 “是否带有情感色彩”。
(实际每个维度的含义很复杂,是模型自动学习的,不用深究具体每个数字代表什么,知道它们共同描述语义即可。)
三、向量有什么用?(结合你的代码后续场景)
你的代码目前只做了 “生成向量”,但向量的真正价值在后续的 “检索” 或 “问答” 中:
比如用户问 “什么水果适合减肥?”,你可以:
- 把问题也转换成一个向量(比如
[0.3, 0.4, -0.2, ...]);- 拿这个问题向量,和你之前生成的所有文本片段向量做比较;
- 找到和问题向量最相似的片段(比如包含 “苹果热量低,适合减肥” 的片段);
- 用这个片段的内容回答用户的问题。
这就是现在流行的 “RAG(检索增强生成)” 的核心逻辑 ——用向量找相关内容,让回答更精准。
总结一下
文本向量就是:
- 文字的 “数字翻译版”;
- 用一串数字描述文字的语义(相似的文字,数字也相似);
- 你的代码里,分割文档是为了让向量更精准,模型是 “翻译官”,768 维是描述语义的 “角度数量”。
这样是不是就好理解了?本质上就是把文字变成计算机能比较的数字,方便后续的语义匹配~
4. 向量存储:把向量和片段存进数据库
需要专门的 “向量数据库” 存储向量和对应的文本片段,方便后续快速搜索。
常用向量数据库:
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| InMemory | 内存中的数据库,无需部署 | 测试、小数据量(<1 万片段) |
| Milvus(开源) | 支持大规模数据(亿级向量) | 企业级应用、大数据量 |
| Pinecone(云) | 托管服务,无需维护服务器 | 快速上线、不想搭环境 |
| Qdrant(开源) | 轻量,支持多种相似度计算 | 中小规模应用、本地部署 |
代码示例(用内存数据库存储):
// 初始化内存向量数据库
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
// 存储所有片段和对应的向量
for (TextSegment segment : segments) {
Embedding embedding = embeddingModel.embed(segment.text());
embeddingStore.add(embedding, segment); // 向量→片段一一对应存储
}
小技巧:实际开发中,可直接用EmbeddingStoreIngestor一键完成 “分割→嵌入→存储”:
// 一键处理:加载文档→分割→转向量→存数据库
EmbeddingStoreIngestor.ingest(
document, // 原始文档
embeddingStore, // 向量数据库
embeddingModel, // 嵌入模型
splitter // 分割器
);
阶段 2:检索阶段 ——AI “查资料答题”(实时处理)
当用户提问时,系统实时完成以下步骤:
1. 处理问题:把用户的问题转换成向量
// 用户提问
String question = "我们公司新款扫地机器人有哪些传感器?";
// 把问题转换成向量
Embedding questionEmbedding = embeddingModel.embed(question);
2. 检索相似片段:从向量数据库找相关资料
// 从数据库中找和问题向量最相似的前3个片段
List<EmbeddingMatch<TextSegment>> matches = embeddingStore.findRelevant(
questionEmbedding, // 问题向量
3 // 最多返回3个最相关的片段
);
// 提取找到的文本片段
List<String> relevantDocs = matches.stream()
.map(match -> match.embedded().text()) // 获取片段内容
.collect(Collectors.toList());
3. 生成答案:让大模型结合资料回答
把 “问题 + 找到的片段” 一起发给大模型,让它基于资料生成答案:
// 初始化大模型(以OpenAI为例)
ChatLanguageModel model = OpenAiChatModel.withApiKey("你的API密钥");
// 构建提示词(问题+相关资料)
String prompt = "根据以下资料回答问题:\n" +
String.join("\n", relevantDocs) + "\n" +
"问题:" + question;
// 调用大模型生成答案
String answer = model.generate(prompt);
System.out.println("答案:" + answer);
输出示例:
答案:根据产品手册,新款扫地机器人搭载了三种传感器:激光雷达(用于建图导航)、3D结构光(识别障碍物)和悬崖传感器(防止跌落)。
4.工作方式
五、新手必踩的 3 个坑及避坑指南
-
坑 1:文档分割不合理,导致答案漏信息
- 症状:用户问的问题明明在文档里,AI 却答不上来。
- 原因:片段切得太小,把相关内容切成了两半,检索时只找到了一半。
- 解决:增大
overlapSize(比如从 30token 调到 50),保证相邻片段有足够重叠。
-
坑 2:向量数据库选不对,性能差
- 症状:数据量超过 1 万条后,检索速度变慢(超过 1 秒)。
- 原因:用了 InMemory 内存数据库(只适合测试)。
- 解决:换成 Milvus 或 Pinecone,支持大规模数据的高效检索。
-
坑 3:嵌入模型选得不好,语义理解差
- 症状:用户问 “轿车”,AI 却返回 “火车” 的内容。
- 原因:用了通用嵌入模型,对专业术语理解不足。
- 解决:中文场景优先用 “BGE 中文模型”,专业领域(如医疗)用领域专用嵌入模型。
六、向量模型和向量存储
1、向量大模型
1.1、介绍
1.2模型配置
#集成阿里通义千问-通用文本向量-v3
langchain4j.community.dashscope.embedding-model.api-key=${DASH_SCOPE_API_KEY}
langchain4j.community.dashscope.embedding-model.model-name=text-embedding-v3
文本向量化
@SpringBootTest
public class EmbeddingTest {
@Autowired
private EmbeddingModel embeddingModel;
@Test
public void testEmbeddingModel() {
Response<Embedding> embed = embeddingModel.embed("你好");
System.out.println("向量维度:" + embed.content().vector().length);
System.out.println("向量输出:" + embed.toString());
}
}
如果出现bean的错误则添加下面的配置
import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import dev.langchain4j.model.embedding.EmbeddingModel;
@Configuration // 标记为配置类
public class LangChain4jConfig {
// 将EmbeddingModel注册为Bean,供Spring自动注入
@Bean
public EmbeddingModel embeddingModel() {
return new AllMiniLmL6V2EmbeddingModel(); // 你使用的嵌入模型
}
}
2、向量存储
2.1、Pinecone简介
- 筛选结果:通过设置 minScore 阈值,能够过滤掉那些与查询文本相关性较低的结果。在代码 里, minScore(0.8) 意味着只有得分大于等于 0.8 的结果才会被返回,低于这个阈值的结果会被舍弃。这样可以确保返回的结果是与查询文本高度相关的,提升检索结果的质量。
- 控制召回率和准确率:调整 minScore 的值可以在召回率和准确率之间进行权衡。如果把阈值设置得较低,那么更多的结果会被返回,召回率会提高,但可能会包含一些相关性不太强的结果,导致准确率下降;反之,如果把阈值设置得较高,返回的结果数量会减少,准确率会提高,但可能会遗漏一些相关的结果,使得召回率降低。在实际应用中,需要根据具体的业务需求来合理设置 minScore 的值。
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-pinecone</artifactId>
</dependency>
更多推荐
所有评论(0)