还在用 LIKE 查询吗?简单的关键词匹配无法准确捕捉文本中的语义信息。
为了解决这一问题,我们可以借助 嵌入向量(embedding) 技术,将文本转换为高维数学向量,进行更加智能的语义化搜索。本文将详细介绍如何使用 OpenAI 的 embedding
模块,以及如何在此基础上实现语义化搜索。
什么是Embedding?
Embedding 是一种将文本、图像等输入数据映射到一个高维空间中,形成一个向量的过程。在这个高维空间里,相似的文本会被映射到彼此靠近的位置。这种表示方式便于我们通过数学计算(如余弦相似度)来比较不同文本的语义相似性。
语义化搜索
在传统的搜索系统中,我们通常使用关键词匹配(如模糊搜索、正则表达式等)。然而,这些方法在处理自然语言语义时表现不佳。例如,当用户输入“百度前端面试题”,我们不仅要匹配关键词,还要理解搜索内容的语义,找到与其相关的文章。
为此,我们可以使用嵌入向量(embedding) 。向量可以将文本转化为高维空间中的点,每个点表示该文本的语义。通过计算用户输入与文章向量的相似度,我们可以找到最相关的内容。这种方法比传统的字符串匹配更加语义化和智能。
Embedding 模块的使用
安装依赖
首先,我们需要安装项目中使用的依赖包。在项目根目录下,执行以下命令安装依赖:
npm install dotenv openai readline fs/promises
其中涉及到隐私的API密钥就要使用到 dotenv
模块用于从.env
文件中加载环境变量。最主要运用的是OPENAI
的Embedding
模块,所以要安装 openai
用于与其API进行通信。readline
模块用于处理用户的命令行输入。 fs/promises
是Node.js原生的文件系统模块,支持使用Promise
的方式读取和写入文件。
文本转化成向量
首先,我们来看如何使用 OpenAI 的 embedding
模块将文本转换为向量。
import OpenAI from 'openai'; // 引入OpenAI模块
import dotenv from 'dotenv'; // 引入dotenv模块以加载环境变量
dotenv.config({
path: '.env' // 配置环境变量文件的路径
});
// 初始化OpenAI客户端
const client = new OpenAI({
apiKey: process.env.OPENAI_KEY, // 从环境变量中加载OpenAI API密钥
baseURL: process.env.BASE_URL // 基础URL(如果需要自定义,可以修改)
});
// 使用embedding将文字转为向量
const response = await client.embeddings.create({
model: 'text-embedding-ada-002', // 指定模型,OpenAI 提供的预训练嵌入模型
input: "百度前端面试题" // 要转换为向量的文本
});
// 打印生成的嵌入向量
console.log(response.data[0].embedding);
首先初始化 OpenAI 客户端,使用 dotenv
模块加载环境变量文件 .env
,以确保 API 密钥安全。client
对象初始化时,通过 apiKey
和 baseURL
指定了 API 访问密钥和请求的基础地址。
生成 Embedding是调用 client.embeddings.create
方法生成文本嵌入向量。参数包括 model
和 input
,其中 model
使用了 text-embedding-ada-002
(这是 OpenAI 提供的一个用于文本嵌入的模型),input
是需要进行向量化的文本,在这个示例中为“百度前端面试题”。
可以看到已经将我们输入的文本转化成了一个有上千维度的向量。
这个生成的向量数据可以表示输入文本的语义信息。对于不同的文本,我们可以生成相应的向量并通过数学计算(如余弦相似度)来衡量这些文本之间的语义相似性。接下来我们将基于此进一步讨论如何使用这些向量实现语义化搜索。
实现语义化搜索
文件转向量
这里我们将存放文章数组的文件生成对应的嵌入向量为例,并将这些向量保存到一个新的文件中。这一过程使用了 OpenAI 的 embedding
模块,将文本转换为高维向量,最终存储用于后续的语义搜索。
import fs from 'fs/promises'; // 引入fs模块以便使用promise API读取和写入文件
import OpenAI from 'openai'; // 引入OpenAI模块,用于调用API
import dotenv from 'dotenv'; // 引入dotenv模块,用于加载环境变量
// 加载环境变量
dotenv.config({
path: '.env'
});
// 初始化OpenAI客户端,传入API密钥和基础URL
const client = new OpenAI({
apiKey: process.env.OPENAI_KEY,
baseURL: process.env.BASE_URL
});
// 输入和输出文件路径
const inputFilePath = './data/posts.json'; // 原始数据文件
const outputFilePath = './data/posts_with_embeddings.json'; // 输出文件
// 读取原始文章数据
const data = await fs.readFile(inputFilePath, 'utf-8');
const posts = JSON.parse(data); // 将读取到的JSON数据解析为JavaScript对象
const postsWithEmbedding = []; // 创建一个数组用于存储带嵌入向量的文章
// 遍历每篇文章,生成嵌入向量
for (const { title, category } of posts) {
// 生成嵌入向量,基于文章标题
const response = await client.embeddings.create({
model: 'text-embedding-ada-002', // 使用text-embedding-ada-002模型
input: `标题: ${title}` // 将文章标题作为嵌入输入
});
// 将标题、分类和生成的嵌入向量保存到新的数据结构中
postsWithEmbedding.push({
title,
category,
embedding: response.data[0].embedding // 提取生成的嵌入向量
});
}
// 将生成的文章和嵌入向量保存到输出文件
await fs.writeFile(outputFilePath, JSON.stringify(postsWithEmbedding));
fs/promises
这个模块提供了文件系统的异步操作版本,通过 await
可以方便地读取和写入文件。
读取输入数据使用 fs.readFile
从指定路径读取包含文章数据的 JSON 文件。文件中的数据被解析为一个包含文章对象的数组,每个文章对象包含 title
和 category
。
生成嵌入向量是通过遍历每篇文章,使用 title
生成文本的嵌入向量。通过 OpenAI 的 embeddings.create
接口,指定模型(text-embedding-ada-002
)并将文章标题作为输入。 调用后,API 返回一个嵌入向量(高维向量),该向量表示输入文本的语义信息。
对于每篇文章,将生成的向量和文章的 title
、category
一起存入 postsWithEmbedding
数组中。
向量计算
通过 OpenAI 的 embedding
模块生成向量后,我们可以利用这些向量来比较用户输入与现有内容的相似度,实现语义化搜索。
import fs from 'fs/promises'; // 引入文件系统模块,支持Promise
import OpenAI from 'openai'; // 引入OpenAI模块
import dotenv from 'dotenv'; // 引入dotenv模块
dotenv.config({
path: '.env'
});
// 初始化OpenAI客户端
const client = new OpenAI({
apiKey: process.env.OPENAI_KEY,
baseURL: process.env.BASE_URL
});
// 读取文章数据及其嵌入向量
const inputFilePath = './data/posts_with_embeddings.json';
const data = await fs.readFile(inputFilePath, 'utf-8');
const posts = JSON.parse(data); // 解析读取的JSON数据
// 计算向量之间的余弦相似度
const cosineSimilarity = (v1, v2) => {
const dotProduct = v1.reduce((acc, curr, i) => acc + curr * v2[i], 0); // 计算点积
const lengthV1 = Math.sqrt(v1.reduce((acc, curr) => acc + curr * curr, 0)); // 计算v1向量的长度
const lengthV2 = Math.sqrt(v2.reduce((acc, curr) => acc + curr * curr, 0)); // 计算v2向量的长度
return dotProduct / (lengthV1 * lengthV2); // 返回余弦相似度
};
// 输入要搜索的内容
const input = "前端性能优化";
// 生成输入文本的嵌入向量
const response = await client.embeddings.create({
model: 'text-embedding-ada-002',
input: input
});
const { embedding } = response.data[0];
// 计算输入向量与每篇文章向量的相似度并排序
const results = posts.map(item => ({
...item,
similarity: cosineSimilarity(embedding, item.embedding)
}))
.sort((a, b) => b.similarity - a.similarity) // 按相似度降序排序
.slice(0, 3) // 只取最相似的3篇文章
.map((item, index) => `${index + 1}. ${item.title} - ${item.category}`);
// 打印搜索结果
console.log(`\n搜索结果:\n${results.join("\n")}\n`);
从 posts_with_embeddings.json
文件中读取包含文章标题、分类及其嵌入向量的数据。这些数据提前通过 OpenAI 的 embedding
模块生成并存储在文件中。
计算余弦相似度 cosineSimilarity
函数用于计算两组向量之间的余弦相似度。通过向量的点积及其长度,计算出两个向量的夹角,夹角越小,相似度越高。余弦相似度是一个常用的衡量向量之间相似性的指标,其值在 -1
到 1
之间,1
表示两个向量完全相同,0
表示它们不相关,-1
表示它们完全相反。在这个搜索系统中,余弦相似度越高的文章越符合用户的输入语义。
使用 client.embeddings.create
方法将用户输入的文本转换为向量,用以与文章的嵌入向量进行对比。遍历每篇文章的嵌入向量,与输入文本的向量进行相似度计算,将结果存入一个新的数组。按相似度降序排序,取出最相似的3篇文章,并输出结果。
总结
通过本文的讲解,我们实现了一个简单的语义化搜索系统。首先,我们介绍了如何使用 OpenAI 的 embedding
模块将文本转换为嵌入向量。然后,基于这些向量,我们可以通过计算余弦相似度,来衡量不同文本之间的语义相似性,从而实现智能搜索。
这种语义化搜索的优势在于,它不仅能找到包含特定关键词的文章,还能理解文本的语义,提供更加精准的搜索结果!文章编写不易,如果对你有帮助可以点个赞哦😊!
如何学习大模型
现在社会上大模型越来越普及了,已经有很多人都想往这里面扎,但是却找不到适合的方法去学习。
作为一名资深码农,初入大模型时也吃了很多亏,踩了无数坑。现在我想把我的经验和知识分享给你们,帮助你们学习AI大模型,能够解决你们学习中的困难。
我已将重要的AI大模型资料包括市面上 AI大模型各大白皮书、AGI大模型系统学习路线、AI大模型视频教程、实战学习,等录播视频免费分享
出来,需要的小伙伴可以扫取。
一、AGI大模型系统学习路线
很多人学习大模型的时候没有方向,东学一点西学一点,像只无头苍蝇乱撞,我下面分享的这个学习路线希望能够帮助到你们学习AI大模型。
二、AI大模型视频教程
三、AI大模型各大学习书籍
四、AI大模型各大场景实战案例
五、结束语
学习AI大模型是当前科技发展的趋势,它不仅能够为我们提供更多的机会和挑战,还能够让我们更好地理解和应用人工智能技术。通过学习AI大模型,我们可以深入了解深度学习、神经网络等核心概念,并将其应用于自然语言处理、计算机视觉、语音识别等领域。同时,掌握AI大模型还能够为我们的职业发展增添竞争力,成为未来技术领域的领导者。
再者,学习AI大模型也能为我们自己创造更多的价值,提供更多的岗位以及副业创收,让自己的生活更上一层楼。
因此,学习AI大模型是一项有前景且值得投入的时间和精力的重要选择。