오늘은 langchain에서 core component 인 document, document_loaders에 대해서 뜯어보려한다.

문서를 처리하는것은 langchain에서 핵심적인 컴포넌트이고 문서 처리 이후 변환하는 작업은 langchain만의 특장점이기도하다. 그래서 메모리에 효율적으로 로딩하고 파싱하는 특별한 방식이 있을 것 같아서 기대를 갖고 분석을 시작했다.
1. document_loaders는 문서를 로드하는 폴더
2. documents는 문서를 처리하는 폴더
로 보여진다.
1. document_loaders
document_loaders는 BaseLoader, BaseBlobParser라는 두가지 추상 클래스를 정의하고 있다.
class BaseLoader(ABC): # noqa: B024
"""Interface for Document Loader.
Implementations should implement the lazy-loading method using generators
to avoid loading all Documents into memory at once.
`load` is provided just for user convenience and should not be overridden.
"""
# Sub-classes should not implement this method directly. Instead, they
# should implement the lazy load method.
##이하 생략
class BaseBlobParser(ABC):
"""Abstract interface for blob parsers.
A blob parser provides a way to parse raw data stored in a blob into one
or more documents.
The parser can be composed with blob loaders, making it easy to reuse
a parser independent of how the blob was originally loaded.
"""
문서를 로딩하는 과정에서 기본적인 파일, API, DB같은 가벼운 문서와 PDF, 이미지 같은 무거운 문서를 나눠서 로딩하는데, langchain은 기본적으로 BaseLoader를 통해 lazy_load 메서드를 통해서 문서를 가져오며, BaseBlobParser를 통해 무거운 Blob 객체를 문서 객체로 변환하며 가져온다.
* Blob(Binary Large Object)
Blob이란 이진데이터를 의미하며 주로 PDF, 이미지 같은 크고 복잡한 비정형 데이터를 의미한다.
* 레이지로딩(Lazy Loading)
Lazy Loading이란 중요도가 떨어지거나 당장 필요하지않는 요소들의 로딩을 우선적으로 시행하지 않으면서 로딩의 퍼포먼스를 최적화하는 기술을 의미한다. 기존에는 모든 리소스를 한번에 로딩하는 방식을 사용하였으나, 메모리를 조금 더 효율적으로 사용하기 위해서 로딩의 우선순위를 정하는 것이다.
2. documents
documents는 문서를 처리하는 기능을 담고 있다. compressor와 transformers를 담고 있는데, compressor부터 살펴보자.
class BaseDocumentCompressor(BaseModel, ABC):
"""Base class for document compressors.
This abstraction is primarily used for post-processing of retrieved documents.
Documents matching a given query are first retrieved.
Then the list of documents can be further processed.
For example, one could re-rank the retrieved documents using an LLM.
.. note::
Users should favor using a RunnableLambda instead of sub-classing from this
interface.
"""
##이하 생략
앞서 로딩한 문서를 압축하는 클래스이다. 구체적인 압축방법은 서브클래스에 정의되어있고, 압축과 동시에 비동기적으로 acompress_documents라는 메소드가 실행된다. 구현체를 볼 수 없으니, 왜 동기처리와 비동기처리가 동시에 실행되어야하는지는 잘 이해가 안된다.
아래는 transformers.py의 클래스이다.
class BaseDocumentTransformer(ABC):
"""Abstract base class for document transformation.
A document transformation takes a sequence of Documents and returns a
sequence of transformed Documents.
Example:
.. code-block:: python
class EmbeddingsRedundantFilter(BaseDocumentTransformer, BaseModel):
embeddings: Embeddings
similarity_fn: Callable = cosine_similarity
similarity_threshold: float = 0.95
class Config:
arbitrary_types_allowed = True
def transform_documents(
self, documents: Sequence[Document], **kwargs: Any
) -> Sequence[Document]:
stateful_documents = get_stateful_documents(documents)
embedded_documents = _get_embeddings_from_stateful_docs(
self.embeddings, stateful_documents
)
included_idxs = _filter_similar_embeddings(
embedded_documents,
self.similarity_fn,
self.similarity_threshold,
)
return [stateful_documents[i] for i in sorted(included_idxs)]
async def atransform_documents(
self, documents: Sequence[Document], **kwargs: Any
) -> Sequence[Document]:
raise NotImplementedError
"""
여러 개의 문서를 받아서 필터링, 정렬, 요약, 임베딩 등 다양한 방식으로 변형시키는 클래스인데, 이 역시도 동기 방식과 비동기 방식이 동시에 수행되도록 되어있다.
langchain이 document를 처리하는 코드를 분석해보았는데, 내가 지금 잘 분석하고 있는건지 약간 의문이 생겼다. 현재 보고 있는 langchain_core에서의 코드들은 구현체가아니라 추상 클래스만 정의해놓은 전체 아키텍처인 것 같은데, 실제 구현체를 봐야하는 것 아닌가? langchain 오픈소스에는 너무 많은 폴더와 파일이 있다보니 실제 구현체가 어디있는지 찾기가 쉽지않다. 아니면 원래 오픈소스에서 실제 구현 로직은 제공을 안하는건가? 아무튼 전체적인 구조에 대해서는 감을 잡아가는데, 세부적인 분석을 해보려면 조금 더 자리를 잘 잡고 봐야할 것 같다.
'오픈소스' 카테고리의 다른 글
| [오픈소스 분석 4일차] LangChain이 API를 관리하는 소스 코드 분석 (0) | 2025.11.04 |
|---|---|
| [오픈소스 분석 3일차] LangChain Agent Core Components (0) | 2025.10.26 |
| [오픈소스 분석 2일차] Langchain 공식문서 톺아보기 (0) | 2025.10.26 |
| [오픈소스 분석 1일차] 어떤 오픈소스를 분석해볼까? (0) | 2025.10.13 |