-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
157 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,6 +51,3 @@ console.log(splitDocs); | |
|
||
![输出结果](./../../public/assets/ai/9.png) | ||
|
||
|
||
|
||
## |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,68 @@ | ||
# Retriever 常见的优化方式 | ||
# Retriever 常见的优化方式 | ||
|
||
上一节我们通过厂商提供的 Embedding 算法去制作匹配向量,通过 Facebook 提供的 Faiss 作为向量数据库,将数据存储到向量数据库中。 | ||
|
||
接下来我们将优化 Retriever 检索数据的方式 | ||
|
||
|
||
## MultiQueryRetriever | ||
|
||
MultiQueryRetriever 思路,或者说其他解决 llm 缺陷的思路基本都是一致的:加入更多 llm。 | ||
|
||
而 MultiQueryRetriever 是其中比较简单的一种解决方案,它使用 LLM 去将用户的输入改写成多个不同写法,从不同的角度来表达同一个意思,来克服因为关键词或者细微措词导致检索效果差的问题。 | ||
|
||
```js | ||
// MultiQueryRetriever: | ||
import "dotenv/config"; | ||
import { FaissStore } from "@langchain/community/vectorstores/faiss"; | ||
import { BaiduQianfanEmbeddings } from "@langchain/community/embeddings/baidu_qianfan"; | ||
import { MultiQueryRetriever } from "langchain/retrievers/multi_query"; | ||
import { TextLoader } from "langchain/document_loaders/fs/text"; | ||
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'; | ||
import ollama from './utils/ollama-llm.mjs'; | ||
import ernieTurbo from './utils/baidu-llm.mjs'; | ||
|
||
const loader = new TextLoader('./data/kong.txt'); | ||
|
||
const docs = await loader.load(); | ||
|
||
const splitter = new RecursiveCharacterTextSplitter({ | ||
chunkSize: 100, // 分块的大小 | ||
chunkOverlap: 20, // 块之间的重叠 | ||
}); | ||
|
||
const splitDocs = await splitter.splitDocuments(docs); // 对文章进行切片 | ||
|
||
const embedding = new BaiduQianfanEmbeddings(); // Embedding-V1是基于百度文心大模型技术的文本表示模型,将文本转化为用数值表示的向量形式,用于文本检索、信息推荐、知识挖掘等场景。 | ||
|
||
const vectorStore = await FaissStore.fromDocuments(splitDocs, embedding); // 从文档中创建一个向量存储 | ||
|
||
const retriever = MultiQueryRetriever.fromLLM({ // 通过 LLM 去生存不同的检索 | ||
llm: ernieTurbo, // 传入的 LLM 模型 | ||
retriever: vectorStore.asRetriever(3), // 向量数据库的 retriever | ||
queryCount: 3, // 生成 3 条不同的描述 | ||
verbose: true, // 设置为 true 会打印出 chain 内部的详细执行过程方便 debug | ||
}); | ||
|
||
const res = await retriever.invoke("茴香豆是做什么用的"); // 一共会生成 9 条数据,再做去重 | ||
|
||
console.log(`res`, res); | ||
``` | ||
|
||
执行上面的代码我们可以看到,通过 LLM 目前,可以将我们的描述生成 3 条不同的描述,避免语意偏差。 | ||
|
||
```js | ||
茴香豆的主要用途是什么? | ||
茴香豆通常用于哪些场合或文化中? | ||
茴香豆在烹饪中有什么作用? | ||
``` | ||
|
||
因为用户的原始输入是 `茴香豆是做什么用的`,这是一个非常模糊和有歧义性的问题,作为写这个问题的用户,他可能了解想要的答案是 “茴香豆是下酒用的”,但因为自然语言的特点,这是有歧义的的。 | ||
|
||
MultiQueryRetriever 的意义就是,找出这句话所有可能的意义,然后用这些可能的意义去检索,避免因为歧义导致检索错误。 | ||
|
||
|
||
## Document Compressor | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,89 @@ | ||
# Retriever 之向量数据库 | ||
# Retriever 之向量数据库 | ||
|
||
经过前面的学习,我们知道了如何对 数据进行加载和切割,接下来我们就要学习如何将数据通过 Embedding 算法转化为向量加载到向量数据库中。 | ||
|
||
## Embedding | ||
|
||
这里我们用最简单的词袋(words bag)模型来描述一下最简单的 embedding 过程,让大家更具象化的理解这个。 | ||
|
||
简单地说,词袋模型首先将一篇文章拆分成一个个单词,然后将其放入袋子里面。 | ||
|
||
例如我们有十篇文章,我们可以将文章拆分成一个个单词,然后统计单词出现的次数 | ||
|
||
```js | ||
|
||
第一篇文章: | ||
enson: 10 cool: 5 handsome: 8 | ||
|
||
第二篇文章: | ||
monkey: 8 cute: 2 handsome: 4 | ||
|
||
``` | ||
|
||
那我们尝试构建一个向量,也就是一个数组,每个位置有一个值,代表每个单词在这个文章中出现的次数 | ||
|
||
`[enson, cool, handsome, monkey, cute]` | ||
|
||
那每篇文章,都能用一个变量来表示 | ||
|
||
```js | ||
[10, 5, 8, 0, 0] | ||
[0, 0, 8, 8, 4] | ||
``` | ||
|
||
可以用最简单的余弦定理去计算两个向量之间的夹角,以此确定两个向量的距离。 这样,我们就有了通过向量和向量之间的余弦夹角的,来衡量文章之间相似度的能力。 | ||
|
||
回到我们 RAG 流程中,我们将切分后的每一个文档块使用 embedding 算法转换成一个向量,存储到向量数据库中(vector store)中。这样,每一个原始数据都有一个对应的向量,可以用来检索。 | ||
|
||
在企业开发中,一般会使用厂商提供的 Embedding 服务,例如 | ||
|
||
|
||
|
||
## VectorStore | ||
|
||
Vector store 提供提供的是存储向量和原始文档,并且提供基于向量进行相关性检索的能力。 | ||
|
||
因为 js 并不是一个面向后端和机器学习相关的语言,所以原生的 vector store 并不多,大多数还是以支持 python 为主。目前也有像 [lanceDB](https://lancedb.com/) 原生支持 js 的,但毕竟是少数。 | ||
|
||
我们将使用由 facebook 开源的 [faiss](https://github.com/facebookresearch/faiss) 向量数据库,目前有 27.7k star,是向量数据库中非常流行的开源解决方案。选择这个的原因是其可以将向量数据库导出成文件,并且提供了 python 和 nodejs 的处理方式。 | ||
|
||
|
||
```js | ||
// 安装 faiss | ||
yarn add faiss-node | ||
``` | ||
|
||
|
||
```js | ||
// https://js.langchain.com/v0.2/docs/integrations/vectorstores/faiss/#create-a-new-index-from-texts | ||
import "dotenv/config"; | ||
import { FaissStore } from "@langchain/community/vectorstores/faiss"; | ||
import { TextLoader } from "langchain/document_loaders/fs/text"; | ||
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'; | ||
import { BaiduQianfanEmbeddings } from "@langchain/community/embeddings/baidu_qianfan"; // 开通千帆 Embedding 模型, https://cloud.baidu.com/doc/VDB/s/Nltgvlg7k | ||
|
||
const loader = new TextLoader('./data/kong.txt'); | ||
|
||
const docs = await loader.load(); | ||
|
||
const splitter = new RecursiveCharacterTextSplitter({ | ||
chunkSize: 100, // 分块的大小 | ||
chunkOverlap: 20, // 块之间的重叠 | ||
}); | ||
|
||
const splitDocs = await splitter.splitDocuments(docs); | ||
|
||
const embedding = new BaiduQianfanEmbeddings(); // Embedding-V1是基于百度文心大模型技术的文本表示模型,将文本转化为用数值表示的向量形式,用于文本检索、信息推荐、知识挖掘等场景。 | ||
|
||
const vectorStore = await FaissStore.fromDocuments(splitDocs, embedding); | ||
|
||
const retriever = vectorStore.asRetriever(2); // 获取最相关的俩个文档片段 | ||
const res = await retriever.invoke("茴香豆是做什么用的"); | ||
|
||
console.log(res); | ||
|
||
``` | ||
|
||
|
||
![输出结果](./../../public/assets/ai/10.png) | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.