개요

이 튜토리얼에서는 LangChain의 document loader, embedding, vector store 추상화에 대해 알아봅니다. 이러한 추상화는 (벡터) 데이터베이스 및 기타 소스에서 데이터를 검색하여 LLM 워크플로우와 통합하는 것을 지원하도록 설계되었습니다. 이는 검색 증강 생성(retrieval-augmented generation) 또는 RAG의 경우처럼 모델 추론의 일부로 추론할 데이터를 가져오는 애플리케이션에 중요합니다. 여기서는 PDF 문서에 대한 검색 엔진을 구축합니다. 이를 통해 입력 쿼리와 유사한 PDF의 구절을 검색할 수 있습니다. 이 가이드에는 검색 엔진 위에 최소한의 RAG 구현도 포함되어 있습니다.

개념

이 가이드는 텍스트 데이터 검색에 중점을 둡니다. 다음 개념을 다룹니다:

설정

설치

이 튜토리얼에는 langchain-communitypypdf 패키지가 필요합니다:
pip install langchain-community pypdf
자세한 내용은 설치 가이드를 참조하세요.

LangSmith

LangChain으로 구축하는 많은 애플리케이션에는 여러 LLM 호출이 포함된 여러 단계가 포함됩니다. 이러한 애플리케이션이 점점 더 복잡해짐에 따라 chain 또는 agent 내부에서 정확히 무슨 일이 일어나고 있는지 검사할 수 있는 것이 중요해집니다. 이를 수행하는 가장 좋은 방법은 LangSmith를 사용하는 것입니다. 위 링크에서 가입한 후 추적 로깅을 시작하려면 환경 변수를 설정해야 합니다:
export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."
또는 노트북에서 다음과 같이 설정할 수 있습니다:
import getpass
import os

os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = getpass.getpass()

1. Documents 및 Document Loaders

LangChain은 텍스트 단위와 관련 메타데이터를 나타내기 위한 Document 추상화를 구현합니다. 세 가지 속성이 있습니다:
  • page_content: 콘텐츠를 나타내는 문자열;
  • metadata: 임의의 메타데이터를 포함하는 dict;
  • id: (선택 사항) 문서의 문자열 식별자.
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"},
    ),
]
그러나 LangChain 생태계는 수백 개의 일반적인 소스와 통합되는 document loaders를 구현합니다. 이를 통해 이러한 소스의 데이터를 AI 애플리케이션에 쉽게 통합할 수 있습니다.

문서 로드하기

PDF를 Document 객체의 시퀀스로 로드해 보겠습니다. 여기 샘플 PDF가 있습니다 — 2023년 Nike의 10-k 제출 서류입니다. 사용 가능한 PDF document loaders에 대한 LangChain 문서를 참조할 수 있습니다.
from langchain_community.document_loaders import PyPDFLoader

file_path = "../example_data/nke-10k-2023.pdf"
loader = PyPDFLoader(file_path)

docs = loader.load()

print(len(docs))
107
PyPDFLoader는 PDF 페이지당 하나의 Document 객체를 로드합니다. 각각에 대해 다음에 쉽게 액세스할 수 있습니다:
  • 페이지의 문자열 콘텐츠;
  • 파일 이름과 페이지 번호를 포함하는 메타데이터.
print(f"{docs[0].page_content[:200]}\n")
print(docs[0].metadata)
Table of Contents
UNITED STATES
SECURITIES AND EXCHANGE COMMISSION
Washington, D.C. 20549
FORM 10-K
(Mark One)
☑ ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934
FO

{'source': '../example_data/nke-10k-2023.pdf', 'page': 0}

분할

