在知識問答系統中,向量資料函式庫扮演著關鍵角色。為了提升效能,我們需要對資料進行分塊處理,並使用高效的向量儲存方案。OpenAI 的嵌入模型能將文字轉換為向量,方便儲存和查詢。LlamaIndex 框架提供多種索引方法,例如向量索引、樹狀索引、列表索引和關鍵字索引,可根據資料特性和應用需求選擇。Deep Lake 作為向量儲存方案,提供便捷的 API 和視覺化介面。整合 LlamaIndex、Deep Lake 和 OpenAI,可以構建高效的 RAG 流程,提升知識問答系統的效能和可控性。針對非結構化資料,需要進行資料清理和擷取,並選擇合適的索引策略和查詢引擎。本文提供的程式碼範例和效能指標分析,可以幫助讀者更好地理解和應用這些技術。

資料分塊最佳化:提升向量資料函式庫效能的根本

在建構高效能知識問答系統時,資料處理的最佳化至關重要。透過將文字資料分塊,我們可以有效地進行嵌入、載入和查詢,進而提升向量資料函式庫的整體效能。以下程式碼示範如何將檔案分塊:

def chunk_text(file_path, chunk_size=1000):
    """
    將指設定檔案按指定大小分塊。
    
    :param file_path: 檔案路徑
    :param chunk_size: 每個區塊的字元數,預設為1000
    :return: 分塊後的文字列表
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            text = f.read()
        return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
    except FileNotFoundError:
        print(f"檔案 {file_path} 不存在。")
        return []
    except Exception as e:
        print(f"讀取檔案 {file_path} 時發生錯誤:{e}")
        return []

# 使用範例
chunked_text = chunk_text("source_text.txt")

內容解密:

這段程式碼定義了一個函式 chunk_text,用於將指設定檔案按指定大小分塊。首先,它嘗試開啟並讀取檔案內容。然後,使用列表生成式將文字切割成多個指定大小的區塊。如果檔案不存在或讀取過程中發生錯誤,會捕捉異常並輸出錯誤資訊。這種分塊策略能有效管理大型文字資料,避免一次性處理過大的資料量,從而提升處理效率。

建立向量資料函式庫:儲存與管理知識向量

完成資料分塊後,我們需要建立一個向量資料函式庫來儲存和管理這些資料向量。以下程式碼示範如何使用 Activeloop 的 Deep Lake 建立向量資料函式庫:

import deeplake
from deeplake.core.vectorstore.deeplake_vectorstore import VectorStore

def create_vector_store(vector_store_path):
    """
    建立或載入向量資料函式庫。
    
    :param vector_store_path: 向量資料函式庫路徑
    :return: VectorStore 物件
    """
    try:
        vector_store = VectorStore(path=vector_store_path)
        print("向量資料函式庫已存在")
        return vector_store
    except FileNotFoundError:
        print("向量資料函式庫不存在,正在建立...")
        vector_store = VectorStore(path=vector_store_path)
        print("向量資料函式庫已成功建立!")
        return vector_store

# 使用範例
vector_store_path = "hub://your_organization/your_dataset_name"
vector_store = create_vector_store(vector_store_path)

內容解密:

這段程式碼定義了一個函式 create_vector_store,用於建立或載入向量資料函式庫。首先,它嘗試載入指定路徑的向量資料函式庫。如果資料函式庫不存在,則會捕捉 FileNotFoundError 異常並建立一個新的向量資料函式庫。這種方式確保了向量資料函式庫的正確初始化和管理。

嵌入函式:將文字轉化為向量

嵌入函式負責將文字區塊轉換為向量,以便進行向量搜尋。以下程式碼示範如何使用 OpenAI 的 text-embedding-3-small 模型建立嵌入函式:

import openai

def embedding_function(texts, model="text-embedding-3-small"):
    """
    將輸入的文字或文字列表轉換為向量。
    
    :param texts: 輸入的文字或文字列表
    :param model: 使用的嵌入模型,預設為"text-embedding-3-small"
    :return: 嵌入向量列表
    """
    if isinstance(texts, str):
        texts = [texts]
    texts = [t.replace("\n", " ") for t in texts]
    try:
        embeddings = openai.embeddings.create(input=texts, model=model, engine=model)
        return [data.embedding for data in embeddings.data]
    except Exception as e:
        print(f"生成嵌入向量時發生錯誤:{e}")
        return []

# 使用範例
embeddings = embedding_function(["這是一個測試文字。"])

內容解密:

這個函式接受一個字串或字串列表作為輸入,使用 OpenAI 的指定模型將每個字串轉換為向量。在轉換前,它會將換行符號替換為空格,以確保嵌入結果的一致性。如果在生成嵌入向量的過程中發生錯誤,會捕捉異常並輸出錯誤資訊。

資料新增:填充向量資料函式庫

建立向量資料函式庫和嵌入函式後,我們可以開始將資料新增到向量資料函式庫中。以下程式碼示範如何將分塊後的文字資料嵌入並儲存到向量資料函式庫:

def add_data_to_vector_store(vector_store, file_path, embedding_function):
    """
    將檔案內容分塊後新增到向量資料函式庫。
    
    :param vector_store: VectorStore 物件
    :param file_path: 檔案路徑
    :param embedding_function: 嵌入函式
    """
    chunked_text = chunk_text(file_path)
    if chunked_text:
        vector_store.add(
            text=chunked_text,
            embedding_function=embedding_function,
            embedding_data=chunked_text,
            metadata=[{"source": file_path}] * len(chunked_text)
        )
        print(vector_store.summary())

# 使用範例
add_to_vector_store = True
if add_to_vector_store:
    add_data_to_vector_store(vector_store, "source_text.txt", embedding_function)

內容解密:

這段程式碼定義了一個函式 add_data_to_vector_store,用於將檔案內容分塊後新增到向量資料函式庫。首先,它呼叫 chunk_text 函式將檔案內容分塊。然後,使用 vector_store.add 方法將分塊後的文字、對應的嵌入向量和中繼資料新增到向量資料函式庫中。最後,列印向量資料函式庫的摘要資訊。

向量資料函式庫資訊與視覺化

Activeloop 提供了便捷的 API 和線上工具,方便我們管理和視覺化資料集。以下程式碼示範如何載入資料集並顯示其大小:

def display_dataset_size(vector_store_path):
    """
    載入 Deep Lake 資料集並顯示其大小。
    
    :param vector_store_path: 資料集路徑
    """
    try:
        ds = deeplake.load(vector_store_path)
        ds_size = ds.size_approx()
        ds_size_mb = ds_size / (1024 * 1024)
        ds_size_gb = ds_size / (1024 * 1024 * 1024)
        print(f"資料集大小(MB):{ds_size_mb:.5f} MB")
        print(f"資料集大小(GB):{ds_size_gb:.5f} GB")
    except Exception as e:
        print(f"載入資料集時發生錯誤:{e}")

# 使用範例
display_dataset_size(vector_store_path)

內容解密:

這段程式碼定義了一個函式 display_dataset_size,用於載入 Deep Lake 資料集並顯示其大小。首先,它嘗試載入指定路徑的資料集。然後,計算資料集的大小,並以 MB 和 GB 為單位顯示。如果在載入過程中發生錯誤,會捕捉異常並輸出錯誤資訊。

以下使用 Plantuml 圖表展示資料處理流程:

圖表翻譯: 此圖表展示了從讀取原始文字到儲存至向量資料函式庫的整個流程。首先,讀取原始文字;然後,將文字分塊;接著,對每塊文字進行嵌入處理;最後,將嵌入結果儲存至向量資料函式庫。這種流程圖幫助讀者清晰理解資料處理的步驟和邏輯。

處理使用者輸入與擴充輸入生成

首先,我們定義一個函式來取得使用者的搜尋查詢:

def get_user_prompt():
    """
    取得使用者的搜尋查詢。
    
    :return: 使用者的搜尋查詢字串
    """
    return input("輸入您的搜尋查詢:")

# 使用範例
user_prompt = "告訴我關於月球和火星的太空探索。"

然後,我們將提示插入搜尋查詢,並將輸出儲存在 search_results 中:

def search_vector_store(vector_store, user_prompt):
    """
    在向量資料函式庫中搜尋與使用者提示相關的結果。
    
    :param vector_store: VectorStore 物件
    :param user_prompt: 使用者的搜尋查詢
    :return: 搜尋結果
    """
    try:
        return vector_store.search(embedding_data=user_prompt)
    except Exception as e:
        print(f"搜尋向量資料函式庫時發生錯誤:{e}")
        return None

# 使用範例
search_results = search_vector_store(vector_store, user_prompt)

內容解密:

這段程式碼定義了一個函式 search_vector_store,用於在向量資料函式庫中搜尋與使用者提示相關的結果。它呼叫 vector_store.search 方法,並傳入使用者的搜尋查詢作為引數。如果在搜尋過程中發生錯誤,會捕捉異常並輸出錯誤資訊。

我們也可以包裝擷取的文字以獲得格式化的輸出:

def wrap_text(text, width=80):
    """
    將文字包裝到指定的寬度。
    
    :param text: 要包裝的文字
    :param width: 寬度,預設為80
    :return: 包裝後的文字字串
    """
    lines = []
    while len(text) > width:
        split_index = text.rfind(' ', 0, width)
        if split_index == -1:
            split_index = width
        lines.append(text[:split_index])
        text = text[split_index:].lstrip()
    lines.append(text)
    return '\n'.join(lines)

# 使用範例
top_text = "這是一個測試文字,用於展示如何包裝文字。"
print(wrap_text(top_text))

內容解密:

這個函式用於將指定的文字包裝到給定的寬度。它透過迴圈檢查文字長度,並在適當的位置進行斷行處理,最後將包裝後的文字以換行符連線並傳回。這樣可以使長文字在輸出時更加易讀。

最後,我們將擷取的最佳文字新增到使用者輸入中,形成擴充輸入:

def augment_input(user_prompt, top_text):
    """
    將擷取的最佳文字新增到使用者輸入中,形成擴充輸入。
    
    :param user_prompt: 使用者的原始輸入
    :param top_text: 擷取的最佳文字
    :return: 擴充後的輸入字串
    """
    return user_prompt + " " + top_text

# 使用範例
augmented_input = augment_input(user_prompt, top_text)
print(augmented_input)

內容解密:

這個函式簡單地將使用者原始輸入和擷取的最佳文字拼接在一起,形成擴充輸入。這樣做的目的是為了給生成模型提供更多的上下文資訊,以產生更準確和豐富的輸出。

深入淺出索引式 RAG:LlamaIndex、Deep Lake 與 OpenAI 的完美結合

在處理大型資料集時,檔案嵌入至關重要,它奠定了檢索增強生成式 AI (RAG) 的基礎。然而,索引的引入更進一步提升了 RAG 的效能,不僅提升了速度和精確度,更重要的是增強了透明度。透過索引,我們可以完整追蹤 RAG 模型回應的來源,清楚地知道所用資料的確切位置和詳細內容。這不僅能減輕模型偏差和幻覺等問題,還能解決版權和資料完整性方面的疑慮。

本文將探討如何利用索引式資料更好地控制生成式 AI 應用。當輸出結果不盡人意時,我們不再束手無策,因為索引可以幫助我們精確找出問題的根源資料。藉此,我們可以調整資料輸入、系統組態,或切換向量儲存軟體和生成模型等元件,最終獲得更理想的結果。

語義搜尋引擎的構建:LlamaIndex 框架與索引方法

LlamaIndex 框架簡化了索引式 RAG 的構建過程。它提供多種索引方法,例如向量索引、樹狀索引、列表索引和關鍵字索引,可以根據資料特性和應用需求選擇最合適的索引型別。

LlamaIndex 的主要功能

  • 向量索引:根據嵌入向量的相似性搜尋。
  • 樹狀索引:將資料組織成樹狀結構,加速查詢。
  • 列表索引:簡單的線性結構,適用於小規模資料。
  • 關鍵字索引:根據關鍵字的搜尋,適合特定查詢需求。

Deep Lake 向量儲存的應用

Deep Lake 作為向量儲存,可以有效地儲存和管理大量的嵌入向量。它提供便捷的 API 和視覺化介面,方便隨時檢視嵌入的文字。

Deep Lake 的優勢

  • 高效儲存:最佳化向量資料的儲存和檢索。
  • 視覺化介面:方便檢視和管理嵌入向量。

LlamaIndex、Deep Lake 與 OpenAI 的整合

LlamaIndex、Deep Lake 和 OpenAI 可以無縫整合,形成一個高效的 RAG 流程。LlamaIndex 負責索引管理和查詢,Deep Lake 負責向量儲存,OpenAI 提供嵌入模型和生成模型。

整合流程

  1. 資料處理:將原始資料進行預處理。
  2. 向量嵌入:使用 OpenAI 的嵌入模型將資料轉換為向量。
  3. 索引構建:利用 LlamaIndex 構建合適的索引。
  4. 查詢處理:透過 LlamaIndex 進行查詢,並從 Deep Lake 中檢索相關資訊。
  5. 生成回應:使用 OpenAI 的生成模型根據檢索結果生成最終回應。
from llama_index import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores import DeepLakeVectorStore
import openai

# 資料載入與處理
documents = SimpleDirectoryReader('./data').load_data()

# Deep Lake 向量儲存設定
vector_store = DeepLakeVectorStore(dataset_path='./deeplake_dataset')

# 索引構建
index = VectorStoreIndex.from_documents(documents, vector_store=vector_store)

# 查詢引擎設定
query_engine = index.as_query_engine()

# 使用 OpenAI 生成回應
openai.api_key = 'your_openai_api_key'
response = query_engine.query('你的查詢內容')

print(response)

內容解密:

以上程式碼展示瞭如何使用 LlamaIndex 和 Deep Lake 構建向量索引,並結合 OpenAI 進行查詢和生成回應。首先,載入資料並建立 Deep Lake 向量儲存,然後構建向量索引。最後,設定查詢引擎並使用 OpenAI 生成回應。

圖表翻譯: 以上流程圖展示了根據索引的 RAG 流程,使用者查詢透過 LlamaIndex 處理後,從 Deep Lake 向量儲存中檢索相關資訊,再由 OpenAI 模型生成最終回應。

圖表翻譯: 原始資料經過處理、向量嵌入後,構建索引並整合至 LlamaIndex 框架。

深入淺出向量資料函式庫:以無人機技術為例開發高效能知識問答系統

在真實世界的專案中,資料很少是完美、相關、結構化與格式良好的。我們的 RAG(Retrieval Augmented Generation)流程必須足夠強健,才能在雜訊環境中擷取相關資料。本文將以無人機技術領域的非結構化資料為例,示範如何構建一個強大的知識問答系統。

資料清理與擷取

首先,我們需要從各種來源收集資料,這些資料可能格式不一,品質也參差不齊。以下程式碼片段示範瞭如何擷取和清理網頁資料:

import re
import requests
from bs4 import BeautifulSoup

def clean_text(content):
    # 清除參考編號和特殊字元
    content = re.sub(r'\[\d+\]', '', content)
    content = re.sub(r'[^\w\s\.]', '', content)
    return content

def fetch_and_clean(url):
    try:
        response = requests.get(url)
        response.raise_for_status()
        soup = BeautifulSoup(response.content, 'html.parser')
        content = soup.find('div', {'class': 'mw-parser-output'})
        if content is None:
            return None
        # 移除特定區塊,包含巢狀區塊
        for section_title in ['References', 'Bibliography', 'External links']:
            section = content.find('span', id=section_title)
            while section:
                for sib in section.parent.find_next_siblings():
                    sib.decompose()
                section.parent.decompose()
                section = content.find('span', id=section_title)
        text = content.get_text(separator=' ', strip=True)
        text = clean_text(text)
        return text
    except requests.exceptions.RequestException as e:
        print(f"從 {url} 擷取內容時發生錯誤: {e}")
        return None

內容解密:

以上程式碼定義了兩個函式:clean_text 用於清除文字中的參考編號和特殊字元;fetch_and_clean 則負責從指定 URL 擷取網頁內容,並使用 BeautifulSoup 解析 HTML,移除不需要的區塊,最後回傳清理後的文字。clean_text 函式利用正則表示式清除特定字元,而 fetch_and_clean 函式處理 HTTP 請求和 HTML 解析。

為了方便管理,我們將每個網頁的內容儲存到獨立的檔案中:

import os

# 儲存檔案的目錄
output_dir = './data/'
os.makedirs(output_dir, exist_ok=True)

# 定義要處理的 URL 清單
urls = [
    "https://github.com/VisDrone/VisDrone-Dataset",
    "https://paperswithcode.com/dataset/visdrone",
    "https://openaccess.thecvf.com/content_ECCVW_2018/papers/111",
    "https://github.com/VisDrone/VisDrone2018-MOT-toolkit",
    "https://en.wikipedia.org/wiki/Object_detection",
]

# 處理每個 URL 並將其內容寫入單獨的檔案
for url in urls:
    article_name = url.split('/')[-1].replace('.html', '')
    filename = os.path.join(output_dir, article_name + '.txt')
    clean_article_text = fetch_and_clean(url)
    with open(filename, 'w', encoding='utf-8') as file:
        file.write(clean_article_text)
    print(f"內容已寫入 {output_dir} 目錄下的檔案")

內容解密:

這段程式碼建立了一個 data 資料夾,並將每個 URL 對應的網頁內容儲存為獨立的 .txt 檔案。檔名由 URL 的最後一部分組成,以確保唯一性。這樣的做法有助於後續的資料處理和管理。

建立 Deep Lake 向量資料函式庫

接下來,我們使用 LlamaIndex 建立 Deep Lake 向量資料函式庫,並將清理後的資料存入其中。

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.deeplake import DeepLakeVectorStore

# 載入資料
documents = SimpleDirectoryReader("./data").load_data()

# 建立 Deep Lake 向量資料函式庫
vector_store = DeepLakeVectorStore(dataset_path="./deeplake_dataset")

# 建立索引
index = VectorStoreIndex.from_documents(documents, vector_store=vector_store)

內容解密:

這段程式碼首先使用 SimpleDirectoryReader 載入 data 資料夾中的所有檔案。然後,建立一個 Deep Lake 向量資料函式庫,並將載入的檔案存入其中,最後建立向量索引。這樣的流程能夠有效地組織和管理資料,以便進行後續的查詢和檢索。

建構 RAG 系統

有了向量資料函式庫後,我們可以建構 RAG 系統來進行知識問答。

from llama_index.core import QueryEngine

# 建立查詢引擎
query_engine = index.as_query_engine()

# 進行查詢
response = query_engine.query("無人機在電腦視覺領域的應用有哪些?")

# 輸出結果
print(response)

內容解密:

這段程式碼利用之前建立的索引建立了一個查詢引擎,並對「無人機在電腦視覺領域的應用有哪些?」這一問題進行了查詢。查詢引擎會根據向量索引檢索相關資訊,並生成相應的答案。最終,將查詢結果輸出到控制檯。

深度解析根據Deep Lake的向量資料函式庫建置與應用

在當今的資料驅動時代,如何高效地儲存、管理和查詢大量非結構化資料已成為一大挑戰。Deep Lake作為一個強大的向量資料函式庫,為我們提供了一個理想的解決方案。本文將探討如何利用Deep Lake構建向量資料函式庫,並將其應用於複雜的RAG(Retrieval-Augmented Generation)系統中。

建置Deep Lake向量資料函式庫

首先,我們需要安裝必要的函式庫並匯入相關模組。接著,我們將建立一個Deep Lake向量資料函式庫,並將非結構化資料轉換為可查詢的格式。

from llama_index.core import StorageContext
from llama_index import VectorStoreIndex
from llama_index.vector_stores import DeepLakeVectorStore
from llama_index import SimpleDirectoryReader

# 定義向量資料函式庫和資料集的路徑
vector_store_path = "hub://你的帳戶名稱/你的資料集名稱"
dataset_path = "hub://你的帳戶名稱/你的資料集名稱"

# 建立Deep Lake向量資料函式庫
vector_store = DeepLakeVectorStore(dataset_path=dataset_path, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)

# 載入data資料夾中的所有檔案
documents = SimpleDirectoryReader("./data/").load_data()

# 建立索引
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)

內容解密:

這段程式碼首先定義了向量資料函式庫和資料集的路徑,請將 你的帳戶名稱你的資料集名稱 替換為你的實際資訊。然後,它建立了一個Deep Lake向量資料函式庫,並使用SimpleDirectoryReader載入data資料夾中的所有檔案。最後,它使用VectorStoreIndex建立索引,以便後續進行查詢。overwrite=True表示覆寫現有的資料集。

資料視覺化與探索

為了更好地理解資料,我們可以使用Deep Lake提供的工具進行視覺化和探索。

import deeplake
import json
import pandas as pd
import numpy as np

# 載入Deep Lake資料集
ds = deeplake.load(dataset_path)

# 將資料轉換為pandas DataFrame
data = {}
for tensor_name in ds.tensors:
    tensor_data = ds[tensor_name].numpy()
    if tensor_data.ndim > 1:
        data[tensor_name] = [np.array(e).flatten().tolist() for e in tensor_data]
    else:
        if tensor_name == "text":
            data[tensor_name] = [t.tobytes().decode('utf-8') if isinstance(t, bytes) else t for t in tensor_data]
        else:
            data[tensor_name] = tensor_data.tolist()
df = pd.DataFrame(data)

# 定義函式以顯示特定記錄
def display_record(record_number):
    record = df.iloc[record_number]
    display_data = {
        "ID": record["id"] if "id" in record else "N/A",
        "Metadata": record["metadata"] if "metadata" in record else "N/A",
        "Text": record["text"] if "text" in record else "N/A",
        "Embedding": record["embedding"] if "embedding" in record else "N/A",
    }
    for key, value in display_data.items():
        print(f"{key}:")
        print(value)

# 顯示第0筆記錄
rec = 0  
display_record(rec)

內容解密:

這段程式碼載入Deep Lake資料集,並將其轉換為pandas DataFrame,方便進行資料操作和分析。display_record函式可以顯示特定記錄的ID、Metadata、Text和Embedding資訊。

資料處理流程視覺化

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 向量資料函式庫效能最佳化實踐

package "NumPy 陣列操作" {
    package "陣列建立" {
        component [ndarray] as arr
        component [zeros/ones] as init
        component [arange/linspace] as range
    }

    package "陣列操作" {
        component [索引切片] as slice
        component [形狀變換 reshape] as reshape
        component [堆疊 stack/concat] as stack
        component [廣播 broadcasting] as broadcast
    }

    package "數學運算" {
        component [元素運算] as element
        component [矩陣運算] as matrix
        component [統計函數] as stats
        component [線性代數] as linalg
    }
}

arr --> slice : 存取元素
arr --> reshape : 改變形狀
arr --> broadcast : 自動擴展
arr --> element : +, -, *, /
arr --> matrix : dot, matmul
arr --> stats : mean, std, sum
arr --> linalg : inv, eig, svd

note right of broadcast
  不同形狀陣列
  自動對齊運算
end note

@enduml

圖表翻譯: 此圖示展示了從資料收集到查詢應用的完整流程。首先收集原始資料,接著進行清理和預處理,然後將資料儲存到Deep Lake向量資料函式庫中,最後可以利用這個資料函式庫進行查詢和應用。

進階應用:根據OpenAI的RAG系統

為了進一步提升系統的功能,我們可以結合OpenAI的LLM(Large Language Model)和嵌入模型,構建一個強大的RAG系統。

import logging
import sys

# 設定日誌記錄
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))

from llama_index import VectorStoreIndex, SimpleDirectoryReader, ServiceContext
from llama_index.storage.storage_context import StorageContext
from llama_index.llms import OpenAI
from llama_index import LLMPredictor
from llama_index.embeddings.openai import OpenAIEmbedding

# 載入資料
documents = SimpleDirectoryReader("./data").load_data()

# 初始化OpenAI LLM和嵌入模型
llm = OpenAI(temperature=0.1, model="gpt-3.5-turbo")
embed_model = OpenAIEmbedding()
llm_predictor = LLMPredictor(llm=llm)
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, embed_model=embed_model)

# 建立向量儲存索引
storage_context = StorageContext.from_defaults()
vector_index = VectorStoreIndex.from_documents(
    documents, storage_context=storage_context, service_context=service_context
)

# 建立查詢引擎並執行查詢
query_engine = vector_index.as_query_engine(similarity_top_k=3)
response = query_engine.query("無人機如何識別車輛?")

# 計算與使用者輸入的餘弦相似度
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

model = SentenceTransformer('all-MiniLM-L6-v2')
def calculate_cosine_similarity_with_embeddings(text1, text2):
    embeddings1 = model.encode(text1)
    embeddings2 = model.encode(text2)
    similarity = cosine_similarity([embeddings1], [embeddings2])
    return similarity[0][0]

similarity_score = calculate_cosine_similarity_with_embeddings("無人機如何識別車輛?", str(response))

內容解密:

這段程式碼展示瞭如何利用OpenAI的LLM和嵌入模型建立一個RAG系統。首先,它載入資料並初始化相關模型,然後建立向量儲存索引。接著,它建立查詢引擎並執行查詢,最後計算回應與使用者輸入之間的餘弦相似度。

輸出結果與評估

print(f"查詢結果:{response}")
print(f"評估結果:{eval_result}")
print(f"與使用者輸入的餘弦相似度:{similarity_score}")

內容解密:

這段程式碼用於輸出查詢結果、評估結果以及與使用者輸入的餘弦相似度。其中:

  • response 是查詢引擎傳回的結果,包含相關的資訊和檔案內容。
  • eval_result 是對查詢結果的評估,可能包括相關性分數或其他指標。
  • similarity_score 表示查詢結果與原始輸入之間的餘弦相似度,用於衡量語義相關性。

向量儲存索引的建立與查詢

在向量空間中,語義相似的檔案會彼此靠近。VectorStoreIndex 可以建立一個新的記憶體向量索引、重新嵌入檔案,並建立新的索引結構。

建立向量儲存索引

from llama_index.core import VectorStoreIndex
vector_store_index = VectorStoreIndex.from_documents(documents)
print(type(vector_store_index))

內容解密:

這段程式碼展示瞭如何使用 VectorStoreIndex 從給定的檔案集合建立向量儲存索引。輸出的型別確認了所建立的索引是 VectorStoreIndex 類別。

建立查詢引擎

vector_query_engine = vector_store_index.as_query_engine(similarity_top_k=3)

內容解密:

這段程式碼將向量儲存索引轉換為查詢引擎,並設定 similarity_top_k=3,表示查詢時會傳回最相似的前 3 個結果。

查詢回應與來源資訊

以下函式用於管理查詢並傳回相關資訊:

import pandas as pd
import textwrap

def index_query(input_query):
    response = vector_query_engine.query(input_query)
    print(textwrap.fill(str(response), 100))
    node_data = []
    for node_with_score in response.source_nodes:
        node = node_with_score.node
        node_info = {
            '節點 ID': node.id_,
            '分數': node_with_score.score,
            '文字': node.text
        }
        node_data.append(node_info)
    df = pd.DataFrame(node_data)
    return df, response

內容解密:

這個函式使用向量查詢引擎執行查詢,並將結果處理成結構化的 DataFrame 格式,包含節點 ID、分數和文字內容。

執行查詢並輸出結果

import time
start_time = time.time()
df, response = index_query(user_input)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"查詢執行時間:{elapsed_time:.4f} 秒")
print(df.to_markdown(index=False, numalign="left", stralign="left"))

內容解密:

這段程式碼呼叫查詢函式並測量查詢執行時間,同時輸出查詢結果和執行時間。

最佳化的分塊與效能指標

自動區塊大小調整

for node_with_score in response.source_nodes:
    node = node_with_score.node
    chunk_size = len(node.text)
    print(f"節點 ID:{node.id_},區塊大小:{chunk_size} 字元")

內容解密:

這段程式碼遍歷查詢結果中的節點,並輸出每個節點的區塊大小,顯示自動調整的區塊大小。

效能指標計算

import numpy as np

def info_metrics(response):
    scores = [node.score for node in response.source_nodes if node.score is not None]
    if scores:
        weights = np.exp(scores) / np.sum(np.exp(scores))
        perf = np.average(scores, weights=weights) / elapsed_time
    else:
        perf = 0
    print(f"平均分數:{np.average(scores):.4f}")
    print(f"查詢執行時間:{elapsed_time:.4f} 秒")
    print(f"效能指標:{perf:.4f}")

info_metrics(response)

內容解密:

這個函式計算查詢的效能指標,包括平均分數和加權平均分數,並將其除以查詢執行時間,以評估查詢效能。

樹狀索引查詢引擎

建立樹狀索引

from llama_index.core import TreeIndex
tree_index = TreeIndex.from_documents(documents)

內容解密:

這段程式碼展示瞭如何使用 TreeIndex 從檔案集合建立樹狀索引,用於高效管理和查詢文字檔案。

輸出樹狀索引型別

print(type(tree_index))

內容解密:

這段程式碼輸出所建立的 tree_index 的型別,確認其為 TreeIndex 類別。

透過以上範例,展示瞭如何在 LlamaIndex 中使用向量儲存索引和樹狀索引進行高效的資訊檢索和查詢。這些技術能夠顯著提升大型資料集的管理和查詢效率。

深入理解LlamaIndex中的索引型別及其查詢效能比較

在現代人工智慧和大資料分析領域,如何高效地檢索和利用海量資訊已成為一項關鍵技術挑戰。LlamaIndex作為一個強大的工具,提供了一系列索引型別以最佳化資料檢索和查詢效能。本文將探討LlamaIndex中的幾種主要索引型別,包括樹狀索引(TreeIndex)、列表索引(ListIndex)、向量儲存索引(Vector Store Index)和關鍵字索引(KeywordTableIndex),並透過具體的程式碼範例和效能指標比較它們的查詢效能。

樹狀索引(TreeIndex)查詢引擎

樹狀索引是一種高效的資料結構,能夠快速定位相關資訊。首先,我們確認使用的TreeIndex類別:

print(type(tree_index))

輸出結果表明我們正在使用<class 'llama_index.core.indices.tree.base.TreeIndex'>類別。接著,將樹狀索引轉換為查詢引擎:

tree_query_engine = tree_index.as_query_engine(similarity_top_k=...)

執行查詢並測量執行時間:

start_time = time.time()
response = tree_query_engine.query(user_input)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"查詢執行時間:{elapsed_time:.4f} 秒")
print(textwrap.fill(str(response), 100))

內容解密:

  1. tree_index.as_query_engine() 將樹狀索引轉換為可執行的查詢引擎。
  2. similarity_top_k 引數控制傳回的最相關結果數量。
  3. time.time() 用於測量查詢的執行時間。

輸出結果顯示,查詢執行時間為4.3360秒,回應內容令人滿意。進一步計算餘弦相似度分數以評估回應品質:

similarity_score = calculate_cosine_similarity_with_embeddings(user_input, str(response))
print(f"餘弦相似度分數:{similarity_score:.3f}")
print(f"查詢執行時間:{elapsed_time:.4f} 秒")
performance = similarity_score / elapsed_time
print(f"效能指標:{performance:.4f}")

內容解密:

  1. calculate_cosine_similarity_with_embeddings 函式計算使用者輸入與回應之間的餘弦相似度。
  2. 餘弦相似度分數越高,表示回應與查詢越相關。
  3. 效能指標綜合考慮了查詢時間和回應品質。

列表索引(ListIndex)查詢引擎

列表索引將檔案列表轉換為可查詢的索引。首先,建立列表索引:

from llama_index.core import ListIndex
list_index = ListIndex.from_documents(documents)

驗證列表索引類別:

print(type(list_index))

輸出結果確認我們使用的是<class 'llama_index.core.indices.list.base.SummaryIndex'>類別。然後,將列表索引轉換為查詢引擎並執行查詢:

list_query_engine = list_index.as_query_engine(similarity_top_k=...)
start_time = time.time()
response = list_query_engine.query(user_input)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"查詢執行時間:{elapsed_time:.4f} 秒")
print(textwrap.fill(str(response), 100))

內容解密:

  1. ListIndex.from_documents(documents) 從檔案列表建立索引。
  2. 列表索引透過遍歷整個列表來執行查詢,因此執行時間較長。

評估列表索引的效能指標:

similarity_score = calculate_cosine_similarity_with_embeddings(user_input, str(response))
print(f"餘弦相似度分數:{similarity_score:.3f}")
print(f"查詢執行時間:{elapsed_time:.4f} 秒")
performance = similarity_score / elapsed_time
print(f"效能指標:{performance:.4f}")

關鍵字索引(KeywordTableIndex)查詢引擎

關鍵字索引提取檔案中的關鍵字並組織成表格結構。首先,建立關鍵字索引:

from llama_index.core import KeywordTableIndex
keyword_index = KeywordTableIndex.from_documents(documents)

提取關鍵字並建立pandas DataFrame以檢視索引結構:

data = []
for keyword, doc_ids in keyword_index.index_struct.table.items():
    for doc_id in doc_ids:
        data.append({"Keyword": keyword, "Document ID": doc_id})
df = pd.DataFrame(data)
df

將關鍵字索引轉換為查詢引擎並執行查詢:

keyword_query_engine = keyword_index.as_query_engine(similarity_...)
start_time = time.time()
response = keyword_query_engine.query(user_input)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"查詢執行時間:{elapsed_time:.4f} 秒")
print(textwrap.fill(str(response), 100))

內容解密:

  1. KeywordTableIndex 從檔案中提取關鍵字並建立表格結構。
  2. 關鍵字索引透過關鍵字比對來執行查詢,因此查詢速度較快。

透過深入理解LlamaIndex提供的不同索引型別及其特性,我們可以根據具體需求選擇最合適的索引策略,從而最佳化資料檢索和查詢效能。