
긴 문서를 그대로 사용하면 LLM의 컨텍스트 제한을 초과하거나 검색 정확도가 떨어질 수 있습니다. Text Splitter를 사용하면 문서를 적절한 크기의 청크(chunk)로 분할할 수 있습니다. 본 포스트에서는 다양한 Text Splitter 사용법을 정리합니다.
Text Splitter를 사용하기 위해 필요한 패키지를 설치합니다.
pip install langchain
| 패키지 | 설명 |
|---|---|
langchain | LangChain 프레임워크 (text-splitters, community 등 의존성 포함) |
SemanticChunker를 사용하려면 추가로
pip install langchain-experimental langchain-openai python-dotenv가 필요합니다.
가장 기본적인 스플리터로, 지정한 구분자를 기준으로 분할합니다.
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) |
여러 구분자를 우선순위대로 시도하여 분할합니다. 가장 권장되는 스플리터입니다.
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은 청크 간에 겹치는 부분을 만들어 문맥 연결을 유지합니다.
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를 분할할 때는 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}")
로더와 스플리터를 한 번에 사용할 수 있습니다.
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)}개")
의미 기반으로 문서를 분할합니다. 임베딩을 사용하여 의미가 유사한 문장끼리 묶습니다.
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 | 특징 | 사용 시점 |
|---|---|---|
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)