정보 검색 및 다운스트림 질문 답변 목적 모두에서 페이지는 너무 거친 표현일 수 있습니다. 최종 목표는 입력 쿼리에 답하는 Document 객체를 검색하는 것이며, PDF를 추가로 분할하면 문서의 관련 부분의 의미가 주변 텍스트에 의해 “희석”되지 않도록 하는 데 도움이 됩니다. 이를 위해 text splitters를 사용할 수 있습니다. 여기서는 문자를 기반으로 분할하는 간단한 text splitter를 사용합니다. 문서를 1000자 청크로 분할하고 청크 간에 200자의 오버랩을 둡니다. 오버랩은 중요한 컨텍스트와 관련된 진술을 분리할 가능성을 완화하는 데 도움이 됩니다. 우리는 RecursiveCharacterTextSplitter를 사용하며, 이는 새 줄과 같은 일반적인 구분 기호를 사용하여 각 청크가 적절한 크기가 될 때까지 문서를 재귀적으로 분할합니다. 이것은 일반 텍스트 사용 사례에 권장되는 text splitter입니다. 각 분할 Document가 초기 Document 내에서 시작하는 문자 인덱스가 메타데이터 속성 “start_index”로 보존되도록 add_start_index=True를 설정합니다.
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)

print(len(all_splits))
514

2. Embeddings

벡터 검색은 비정형 데이터(예: 비정형 텍스트)를 저장하고 검색하는 일반적인 방법입니다. 아이디어는 텍스트와 연관된 숫자 벡터를 저장하는 것입니다. 쿼리가 주어지면 동일한 차원의 벡터로 embed하고 벡터 유사도 메트릭(예: 코사인 유사도)을 사용하여 관련 텍스트를 식별할 수 있습니다. LangChain은 수십 개의 제공업체의 embeddings를 지원합니다. 이러한 모델은 텍스트를 숫자 벡터로 변환하는 방법을 지정합니다. 모델을 선택해 보겠습니다:
  • OpenAI
  • Azure
  • Google Gemini
  • Google Vertex
  • AWS
  • HuggingFace
  • Ollama
  • Cohere
  • MistralAI
  • Nomic
  • NVIDIA
  • Voyage AI
  • IBM watsonx
  • Fake
pip install -U "langchain-openai"
import getpass
import os

if not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter API key for OpenAI: ")

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vector_1 = embeddings.embed_query(all_splits[0].page_content)
vector_2 = embeddings.embed_query(all_splits[1].page_content)

assert len(vector_1) == len(vector_2)
print(f"Generated vectors of length {len(vector_1)}\n")
print(vector_1[:10])
Generated vectors of length 1536

[-0.008586574345827103, -0.03341241180896759, -0.008936782367527485, -0.0036674530711025, 0.010564599186182022, 0.009598285891115665, -0.028587326407432556, -0.015824200585484505, 0.0030416189692914486, -0.012899317778646946]
텍스트 embeddings를 생성하는 모델을 갖추었으므로 이제 효율적인 유사도 검색을 지원하는 특수 데이터 구조에 저장할 수 있습니다.

3. Vector stores

LangChain VectorStore 객체에는 텍스트 및 Document 객체를 저장소에 추가하고 다양한 유사도 메트릭을 사용하여 쿼리하는 메서드가 포함되어 있습니다. 이들은 종종 텍스트 데이터가 숫자 벡터로 변환되는 방법을 결정하는 embedding 모델로 초기화됩니다. LangChain에는 다양한 vector store 기술과의 통합 모음이 포함되어 있습니다. 일부 vector stores는 제공업체(예: 다양한 클라우드 제공업체)가 호스팅하며 사용하려면 특정 자격 증명이 필요합니다. 일부(예: Postgres)는 로컬 또는 타사를 통해 실행할 수 있는 별도의 인프라에서 실행됩니다. 다른 것들은 경량 워크로드를 위해 인메모리로 실행할 수 있습니다. vector store를 선택해 보겠습니다:
  • In-memory
  • AstraDB
  • Chroma
  • FAISS
  • Milvus
  • MongoDB
  • PGVector
  • PGVectorStore
  • Pinecone
  • Qdrant
pip install -U "langchain-core"
from langchain_core.vectorstores import InMemoryVectorStore

vector_store = InMemoryVectorStore(embeddings)
vector store를 인스턴스화했으므로 이제 문서를 인덱싱할 수 있습니다.
ids = vector_store.add_documents(documents=all_splits)
대부분의 vector store 구현에서는 기존 vector store에 연결할 수 있습니다. 예를 들어 클라이언트, 인덱스 이름 또는 기타 정보를 제공하여 연결할 수 있습니다. 자세한 내용은 특정 통합에 대한 문서를 참조하세요. 문서가 포함된 VectorStore를 인스턴스화하면 쿼리할 수 있습니다. VectorStore에는 쿼리를 위한 메서드가 포함되어 있습니다:
  • 동기 및 비동기;
  • 문자열 쿼리 및 벡터별;
  • 유사도 점수 반환 여부;
  • 유사도 및 @[maximum marginal relevance][VectorStore.max_marginal_relevance_search](쿼리와의 유사도와 검색된 결과의 다양성 간의 균형을 맞추기 위해).
