博客專欄

EEPW首頁 > 博客 > 如何實(shí)現(xiàn)AI的矢量數(shù)據(jù)庫

如何實(shí)現(xiàn)AI的矢量數(shù)據(jù)庫

發(fā)布人:ygtu 時(shí)間:2023-08-29 來源:工程師 發(fā)布文章
推薦:使用NSDT場(chǎng)景編輯器助你快速搭建3D應(yīng)用場(chǎng)景

然而,人工智能模型有點(diǎn)像美食廚師。他們可以創(chuàng)造奇跡,但他們需要優(yōu)質(zhì)的成分。人工智能模型在大多數(shù)輸入上都做得很好,但如果它們以最優(yōu)化的格式接收輸入,它們就會(huì)真正發(fā)光。這就是矢量數(shù)據(jù)庫的重點(diǎn)。

在本文的過程中,我們將深入探討什么是矢量數(shù)據(jù)庫,為什么它們?cè)谌斯ぶ悄苁澜缰凶兊迷絹碓街匾缓笪覀儗⒉榭磳?shí)現(xiàn)矢量數(shù)據(jù)庫的分步指南。

跳躍前進(jìn):

  • 什么是矢量數(shù)據(jù)庫?

  • 為什么需要矢量數(shù)據(jù)庫?

  • 實(shí)現(xiàn)矢量數(shù)據(jù)庫:分步指南

  • 先決條件

  • 設(shè)置Weaviate項(xiàng)目

  • 創(chuàng)建我們的節(jié)點(diǎn).js項(xiàng)目

  • 設(shè)置我們的矢量數(shù)據(jù)庫

  • 設(shè)置客戶端

  • 遷移數(shù)據(jù)

  • 添加文檔

  • 刪除文檔

  • 向數(shù)據(jù)庫添加查詢函數(shù)

  • 結(jié)合向量嵌入和 AI

  • 人工智能模型設(shè)置

  • 查詢我們的數(shù)據(jù)

  • 測(cè)試我們的查詢

什么是矢量數(shù)據(jù)庫?

在我們開始探索矢量數(shù)據(jù)庫之前,了解在編程和機(jī)器學(xué)習(xí)的上下文中什么是矢量非常重要。

在編程中,向量本質(zhì)上是一個(gè)一維數(shù)字?jǐn)?shù)組。如果您曾經(jīng)編寫過涉及 3D 圖形或機(jī)器學(xué)習(xí)算法的代碼,那么您很可能使用過向量。

const vector4_example = [0.5, 1.5, 6.0, 3.4]

它們只是數(shù)字?jǐn)?shù)組,通常是浮點(diǎn)數(shù),我們用它們的維度來指代。例如,a 是浮點(diǎn)數(shù)的三元素?cái)?shù)組,a 是浮點(diǎn)數(shù)的四元素?cái)?shù)組。就這么簡(jiǎn)單!vector3vector4

但向量不僅僅是數(shù)字?jǐn)?shù)組。在機(jī)器學(xué)習(xí)的背景下,向量在高維空間中表示和操作數(shù)據(jù)方面發(fā)揮著關(guān)鍵作用。這使我們能夠執(zhí)行驅(qū)動(dòng)AI模型的復(fù)雜操作和計(jì)算。

現(xiàn)在我們已經(jīng)掌握了向量,讓我們把注意力轉(zhuǎn)向向量數(shù)據(jù)庫。

乍一看,你可能會(huì)想,“嘿,既然向量只是數(shù)字?jǐn)?shù)組,我們不能使用常規(guī)數(shù)據(jù)庫來存儲(chǔ)它們嗎?好吧,從技術(shù)上講,你可以。但這就是事情變得有趣的地方。

矢量數(shù)據(jù)庫是一種特殊類型的數(shù)據(jù)庫,針對(duì)存儲(chǔ)和執(zhí)行對(duì)大量矢量數(shù)據(jù)的操作進(jìn)行了優(yōu)化。因此,雖然您的常規(guī)數(shù)據(jù)庫確實(shí)可以存儲(chǔ)數(shù)組,但矢量數(shù)據(jù)庫更進(jìn)一步,提供了專門的工具和操作來處理矢量。

在下一節(jié)中,我們將討論為什么矢量數(shù)據(jù)庫是必要的,以及它們帶來的優(yōu)勢(shì)。所以堅(jiān)持下去,因?yàn)槭虑闀?huì)變得更加有趣!

