Fleet Context 임베딩 - LlamaIndex 라이브러리용 하이브리드 검색 엔진 구축하기

Fleet Context 임베딩 - LlamaIndex 라이브러리용 하이브리드 검색 엔진 구축하기

Fleet Context로 LlamaIndex 문서의 임베딩을 받아와서, 그 위에 밀집/희소 하이브리드 벡터 검색 엔진을 만드는 과정을 배워요.

출처: 문서

본문

이 가이드에서는 Fleet Context를 사용해 LlamaIndex 문서의 임베딩을 다운로드하고, 그 위에 하이브리드 밀집/희소(dense/sparse) 벡터 검색 엔진을 구축해 보겠습니다.

선행 조건

!pip install llama-index
!pip install --upgrade fleet-context
import os
import openai


os.environ["OPENAI_API_KEY"] = "sk-..." # add your API key here!
openai.api_key = os.environ["OPENAI_API_KEY"]

Fleet Context에서 임베딩 다운로드하기

Fleet Context를 사용해 LlamaIndex 문서 전체(~12k 청크, ~100mb 콘텐츠)의 임베딩을 다운로드하겠습니다. 상위 1220개 라이브러리 중 어떤 것이든 라이브러리 이름을 파라미터로 지정해 다운로드할 수 있습니다. 지원되는 라이브러리의 전체 목록은 여기 페이지 하단에서 확인할 수 있습니다.

이렇게 하는 이유는 Fleet이 재랭킹에 유용한 페이지 내 위치(positon on page), 청크 유형(클래스/함수/속성 등), 상위 섹션(parent section) 등 검색과 생성을 개선할 중요한 정보를 보존하는 임베딩 파이프라인을 구축했기 때문입니다. 이에 대한 자세한 내용은 Github 페이지에서 읽을 수 있습니다.

from context import download_embeddings


df = download_embeddings("llamaindex")

출력:

터미널 창

    100%|██████████| 83.7M/83.7M [00:03<00:00, 27.4MiB/s]
                                         id  \
    0  e268e2a1-9193-4e7b-bb9b-7a4cb88fc735
    1  e495514b-1378-4696-aaf9-44af948de1a1
    2  e804f616-7db0-4455-9a06-49dd275f3139
    3  eb85c854-78f1-4116-ae08-53b2a2a9fa41
    4  edfc116e-cf58-4118-bad4-c4bc0ca1495e
# Show some examples of the metadata
df["metadata"][0]
display(Markdown(f"{df['metadata'][8000]['text']}"))

출력:

터미널 창

classmethod from_dict(data: Dict[str, Any], kwargs: Any) → Self classmethod from_json(data_str: str, kwargs: Any) → Self classmethod from_orm(obj: Any) → Model json(, include: Optional[Union[AbstractSetIntStr, MappingIntStrAny]] = None, exclude: Optional[Union[AbstractSetIntStr, MappingIntStrAny]] = None, by_alias: bool = False, skip_defaults: Optional[bool] = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, encoder: Optional[Callable[[Any], Any]] = None, models_as_dict: bool = True*, dumps_kwargs: Any) → unicode Generate a JSON representation of the model, include and exclude arguments as per dict().

LlamaIndex 하이브리드 검색을 위한 Pinecone 인덱스 생성하기

Pinecone 인덱스를 만들고 그 안에 벡터를 upsert해서 희소 벡터와 밀집 벡터로 하이브리드 검색을 수행하겠습니다. 진행하기 전에 Pinecone 계정이 있는지 확인하세요.

import logging
import sys


logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().handlers = []
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
import pinecone


api_key = "..."  # Add your Pinecone API key here
pinecone.init(
    api_key=api_key, environment="us-east-1-aws"
)  # Add your db region here
# Fleet Context uses the text-embedding-ada-002 model from OpenAI with 1536 dimensions.


# NOTE: Pinecone requires dotproduct similarity for hybrid search
pinecone.create_index(
    "quickstart-fleet-context",
    dimension=1536,
    metric="dotproduct",
    pod_type="p1",
)


pinecone.describe_index(
    "quickstart-fleet-context"
)  # Make sure you create an index in pinecone
from llama_index.vector_stores.pinecone import PineconeVectorStore


pinecone_index = pinecone.Index("quickstart-fleet-context")
vector_store = PineconeVectorStore(pinecone_index, add_sparse_vector=True)

벡터를 배치로 Pinecone에 upsert하기

Pinecone은 한 번에 100개의 벡터를 upsert할 것을 권장합니다. 데이터 형식을 조금 수정한 뒤 그렇게 수행하겠습니다.

import random
import itertools




def chunks(iterable, batch_size=100):
    """A helper function to break an iterable into chunks of size batch_size."""
    it = iter(iterable)
    chunk = tuple(itertools.islice(it, batch_size))
    while chunk:
        yield chunk
        chunk = tuple(itertools.islice(it, batch_size))




# generator that generates many (id, vector, metadata, sparse_values) pairs
data_generator = map(
    lambda row: {
        "id": row[1]["id"],
        "values": row[1]["values"],
        "metadata": row[1]["metadata"],
        "sparse_values": row[1]["sparse_values"],
    },
    df.iterrows(),
)

# Upsert data with 1000 vectors per upsert request
for ids_vectors_chunk in chunks(data_generator, batch_size=100):
    print(f"Upserting {len(ids_vectors_chunk)} vectors...")
    pinecone_index.upsert(vectors=ids_vectors_chunk)

LlamaIndex에서 Pinecone 벡터 저장소 구축하기

마지막으로 LlamaIndex를 통해 Pinecone 벡터 저장소를 구축하고 이를 쿼리해 결과를 얻겠습니다.

from llama_index.core import VectorStoreIndex
from IPython.display import Markdown, display
index = VectorStoreIndex.from_vector_store(vector_store=vector_store)

인덱스 쿼리하기!

query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=8
)
response = query_engine.query("How do I use llama_index SimpleDirectoryReader")
display(Markdown(f"<b>{response}</b>"))

출력:

터미널 창

<b>To use the SimpleDirectoryReader in llama_index, you need to import it from the llama_index library. Once imported, you can create an instance of the SimpleDirectoryReader class by providing the directory path as an argument. Then, you can use the `load_data()` method on the SimpleDirectoryReader instance to load the documents from the specified directory.</b>

더 알아보기 (Learn more)