Sign in to save your progressYou can keep reading without an account, but completed lessons won't be saved.
Sign in

컨텍스트 기반 검색(Contextual Retrieval)은 근본적인 문제를 해결함으로써 RAG 파이프라인의 정확도를 개선하는 기법입니다: 문서를 청크(chunk)로 분할하면 각 청크는 더 넓은 문서 컨텍스트와의 연결을 잃게 됩니다.

표준 청킹의 문제점

소스 문서를 가져와 벡터 데이터베이스용 청크로 분할하면, 각 개별 조각은 자신이 어디에서 왔는지 또는 문서의 나머지 부분과 어떻게 관련되는지 더 이상 알지 못합니다. 이는 청크가 중요한 컨텍스트 정보를 결여하고 있기 때문에 검색 정확도를 저해할 수 있습니다.

컨텍스트 기반 검색의 작동 방식

컨텍스트 기반 검색은 청크를 검색기(retriever) 데이터베이스에 삽입하기 전에 전처리 단계를 추가합니다. 그 과정은 다음과 같습니다:

  • 각 개별 청크와 원본 소스 문서를 가져옵니다
  • 둘 다를 Claude에 전송하여 컨텍스트를 추가하도록 요청하는 특정 프롬프트와 함께 보냅니다
  • Claude는 더 큰 문서 내에서 해당 청크를 "위치시키는(situates)" 짧은 스니펫을 생성합니다
  • 이 컨텍스트를 원본 청크와 결합하여 "컨텍스트화된 청크(contextualized chunk)"를 만듭니다
  • 컨텍스트화된 청크를 벡터 및 BM25 인덱스에 사용합니다

예를 들어, 2023년에 발생한 사건을 언급하는 소프트웨어 엔지니어링 관련 섹션이 있다면, Claude는 다음과 같은 컨텍스트를 생성할 수 있습니다: "이 섹션은 여러 분야가 협력하는 그룹에 관한 더 큰 보고서에서 발췌한 것입니다. 여기에는 사이버보안 분석 섹션에서도 언급된 INC-2023-04-011에 대한 언급이 포함되어 있습니다."

대용량 문서 처리하기

흔히 발생하는 문제는 소스 문서가 너무 커서 Claude의 컨텍스트 윈도우에 맞지 않는 경우입니다. 이 경우에도 축소된 컨텍스트 세트를 제공함으로써 컨텍스트 기반 검색을 계속 사용할 수 있습니다:

전체 문서를 포함하는 대신 다음을 제공하세요:

  • 문서 시작 부분의 몇 개 청크(주로 요약이나 초록을 포함)
  • 컨텍스트화하려는 청크 바로 앞의 청크들

이 접근 방식은 프롬프트를 과도하게 채우지 않으면서도 Claude가 문서 구조와 직접적인 컨텍스트를 이해할 수 있는 충분한 정보를 제공합니다.

구현 예시

청크에 컨텍스트를 추가하는 기본 함수는 다음과 같습니다:

python
def add_context(text_chunk, source_text):
    prompt = """
Write a short and succinct snippet of text to situate this chunk within the
overall source document for the purposes of improving search retrieval of the chunk.

Here is the original source document:
<document>
{source_text}
</document>

Here is the chunk we want to situate within the whole document:
<chunk>
{text_chunk}
</chunk>

Answer only with the succinct context and nothing else.
"""
    
    messages = []
    add_user_message(messages, prompt)
    result = chat(messages)
    
    return result["text"] + "\n" + text_chunk

대용량 문서의 경우, 관련 컨텍스트 청크를 선택하는 전략을 구현할 수 있습니다:

python
# 각 청크에 컨텍스트를 추가한 후 retriever에 추가
num_start_chunks = 2
num_prev_chunks = 2

for i, chunk in enumerate(chunks):
    context_parts = []
    
    # 문서 시작 부분의 초기 청크 집합
    context_parts.extend(chunks[: min(num_start_chunks, len(chunks))])
    
    # 현재 컨텍스트화 중인 청크 앞에 있는 추가 청크
    start_idx = max(0, i - num_prev_chunks)
    context_parts.extend(chunks[start_idx:i])
    
    context = "\n".join(context_parts)
    
    contextualized_chunk = add_context(chunk, context)
    retriever.add_document({"content": contextualized_chunk})

컨텍스트 기반 검색을 사용해야 하는 경우

이 기법은 다음과 같은 경우에 가장 유용합니다:

  • 문서의 섹션 간에 복잡한 내부 관계가 있는 경우
  • 청크가 문서의 다른 곳에서 정의된 개념을 참조하는 경우
  • 정확한 검색을 위해 문서 구조를 이해하는 것이 중요한 경우
  • 기술 문서, 보고서 또는 학술 논문을 다루는 경우

컨텍스트 기반 검색은 처리 시간과 비용을 추가하지만(추가 API 호출을 하기 때문에), 컨텍스트가 중요한 복잡한 문서의 경우 검색 정확도를 크게 향상시킬 수 있습니다.