Text Splitters로 문서 청킹하기

gclee·2026년 1월 21일

LangChain-RAG

목록 보기
8/13

긴 문서를 그대로 사용하면 LLM의 컨텍스트 제한을 초과하거나 검색 정확도가 떨어질 수 있습니다. Text Splitter를 사용하면 문서를 적절한 크기의 청크(chunk)로 분할할 수 있습니다. 본 포스트에서는 다양한 Text Splitter 사용법을 정리합니다.


준비 사항

  • Python 3.9 이상
  • 테스트용 문서 파일

라이브러리 설치

Text Splitter를 사용하기 위해 필요한 패키지를 설치합니다.

pip install langchain
패키지설명
langchainLangChain 프레임워크 (text-splitters, community 등 의존성 포함)

SemanticChunker를 사용하려면 추가로 pip install langchain-experimental langchain-openai python-dotenv가 필요합니다.


청킹이 필요한 이유

  • LLM 컨텍스트 제한: LLM은 한 번에 처리할 수 있는 토큰 수에 제한이 있음
  • 검색 정확도: 작은 청크가 더 정확한 유사도 검색 가능
  • 비용 효율성: 필요한 부분만 LLM에 전달하여 토큰 사용량 절약

CharacterTextSplitter

가장 기본적인 스플리터로, 지정한 구분자를 기준으로 분할합니다.

from langchain_text_splitters import CharacterTextSplitter

text = """첫 번째 문단입니다.
여기에 내용이 있습니다.

두 번째 문단입니다.
다른 내용이 있습니다.

세 번째 문단입니다.
마지막 내용입니다."""

splitter = CharacterTextSplitter(
    separator="\n\n",
    chunk_size=50,
    chunk_overlap=10
)

chunks = splitter.split_text(text)

for i, chunk in enumerate(chunks):
    print(f"청크 {i+1}: {chunk}")
    print("---")

주요 파라미터

파라미터설명
separator분할 기준 문자 (기본: \n\n)
chunk_size청크 최대 크기
chunk_overlap청크 간 겹치는 크기
length_function길이 계산 함수 (기본: len)

RecursiveCharacterTextSplitter

여러 구분자를 우선순위대로 시도하여 분할합니다. 가장 권장되는 스플리터입니다.

from langchain_text_splitters import RecursiveCharacterTextSplitter

text = """# 제목

## 소제목 1

첫 번째 섹션의 내용입니다.
여러 줄로 구성되어 있습니다.

## 소제목 2

두 번째 섹션의 내용입니다.
이것도 여러 줄입니다."""

splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=20,
    separators=["\n\n", "\n", " ", ""]
)

chunks = splitter.split_text(text)

for i, chunk in enumerate(chunks):
    print(f"청크 {i+1} (길이: {len(chunk)})")
    print(chunk)
    print("---")

기본 구분자 순서

separators = ["\n\n", "\n", " ", ""]
# 1. 빈 줄 기준으로 분할 시도
# 2. 줄바꿈 기준으로 분할 시도
# 3. 공백 기준으로 분할 시도
# 4. 문자 단위로 분할

chunk_overlap의 역할

chunk_overlap은 청크 간에 겹치는 부분을 만들어 문맥 연결을 유지합니다.

from langchain_text_splitters import RecursiveCharacterTextSplitter

text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# overlap 없음
splitter_no_overlap = RecursiveCharacterTextSplitter(
    chunk_size=10,
    chunk_overlap=0
)
print("Overlap 0:", splitter_no_overlap.split_text(text))
# ['ABCDEFGHIJ', 'KLMNOPQRST', 'UVWXYZ']

# overlap 있음
splitter_with_overlap = RecursiveCharacterTextSplitter(
    chunk_size=10,
    chunk_overlap=3
)
print("Overlap 3:", splitter_with_overlap.split_text(text))
# ['ABCDEFGHIJ', 'HIJKLMNOPQ', 'OPQRSTUVWX', 'VWXYZ']

Document와 함께 사용하기

로더에서 불러온 Document를 분할할 때는 split_documents() 메서드를 사용합니다.

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 1. 문서 로드
loader = TextLoader("./docs/sample.txt", encoding="utf-8")
documents = loader.load()

# 2. 문서 분할
splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,
    chunk_overlap=50
)

chunks = splitter.split_documents(documents)

print(f"원본 문서: {len(documents)}개")
print(f"분할된 청크: {len(chunks)}개")

for i, chunk in enumerate(chunks[:3]):
    print(f"\n청크 {i+1}:")
    print(f"내용: {chunk.page_content[:50]}...")
    print(f"메타데이터: {chunk.metadata}")

load_and_split() 메서드

로더와 스플리터를 한 번에 사용할 수 있습니다.

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

loader = TextLoader("./docs/sample.txt", encoding="utf-8")
splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,
    chunk_overlap=50
)

# 로드와 분할을 한 번에
chunks = loader.load_and_split(splitter)

print(f"분할된 청크: {len(chunks)}개")

SemanticChunker

의미 기반으로 문서를 분할합니다. 임베딩을 사용하여 의미가 유사한 문장끼리 묶습니다.

pip install langchain-experimental
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings
from dotenv import load_dotenv

load_dotenv()

embeddings = OpenAIEmbeddings()

splitter = SemanticChunker(embeddings)

text = """인공지능은 컴퓨터가 인간처럼 생각하게 하는 기술입니다.
머신러닝은 인공지능의 한 분야입니다.

오늘 날씨가 매우 좋습니다.
산책하기 좋은 날씨입니다."""

chunks = splitter.split_text(text)

for i, chunk in enumerate(chunks):
    print(f"청크 {i+1}: {chunk}")

주의: SemanticChunker는 임베딩 API를 호출하므로 비용이 발생할 수 있습니다.


Splitter 비교 정리

Splitter특징사용 시점
CharacterTextSplitter단일 구분자 사용단순한 분할
RecursiveCharacterTextSplitter여러 구분자 우선순위 적용일반적인 상황 (권장)
SemanticChunker의미 기반 분할정교한 분할 필요 시

전체 예제 코드

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 1. 문서 로드
loader = TextLoader("./docs/sample.txt", encoding="utf-8")

# 2. 스플리터 설정
splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,
    chunk_overlap=50,
    separators=["\n\n", "\n", " ", ""]
)

# 3. 로드 및 분할
chunks = loader.load_and_split(splitter)

# 4. 결과 확인
print(f"총 청크 수: {len(chunks)}")
print("\n=== 첫 3개 청크 ===")

for i, chunk in enumerate(chunks[:3]):
    print(f"\n[청크 {i+1}] 길이: {len(chunk.page_content)}")
    print(chunk.page_content)
    print("-" * 50)

0개의 댓글