為什么需要矢量數(shù)據(jù)庫?

現(xiàn)在我們已經(jīng)對(duì)什么是矢量數(shù)據(jù)庫有了深入的了解,讓我們深入了解為什么它們?cè)谌斯ぶ悄芎蜋C(jī)器學(xué)習(xí)領(lǐng)域如此必要。

這里的關(guān)鍵詞是性能。矢量數(shù)據(jù)庫通常每次查詢處理數(shù)億個(gè)向量,這種性能比傳統(tǒng)數(shù)據(jù)庫在處理向量時(shí)能夠達(dá)到的性能要快得多。

那么,是什么讓矢量數(shù)據(jù)庫如此快速高效呢?讓我們來看看使它們與眾不同的一些關(guān)鍵功能。

復(fù)雜的數(shù)學(xué)運(yùn)算

向量數(shù)據(jù)庫旨在對(duì)向量執(zhí)行復(fù)雜的數(shù)學(xué)運(yùn)算,例如過濾和定位“附近”向量。這些操作在機(jī)器學(xué)習(xí)環(huán)境中至關(guān)重要,其中模型通常需要在高維空間中找到彼此接近的向量。

例如,一種常見的數(shù)據(jù)分析技術(shù)余弦相似性通常用于測(cè)量?jī)蓚€(gè)向量的相似程度。矢量數(shù)據(jù)庫擅長(zhǎng)這些類型的計(jì)算。

專用矢量索引

與組織良好的庫一樣,數(shù)據(jù)庫需要一個(gè)良好的索引系統(tǒng)來快速檢索請(qǐng)求的數(shù)據(jù)。矢量數(shù)據(jù)庫提供專門的矢量索引,與傳統(tǒng)數(shù)據(jù)庫相比,檢索數(shù)據(jù)的速度更快、更確定(與隨機(jī)數(shù)據(jù)庫相反)。

借助這些索引,向量數(shù)據(jù)庫可以快速定位 AI 模型所需的向量并快速生成結(jié)果。

緊湊的存儲(chǔ)

在大數(shù)據(jù)的世界里,存儲(chǔ)空間是一種寶貴的商品。矢量數(shù)據(jù)庫在這里也大放異彩,以使其更緊湊的方式存儲(chǔ)矢量。壓縮和量化向量等技術(shù)用于在內(nèi)存中保留盡可能多的數(shù)據(jù),從而進(jìn)一步減少負(fù)載和查詢延遲。

分片

在處理大量數(shù)據(jù)時(shí),將數(shù)據(jù)分布在多臺(tái)機(jī)器上可能是有益的,這個(gè)過程稱為分片。許多數(shù)據(jù)庫都可以執(zhí)行此操作,但 SQL 數(shù)據(jù)庫尤其需要付出更多努力才能橫向擴(kuò)展。另一方面,矢量數(shù)據(jù)庫通常在其架構(gòu)中內(nèi)置分片,使它們能夠輕松處理大量數(shù)據(jù)。

簡(jiǎn)而言之,雖然傳統(tǒng)數(shù)據(jù)庫可以存儲(chǔ)和對(duì)向量執(zhí)行操作,但它們并未針對(duì)任務(wù)進(jìn)行優(yōu)化。另一方面,矢量數(shù)據(jù)庫正是為此目的而構(gòu)建的。它們提供了處理大量矢量數(shù)據(jù)所需的速度、效率和專用工具,使其成為人工智能和機(jī)器學(xué)習(xí)領(lǐng)域必不可少的工具。

在下一節(jié)中,我們將向量數(shù)據(jù)庫與其他類型的數(shù)據(jù)庫進(jìn)行比較,并解釋它們?nèi)绾芜m應(yīng)更大的數(shù)據(jù)庫生態(tài)系統(tǒng)。我們才剛剛開始!

實(shí)現(xiàn)矢量數(shù)據(jù)庫:分步指南

出于本指南的目的,我們將使用 Weaviate(一種流行的矢量數(shù)據(jù)庫服務(wù))來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的矢量數(shù)據(jù)庫,您可以基于該數(shù)據(jù)庫為任何用例進(jìn)行構(gòu)建。

您可以在此處克隆初學(xué)者模板并運(yùn)行以進(jìn)行設(shè)置。npm install

先決條件
  • 先前的JS知識(shí)將有所幫助:本教程中編寫的所有代碼都將使用JavaScript,我們也將使用Weaviate JavaScript SDK。

  • Node 和 npm:我們將在服務(wù)器上的 JavaScript 環(huán)境中工作。

  • OpenAI API密鑰:我們將使用他們的嵌入模型將我們的數(shù)據(jù)轉(zhuǎn)換為嵌入以存儲(chǔ)在我們的數(shù)據(jù)庫中

  • Weaviate帳戶:我們將使用他們的托管數(shù)據(jù)庫服務(wù);您可以在此處獲得免費(fèi)帳戶

設(shè)置Weaviate項(xiàng)目

創(chuàng)建帳戶后,您需要通過Weaviate儀表板設(shè)置項(xiàng)目。轉(zhuǎn)到 WCS 控制臺(tái),然后單擊創(chuàng)建集群

創(chuàng)建 Weaviate 集群

選擇“免費(fèi)沙盒”層并提供群集名稱。當(dāng)它要求您啟用身份驗(yàn)證時(shí),請(qǐng)選擇“”:

在群集中啟用身份驗(yàn)證

單擊創(chuàng)建。幾分鐘后,您應(yīng)該會(huì)在完成后看到一個(gè)復(fù)選標(biāo)記。

單擊“詳細(xì)信息”以查看群集詳細(xì)信息,因?yàn)槲覀儗⒃谙乱徊糠钟玫剿鼈儭F渲邪ǎ?/p>

  • 一個(gè)編織的****

  • 身份驗(yàn)證詳細(xì)信息(Weaviate API 密鑰;單擊密鑰圖標(biāo)以顯示)

創(chuàng)建我們的節(jié)點(diǎn).js項(xiàng)目

有了先決條件,我們可以創(chuàng)建向量數(shù)據(jù)庫并查詢它。要繼續(xù)操作,您需要一個(gè)新的 Node 項(xiàng)目;您可以在此處克隆 GitHub 上的模板,其中包括入門所需的一切。

或者,您可以通過運(yùn)行以下命令創(chuàng)建一個(gè):

mkdir weaviate-vector-database && cd weaviate-vector-database
npm init -y && npm install dotenv openai weaviate-ts-client
mkdir src

編輯文件并添加腳本,如下所示:package.jsonstart

// ...rest of package.json
"scripts": {
"start": "node src/index.js"
},
// ...rest of package.json

創(chuàng)建一個(gè)文件來存儲(chǔ)敏感信息,如 API 密鑰。編寫命令并在代碼編輯器中打開新創(chuàng)建的文件,然后粘貼以下內(nèi)容并確保將占位符替換為實(shí)際值:.envtouch .env.env

// .env
OPENAI_KEY="<OPENAI_API_KEY>"
WEAVIATE_API_KEY="<WEAVIATE_API_KEY>"
WEAVIATE_URL="<WEAVIATE_URL>"
DATA_CLASSNAME="Document"

設(shè)置我們的矢量數(shù)據(jù)庫

項(xiàng)目設(shè)置完成后,我們可以添加一些代碼來設(shè)置和使用我們的矢量數(shù)據(jù)庫。讓我們快速總結(jié)一下我們將要實(shí)現(xiàn)的內(nèi)容:

  • 幫助程序函數(shù),它:

  • 連接到我們的數(shù)據(jù)庫

  • 批量矢量化和上傳文檔

  • 查詢最相似的項(xiàng)目

  • 一個(gè) main 函數(shù),它使用上面的輔助函數(shù)一次性上傳文檔和查詢數(shù)據(jù)庫

設(shè)置客戶端

話雖如此,讓我們創(chuàng)建第一個(gè)文件來存儲(chǔ)數(shù)據(jù)庫連接和幫助程序函數(shù)。通過運(yùn)行創(chuàng)建一個(gè)新文件,讓我們開始填寫它:touch src/database.js

// src/database.js
import weaviate, { ApiKey } from "weaviate-ts-client";
import { config } from "dotenv";

config();

async function setupClient() {
let client;

try {
client = weaviate.client({
scheme: "https",
host: process.env.WEAVIATE_URL,
apiKey: new ApiKey(process.env.WEAVIATE_API_KEY),
headers: { "X-OpenAI-Api-Key": process.env.OPENAI_API_KEY },
});
} catch (err) {
console.error("error >>>", err.message);
}

return client;
}
// ... code continues below

讓我們分解一下這里發(fā)生的事情。首先,我們導(dǎo)入必要的軟件包,Weaviate客戶端和dotenv配置。dotenv 是一個(gè)將環(huán)境變量從文件加載到 .Weaviate和OpenAI密鑰和URL通常存儲(chǔ)在環(huán)境變量中,以保持機(jī)密性并遠(yuǎn)離代碼庫。.envprocess.env

以下是函數(shù)中發(fā)生的情況:setupClient()

  1. 我們初始化了一個(gè)變量client

  2. 我們有一個(gè)塊,用于設(shè)置與 Weaviate 服務(wù)器的連接。如果在此過程中發(fā)生任何錯(cuò)誤,我們會(huì)將錯(cuò)誤消息打印到控制臺(tái)try…catch

  • 在塊內(nèi),我們使用該方法創(chuàng)建一個(gè)新的 Weaviate 客戶端。、 和 參數(shù)取自我們?cè)O(shè)置的環(huán)境變量tryweaviate.client()schemehostapiKey

  1. 最后,我們傳入OpenAI的標(biāo)頭,因?yàn)槲覀儗⑹褂肙penAI的Ada模型來矢量化我們的數(shù)據(jù)。

遷移數(shù)據(jù)

設(shè)置客戶端后,讓我們使用一些虛擬數(shù)據(jù)、虛構(gòu)生物、地點(diǎn)和事件的集合來運(yùn)行遷移。稍后,我們將針對(duì)此數(shù)據(jù)查詢 GPT-3。

如果您沒有克隆初學(xué)者模板,請(qǐng)按照以下步驟操作:

  • 通過運(yùn)行創(chuàng)建新文件touch src/data.js

  • 從此處復(fù)制文件的內(nèi)容并將其粘貼到

花一些時(shí)間瀏覽 中的數(shù)據(jù)。然后,在文件頂部添加新導(dǎo)入:src/data.jssrc/database.js

// ...other imports
import { FAKE_XORDIA_HISTORY } from "./data";

在函數(shù)下方,添加一個(gè)新函數(shù),如下所示:setupClient

async function migrate(shouldDeleteAllDocuments = false) {
try {
const classObj = {
class: process.env.DATA_CLASSNAME,
vectorizer: "text2vec-openai",
moduleConfig: {
"text2vec-openai": {
model: "ada",
modelVersion: "002",
type: "text",
},
},
};

const client = await setupClient();

try {
  const schema = await client.schema
    .classCreator()
    .withClass(classObj)
    .do();
  console.info("created schema >>>", schema);
} catch (err) {
  console.error("schema already exists");
}

if (!FAKE_XORDIA_HISTORY.length) {
  console.error(`Data is empty`);
  process.exit(1);
}

if (shouldDeleteAllDocuments) {
  console.info(`Deleting all documents`);
  await deleteAllDocuments();
}

console.info(`Inserting documents`);
await addDocuments(FAKE_XORDIA_HISTORY);

} catch (err) {
console.error("error >>>", err.message);
}
}

再一次,讓我們分解一下這里發(fā)生的事情。

該函數(shù)接受單個(gè)參數(shù),該參數(shù)確定在遷移數(shù)據(jù)時(shí)是否清除數(shù)據(jù)庫。migrateshouldDeleteAllDocuments

在我們的塊中,我們創(chuàng)建一個(gè)名為 .此對(duì)象表示 Weaviate 中類的架構(gòu)(確保在文件中添加 a),該類使用矢量化器。這決定了文本文檔在數(shù)據(jù)庫中的配置和表示方式,并告訴Weaviate使用OpenAI的“ada”模型對(duì)我們的數(shù)據(jù)進(jìn)行矢量化。try…catchclassObjCLASS_NAME.envtext2vec-openai

然后,我們使用方法鏈創(chuàng)建模式。這會(huì)向 Weaviate 服務(wù)器發(fā)送請(qǐng)求,以創(chuàng)建 中定義的文檔類。成功創(chuàng)建架構(gòu)后,我們將模式對(duì)象記錄到控制臺(tái),并顯示消息 .現(xiàn)在,錯(cuò)誤通過記錄到控制臺(tái)的簡(jiǎn)單消息進(jìn)行處理。client.schema.classCreator().withClass(classObj).do()classObjcreated schema >>>

我們可以檢查要遷移的虛擬數(shù)據(jù)的長(zhǎng)度。如果為空,則代碼在此處結(jié)束。我們可以使用函數(shù)(稍后會(huì)添加)清除數(shù)據(jù)庫,如果 是 .deleteAllDocumentsshouldDeleteAllDocumentstrue

最后,使用一個(gè)函數(shù)(我們接下來將添加),我們上傳所有要矢量化并存儲(chǔ)在 Weaviate 中的條目。addDocuments

添加文檔

我們可以繼續(xù)矢量化和上傳我們的文本文檔。這實(shí)際上是一個(gè)兩步過程,其中:

  1. 原始文本字符串使用 OpenAI Ada 模型轉(zhuǎn)換為矢量

  2. 轉(zhuǎn)換后的載體將上傳到我們的 Weaviate 數(shù)據(jù)庫

值得慶幸的是,這些是由我們使用的Weaviate SDK自動(dòng)處理的。讓我們繼續(xù)創(chuàng)建函數(shù)來執(zhí)行此操作。打開同一文件并粘貼以下內(nèi)容:src/database.js

// code continues from above
const addDocuments = async (data = []) => {
const client = await setupClient();
let batcher = client.batch.objectsBatcher();
let counter = 0;
const batchSize = 100;

for (const document of data) {
const obj = {
class: process.env.DATA_CLASSNAME,
properties: { ...document },
};

batcher = batcher.withObject(obj);
if (counter++ == batchSize) {
  await batcher.do();
  counter = 0;
  batcher = client.batch.objectsBatcher();
}

}

const res = await batcher.do();
return res;
};
// ... code continues below

和以前一樣,讓我們分解一下這里發(fā)生的事情。

  1. 首先,我們調(diào)用前面定義的函數(shù)來設(shè)置并獲取 Weaviate 客戶端實(shí)例setupClient()

  2. 我們使用初始化一個(gè)批處理器,用于收集文檔并一次性將它們上傳到Weaviate,使過程更高效client.batch.objectsBatcher()

  3. 我們還定義了一個(gè)計(jì)數(shù)器變量和一個(gè)變量,并將其設(shè)置為 100。計(jì)數(shù)器跟蹤已添加到當(dāng)前批次的文檔數(shù),并定義每個(gè)批次中應(yīng)包含的文檔數(shù)batchSizebatchSize

  4. 然后,我們遍歷數(shù)據(jù)數(shù)組中的每個(gè)文檔:

  • 對(duì)于每個(gè)文檔,我們創(chuàng)建一個(gè)對(duì)象,該對(duì)象以Weaviate期望的格式表示文檔,以便可以將其擴(kuò)展到該對(duì)象的屬性中

  • 然后,我們使用batcher.withObject(obj)

  • 如果計(jì)數(shù)器等于批大?。ㄒ馕吨褲M),我們將批上傳到 Weaviate,將計(jì)數(shù)器重置為 ,并為下一批文檔創(chuàng)建一個(gè)新的批處理器batcher.do()0

處理完所有文檔并將其添加到批處理后,如果還有剩余的批處理尚未上載(因?yàn)樗吹竭_(dá) ),則可以使用 上載剩余的批處理。batchSizebatcher.do()

此處的最后一步發(fā)生在函數(shù)返回上次調(diào)用的響應(yīng)時(shí)。此響應(yīng)將包含有關(guān)上傳的詳細(xì)信息,例如上傳是否成功以及發(fā)生的任何錯(cuò)誤。batcher.do()

從本質(zhì)上講,該函數(shù)通過將大量文檔分組為可管理的批次來幫助我們有效地將大量文檔上傳到我們的 Weaviate 實(shí)例。addDocuments()

刪除文檔

讓我們添加函數(shù)中使用的代碼。在函數(shù)下方,添加以下代碼:deleteAllDocumentsmigrateaddDocuments

// code continues from above
async function deleteAllDocuments() {
const client = await setupClient();
const documents = await client.graphql
.get()
.withClassName(process.env.DATA_CLASSNAME)
.withFields("_additional { id }")
.do();

for (const document of documents.data.Get[process.env.DATA_CLASSNAME]) {
await client.data
.deleter()
.withClassName(process.env.DATA_CLASSNAME)
.withId(document._additional.id)
.do();
}
}
// ... code continues below

