SemanticChunker

텍스트 분할

효율적인 문서 청킹을 위한 다양한 텍스트 분할 전략을 다룬다.

AI
RAG
LangChain
저자

Kwangmin Kim

공개

2024년 12월 31일

텍스트를 의미론적 유사성에 기반하여 분할합니다.

Reference

이 방법은 텍스트를 문장 단위로 분할한 후, 3개의 문장씩 그룹화하고, 임베딩 공간에서 유사한 문장들을 병합하는 과정을 거칩니다.

샘플 텍스트를 로드하고 내용을 출력합니다.

# data/appendix-keywords.txt 파일을 열어서 f라는 파일 객체를 생성합니다.
with open("./data/appendix-keywords.txt") as f:
    file = f.read()  # 파일의 내용을 읽어서 file 변수에 저장합니다.

# 파일으로부터 읽은 내용을 일부 출력합니다.
print(file[:350])

1 SemanticChunker 생성

SemanticChunker는 LangChain의 실험적 기능 중 하나로, 텍스트를 의미론적으로 유사한 청크로 분할하는 역할을 합니다.

이를 통해 텍스트 데이터를 보다 효과적으로 처리하고 분석할 수 있습니다.

# API 키를 환경변수로 관리하기 위한 설정 파일
from dotenv import load_dotenv

# API 키 정보 로드
load_dotenv()

SemanticChunker를 사용하여 텍스트를 의미적으로 관련된 청크로 분할합니다.

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings

# OpenAI 임베딩을 사용하여 의미론적 청크 분할기를 초기화합니다.
text_splitter = SemanticChunker(OpenAIEmbeddings())

2 텍스트 분할

  • text_splitter를 사용하여 file 텍스트를 문서 단위로 분할합니다.
chunks = text_splitter.split_text(file)

분할된 청크를 확인합니다.

# 분할된 청크 중 첫 번째 청크를 출력합니다.
print(chunks[0])

create_documents() 함수를 사용하여 청크를 문서로 변환할 수 있습니다.

# text_splitter를 사용하여 분할합니다.
docs = text_splitter.create_documents([file])
print(docs[0].page_content)  # 분할된 문서 중 첫 번째 문서의 내용을 출력합니다.

3 Breakpoints

이 chunker는 문장을 “분리”할 시점을 결정하여 작동합니다. 이는 두 문장 간의 임베딩 차이를 살펴봄으로써 이루어집니다.

그 차이가 특정 임계값을 넘으면 문장이 분리됩니다.

  • 참고 영상: https://youtu.be/8OJC21T2SL4?si=PzUtNGYJ_KULq3-w&t=2580

3.1 Percentile

기본적인 분리 방식은 백분위수(Percentile) 를 기반으로 합니다.

이 방법에서는 문장 간의 모든 차이를 계산한 다음, 지정한 백분위수를 기준으로 분리합니다.

text_splitter = SemanticChunker(
    # OpenAI의 임베딩 모델을 사용하여 시맨틱 청커를 초기화합니다.
    OpenAIEmbeddings(),
    # 분할 기준점 유형을 백분위수로 설정합니다.
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=70,
)

분할된 결과를 확인합니다.

docs = text_splitter.create_documents([file])
for i, doc in enumerate(docs[:5]):
    print(f"[Chunk {i}]", end="\n\n")
    print(doc.page_content)  # 분할된 문서 중 첫 번째 문서의 내용을 출력합니다.
    print("===" * 20)

docs의 길이를 출력합니다.

print(len(docs))  # docs의 길이를 출력합니다.

3.2 Standard Deviation

이 방법에서는 지정한 breakpoint_threshold_amount 표준편차보다 큰 차이가 있는 경우 분할됩니다.

  • breakpoint_threshold_type 매개변수를 “standard_deviation”으로 설정하여 청크 분할 기준을 표준편차 기반으로 지정합니다.
text_splitter = SemanticChunker(
    # OpenAI의 임베딩 모델을 사용하여 시맨틱 청커를 초기화합니다.
    OpenAIEmbeddings(),
    # 분할 기준으로 표준 편차를 사용합니다.
    breakpoint_threshold_type="standard_deviation",
    breakpoint_threshold_amount=1.25,
)

분할된 결과를 확인합니다.

# text_splitter를 사용하여 분할합니다.
docs = text_splitter.create_documents([file])
docs = text_splitter.create_documents([file])
for i, doc in enumerate(docs[:5]):
    print(f"[Chunk {i}]", end="\n\n")
    print(doc.page_content)  # 분할된 문서 중 첫 번째 문서의 내용을 출력합니다.
    print("===" * 20)

docs의 길이를 출력합니다.

print(len(docs))  # docs의 길이를 출력합니다.

3.3 Interquartile

이 방법에서는 사분위수 범위(interquartile range)를 사용하여 청크를 분할합니다.

  • breakpoint_threshold_type 매개변수를 “interquartile”로 설정하여 청크 분할 기준을 사분위수 범위로 지정합니다.
text_splitter = SemanticChunker(
    # OpenAI의 임베딩 모델을 사용하여 의미론적 청크 분할기를 초기화합니다.
    OpenAIEmbeddings(),
    # 분할 기준점 임계값 유형을 사분위수 범위로 설정합니다.
    breakpoint_threshold_type="interquartile",
    breakpoint_threshold_amount=0.5,
)
# text_splitter를 사용하여 분할합니다.
docs = text_splitter.create_documents([file])

# 결과를 출력합니다.
for i, doc in enumerate(docs[:5]):
    print(f"[Chunk {i}]", end="\n\n")
    print(doc.page_content)  # 분할된 문서 중 첫 번째 문서의 내용을 출력합니다.
    print("===" * 20)

docs의 길이를 출력합니다.

print(len(docs))  # docs의 길이를 출력합니다.

Subscribe

Enjoy this blog? Get notified of new posts by email: