나만의 Document Store 만들기

나만의 Document Store 만들기 (Creating Custom Document Stores)

Haystack에 준비된 Document Store만으로는 안 되는 상황이 분명히 있어요. 아직 Haystack에서 지원하지 않는 벡터 저장소를 써야 한다거나, 문서를 찾는 아주 특별한 검색 전략이 필요하다거나, Haystack이 문서를 읽고 쓰는 방식을 직접 바꾸고 싶다거나요. 그럴 땐 나만의 커스텀 Document Store를 만들면 됩니다. 이 문서는 그 과정을 처음부터 끝까지 안내해요.

출처: Creating Custom Document Stores (공식 문서)

커스텀 Document Store는 준비된 해결책이 없는 상황에서 직접 만들고 활용할 수 있는 자원이에요. 예를 들어 이런 경우죠.

  • Haystack에서 아직 지원하지 않는 벡터 저장소를 쓰고 있을 때
  • 문서를 검색하기 위해 아주 특정한 검색 전략이 필요할 때
  • Haystack이 문서를 읽고 쓰는 방식을 커스터마이즈하고 싶을 때

커스텀 컴포넌트와 마찬가지로, 코드를 파이썬 프로그램에 import할 수만 있으면 커스텀 Document Store를 Haystack 파이프라인에서 쓸 수 있어요. 가장 좋은 방법은 커스텀 Document Store를 독립된 통합 패키지로 배포하는 거예요.

시작하기 전 권장사항 (Recommendations)

커스텀 Document Store가 Haystack 생태계의 나머지와 일관되게 동작하도록, 몇 가지 권장사항을 안내할게요. 결국 Document Store는 Haystack이 이해할 수 있는 방식으로 쓰인 파이썬 코드에 불과하지만, 이름을 어떻게 짓고, 구조를 어떻게 조직하고, 어떻게 배포하느냐가 큰 차이를 만들 수 있어요. 이 권장사항 중 어느 것도 필수는 아니지만, 가능한 한 많이 따르길 권해요.

이름 규칙 (Naming Convention)

Document Store 이름은 <TECHNOLOGY>-haystack 형식으로 지을 것을 권해요. 예를 들어 chroma-haystack처럼요. 이렇게 하면 다른 것들과 일관성이 생겨서, 사용자의 인지 부담을 낮추고 발견 가능성을 높여요.

