OpenAI 嵌入模型是構建高效能向量搜尋系統的關鍵。選擇合適的模型需要考量成本、效能和準確度。text-embedding-3-small 模型通常是價效比最高的選擇,而 text-embedding-3-large 適用於對準確度要求更高的場景。text-embedding-ada-002 則以其快速處理速度著稱。批次處理資料可以顯著提高嵌入效率,避免觸發 API 速率限制。Pinecone 向量資料函式庫提供高效的向量儲存和查詢功能,配合適當的索引引數和批次更新策略,可以進一步提升系統效能。此外,結合生成式 AI 模型,可以根據向量搜尋結果生成客製化內容,例如推薦郵件,提升使用者經驗。

向量嵌入策略最佳實踐

在建構客製化增強生成式 AI 知識函式庫的過程中,向量嵌入策略扮演著至關重要的角色。OpenAI 提供了多種嵌入模型,這些模型在成本、效能和準確度上各有不同。選擇合適的模型對於整體系統的效能有著巨大的影響。

嵌入模型的選擇

根據實際需求和應用場景,選擇最合適的嵌入模型是首要任務。text-embedding-3-smalltext-embedding-3-largetext-embedding-ada-002 是目前 OpenAI 提供的幾種主要嵌入模型。每種模型都有其特定的優缺點和適用場景。

text-embedding-3-small

此模型在成本和效能之間取得了良好的平衡。它適合於大多數應用場景,尤其是在需要處理大量資料且對效能有一定要求時。

text-embedding-3-large

相較於 text-embedding-3-small,此模型提供了更高的準確度,但同時也伴隨著更高的成本和計算資源需求。它適合於對準確度要求較高的應用場景。

text-embedding-ada-002

此模型以其快速的處理速度著稱,適合於需要即時處理的應用場景。

程式碼實作:取得向量嵌入

以下程式碼定義了一個 get_embedding 函式,用於取得指定文字的向量嵌入:

import openai
import time

# 指定嵌入模型
embedding_model = "text-embedding-3-small"
client = openai.OpenAI()

def get_embedding(text, model=embedding_model):
    # 將換行符替換為空格,以確保輸入格式一致
    text = text.replace("\n", " ")
    response = client.embeddings.create(input=[text], model=model)
    embedding = response.data[0].embedding
    return embedding

內容解密:

這段程式碼使用 OpenAI 的 embeddings.create 方法來取得指定文字的向量嵌入。函式內部將換行符替換為空格,以確保輸入格式的一致性。這樣可以避免因格式問題導致的錯誤或不一致的結果。

資料批次處理的最佳實踐

在處理大量資料時,批次處理是提高效率的關鍵。以下程式碼示範瞭如何以 1,000 個 chunk 為一批進行嵌入:

start_time = time.time()
chunk_start = 0
chunk_end = 1000
pause_time = 3  # 避免觸發 API 速率限制
embeddings = []
counter = 1

while chunk_end <= len(chunks):
    chunks_to_embed = chunks[chunk_start:chunk_end]
    current_embeddings = []
    for chunk in chunks_to_embed:
        embedding = get_embedding(chunk, model=embedding_model)
        current_embeddings.append(embedding)
    embeddings.extend(current_embeddings)
    chunk_start += 1000
    chunk_end += 1000
    time.sleep(pause_time)  
    counter += 1
    print(f"Batch {counter -1} embedded.")

# 處理剩餘的 chunk
if chunk_end < len(chunks):  
    remaining_chunks = chunks[chunk_end:]
    remaining_embeddings = [get_embedding(chunk, model=embedding_model) for chunk in remaining_chunks]
    embeddings.extend(remaining_embeddings)

print("All chunks processed.")
print(f"Response Time: {time.time() - start_time} seconds")

內容解密:

這段程式碼實作了資料的批次嵌入。它使用 while 迴圈迭代所有 chunk,每次處理 1,000 個。time.sleep(pause_time) 用於避免觸發 OpenAI API 的速率限制。最後,它處理了剩餘的 chunk 並輸出了總處理時間。這種批次處理的方式可以有效地提高資料處理的效率。