메서드는 일반적으로 출력에 Document 객체 목록을 포함합니다. 사용법 Embeddings는 일반적으로 텍스트를 “밀집” 벡터로 표현하여 유사한 의미를 가진 텍스트가 기하학적으로 가까워지도록 합니다. 이를 통해 문서에 사용된 특정 키워드에 대한 지식 없이 질문만 전달하여 관련 정보를 검색할 수 있습니다. 문자열 쿼리와의 유사도를 기반으로 문서 반환:
results = vector_store.similarity_search(
    "How many distribution centers does Nike have in the US?"
)

print(results[0])
page_content='direct to consumer operations sell products through the following number of retail stores in the United States:
U.S. RETAIL STORES NUMBER
NIKE Brand factory stores 213
NIKE Brand in-line stores (including employee-only stores) 74
Converse stores (including factory stores) 82
TOTAL 369
In the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.
2023 FORM 10-K 2' metadata={'page': 4, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 3125}
비동기 쿼리:
results = await vector_store.asimilarity_search("When was Nike incorporated?")

print(results[0])
page_content='Table of Contents
PART I
ITEM 1. BUSINESS
GENERAL
NIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"
"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.
Our principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is
the largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores
and sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales' metadata={'page': 3, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 0}
점수 반환:
# Note that providers implement different scores; the score here
# is a distance metric that varies inversely with similarity.

results = vector_store.similarity_search_with_score("What was Nike's revenue in 2023?")
doc, score = results[0]
print(f"Score: {score}\n")
print(doc)
Score: 0.23699893057346344

page_content='Table of Contents
FISCAL 2023 NIKE BRAND REVENUE HIGHLIGHTS
The following tables present NIKE Brand revenues disaggregated by reportable operating segment, distribution channel and major product line:
FISCAL 2023 COMPARED TO FISCAL 2022
•NIKE, Inc. Revenues were $51.2 billion in fiscal 2023, which increased 10% and 16% compared to fiscal 2022 on a reported and currency-neutral basis, respectively.
The increase was due to higher revenues in North America, Europe, Middle East & Africa ("EMEA"), APLA and Greater China, which contributed approximately 7, 6,
2 and 1 percentage points to NIKE, Inc. Revenues, respectively.
•NIKE Brand revenues, which represented over 90% of NIKE, Inc. Revenues, increased 10% and 16% on a reported and currency-neutral basis, respectively. This
increase was primarily due to higher revenues in Men's, the Jordan Brand, Women's and Kids' which grew 17%, 35%,11% and 10%, respectively, on a wholesale
equivalent basis.' metadata={'page': 35, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 0}
임베딩된 쿼리와의 유사도를 기반으로 문서 반환:
embedding = embeddings.embed_query("How were Nike's margins impacted in 2023?")

results = vector_store.similarity_search_by_vector(embedding)
print(results[0])
page_content='Table of Contents
GROSS MARGIN
FISCAL 2023 COMPARED TO FISCAL 2022
For fiscal 2023, our consolidated gross profit increased 4% to $22,292 million compared to $21,479 million for fiscal 2022. Gross margin decreased 250 basis points to
43.5% for fiscal 2023 compared to 46.0% for fiscal 2022 due to the following:
*Wholesale equivalent
The decrease in gross margin for fiscal 2023 was primarily due to:
•Higher NIKE Brand product costs, on a wholesale equivalent basis, primarily due to higher input costs and elevated inbound freight and logistics costs as well as
product mix;
•Lower margin in our NIKE Direct business, driven by higher promotional activity to liquidate inventory in the current period compared to lower promotional activity in
the prior period resulting from lower available inventory supply;
•Unfavorable changes in net foreign currency exchange rates, including hedges; and
•Lower off-price margin, on a wholesale equivalent basis.
This was partially offset by:' metadata={'page': 36, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 0}
자세히 알아보기:

