LangChain - Vector stores and retrievers

14 Aug 2024  Khlee  6 mins read.

LangChain 튜토리얼을 읽고 정리한 내용이다.

Documents

LangChain에서는 문서를 추상화하는 Document 클래스를 제공한다. Document는 다음과 같은 두 개의 속성을 포함한다.

  • page_content: 문서의 내용
  • metadata: 임의로 설정할 수 있는 메타데이터로, 문서의 출처나 다른 문서와의 관계 등에 관한 내용이 들어갈 수 있다.

샘플 Document를 다음과 같이 생성한다.

from langchain_core.documents import Document

documents = [
    Document(
        page_content="Dogs are great companions, known for their loyalty and friendliness.",
        metadata={"source": "mammal-pets-doc"},
    ),
    Document(
        page_content="Cats are independent pets that often enjoy their own space.",
        metadata={"source": "mammal-pets-doc"},
    ),
    Document(
        page_content="Goldfish are popular pets for beginners, requiring relatively simple care.",
        metadata={"source": "fish-pets-doc"},
    ),
    Document(
        page_content="Parrots are intelligent birds capable of mimicking human speech.",
        metadata={"source": "bird-pets-doc"},
    ),
    Document(
        page_content="Rabbits are social animals that need plenty of space to hop around.",
        metadata={"source": "mammal-pets-doc"},
    ),
]

5개의 Document를 생성했으며, 각각의 메타데이터로 source를 포함하고 있다.

Vector stores

Vector stores는 구조화되지 않은 데이터(예를 들어 위의 page_content와 같이 특별한 구조가 없는 텍스트)를 저장하고 검색하는 방법이다. Vector stores는 텍스트와 연관된 벡터를 저장하고, 쿼리가 주어지면 그것을 동일한 차원의 벡터로 변환한 후 가장 유사한 벡터에 해당하는 텍스트를 찾는 방식으로 동작한다.

LangChain의 VectorStore 객체는 텍스트나 Document 객체를 추가하거나 쿼리하는 메서드를 제공한다. 이 객체는 텍스트가 벡터로 변환되는 방식을 결정하는 임베딩 모델로 초기화 된다. 여기서는 OpenAIEmbeddings을 사용할 것이다.

LangChain에는 다양한 vector store 기술과의 통합이 포함되어 있다. 일부 vector store는 클라우드에서 실행되거나 별도의 인프라에서 실행되지면 여기서는 로컬에서 실행할 수 있는 Chroma를 사용할 것이다.

> pip install langchain-chroma
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = Chroma.from_documents(
    documents,
    embedding=OpenAIEmbeddings(),
)

Chromafrom_documents() 함수를 호출하면 Document로부터 VectorStore 객체를 얻을 수 있다.

VectorStore 객체는 다음과 같이 다양한 쿼리 방법을 제공한다.

  • 동기적 또는 비동기적 쿼리
  • 문자열 또는 벡터로 쿼리
  • similarity scores를 반환할 수 있음
  • By similarity and maximum marginal relevance (to balance similarity with query to diversity in retrieved results).

예를 들어 ‘cat’과의 유사성을 확인하려면

response = vectorstore.similarity_search("cat")
print(response)
[
    Document(metadata={'source': 'mammal-pets-doc'}, page_content='Cats are independent pets that often enjoy their own space.'),
    Document(metadata={'source': 'mammal-pets-doc'}, page_content='Dogs are great companions, known for their loyalty and friendliness.'),
    Document(metadata={'source': 'mammal-pets-doc'}, page_content='Rabbits are social animals that need plenty of space to hop around.'),
    Document(metadata={'source': 'bird-pets-doc'}, page_content='Parrots are intelligent birds capable of mimicking human speech.')
]

유사도 점수와 함께 확인하려면

response = vectorstore.similarity_search_with_score("cat")
print(response)
[
    (Document(metadata={'source': 'mammal-pets-doc'}, page_content='Cats are independent pets that often enjoy their own space.'), 0.375326931476593),
    (Document(metadata={'source': 'mammal-pets-doc'}, page_content='Dogs are great companions, known for their loyalty and friendliness.'), 0.4833090305328369),
    (Document(metadata={'source': 'mammal-pets-doc'}, page_content='Rabbits are social animals that need plenty of space to hop around.'), 0.4958883225917816),
    (Document(metadata={'source': 'bird-pets-doc'}, page_content='Parrots are intelligent birds capable of mimicking human speech.'), 0.4974174499511719)
]

또는 문자열 대신 벡터와의 유사성도 확인할 수 있다.

embedding = OpenAIEmbeddings().embed_query("cat")
response = vectorstore.similarity_search_by_vector(embedding)
print(response)
[
    Document(metadata={'source': 'mammal-pets-doc'}, page_content='Cats are independent pets that often enjoy their own space.'),
    Document(metadata={'source': 'mammal-pets-doc'}, page_content='Dogs are great companions, known for their loyalty and friendliness.'),
    Document(metadata={'source': 'mammal-pets-doc'}, page_content='Rabbits are social animals that need plenty of space to hop around.'),
    Document(metadata={'source': 'bird-pets-doc'}, page_content='Parrots are intelligent birds capable of mimicking human speech.')
]

Retrievers

LangChain의 VectorStoreRunnable이 아니기 때문에 LCEL chain을 구성하려면 RunnableRetriever로 변환할 필요가 있다.

from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda

retriever = RunnableLambda(vectorstore.similarity_search).bind(k=1)  # select top result

response = retriever.batch(["cat", "shark"])
print(response)
[
    [Document(metadata={'source': 'mammal-pets-doc'}, page_content='Cats are independent pets that often enjoy their own space.')],
    [Document(metadata={'source': 'fish-pets-doc'}, page_content='Goldfish are popular pets for beginners, requiring relatively simple care.')]
]

또는 VectorStoreas_retriever() 함수를 사용해서 Retriever로 변환할 수 있다.

retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 1},
)

response = retriever.batch(["cat", "shark"])
print(response)
[
    [Document(metadata={'source': 'mammal-pets-doc'}, page_content='Cats are independent pets that often enjoy their own space.')],
    [Document(metadata={'source': 'fish-pets-doc'}, page_content='Goldfish are popular pets for beginners, requiring relatively simple care.')]
]

Vector store를 사용해서 간단한 RAG 구현하기

RAG에 대한 설명은 여기 참고.

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

message = """
Answer this question using the provided context only.

{question}

Context:
{context}
"""

prompt = ChatPromptTemplate.from_messages([("human", message)])
rag_chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | model

response = rag_chain.invoke("tell me about cats")
print(response.content)
Cats are independent pets that often enjoy their own space.

이번에 만든 retrievercontext 변수에 넣었는데, 프롬프트를 보면 Context: 문자열 다음으로 들어가는 것을 알 수 있다.

LangSmith를 통해 최종 프롬프트를 확인해 보면 다음과 같다.

Answer this question using the provided context only.

tell me about cats

Context:
[Document(metadata={'source': 'mammal-pets-doc'}, page_content='Cats are independent pets that often enjoy their own space.')]

Context에 cat과 관련된 문서가 들어간 것을 확인할 수 있다.

khlee
khlee