資料複製與模擬擴充套件

為了模擬更大的資料量,可以複製現有的資料。以下程式碼示範瞭如何將資料複製五倍:

dsize = 5
total = dsize * len(chunks)
print("Total size", total)

duplicated_chunks = []
duplicated_embeddings = []

for i in range(len(chunks)):
    for _ in range(dsize):
        duplicated_chunks.append(chunks[i])
        duplicated_embeddings.append(embeddings[i])

print(f"Number of duplicated chunks: {len(duplicated_chunks)}")
print(f"Number of duplicated embeddings: {len(duplicated_embeddings)}")

內容解密:

這段程式碼將 chunksembeddings 複製 dsize 倍,以便模擬更大規模的資料集。複製後的資料儲存在 duplicated_chunksduplicated_embeddings 中。這種方法可以用於測試和評估系統在大資料量下的效能。

建立 Pinecone Index

Pinecone 是一種高效的向量資料函式庫,用於儲存和查詢向量嵌入。以下程式碼示範瞭如何建立 Pinecone Index:

import os
from pinecone import Pinecone, ServerlessSpec

api_key = os.environ.get('PINECONE_API_KEY') or 'YOUR_API_KEY'
pc = Pinecone(api_key=api_key)

index_name = "your-index-name"
cloud = os.environ.get('PINECONE_CLOUD') or 'aws'
region = os.environ.get('PINECONE_REGION') or 'us-east-1'
spec = ServerlessSpec(cloud=cloud, region=region)

if index_name not in pc.list_indexes().names():
    pc.create_index(
        index_name,
        dimension=1536,
        metric='cosine',
        spec=spec
    )
    time.sleep(1)

index = pc.Index(index_name)
index.describe_index_stats()

內容解密:

這段程式碼首先初始化 Pinecone 客戶端,然後建立一個名為 your-index-name 的索引。dimension 引數設定為 1536,與嵌入向量的維度比對。metric 引數設定為 cosine,表示使用餘弦相似度計算向量之間的距離。這樣可以根據向量的相似度進行高效的查詢。

向量嵌入流程圖

圖表翻譯: 此流程圖展示了從資料擷取到 Upserting 的完整流程。首先進行資料擷取,接著進行資料清理,然後將資料切割成適當的 chunk,接著進行向量嵌入,最後建立 Pinecone Index 並進行 upserting 操作。

OpenAI 嵌入模型比較

圖表翻譯: 此圖表比較了不同 OpenAI 嵌入模型的特性。text-embedding-3-small 在成本和效能之間取得了良好的平衡,text-embedding-3-large 提供了更高的準確度,而 text-embedding-ada-002 則具有快速的處理速度。

批次更新資料:提升效能的最佳實踐

在向量搜尋的應用中,資料函式庫的效能至關重要。本文將聚焦於 Pinecone 向量資料函式庫,分享批次更新和高效查詢的最佳實踐。

為何需要批次更新?

單筆更新向量資料函式庫效率很低,尤其在處理大量資料時。因此,批次更新是提升效能的關鍵。

程式碼實作:批次更新 Pinecone 資料函式庫

以下程式碼示範瞭如何批次更新 Pinecone 資料函式庫:

import pinecone
import time
import sys

def upsert_to_pinecone(data, batch_size):
    for i in range(0, len(data), batch_size):
        batch = data[i:i + batch_size]
        index.upsert(vectors=batch)

def get_batch_size(data, limit=4000000):  
    total_size = 0
    batch_size = 0
    for item in data:
        item_size = sum([sys.getsizeof(v) for v in item.values()])
        if total_size + item_size > limit:
            break
        total_size += item_size
        batch_size += 1
    return batch_size

def batch_upsert(data):
    total = len(data)
    i = 0
    while i < total:
        batch_size = get_batch_size(data[i:])
        batch = data[i:i + batch_size]
        if batch:
            upsert_to_pinecone(batch, batch_size)
            i += batch_size
            print(f"Upserted {i}/{total} items...")  
        else:
            break
    print("Upsert complete.")