這個(gè)函數(shù)相對(duì)簡(jiǎn)單。

  1. 我們使用類名為setupClientidDocument

  2. 然后使用循環(huán),我們使用其刪除每個(gè)文檔for...ofid

這種方法之所以有效,是因?yàn)槲覀儞碛猩倭繑?shù)據(jù)。對(duì)于較大的數(shù)據(jù)庫,需要一種技術(shù)來刪除所有文檔,因?yàn)槊總€(gè)請(qǐng)求的限制是一次只有 200 個(gè)條目。batching

向數(shù)據(jù)庫添加查詢函數(shù)

現(xiàn)在我們有了將數(shù)據(jù)上傳到數(shù)據(jù)庫的方法,讓我們添加一個(gè)函數(shù)來查詢數(shù)據(jù)庫。在本例中,我們將執(zhí)行“最近鄰搜索”以查找與我們的查詢相似的文檔。

在同一文件中,添加以下內(nèi)容:src/database.js

// code continues from above
async function nearTextQuery({
concepts = [""],
fields = "text category",
limit = 1,
}) {
const client = await setupClient();
const res = await client.graphql
.get()
.withClassName("Document")
.withFields(fields)
.withNearText({ concepts })
.withLimit(limit)
.do();

return res.data.Get[process.env.DATA_CLASSNAME];
}

export { migrate, addDocuments, deleteAllDocuments, nearTextQuery };

同樣,讓我們對(duì)這里發(fā)生的事情進(jìn)行細(xì)分:

  1. nearTextQuery()是一個(gè)接受對(duì)象作為參數(shù)的異步函數(shù)。此對(duì)象可以包含三個(gè)屬性:

  • 概念:表示我們正在搜索的術(shù)語的字符串?dāng)?shù)組

  • 字段:一個(gè)字符串,表示我們希望在搜索結(jié)果中返回的字段。在本例中,我們從 和 字段請(qǐng)求textcategory

  • 限制:我們希望從搜索查詢中返回的最大結(jié)果數(shù)

  1. 我們調(diào)用函數(shù)來獲取 Weaviate 客戶端實(shí)例setupClient()

  2. 我們使用一系列方法構(gòu)建 GraphQL 查詢:

  • client.graphql.get():初始化 GraphQL 查詢

  • .withClassName("Document"):我們指定要在“文檔”對(duì)象中搜索

  • .withFields(fields):我們指定要在結(jié)果中返回哪些字段

  • .withNearText({ concepts }):這就是魔術(shù)發(fā)生的地方!我們指定了 Weaviate 將用于搜索語義相似的文檔的概念

  • .withLimit(limit):我們指定要返回的最大結(jié)果數(shù)

  • 最后,執(zhí)行查詢.do()

  1. 來自查詢的響應(yīng)存儲(chǔ)在變量中,然后在下一行返回res

  2. 最后,我們導(dǎo)出此處定義的所有函數(shù)以在其他地方使用

簡(jiǎn)而言之,該函數(shù)幫助我們根據(jù)提供的術(shù)語在 Weaviate 實(shí)例中搜索語義相似的文檔。nearTextQuery()

讓我們遷移數(shù)據(jù),以便在下一節(jié)中查詢它。打開終端并運(yùn)行 。npm run start"migrate"

結(jié)合向量嵌入和 AI

像 GPT-3 和 ChatGPT 這樣的大型語言模型旨在處理輸入并生成有用的輸出,這是一項(xiàng)需要了解單詞和短語之間復(fù)雜含義和關(guān)系的任務(wù)。

他們通過將單詞、句子甚至整個(gè)文檔表示為高維向量來做到這一點(diǎn)。通過分析這些向量之間的異同,人工智能模型可以理解我們語言中的上下文、語義甚至細(xì)微差別。

那么,矢量數(shù)據(jù)庫從何而來?讓我們將矢量數(shù)據(jù)庫視為 AI 模型的圖書館員。在龐大的書籍庫(或者,在我們的例子中,向量)中,人工智能模型需要快速找到與特定查詢最相關(guān)的書籍。矢量數(shù)據(jù)庫通過有效地存儲(chǔ)這些“書籍”并在需要時(shí)提供快速精確的檢索來實(shí)現(xiàn)這一點(diǎn)。