4. Retrievers

LangChain VectorStore 객체는 @[Runnable]을 서브클래스하지 않습니다. LangChain @[Retrievers]는 Runnables이므로 표준 메서드 세트(예: 동기 및 비동기 invokebatch 작업)를 구현합니다. vector stores에서 retrievers를 구성할 수 있지만, retrievers는 비벡터 저장소 데이터 소스(예: 외부 API)와도 인터페이스할 수 있습니다. Retriever를 서브클래스하지 않고 이것의 간단한 버전을 직접 만들 수 있습니다. 문서를 검색하는 데 사용할 메서드를 선택하면 runnable을 쉽게 만들 수 있습니다. 아래에서는 similarity_search 메서드를 중심으로 하나를 구축합니다:
from typing import List

from langchain_core.documents import Document
from langchain_core.runnables import chain


@chain
def retriever(query: str) -> List[Document]:
    return vector_store.similarity_search(query, k=1)


retriever.batch(
    [
        "How many distribution centers does Nike have in the US?",
        "When was Nike incorporated?",
    ],
)
[[Document(metadata={'page': 4, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 3125}, page_content='direct to consumer operations sell products through the following number of retail stores in the United States:\nU.S. RETAIL STORES NUMBER\nNIKE Brand factory stores 213 \nNIKE Brand in-line stores (including employee-only stores) 74 \nConverse stores (including factory stores) 82 \nTOTAL 369 \nIn the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.\n2023 FORM 10-K 2')],
 [Document(metadata={'page': 3, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 0}, page_content='Table of Contents\nPART I\nITEM 1. BUSINESS\nGENERAL\nNIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"\n"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.\nOur principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is\nthe largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores\nand sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales')]]
Vectorstores는 Retriever, 특히 VectorStoreRetriever를 생성하는 as_retriever 메서드를 구현합니다. 이러한 retrievers에는 기본 vector store의 어떤 메서드를 호출할지, 그리고 매개변수화하는 방법을 식별하는 특정 search_typesearch_kwargs 속성이 포함됩니다. 예를 들어 다음과 같이 위의 내용을 복제할 수 있습니다:
retriever = vector_store.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 1},
)

retriever.batch(
    [
        "How many distribution centers does Nike have in the US?",
        "When was Nike incorporated?",
    ],
)
[[Document(metadata={'page': 4, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 3125}, page_content='direct to consumer operations sell products through the following number of retail stores in the United States:\nU.S. RETAIL STORES NUMBER\nNIKE Brand factory stores 213 \nNIKE Brand in-line stores (including employee-only stores) 74 \nConverse stores (including factory stores) 82 \nTOTAL 369 \nIn the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.\n2023 FORM 10-K 2')],
 [Document(metadata={'page': 3, 'source': '../example_data/nke-10k-2023.pdf', 'start_index': 0}, page_content='Table of Contents\nPART I\nITEM 1. BUSINESS\nGENERAL\nNIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"\n"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.\nOur principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is\nthe largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores\nand sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales')]]
VectorStoreRetriever"similarity"(기본값), "mmr"(위에서 설명한 maximum marginal relevance) 및 "similarity_score_threshold"의 검색 유형을 지원합니다. 후자를 사용하여 유사도 점수로 retriever가 출력하는 문서를 임계값으로 설정할 수 있습니다. Retrievers는 주어진 질문과 검색된 컨텍스트를 LLM의 프롬프트로 결합하는 검색 증강 생성(RAG) 애플리케이션과 같은 더 복잡한 애플리케이션에 쉽게 통합될 수 있습니다. 이러한 애플리케이션 구축에 대해 자세히 알아보려면 RAG 튜토리얼 튜토리얼을 확인하세요.

다음 단계

이제 PDF 문서에 대한 시맨틱 검색 엔진을 구축하는 방법을 살펴보았습니다. document loaders에 대한 자세한 내용: embeddings에 대한 자세한 내용: vector stores에 대한 자세한 내용: RAG에 대한 자세한 내용:
Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.
I