langchain 공부

LongContextReorder는 어떤 원리로 Context를 재배치할까?

필만이 2024. 11. 16. 00:33

배경

  1. Lost in the Middle: How Language Models Use Long Contexts 논문
    (https://arxiv.org/abs/2307.03172)

-> Context가 10장이 넘어가면 중간에 있는 데이터의 내용이 무시되는 경향이 있다.
2. 그래서 양끝에 가장 관련도가 높은 문서를 배치하는지 하는게 좋은 전략이 된다.
3. 실제로 내 프로젝트에 적용했을때도, 정답률이 10% 향상 되는 효과를 보였다.
4. 그렇다면 어떤 원리로 양끝에 가장 관련도가 높은 문서를 배치하는지 알아보고자 한다.

코드

"""Reorder documents"""

from typing import Any, List, Sequence

from langchain_core.documents import BaseDocumentTransformer, Document  # 문서 관련 기본 클래스
from langchain_core.pydantic_v1 import BaseModel  # 데이터 검증 및 설정 클래스


def _litm_reordering(documents: List[Document]) -> List[Document]:
    """
    Lost in the middle reorder:
    덜 중요한 문서를 리스트의 중간에 배치하고, 더 중요한 문서를 리스트의 양 끝에 배치합니다.
    (참고: https://arxiv.org/abs//2307.03172)

    Args:
        documents: 재정렬할 문서의 리스트.

    Returns:
        재정렬된 문서의 리스트.
    """
    documents.reverse()  # 입력 문서를 역순으로 뒤집음
    reordered_result = []  # 재정렬된 결과를 저장할 리스트
    for i, value in enumerate(documents):  # 문서 리스트를 반복
        if i % 2 == 1:  # 인덱스가 홀수인 경우
            reordered_result.append(value)  # 리스트 끝에 추가
        else:  # 인덱스가 짝수인 경우
            reordered_result.insert(0, value)  # 리스트 시작에 추가
    return reordered_result  # 최종적으로 재정렬된 리스트 반환


class LongContextReorder(BaseDocumentTransformer, BaseModel):
    """
    긴 문맥을 재정렬하기 위한 클래스.

    "Lost in the middle" 문제를 해결하기 위해,
    모델이 중간 정보에 의존하지 않도록 문서를 재배치합니다.

    참조 논문:
    - https://arxiv.org/abs//2307.03172
    """

    class Config:
        """
        pydantic 설정 클래스.

        - arbitrary_types_allowed: 사용자 정의 타입(Document 등)을 허용하도록 설정.
        """
        arbitrary_types_allowed = True

    def transform_documents(
        self, documents: Sequence[Document], **kwargs: Any
    ) -> Sequence[Document]:
        """
        입력된 문서를 재정렬합니다.

        Args:
            documents: 재정렬할 문서의 시퀀스.
            kwargs: 추가적인 매개변수 (현재는 사용되지 않음).

        Returns:
            재정렬된 문서의 시퀀스.
        """
        return _litm_reordering(list(documents))  # _litm_reordering 함수를 호출하여 문서 재정렬

    async def atransform_documents(
        self, documents: Sequence[Document], **kwargs: Any
    ) -> Sequence[Document]:
        """
        입력된 문서를 비동기적으로 재정렬합니다.

        Args:
            documents: 재정렬할 문서의 시퀀스.
            kwargs: 추가적인 매개변수 (현재는 사용되지 않음).

        Returns:
            재정렬된 문서의 시퀀스.
        """
        return _litm_reordering(list(documents))  # 비동기 환경에서도 동일하게 _litm_reordering 호출