이 이름 규칙은 git 저장소 이름(https://github.com/your-org/example-haystack)과 파이썬 패키지 이름(example-haystack) 모두에 적용돼요.

구조 (Structure)

Document Store는 대부분 꽤 복잡할 수 있어서, 전용 Git 저장소를 마련해 두는 게 편하고 미래에도 안전해요. 이를 돕기 위해 Haystack이 준비한 GitHub 템플릿이 있어요. 커스텀 Document Store를 전용 저장소에 호스팅하는 데 필요한 구조를 제공하죠. 패키징·테스트·배포의 보일러플레이트가 포함되어 있어서, 커스텀 Document Store를 독립된 파이썬 패키지로 만들 수 있어요.

템플릿 저장소의 지침을 따라 시작하고, 단계별 가이드는 비디오 워크스루도 볼 수 있어요.

패키징 (Packaging)

다른 Haystack 통합과 마찬가지로, Document Store는 추가 파이썬 패키지를 설치(예: pip)해서 Haystack 애플리케이션에 추가할 수 있어요. Document Store를 호스팅하는 Git 저장소와 pyproject.toml 파일이 있으면(우리 GitHub 템플릿 사용), 소스에서 직접 pip install 할 수 있어요.

pip install git+https://github.com/your-org/example-haystack.git

프로토타입을 빠르게 전달하기에는 아주 실용적이지만, 여러분의 커스텀 Document Store를 다른 사람도 쓰게 하고 싶다면 PyPI에 패키지를 배포하는 것을 권해요. 그러면 버전이 관리되고, 이렇게 간단히 설치할 수 있게 돼요.

pip install example-haystack

tip

👍 우리 GitHub 템플릿에는 Document Store 패키지를 PyPI에 자동으로 배포하는 GitHub 워크플로우가 포함되어 있어요.

문서화 (Documentation)

커스텀 Document Store를 상세한 README 파일로 꼼꼼히 문서화하고, 가능하면 정적 생성기로 API 문서를 만들 것을 권해요.

영감을 얻으려면 neo4j-haystack 저장소와 그 문서 페이지를 참고하세요.

구현 (Implementation)

DocumentStore 프로토콜

Haystack에서 정의한 DocumentStore 파이썬 프로토콜의 모든 메서드를 구현하기만 하면, 어떤 파이썬 클래스든 Document Store로 쓸 수 있어요.

class DocumentStore(Protocol):
    def to_dict(self) -> Dict[str, Any]:
        """
        Serializes this store to a dictionary.
        """

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "DocumentStore":
        """
        Deserializes the store from a dictionary.
        """

    def count_documents(self) -> int:
        """
        Returns the number of documents stored.
        """

    def filter_documents(
        self,
        filters: Optional[Dict[str, Any]] = None,
    ) -> List[Document]:
        """
        Returns the documents that match the filters provided.
        """

    def write_documents(
        self,
        documents: List[Document],
        policy: DuplicatePolicy = DuplicatePolicy.FAIL,
    ) -> int:
        """
        Writes (or overwrites) documents into the DocumentStore, return the number of documents that was written.
        """

    def delete_documents(self, document_ids: List[str]) -> None:
        """
        Deletes all documents with a matching document_ids from the DocumentStore.
        """

DocumentStore 인터페이스는 데이터베이스나 저장 시스템에서 보통 수행하는 기본 CRUD 연산을 지원해요. 그리고 DocumentWriter 같은 대부분의 범용 컴포넌트가 이를 사용해요.

추가 메서드 (Additional Methods)

보통 Document Store에는 고급 검색 기능을 제공하는 추가 메서드가 함께 붙어요. 이런 메서드는 DocumentStore 프로토콜의 일부가 아니고 어떤 특별한 규약도 따르지 않아요. 이렇게 설계한 이유는 Document Store가 기반 데이터베이스의 특정 기능을 쓸 때 최대한의 유연성을 제공하기 위해서예요.

DocumentStore 프로토콜에 속하지 않지만 Haystack의 대부분 Document Store가 구현하는 추가 메서드로는 이런 것들이 있어요.

def delete_all_documents(recreate_index: bool = False)
def update_by_filter(filters: dict[str, Any], meta: dict[str, Any], refresh: bool = False) -> int:
def delete_by_filter(filters: dict[str, Any]) -> int:

이 메서드들은 프로토콜에 속하지 않지만, 사용자들이 흔히 있길 기대하기 때문에 커스텀 Document Store에 구현하는 것을 적극 권장해요.

예를 들어, 특정 벡터 DB의 맥락에서만 의미가 있는 긴 파라미터 목록을 받는 search 메서드를 Document Store가 정의해도 Haystack은 방해하지 않아요. 보통은 Retriever 컴포넌트가 이 추가 search 메서드를 사용하게 되죠.

리트리버 (Retrievers)

커스텀 Document Store를 최대한 활용하려면, 대부분 위에서 말한 추가 검색 메서드를 사용하는 리트리버를 하나 이상 함께 만들어야 해요. 커스텀 Retriever를 구현하기 전에 Haystack 문서에서 Retrievers에 대해 먼저 배워 두는 게 도움이 돼요.

구현 관점에서 Haystack의 Retriever는 다른 커스텀 컴포넌트와 완전히 같아요. 자세한 내용은 커스텀 컴포넌트 만들기 문서를 참고하세요.

필수는 아니지만, 커스텀 Retriever에 대해 더 구체적인 이름 규칙을 따르는 걸 권장해요.

직렬화 (Serialization)

Haystack은 올바른 직렬화 구현을 위해 모든 컴포넌트가 파이썬 딕셔너리로 표현 가능해야 해요. Retriever나 Writer 같은 일부 컴포넌트는 Document Store 인스턴스에 대한 참조를 유지하죠. 그래서 DocumentStore 클래스는 from_dictto_dict 메서드를 구현해야 해요. 이래야 파일에서 파이프라인을 읽은 뒤 인스턴스를 다시 만들 수 있어요.

커스텀 Document Store에서 무엇을 직렬화할지에 대한 실용적인 예로, IP 주소와 데이터베이스 이름으로 만든 DB 클라이언트를 생각해 보세요. to_dict에서 반환할 딕셔너리를 만들 때, DB 클라이언트 인스턴스가 아니라 IP 주소와 데이터베이스 이름을 저장해야 해요.

시크릿 관리 (Secrets Management)

사용자가 Document Store 인스턴스를 만들기 위해 비밀번호, API 키, 비공개 URL 같은 민감한 데이터를 제공해야 할 가능성이 있어요. 이 민감한 데이터가 평문으로 전달되면 유출될 수 있어요.

Haystack에는 민감한 데이터를 Secrets라는 특별한 객체로 감싸는 방법이 있어요. 이렇게 하면 직렬화 왕복 과정에서 데이터가 유출되는 것을 막아요. 데이터 보안을 위해 이 기능을 적극적으로 사용하는 것을 강력히 권장해요(안 하는 것보다는 낫죠!).

Haystack의 Secret 관리에 대한 자세한 내용은 문서에서 읽을 수 있어요.

테스팅 (Testing)

Haystack은 커스텀 Document Store에서 쓸 수 있는 테스트 기능을 함께 제공해요. 특히 DocumentStoreBaseTests에서 상속받는 빈 클래스만으로도, 어떤 Document Store라도 제대로 동작하려면 통과해야 하는 표준 테스트가 이미 실행돼요.

구현 팁 (Implementation Tips)

  • 커스텀 Document Store를 작성하는 법을 배우는 가장 좋은 방법은 기존 것을 보는 거예요. Haystack에 포함된 InMemoryDocumentStore나 코어 통합인 ElasticsearchDocumentStore가 시작하기 좋은 예시예요.
  • 처음부터 만들 때는 DocumentStore 프로토콜의 CRUD 메서드 네 개를 하나씩 만들고, 각각을 하나씩 테스트하는 게 더 쉬울 수 있어요. 예를 들어:
    1. count_documents의 로직을 구현한다.
    2. test_document_store.py 모듈에서 TestDocumentStore(CountDocumentsTest)와 같이 특정 테스트 믹스인 CountDocumentsTest 상속받는 테스트 클래스를 정의한다.
    3. 테스트를 통과시킨다.
    4. write_documents의 로직을 구현한다.
    5. test_document_store.py를 수정해 이제 WriteDocumentsTest 믹스인도 상속받게 한다: TestDocumentStore(CountDocumentsTest, WriteDocumentsTest).
    6. 나머지 메서드들로 계속 반복한다.
  • 사용자가 전체 파이프라인에서 Document Store를 써 볼 수 있는 노트북을 마련해 두면 도입에 큰 도움이 되고 훌륭한 문서이기도 해요. haystack-cookbook 저장소는 가시성이 좋으니, 기여자는 PR을 만들어 직접 추가하길 권해요.

구현이 모든 DocumentStoreBaseTests 테스트를 통과하는지 확인하는 것은, 커스텀 Document Store가 Haystack 생태계의 나머지와 일관되게 동작하기 위한 최소 요구사항이에요.

이상적으로는 DocumentStoreBaseExtendedTests 테스트와도 호환되게 만드는 게 좋아요. 그러면 delete_all_documentsupdate_by_filter처럼 사용자가 Document Store에서 기대하는 흔한 기능들을 모두 충족한다는 보장을 받을 수 있어요.

Document Store에 쓰는 기술이 비동기 연산을 지원한다면, DocumentStore 프로토콜의 메서드에 대한 async 버전도 구현하는 것을 권장해요. 이렇게 하면 사용자가 애플리케이션과 파이프라인에서 비동기 기능을 활용해 성능과 확장성을 높일 수 있어요.

Integrations 페이지에 소개받기

Integrations 웹페이지는 Haystack 통합을 커뮤니티에 알리는 곳이고, 여러분의 작업을 선보일 좋은 기회예요. Document Store가 사용 가능하고 제대로 패키징되면, haystack-integrations GitHub 저장소에 통합 타일을 추가하는 pull request를 열 수 있어요.

자세한 내용은 통합 문서 페이지를 참고하세요.

더 알아보기 (Learn more)