RAG 파이프라인의 2단계인 핵심 전처리: 크고 복잡한 문서를 LLM이 처리 가능한 청크로 쪼개 정확하고 경제적인 검색·답변을 노린다.
기본 가이드:
- 텍스트형 문서: 300–800 토큰 / 10–20% overlap
- 고구조 문서(JSON/코드/Markdown/HTML): 구조 기준 분할 + 소형 재분할(200–500 토큰, 10–15%)
- 긴 문단/서사형: 의미 기반(SemanticChunker) + 250–700 토큰, 10–15%
- “문자 수” 기준 분할 시: 토큰≈문자/3(한-영 혼용은 가변)로 대략 환산
| Splitter | 기준 | 특징 | 장점 | 단점 | 추천 chunk_size | 추천 overlap | 적합한 상황 |
|---|---|---|---|---|---|---|---|
| CharacterTextSplitter | 문자(\n\n 기본) | 단순, 빠름 | 구현 쉬움 | 의미 단위 손실 | 1200–2400자 | 10–15% | 구조 적은 텍스트, 로그 |
| RecursiveCharacterTextSplitter | ["\n\n","\n"," ",""] 재귀 | 단락→문장→단어 | 맥락 유지 | 약간 느림 | 300–800토큰 | 10–20% | 일반 문서/기사/리포트 |
| TokenTextSplitter | 토큰 | LLM 한계 정확 대응 | 의미 단위 무시 가능 | 300–800토큰 | 10–15% | 모델 입력 최적화 필수일 때 | |
| from_tiktoken / HF tokenizer | 토크나이저 | 모델별 토큰 정확 | 구현 복잡 | 300–800토큰 | 10–15% | OpenAI/HF 모델 정밀 제어 | |
| SentenceTransformersTokenTextSplitter | 토큰 + 의미 유지 | sBERT류에 최적화 | 의존성↑ | 200–500토큰 | 0–10% | 임베딩 검색 정확도↑ | |
| spaCyTextSplitter | 문장 | 유럽 언어 강점 | 언어 모델 필요 | 300–700토큰 | 10–15% | 영어 문장 위주 문서 | |
| NLTKTextSplitter | 문장 | 가볍고 빠름 | 품질이 다소 낮을 수 | 300–700토큰 | 10–15% | 학습 자료, 문서 초벌 | |
| KoNLPy(Kkma) Splitter | 한국어 문장·형태소 | 한국어 강점 | 속도↓ | 250–600토큰 | 10–15% | 한국어 긴 문장 처리 | |
| SemanticChunker | 임베딩 유사도 | 의미 유지 최고 | 비용·속도 부담 | 250–700토큰 | 10–15% | 정확도 최우선 RAG | |
| CodeTextSplitter | 언어별 구분자 | 함수/클래스 단위 | 언어 세팅 필요 | 80–200토큰 | 0–5% | 코드 검색·설명 | |
| MarkdownHeaderTextSplitter | 헤더 | 구조 인식, 메타 유지 | 헤더 없으면 X | (헤더별) 300–700토큰로 재분할 | 10% | 기술문서/README | |
| HTMLHeaderTextSplitter | h1~h4 | 웹 문서 구조 반영 | HTML 구조 편차 | (섹션별) 300–700토큰로 재분할 | 10% | 웹페이지, 뉴스 | |
| RecursiveJsonSplitter | JSON 값 | 중첩 보존, DFS | 리스트 기본 비분할 | (객체 청크화 후) 200–500토큰로 재분할 | 5–10% | API 응답/스키마 |
✅ 모델 컨텍스트 창이 크더라도, 청크는 너무 크게 잡지 않는 것이 검색 품질과 재랭킹 효율에 유리(Top-k가 의미 있게 작동).
문서 구조 먼저 파악
chunk_size
overlap
쿼리-청크 매칭 실패 시
성능-비용 트레이드오프
RecursiveCharacterTextSplitter(300–800, 10–20%)MarkdownHeaderTextSplitter(strip_headers=False)RecursiveCharacterTextSplitter(300–700, 10%)HTMLHeaderTextSplitter(h1~h4)RecursiveCharacterTextSplitter(300–700, 10%)RecursiveJsonSplitter(max_chunk_size≈2–4KB)convert_lists=TrueRecursiveCharacterTextSplitter(200–500, 5–10%)로 2차 분할CodeTextSplitter(Language=언어)로 함수/클래스 단위KoNLPy(Kkma)로 문장 분할RecursiveCharacterTextSplitter(250–600, 10–15%)SemanticChunker(Percentile 60–75)# 1) 일반 문서
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=80)
docs = splitter.create_documents([text])
# 2) Markdown → 구조 유지 후 재분할
from langchain_text_splitters import MarkdownHeaderTextSplitter
md = MarkdownHeaderTextSplitter(headers_to_split_on=[("#","H1"),("##","H2")], strip_headers=False)
sections = md.split_text(markdown_text)
fine = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50).split_documents(sections)
# 3) 의미 기반
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings
sem = SemanticChunker(OpenAIEmbeddings(), breakpoint_threshold_type="percentile", breakpoint_threshold_amount=70)
sem_chunks = sem.create_documents([text])
# 4) JSON
from langchain_text_splitters import RecursiveJsonSplitter
js = RecursiveJsonSplitter(max_chunk_size=3000)
json_docs = js.create_documents([json_obj]) # 이후 200–500 토큰으로 재분할 권장
✨ 추천 기본값(안전빵): 600 토큰 / 80 토큰 overlap(≈13%)
문서·질문 특성에 따라 ±200 토큰 범위에서 조정해보자.