這對(duì)于許多AI應(yīng)用程序至關(guān)重要。例如,在聊天機(jī)器人應(yīng)用程序中,AI 模型需要找到對(duì)用戶問題最相關(guān)的響應(yīng)。它通過將用戶的問題和潛在響應(yīng)轉(zhuǎn)換為向量,然后使用向量數(shù)據(jù)庫查找與用戶問題最相似的響應(yīng)來實(shí)現(xiàn)這一點(diǎn)。

考慮到這一點(diǎn),我們將使用上面的數(shù)據(jù)庫來提供一個(gè) AI 模型 GPT-3.5,其中包含我們自己數(shù)據(jù)的上下文。這將允許模型回答有關(guān)未訓(xùn)練的數(shù)據(jù)的問題。

人工智能模型設(shè)置

通過運(yùn)行并粘貼以下內(nèi)容來創(chuàng)建新文件:touch src/data.js

import { Configuration, OpenAIApi } from "openai";

const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

async function getChatCompletion({ prompt, context }) {
const chatCompletion = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: You are a knowledgebase oracle. You are given a question and a context. You answer the question based on the context. Analyse the information from the context and draw fundamental insights to accurately answer the question to the best of your ability. Context: ${context} ,
},
{ role: "user", content: prompt },
],
});

return chatCompletion.data.choices[0].message;
}

export { getChatCompletion };

像往常一樣,讓我們分解一下文件:

  1. 我們從包中導(dǎo)入一些必需的模塊并初始化一個(gè)實(shí)例openaiopenai

  2. 我們定義了一個(gè)函數(shù),該函數(shù)接受提示、一些上下文,并將 GPT-3.5 模型配置為作為知識(shí)庫預(yù)言機(jī)進(jìn)行響應(yīng)getChatCompletion

  3. 最后,我們返回響應(yīng)并導(dǎo)出函數(shù)

查詢我們的數(shù)據(jù)

通過設(shè)置我們的矢量數(shù)據(jù)庫和 AI 模型,我們最終可以通過結(jié)合這兩個(gè)系統(tǒng)來查詢我們的數(shù)據(jù)。利用嵌入的強(qiáng)大效果和 GPT-3.5 令人印象深刻的自然語言功能,我們將能夠以更具表現(xiàn)力和可定制的方式與我們的數(shù)據(jù)進(jìn)行交互。

首先創(chuàng)建一個(gè)新文件并運(yùn)行 .然后粘貼以下內(nèi)容:touch src/index.js

import { config } from "dotenv";
import { nearTextQuery } from "./database.js";
import { getChatCompletion } from "./model.js";

config();

const queryDatabase = async (prompt) => {
console.info(Querying database);
const questionContext = await nearTextQuery({
concepts: [prompt],
fields: "title text date",
limit: 50,
});

const context = questionContext
.map((context, index) => {
const { title, text, date } = context;
return Document ${index + 1} Date: ${date} Title: ${title} ${text} ;
})
.join("\n\n");

const aiResponse = await getChatCompletion({ prompt, context });
return aiResponse.content;
};

const main = async () => {
const command = process.argv[2];
const params = process.argv[3];

switch (command) {
case "migrate":
return await migrate(params === "--delete-all");
case "query":
return console.log(await queryDatabase(params));
default:
// do nothing
break;
}
};

main();

在此文件中,我們將到目前為止所做的所有工作匯集在一起,以允許我們通過命令行查詢數(shù)據(jù)。像往常一樣,讓我們探討一下這里發(fā)生了什么:

  1. 首先,我們導(dǎo)入必要的模塊并使用包設(shè)置我們的環(huán)境變量dotenv

  2. 接下來,我們創(chuàng)建一個(gè)接受文本提示的函數(shù),我們使用它對(duì)向量數(shù)據(jù)庫執(zhí)行“近文本”查詢。我們將結(jié)果限制為 50 個(gè),并且我們特別要求提供匹配概念的“標(biāo)題”、“文本”和“日期”字段queryDatabase

  3. 這基本上返回了語義上類似于我們搜索查詢中的任何重要術(shù)語的文檔(嵌入功能強(qiáng)大!

  4. 然后,我們映射接收到的上下文,對(duì)其進(jìn)行格式化,并將其傳遞給AI模型以生成完成。使用上下文,GPT-3.5 的自然語言處理 (NLP) 功能大放異彩,因?yàn)樗軌蚋鶕?jù)我們的數(shù)據(jù)生成更準(zhǔn)確和有意義的響應(yīng)

  5. 最后,我們到達(dá)函數(shù)。在這里,我們使用命令行參數(shù)來執(zhí)行各種任務(wù)。如果我們通過,我們可以遷移我們的數(shù)據(jù)(帶有可選標(biāo)志,以防萬一我們想清理我們的石板并重新開始),并且有了,我們可以測(cè)試我們的查詢函數(shù)mainmigrate--delete-allquery

