Skip to main content

개요

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

개념

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

설정

설치

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

LangSmith

LangChain으로 구축하는 많은 애플리케이션에는 여러 LLM 호출을 포함하는 여러 단계가 포함됩니다. 이러한 애플리케이션이 점점 더 복잡해짐에 따라 체인 또는 에이전트 내부에서 정확히 무슨 일이 일어나고 있는지 검사할 수 있는 것이 중요합니다. 이를 수행하는 가장 좋은 방법은 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. 문서 및 문서 로더

LangChain은 텍스트 단위와 관련 메타데이터를 나타내기 위한 Document 추상화를 구현합니다. 이 추상화는 세 가지 속성을 가집니다:
  • page_content: 콘텐츠를 나타내는 문자열;
  • metadata: 임의의 메타데이터를 포함하는 딕셔너리;
  • 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 에코시스템은 수백 개의 일반적인 소스와 통합하는 문서 로더를 구현합니다. 이를 통해 이러한 소스의 데이터를 AI 애플리케이션에 쉽게 통합할 수 있습니다.

문서 로드하기

PDF를 Document 객체의 시퀀스로 로드해 보겠습니다. 여기 샘플 PDF가 있습니다 — 2023년 Nike의 10-k 보고서입니다. 사용 가능한 PDF 문서 로더는 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를 더 분할하면 관련 문서 부분의 의미가 주변 텍스트에 의해 “희석되지” 않도록 하는 데 도움이 됩니다. 이를 위해 텍스트 분할기를 사용할 수 있습니다. 여기서는 문자를 기반으로 분할하는 간단한 텍스트 분할기를 사용합니다. 문서를 청크 간 200자의 오버랩과 함께 1000자 청크로 분할합니다. 오버랩은 중요한 컨텍스트에서 문장이 분리될 가능성을 완화하는 데 도움이 됩니다. 우리는 줄바꿈과 같은 일반적인 구분자를 사용하여 각 청크가 적절한 크기가 될 때까지 문서를 재귀적으로 분할하는 RecursiveCharacterTextSplitter를 사용합니다. 이것은 일반적인 텍스트 사용 사례에 권장되는 텍스트 분할기입니다. add_start_index=True를 설정하여 각 분할 Document가 초기 Document 내에서 시작하는 문자 인덱스를 메타데이터 속성 “start_index”로 보존합니다.
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. 임베딩

벡터 검색은 비정형 데이터(예: 비정형 텍스트)를 저장하고 검색하는 일반적인 방법입니다. 아이디어는 텍스트와 연관된 숫자 벡터를 저장하는 것입니다. 쿼리가 주어지면 동일한 차원의 벡터로 임베딩하고 벡터 유사도 메트릭(예: 코사인 유사도)을 사용하여 관련 텍스트를 식별할 수 있습니다. LangChain은 수십 개의 제공업체로부터 임베딩을 지원합니다. 이러한 모델은 텍스트를 숫자 벡터로 변환하는 방법을 지정합니다. 모델을 선택해 보겠습니다:
  • 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]
텍스트 임베딩을 생성하는 모델을 갖추었으므로, 이제 효율적인 유사도 검색을 지원하는 특수 데이터 구조에 이를 저장할 수 있습니다.

3. 벡터 저장소

LangChain VectorStore 객체는 저장소에 텍스트 및 Document 객체를 추가하고 다양한 유사도 메트릭을 사용하여 쿼리하는 메서드를 포함합니다. 이들은 종종 텍스트 데이터를 숫자 벡터로 변환하는 방법을 결정하는 임베딩 모델로 초기화됩니다. LangChain은 다양한 벡터 저장소 기술과의 통합 모음을 포함합니다. 일부 벡터 저장소는 제공업체(예: 다양한 클라우드 제공업체)에 의해 호스팅되며 사용하려면 특정 자격 증명이 필요합니다. 일부(예: Postgres)는 로컬 또는 타사를 통해 실행할 수 있는 별도의 인프라에서 실행됩니다. 다른 것들은 가벼운 워크로드를 위해 인메모리로 실행할 수 있습니다. 벡터 저장소를 선택해 보겠습니다:
  • 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)
벡터 저장소를 인스턴스화했으므로 이제 문서를 인덱싱할 수 있습니다.
ids = vector_store.add_documents(documents=all_splits)
대부분의 벡터 저장소 구현에서는 기존 벡터 저장소에 연결할 수 있습니다(예: 클라이언트, 인덱스 이름 또는 기타 정보 제공). 자세한 내용은 특정 통합 문서를 참조하세요. 문서를 포함하는 VectorStore를 인스턴스화한 후에는 쿼리할 수 있습니다. VectorStore는 다음과 같은 쿼리 메서드를 포함합니다:
  • 동기 및 비동기;
  • 문자열 쿼리 및 벡터로;
  • 유사도 점수 반환 유무;
  • 유사도 및 @[maximum marginal relevance][VectorStore.max_marginal_relevance_search] (검색된 결과의 쿼리와의 유사도와 다양성의 균형을 맞추기 위해).
이러한 메서드는 일반적으로 출력에 Document 객체 목록을 포함합니다. 사용법 임베딩은 일반적으로 텍스트를 유사한 의미를 가진 텍스트가 기하학적으로 가까운 “밀집” 벡터로 나타냅니다. 이를 통해 문서에 사용된 특정 핵심 용어에 대한 지식 없이 질문을 전달하는 것만으로 관련 정보를 검색할 수 있습니다. 문자열 쿼리와의 유사도를 기반으로 문서를 반환합니다:
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}
점수 반환:
# 제공업체마다 다른 점수를 구현한다는 점에 유의하세요. 여기의 점수는
# 유사도와 반비례하는 거리 메트릭입니다.

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. 리트리버

LangChain VectorStore 객체는 @[Runnable]을 하위 클래스로 하지 않습니다. LangChain @[Retrievers]는 Runnable이므로 표준 메서드 세트(예: 동기 및 비동기 invokebatch 작업)를 구현합니다. 벡터 저장소에서 리트리버를 구성할 수 있지만 리트리버는 벡터 저장소가 아닌 데이터 소스(예: 외부 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')]]
벡터 저장소는 Retriever, 특히 VectorStoreRetriever를 생성하는 as_retriever 메서드를 구현합니다. 이러한 리트리버에는 기본 벡터 저장소의 어떤 메서드를 호출할지, 어떻게 매개변수화할지를 식별하는 특정 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"(위에서 설명한 최대 한계 관련성), "similarity_score_threshold"의 검색 유형을 지원합니다. 후자를 사용하여 유사도 점수로 리트리버가 출력하는 문서에 임계값을 설정할 수 있습니다. 리트리버는 주어진 질문과 검색된 컨텍스트를 LLM용 프롬프트로 결합하는 검색 증강 생성(RAG) 애플리케이션과 같이 더 복잡한 애플리케이션에 쉽게 통합할 수 있습니다. 이러한 애플리케이션 구축에 대해 자세히 알아보려면 RAG 튜토리얼을 확인하세요.

다음 단계

이제 PDF 문서에 대한 시맨틱 검색 엔진을 구축하는 방법을 살펴보았습니다. 문서 로더에 대한 자세한 내용은: 임베딩에 대한 자세한 내용은: 벡터 저장소에 대한 자세한 내용은: RAG에 대한 자세한 내용은:
Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.
I