內容解密:

這段程式碼實作了批次更新 Pinecone 資料函式庫的功能。upsert_to_pinecone 函式負責將資料分批插入 Pinecone 索引中,而 get_batch_size 函式則根據設定的大小限制動態計算每個批次的大小。batch_upsert 函式則負責整個批次更新的流程控制。這樣可以有效地避免單筆更新的效率問題,並提高整體處理速度。

精準推薦系統:向量資料函式庫與生成式 AI 的完美結合

在應用程式規模擴充的過程中,查詢速度至關重要。本文將探討如何利用 Pinecone 向量資料函式庫,結合生成式 AI 模型,開發高效能的推薦系統。我們將以一個包含百萬以上向量的 Pinecone 索引為例,實際測試查詢效能。

向量嵌入與查詢

首先,需要一個嵌入函式將輸入文字轉換為向量。以下使用與先前步驟相同的嵌入模型 text-embedding-3-small

import openai
import time

embedding_model = "text-embedding-3-small"

# 初始化 OpenAI 客戶端
client = openai.OpenAI()

def get_embedding(text, model=embedding_model):
    text = text.replace("\n", " ")
    response = client.embeddings.create(input=[text], model=model)
    embedding = response.data[0].embedding
    return embedding

內容解密:

這段程式碼定義了一個名為 get_embedding 的函式,它使用 OpenAI 的嵌入模型將輸入文字轉換為向量表示。函式首先將文字中的換行符替換為空格,然後呼叫 OpenAI API 取得嵌入向量。

定義目標向量

目標向量代表行銷團隊希望關注的特定市場區隔,用於提高客戶忠誠度的推薦。此目標向量的設計需要結合行銷團隊的專業知識和創造力。

在本例中,我們將目標客群設定為 42 歲左右、估計年薪超過 10 萬、曾經抱怨過與可能流失的客戶。

import time
start_time = time.time() # 開始計時

# 目標向量
query_text = "Customer Henderson CreditScore 599 Age 37 Tenure 2 Balance 83788.88 EstimatedSalary 101348.88 HasCrCard 1 IsActiveMember 1 Complain 1 Exited 1"
query_embedding = get_embedding(query_text, model=embedding_model)

內容解密:

這段程式碼定義了目標客戶的文字描述 query_text,並使用 get_embedding 函式將其轉換為向量 query_embedding。同時,程式碼開始計時,用於測量查詢時間。

查詢 Pinecone 索引

# 查詢 Pinecone 索引
query_results = index.query(
    vector=query_embedding,
    top_k=5,
    include_metadata=True,
)

# 顯示查詢結果和中繼資料
print("Query Results:")
for match in query_results['matches']:
    print(f"ID: {match['id']}, Score: {match['score']}")
    if 'metadata' in match and 'text' in match['metadata']:
        print(f"Text: {match['metadata']['text']}")
    else:
        print("No metadata available.")

response_time = time.time() - start_time # 停止計時
print(f"Querying response time: {response_time:.2f} seconds") # 顯示查詢時間

內容解密:

這段程式碼使用 query_embedding 查詢 Pinecone 索引,傳回最相似的 top_k=5 個結果,並包含中繼資料。然後,程式碼印出每個比對項的 ID、分數和中繼資料中的文字內容。最後,程式碼停止計時並顯示查詢時間。

提取相關文字

relevant_texts = [match['metadata']['text'] for match in query_results['matches']]
combined_text = '\n'.join(relevant_texts) # 使用換行符連線文字
print(combined_text)

內容解密:

這段程式碼從查詢結果中提取相關文字,並將它們合併成一個字串 combined_text

圖表翻譯: 這個流程圖展示了使用Pinecone進行向量搜尋的典型流程,從資料準備到最終結果呈現。

圖表翻譯: 這個類別圖展示了 Pinecone 索引的核心方法,包含 upsertquerydescribe_index_stats

