Milvus 및 LlamaIndex를 사용한 검색 증강 생성(RAG)
이 가이드에서는 LlamaIndex와 Milvus를 사용하여 검색 증강 생성(RAG) 시스템을 구축하는 방법을 설명합니다.
RAG 시스템은 검색 시스템과 생성 모델을 결합하여 주어진 프롬프트에 따라 새 텍스트를 생성하는 시스템입니다. 이 시스템은 먼저 Milvus를 사용하여 말뭉치에서 관련 문서를 검색한 다음 생성 모델을 사용하여 검색된 문서를 기반으로 새 텍스트를 생성합니다.
LlamaIndex는 사용자 정의 데이터 소스를 대규모 언어 모델(LLM)에 연결하기 위한 간단하고 유연한 데이터 프레임워크입니다. Milvus는 세계에서 가장 진보된 오픈 소스 벡터 데이터베이스로, 임베딩 유사도 검색 및 AI 애플리케이션을 강화하기 위해 구축되었습니다.
이 노트북에서는 MilvusVectorStore를 사용하는 간단한 데모를 보여드리겠습니다.
시작하기 전에
종속성 설치
이 페이지의 코드 스니펫에는 pymilvus 및 llamaindex 종속성이 필요합니다. 다음 명령을 사용하여 설치할 수 있습니다:
$ pip install pymilvus>=2.4.2 milvus-lite
$ pip install llama-index-vector-stores-milvus
$ pip install llama-index
Google Colab을 사용하는 경우 방금 설치한 종속성을 활성화하려면 런타임을 다시 시작해야 할 수 있습니다. (화면 상단의 "런타임" 메뉴를 클릭하고 드롭다운 메뉴에서 "세션 다시 시작"을 선택합니다.)
OpenAI 설정
먼저 OpenAI API 키를 추가하는 것으로 시작하겠습니다. 이렇게 하면 chatgpt에 액세스할 수 있습니다.
import openai
openai.api_key = "sk-***********"
데이터 준비하기
다음 명령을 사용하여 샘플 데이터를 다운로드할 수 있습니다:
! mkdir -p 'data/'
! wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham_essay.txt'
! wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/uber_2021.pdf' -O 'data/uber_2021.pdf'
시작하기
데이터 생성하기
첫 번째 예로 paul_graham_essay.txt 파일에서 문서를 생성해 보겠습니다. 폴 그레이엄이 작성한 What I Worked On 이라는 제목의 에세이 한 편입니다. 문서를 생성하기 위해 SimpleDirectoryReader를 사용하겠습니다.
from llama_index.core import SimpleDirectoryReader
# load documents
documents = SimpleDirectoryReader(
input_files=["./data/paul_graham_essay.txt"]
).load_data()
print("Document ID:", documents[0].doc_id)
Document ID: 95f25e4d-f270-4650-87ce-006d69d82033
데이터 전체에 인덱스 만들기
이제 문서가 생겼으니 색인을 만들고 문서를 삽입할 수 있습니다. 인덱스에는 MilvusVectorStore를 사용하겠습니다. MilvusVectorStore는 몇 가지 인수를 받습니다:
기본 인수
uri (str, optional): 연결할 URI로, Milvus 또는 Zilliz Cloud 서비스의 경우 "https://address:port", 라이트 로컬 Milvus의 경우 "path/to/local/milvus.db"의 형태입니다. 기본값은 "./milvus_llamaindex.db"입니다.token (str, optional): 로그인을 위한 토큰. rbac을 사용하지 않는 경우 비어 있으며, rbac을 사용하는 경우 "사용자 이름:비밀번호"일 가능성이 높습니다.collection_name (str, optional): 데이터가 저장될 컬렉션의 이름입니다. 기본값은 "llamalection"입니다.overwrite (bool, optional): 같은 이름의 기존 컬렉션을 덮어쓸지 여부. 기본값은 False입니다.
문서 ID 및 텍스트를 포함한 스칼라 필드
doc_id_field (str, optional): 컬렉션의 doc_id 필드 이름입니다. 기본값은 DEFAULT_DOC_ID_KEY입니다.text_key (str, optional): 전달된 컬렉션에서 어떤 키 텍스트에 저장되는지. 자체 컬렉션을 가져올 때 사용됩니다. 기본값은 DEFAULT_TEXT_KEY.scalar_field_names (list, optional): 컬렉션 스키마에 포함할 추가 스칼라 필드의 이름입니다.scalar_field_types (list, optional): 추가 스칼라 필드의 유형입니다.
밀도 필드
enable_dense (bool): 고밀도 임베딩을 활성화 또는 비활성화하는 부울 플래그입니다. 기본값은 True입니다.dim (int, optional): 컬렉션에 대한 임베딩 벡터의 차원입니다. enable_sparse가 False인 새 컬렉션을 만들 때 필요합니다.embedding_field (str, optional): 컬렉션에 대한 고밀도 임베딩 필드의 이름, 기본값은 DEFAULT_EMBEDDING_KEY입니다.index_config (dict, optional): 고밀도 임베딩 인덱스를 구축하는 데 사용되는 구성입니다. 기본값은 없음입니다.search_config (dict, optional): 밀버스 고밀도 인덱스 검색에 사용되는 구성입니다.index_config에서 지정한 인덱스 유형과 호환되어야 합니다. 기본값은 없음입니다.similarity_metric (str, optional): 밀도 임베딩에 사용할 유사성 메트릭으로, 현재 IP, COSINE 및 L2를 지원합니다.
스파스 필드
enable_sparse (bool): 스파스 임베딩을 활성화 또는 비활성화하는 부울 플래그입니다. 기본값은 False입니다.sparse_embedding_field (str): 스파스 임베딩 필드의 이름, 기본값은 DEFAULT_SPARSE_EMBEDDING_KEY입니다.sparse_embedding_function (Union[BaseSparseEmbeddingFunction, BaseMilvusBuiltInFunction], optional): enable_sparse가 True인 경우, 텍스트를 스파스 임베딩으로 변환하려면 이 객체를 제공해야 합니다. None이면 기본 스파스 임베딩 함수(BGEM3SparseEmbeddingFunction)가 사용됩니다.sparse_index_config (dict, optional): 스파스 임베딩 인덱스를 구축하는 데 사용되는 구성입니다. 기본값은 None입니다.
하이브리드 랭커
hybrid_ranker (str): 하이브리드 검색 쿼리에 사용되는 랭킹러의 유형을 지정합니다. 현재 ["RRFRanker", "WeightedRanker"]만 지원합니다. 기본값은 "RRFRanker"입니다.hybrid_ranker_params (dict, optional): 하이브리드 랭커의 구성 매개변수입니다. 이 사전의 구조는 사용 중인 특정 랭커에 따라 다릅니다:- "RRFRanker"의 경우 다음을 포함해야 합니다:
- "k" (int): 상호 순위 융합(RRF)에 사용되는 매개변수입니다. 이 값은 검색 관련성을 높이기 위해 여러 순위 전략을 단일 점수로 결합하는 RRF 알고리즘의 일부로 순위 점수를 계산하는 데 사용됩니다.
- "가중랭커"의 경우, 예상되는 값은 다음과 같습니다:
- "가중치"(플로트 목록): 정확히 두 개의 가중치 목록입니다:
- 밀집 임베딩 컴포넌트에 대한 가중치.
- 희소 임베딩 구성 요소에 대한 가중치. 이러한 가중치는 하이브리드 검색 프로세스에서 임베딩의 밀도 및 희소 구성 요소의 중요성을 조정하는 데 사용됩니다. 기본값은 빈 사전으로, 이는 랭커가 미리 정의된 기본 설정으로 작동한다는 것을 의미합니다.
- "가중치"(플로트 목록): 정확히 두 개의 가중치 목록입니다:
- "RRFRanker"의 경우 다음을 포함해야 합니다:
others
collection_properties (dict, optional): TTL(Time-To-Live) 및 MMAP(메모리 매핑)과 같은 컬렉션 속성입니다. 기본값은 없음입니다. 포함될 수 있습니다:- "collection.ttl.seconds"(int): 이 속성을 설정하면 현재 컬렉션의 데이터가 지정된 시간 내에 만료됩니다. 컬렉션의 만료된 데이터는 정리되며 검색이나 쿼리에 포함되지 않습니다.
- "mmap.enabled"(bool): 컬렉션 수준에서 메모리 맵 저장소를 활성화할지 여부입니다.
index_management (IndexManagement): 사용할 인덱스 관리 전략을 지정합니다. 기본값은 "create_if_not_exists"입니다.batch_size (int): 밀버스에 데이터를 삽입할 때 한 번에 처리하는 문서 수를 설정합니다. 기본값은 DEFAULT_BATCH_SIZE입니다.consistency_level (str, optional): 새로 생성된 컬렉션에 사용할 일관성 수준입니다. 기본값은 "세션"입니다.
# Create an index over the documents
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.milvus import MilvusVectorStore
vector_store = MilvusVectorStore(uri="./milvus_demo.db", dim=1536, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
MilvusVectorStore 의 매개변수입니다:
uri을 로컬 파일(예:./milvus.db)로 설정하는 것이 가장 편리한 방법이며, 이 파일에 모든 데이터를 저장하기 위해 Milvus Lite를 자동으로 활용하기 때문입니다.- 데이터 규모가 큰 경우, 도커나 쿠버네티스에 더 고성능의 Milvus 서버를 설정할 수 있습니다. 이 설정에서는 서버 URL(예:
http://localhost:19530)을uri으로 사용하세요. - 밀버스의 완전 관리형 클라우드 서비스인 질리즈 클라우드를 사용하려면, 질리즈 클라우드의 퍼블릭 엔드포인트와 API 키에 해당하는
uri와token을 조정하세요.
데이터 쿼리하기
이제 문서가 인덱스에 저장되었으므로 인덱스에 대해 질문할 수 있습니다. 인덱스는 자체에 저장된 데이터를 chatgpt의 지식 베이스로 사용합니다.
query_engine = index.as_query_engine()
res = query_engine.query("What did the author learn?")
print(res)
The author learned that philosophy courses in college were boring to him, leading him to switch his focus to studying AI.
res = query_engine.query("What challenges did the disease pose for the author?")
print(res)
The disease posed challenges for the author as it affected his mother's health, leading to a stroke caused by colon cancer. This resulted in her losing her balance and needing to be placed in a nursing home. The author and his sister were determined to help their mother get out of the nursing home and back to her house.
다음 테스트는 덮어쓰기가 이전 데이터를 제거한다는 것을 보여줍니다.
from llama_index.core import Document
vector_store = MilvusVectorStore(uri="./milvus_demo.db", dim=1536, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
[Document(text="The number that is being searched for is ten.")],
storage_context,
)
query_engine = index.as_query_engine()
res = query_engine.query("Who is the author?")
print(res)
The author is the individual who created the context information.
다음 테스트는 이미 존재하는 인덱스에 추가 데이터를 추가하는 것을 보여줍니다.
del index, vector_store, storage_context, query_engine
vector_store = MilvusVectorStore(uri="./milvus_demo.db", overwrite=False)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
query_engine = index.as_query_engine()
res = query_engine.query("What is the number?")
print(res)
The number is ten.
res = query_engine.query("Who is the author?")
print(res)
Paul Graham
메타데이터 필터링
특정 소스를 필터링하여 결과를 생성할 수 있습니다. 다음 예는 디렉터리에서 모든 문서를 로드한 다음 메타데이터를 기준으로 필터링하는 것을 보여줍니다.
from llama_index.core.vector_stores import ExactMatchFilter, MetadataFilters
# Load all the two documents loaded before
documents_all = SimpleDirectoryReader("./data/").load_data()
vector_store = MilvusVectorStore(uri="./milvus_demo.db", dim=1536, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents_all, storage_context)
uber_2021.pdf 파일에서 문서만 검색하려고 합니다.
filters = MetadataFilters(
filters=[ExactMatchFilter(key="file_name", value="uber_2021.pdf")]
)
query_engine = index.as_query_engine(filters=filters)
res = query_engine.query("What challenges did the disease pose for the author?")
print(res)
The disease posed challenges related to the adverse impact on the business and operations, including reduced demand for Mobility offerings globally, affecting travel behavior and demand. Additionally, the pandemic led to driver supply constraints, impacted by concerns regarding COVID-19, with uncertainties about when supply levels would return to normal. The rise of the Omicron variant further affected travel, resulting in advisories and restrictions that could adversely impact both driver supply and consumer demand for Mobility offerings.
이번에는 paul_graham_essay.txt 파일에서 검색할 때 다른 결과를 얻습니다.
filters = MetadataFilters(
filters=[ExactMatchFilter(key="file_name", value="paul_graham_essay.txt")]
)
query_engine = index.as_query_engine(filters=filters)
res = query_engine.query("What challenges did the disease pose for the author?")
print(res)
The disease posed challenges for the author as it affected his mother's health, leading to a stroke caused by colon cancer. This resulted in his mother losing her balance and needing to be placed in a nursing home. The author and his sister were determined to help their mother get out of the nursing home and back to her house.