Huggingface, OpenAI 등 Embedding 관련 모듈을 유지보수성과 확장성을 길게 고려한 설계, 구체적인 구현(OpenAI, HuggingFace)에 의존하지 않고 Interface에 의존
from __future__ import annotations
from typing import Protocol, List, Sequence, Union
from langchain_core.documents import Document
DocLike = Union[str, Document]
class Embedder(Protocol):
def embed_query(self, text: str) -> List[float]: ... def embed_documents(self, documents: Sequence[DocLike]) -> List[List[float]]: ... # → vectors
abc.ABC 대신 typing.Protocol을 사용
- 유연성: 상속(class HFEmbedder(Embedder))을 강제하지 않습니다. 즉, 외부 라이브러리에서 가져온 클래스라도 embed_query와 embed_documents 메서드만 가지고 있다면 별도의 수정 없이 Embedder 타입으로 간주합니다.
- 결합도 감소: 인터페이스와 구현체 사이의 물리적 연결 고리를 느슨하게 유지하여, 테스트 시 Mock 객체를 만들거나 새로운 엔진을 추가할 때 매우 자유롭습니다.
DocLike = Union[str, Document] 정의는 데이터의 형태보다 본질에 집중하는 전략입니다.
- 다형성 지원: 사용자는 단순히 문자열 리스트를 넣을 수도 있고, 메타데이터가 포함된 LangChain의 Document 객체를 넣을 수도 있습니다.
- 일관된 인터페이스: 내부적으로 Document에서 page_content를 추출하는 로직을 구현체(hf, openai)가 담당하게 함으로써, 호출부(Caller)의 코드를 깔끔하게 유지합니다.
Sequence, List[List[float]] 등을 명시하여 대규모 프로젝트에서 발생할 수 있는 런타임 에러를 정적 단계에서 방지합니다.
- Sequence 활용: List뿐만 아니라 Tuple이나 Generator 등 순회 가능한 모든 타입을 허용하여 메모리 효율적인 데이터 처리를 가능하게 합니다.
- 명확한 반환값: 임베딩 결과가 항상 2차원 리스트(List[List[float]])임을 보장하여 후속 작업(벡터 DB 저장 등)의 규격을 고정합니다.