玄貓的效能最佳化建議

根據玄貓的經驗,以下是一些Pinecone效能最佳化的建議:

  • 選擇合適的向量維度: 向量維度會影響索引大小和查詢速度。
  • 調整索引引數: Pinecone 提供了多種索引引數,可以根據需求調整。
  • 監控查詢效能: 定期監控查詢效能,找出瓶頸並進行最佳化。

透過以上技巧,您可以有效提升 Pinecone 向量資料函式庫的效能,讓您的向量搜尋應用更加快速和高效。

增強提示

將查詢提示、目標向量和相關文字組合起來,構建增強的提示:

# 組合文字
combined_context = "\n".join(relevant_texts)

# 提示
query_prompt = "根據以下客戶銀行記錄,撰寫一封客製化的電子郵件:"
itext = query_prompt + query_text + combined_context

# 增強的輸入
print("Prompt for the Generative AI model:", itext)

內容解密:

這段程式碼將查詢提示、目標向量和提取的相關文字組合成一個完整的提示 itext,用於生成式 AI 模型。它首先使用 \n.join() 方法將相關文字列表 relevant_texts 結合為一個字串,並儲存在 combined_context 變數中。然後,它將查詢提示 query_prompt、查詢文字 query_textcombined_context 連線起來,形成最終的輸入文字 itext,並將其輸出以供生成式 AI 模型使用。

生成式 AI 模型

使用 OpenAI 生成式 AI 模型生成客製化郵件:

from openai import OpenAI
client = OpenAI()
gpt_model = "gpt-4"

import time
start_time = time.time()  # 開始計時

response = client.chat.completions.create(
    model=gpt_model,
    messages=[
        {
            "role": "system",
            "content": "你是一位社群經理,可以撰寫引人入勝的電子郵件。"
        },
        {
            "role": "user",
            "content": itext
        }
    ],
    temperature=0,
    max_tokens=300,
    top_p=1,
    frequency_penalty=0,
    presence_penalty=0
)

print(response.choices[0].message.content)

response_time = time.time() - start_time  # 停止計時
print(f"Querying response time: {response_time:.2f} seconds")  # 顯示查詢時間

內容解密:

這段程式碼使用 OpenAI 的 gpt-4 模型生成客製化郵件。它首先匯入必要的函式庫並初始化 OpenAI 客戶端。然後,它定義了一個 GPT 模型並開始計時。接著,它呼叫 client.chat.completions.create() 方法,傳入模型名稱和一系列訊息(包括系統角色和使用者角色的內容)。該方法傳回一個包含生成結果的物件,並將生成的郵件內容和查詢時間列印出來。

透過向量資料函式庫和生成式 AI 的結合,我們可以高效地構建精準推薦系統,並根據目標客群生成客製化內容。這個方法適用於各種領域,具有高度的靈活性和擴充套件性。

圖表翻譯: 此圖表展示了從目標向量到生成客製化郵件的整個流程。首先,目標向量被用於查詢向量資料函式庫,然後提取相關文字,接著構建增強提示,最後透過生成式 AI 模型生成客製化郵件。

利用維基百科 API 與 LlamaIndex 建構可擴充套件的根據知識圖譜的 RAG

大型資料集的管理很快就會變得極具挑戰性。在實際專案中,資料管理比 AI 更令人頭痛!專案經理、顧問和開發人員經常努力取得必要的資料來啟動任何專案,更不用說 RAG 驅動的生成式 AI 應用程式了。資料通常是非結構化的,然後透過痛苦的決策過程以某種方式組織起來。維基百科是一個很好的例子,說明瞭資料擴充套件如何導致大部分可靠但有時不正確的資訊。

主要問題之一是瞭解大量資料如何組合在一起,而知識圖譜提供了一種視覺化不同型別資料之間關係的有效方法。本章首先定義為 RAG 驅動的生成式 AI 設計的知識函式庫生態系統架構。該生態系統包含三個流程:資料收集、填充向量儲存函式庫和執行根據知識圖譜索引的 RAG 程式。