測(cè)試我們的查詢

祝賀。如果你走到了這一步,你應(yīng)該得到拍拍——你終于可以測(cè)試你的代碼了。

打開終端并運(yùn)行以下命令:

npm run start "query" "what are the 3 most impressive achievements of humanity in the story?"

查詢將發(fā)送到您的 Weaviate 矢量數(shù)據(jù)庫,在那里它與其他類似矢量進(jìn)行比較,并根據(jù)其文本返回 50 個(gè)最相似的矢量。然后,此上下文數(shù)據(jù)將被格式化并與您的查詢一起發(fā)送到 OpenAI 的 GPT-3.5 模型,在那里對(duì)其進(jìn)行處理并生成響應(yīng)。

如果一切順利,您應(yīng)該得到與以下類似的響應(yīng):

來自查詢測(cè)試的響應(yīng)

隨意探索這個(gè)虛構(gòu)的世界,更多的查詢,或者更好的是,帶上自己的數(shù)據(jù),親眼目睹向量和嵌入的力量。

如果此時(shí)遇到任何錯(cuò)誤,請(qǐng)?jiān)诖颂帉⒛拇a與最終版本進(jìn)行比較,并確保已創(chuàng)建并填寫文件。.env

結(jié)論和今后的步驟

在本教程中,我們略微探索了矢量和矢量數(shù)據(jù)庫的強(qiáng)大功能。使用Weaviate和GPT-3等工具,我們親眼目睹了這些技術(shù)在塑造AI應(yīng)用程序方面的潛力,從改進(jìn)個(gè)性化聊天機(jī)器人到增強(qiáng)機(jī)器學(xué)習(xí)算法。請(qǐng)務(wù)必也看看我們的GitHub!

然而,這僅僅是個(gè)開始。如果您想了解有關(guān)使用矢量數(shù)據(jù)庫的更多信息,請(qǐng)考慮:

  • 深入了解高級(jí)概念,例如使用矢量元數(shù)據(jù)、分片、壓縮,以實(shí)現(xiàn)更靈活、更高效的數(shù)據(jù)存儲(chǔ)和檢索

  • 嘗試更復(fù)雜的方法將向量嵌入集成到 AI 應(yīng)用程序中,以獲得更豐富、更細(xì)微的結(jié)果

感謝您堅(jiān)持到最后,希望這是對(duì)您的時(shí)間的有效利用。

您是否正在添加新的 JS 庫以提高性能或構(gòu)建新功能?如果他們反其道而行之呢?

毫無疑問,前端變得越來越復(fù)雜。當(dāng)您向應(yīng)用添加新的 JavaScript 庫和其他依賴項(xiàng)時(shí),您將需要更高的可見性,以確保您的用戶不會(huì)遇到未知問題。

LogRocket 是一個(gè)前端應(yīng)用程序監(jiān)控解決方案,可讓您重播 JavaScript 錯(cuò)誤,就好像它們發(fā)生在您自己的瀏覽器中一樣,這樣您就可以更有效地對(duì)錯(cuò)誤做出反應(yīng)。

日志火箭儀表板免費(fèi)試用橫幅

LogRocket 可以完美地與任何應(yīng)用程序配合使用,無論框架如何,并且具有用于記錄來自 Redux、Vuex 和 @ngrx/store 的其他上下文的插件。無需猜測(cè)問題發(fā)生的原因,您可以匯總并報(bào)告問題發(fā)生時(shí)應(yīng)用程序所處的狀態(tài)。LogRocket 還會(huì)監(jiān)控應(yīng)用的性能,報(bào)告客戶端 CPU 負(fù)載、客戶端內(nèi)存使用情況等指標(biāo)。

原文鏈接:如何實(shí)現(xiàn)AI的矢量數(shù)據(jù)庫 (mvrlink.com)


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。




相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