1. Retrievers
LangChain에서 캡슐화된 인터페이스인 Retriever는 구조화되지 않은 쿼리를 기반으로 관련 문서를 반환할 수 있습니다. Retriever 디자인의 목적은 로컬 데이터를 쿼리하기 쉽게 하는 것입니다. 벡터 저장소는 Retriever의 기본 구현으로 사용될 수 있으며, LangChain은 Retriever 인터페이스의 여러 기본 구현을 지원합니다.
2. Retriever 시작하기
2.1. 설치
Retriever를 얻는 방법을 보여주기 위해 Qdrant 벡터 데이터베이스를 사용하겠습니다.
%pip install --upgrade --quiet qdrant-client
2.2. OpenAI API 키 얻기
OpenAIEmbeddings
를 사용하기 전에, OpenAI API 키를 얻어야 합니다.
import getpass
import os
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API 키:")
2.3. 문서 데이터 가져오고 Qdrant 클라이언트 얻기
다음 코드는 문서 데이터를 가져오고 Qdrant 클라이언트를 얻기 위한 방법을 보여줍니다.
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import Qdrant
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
loader = TextLoader("../../modules/state_of_the_union.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings()
qdrant = Qdrant.from_documents(
docs,
embeddings,
path="/tmp/local_qdrant",
collection_name="my_documents",
)
2.4. Retriever 얻기
다음 코드는 Qdrant에서 Retriever를 얻는 방법을 보여줍니다.
retriever = qdrant.as_retriever()
retriever
다음과 같이 질문과 관련된 문서를 쿼리할 수 있습니다:
docs = retriever.get_relevant_documents("케터지 브라운 잭슨에 대해 어떻게 말했는가")
또한, 다음과 같이 Retriever의 유사도 임계값을 설정할 수도 있습니다:
retriever = db.as_retriever(
search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.5}
)
추가로, Retriever를 최상위 'K'개의 가장 유사한 레코드를 반환하도록 설정할 수도 있습니다. 예를 들어, 최상위 2개의 가장 유사한 레코드를 반환하도록 설정합니다:
retriever = db.as_retriever(search_kwargs={"k": 2})
2.5. LCEL에서 Retriever 사용하기
Retriever는 Runnable
객체이기 때문에, 다른 Runnable
객체와 쉽게 결합하여 워크플로우를 조율할 수 있습니다:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
template = """다음 문맥을 기반으로 질문에 답변하세요:
{context}
질문: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI()
def format_docs(docs):
return "\n\n".join([d.page_content for d in docs])
chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
chain.invoke("대통령이 기술에 대해 어떻게 얘기했나요?")
과정 설명:
- 단계 1: 첫 번째 단계는 프롬프트 템플릿을 위한 매개변수를 준비하기 위해
context
및question
두 속성을 포함한 사전을 생성하는 것입니다.context
매개변수는invoke
메서드에 전달된 매개변수인 "대통령이 기술에 대해 어떻게 얘기했나요?"에 기반하여retriever
에서 생성되며, 이는 질문과 유사한 문서를 검색한 후format_docs
함수를 사용하여 문서 배열을 형식화하고context
속성에 할당합니다.RunnablePassthrough
함수는 체인의 매개변수(사용자의 입력 질문)를question
속성에 복사합니다. - 단계 2: 첫 번째 단계에서 생성된 사전을 프롬프트 템플릿에 전달하여 서식을 지정합니다.
- 단계 3: 프롬프트 템플릿에서 생성된 서식이 모델에 전달됩니다.
- 단계 4: 모델 호출 결과를 출력 파서
StrOutputParser
에 전달합니다.
3. 사용자 정의 Retriever
4.1. Retriever 인터페이스 소개
Retriever 인터페이스는 매우 간단하며, 사용자 정의 Retriever를 쉽게 작성할 수 있습니다.
4.2. 사용자 정의 검색기 예제
다음은 사용자 정의 검색기의 예제입니다. 이 예제는 어떻게 사용자 정의 검색기를 작성하고 관련 문서를 검색하는지를 보여줍니다.
from langchain_core.retrievers import BaseRetriever
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from typing import List
class CustomRetriever(BaseRetriever):
def _get_relevant_documents(
self, query: str, *, run_manager: CallbackManagerForRetrieverRun
) -> List[Document]:
return [Document(page_content=query]
retriever = CustomRetriever()
retriever.get_relevant_documents("bar")
위의 섹션을 공부하여, 개념, 검색 방법 및 검색기의 사용자 정의에 대한 깊은 이해를 얻을 수 있습니다.