根據知識圖譜的語義搜尋的 RAG 架構

如前所述,我們將在本章中建構一個根據圖譜的 RAG 程式。該圖表將使我們能夠視覺化地繪製 RAG 資料集中檔案之間的關係。它可以使用 LlamaIndex 自動建立,就像我們將在本章的流程 3:根據知識圖譜索引的 RAG 部分中所做的那樣。本章中的程式將設計用於任何維基百科主題,如下圖所示:

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 向量嵌入與 Pinecone 索引流程

package "OpenAI 嵌入模型選擇" {
    component [text-embedding-3-small\n(高性價比)] as small
    component [text-embedding-3-large\n(高準確度)] as large
    component [text-embedding-ada-002\n(快速處理)] as ada
}

package "批次嵌入處理" {
    component [文字 Chunks] as chunks
    component [get_embedding()] as embed_fn
    component [批次 1000 筆] as batch
    component [速率限制暫停] as pause
    component [嵌入向量集合] as vectors
}

package "Pinecone 向量資料庫" {
    component [建立索引 Index] as create_idx
    component [Upsert 批次更新] as upsert
    component [向量儲存] as store
    component [相似度查詢] as query
}

package "生成式 AI 應用" {
    component [查詢向量化] as q_embed
    component [Top-K 相似結果] as topk
    component [LLM 生成回應] as llm
}

small --> embed_fn : 選用模型
large --> embed_fn
ada --> embed_fn

chunks --> batch : 分批處理
batch --> embed_fn : 呼叫 API
embed_fn --> pause : 避免速率限制
pause --> vectors : 收集結果

create_idx --> upsert : 準備索引
vectors --> upsert : 批次寫入
upsert --> store : 持久化

q_embed --> query : 查詢向量
query --> store : 搜尋相似
store --> topk : 返回結果
topk --> llm : 上下文增強

note right of batch
  批次處理策略:
  - 每批 1000 筆
  - pause_time = 3s
  - 避免 API 限流
end note

note right of query
  查詢參數:
  - top_k: 返回數量
  - include_metadata
  - namespace 過濾
end note

@enduml

圖表翻譯: 此圖表說明瞭從維基百科主題到與根據圖表的向量儲存函式庫索引互動的整個流程。它展示瞭如何透過維基百科 API 取得後設資料,並將其儲存在 Deep Lake 向量儲存函式庫中,然後使用 LlamaIndex 建立知識圖譜索引,並最終透過 OpenAI 嵌入模型生成 LLM 回應。

在本章中,我們將構建一個根據索引的知識圖譜增強型RAG系統。我將利用先前章節中構建的元件,實作三個關鍵流程(Pipeline):

  1. 收集與準備檔案: 我將開發一個利用維基百科API的程式,用於從指定維基百科頁面擷取連結和所有相關頁面的後設資料。接著,我將載入並解析這些URL,為資料更新做好準備。

  2. 建立和填充Deep Lake向量資料函式庫: 我將使用Pipeline 1準備好的維基百科頁面內容,進行嵌入並更新到Deep Lake向量資料函式庫。

  3. 根據知識圖譜索引的RAG: 我將使用LlamaIndex和嵌入模型構建知識圖譜索引,並將其視覺化呈現。接著,我將構建查詢知識函式庫索引的功能,並利用LlamaIndex內建的LLM根據更新後的資料集生成回應。

這三個流程將由一個控制場景協調,允許管理員查詢向量資料函式庫或增加新的維基百科頁面。這種架構支援無限擴充套件,因為它可以逐批處理和填充維基百科頁面資料。系統僅使用CPU和最佳化的記憶體資源。當然,這種方法也存在一些限制,例如LlamaIndex知識圖譜索引需要載入整個資料集。隨著向量資料函式庫的增長,我們可能需要分批載入資料,或者針對不同主題建立多個Deep Lake向量資料函式庫並執行跨資料函式庫查詢。在實際專案中,需要根據具體需求仔細規劃和決策。