청킹 전략의 모든 것 — 문서를 어떻게 쪼갤 것인가
RAG 파이프라인에서 가장 과소평가되는 단계가 **청킹(Chunking)**입니다. 청크가 너무 크면 노이즈가 많아 LLM이 핵심을 못 찾고, 너무 작으면 컨텍스트가 부족해 엉뚱한 답변이 나옵니다. 어떻게 쪼개느냐가 RAG 전체 품질을 결정합니다.
고정 크기 청킹 (Fixed-size Chunking)
가장 단순한 방법입니다. 지정한 토큰 수마다 자릅니다.
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=64,
separators=["\n\n", "\n", ".", " "]
)
chunks = splitter.split_text(document)chunk_overlap은 청크 경계에서 문맥이 끊기는 문제를 완화합니다. 앞 청크의 끝 64토큰을 다음 청크 시작에 포함시킵니다.
적합한 경우: 구조가 없는 원시 텍스트, 빠른 프로토타이핑
의미 기반 청킹 (Semantic Chunking)
문장 간 의미 변화를 감지해서 자릅니다.
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings
chunker = SemanticChunker(
OpenAIEmbeddings(),
breakpoint_threshold_type="percentile",
breakpoint_threshold_amount=95
)
chunks = chunker.split_text(long_document)연속된 두 문장의 임베딩 코사인 유사도가 급격히 낮아지는 지점을 경계로 삼습니다. 문단이 자연스럽게 나뉘어 품질이 높지만, 임베딩 API 호출 비용이 발생합니다.
적합한 경우: 다양한 주제를 다루는 긴 문서, 품질이 중요한 경우
계층적 청킹 (Hierarchical Chunking)
문서의 구조(헤더, 섹션)를 존중하면서 계층적으로 분리합니다.
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers = [
("#", "H1"),
("##", "H2"),
("###", "H3"),
]
splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers)
chunks = splitter.split_text(markdown_doc)
# 각 청크에 메타데이터 포함됨
# chunk.metadata = {"H1": "RAG란 무엇인가", "H2": "핵심 아이디어"}메타데이터에 섹션 정보가 포함되어 검색 정확도가 높아집니다.
적합한 경우: Markdown, HTML, PDF처럼 구조가 명확한 문서
부모-자식 청킹 (Parent-Child Chunking)
저장은 작은 청크로(검색 정확도 향상), 검색 결과는 큰 청크로 LLM에 전달(컨텍스트 풍부)합니다.
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=InMemoryStore(),
child_splitter=child_splitter,
parent_splitter=parent_splitter,
)벡터 DB에는 400토큰 청크의 임베딩을 저장하고, 실제 반환할 때는 해당 청크가 속한 2000토큰 부모 청크를 가져옵니다.
전략별 비교
| 전략 | 구현 난이도 | 품질 | 비용 | 추천 상황 |
|---|---|---|---|---|
| 고정 크기 | 낮음 | 보통 | 낮음 | 빠른 MVP |
| 의미 기반 | 중간 | 높음 | 중간 | 품질 우선 |
| 계층적 | 중간 | 높음 | 낮음 | 구조화 문서 |
| 부모-자식 | 높음 | 매우 높음 | 낮음 | 프로덕션 |
메타데이터는 필수다
어떤 전략을 쓰든, 청크에 메타데이터를 반드시 붙이세요.
{
"text": "청크 내용...",
"source": "docs/api-guide.md",
"page": 3,
"section": "인증 방식",
"created_at": "2024-01-15"
}메타데이터 필터링으로 검색 범위를 좁히면 정확도가 크게 올라갑니다. "2026년 이후 문서에서만 찾기" 같은 조건이 가능해집니다.
다음 편에서는 이렇게 구축한 RAG 파이프라인을 RAGAS 프레임워크로 정량 평가하는 방법을 다룹니다.
문서 유형별 청킹 의사결정표
어떤 전략이 '항상' 옳지는 않습니다 — 문서 유형이 전략을 결정합니다.
| 문서 유형 | 권장 전략 | 이유·주의 |
|---|---|---|
| 기술 문서·매뉴얼 (헤딩 구조 명확) | 계층적 청킹 (헤딩 경계) | 섹션이 곧 의미 단위 — 헤딩을 메타데이터로 보존 |
| FAQ·Q&A | Q+A 한 쌍 = 1청크 | 쪼개면 질문-답 연결이 끊어져 최악의 결과 |
| 법령·계약서 | 조·항 단위 + 상위 조 참조 메타데이터 | "제3조에 따라" 같은 상호참조가 많아 부모-자식이 유리 |
| 코드·API 문서 | 함수/클래스 단위 | 고정 크기로 자르면 시그니처와 본문이 분리됨 |
| 표가 많은 문서 | 표는 통째로 1청크 + 표 요약문 병행 저장 | 표를 중간에 자르면 의미가 사라짐 |
| 채팅·회의록 | 화자 턴 묶음 + 시간 메타데이터 | 고정 크기 무난, 시간 필터가 검색 품질을 좌우 |
청킹 품질을 확인하는 법
- 대표 질문 50개로 검색된 청크를 직접 눈으로 검수 — "이 청크만 보고 답할 수 있는가?"
- 청크 단독 가독성 테스트: 무작위 청크 20개를 뽑아 문맥 없이 읽어 이해되는 비율 확인
- 실패 질문은 청크 크기 문제인지 검색 문제인지 구분 — 정답 문서의 청크가 검색은 됐는데 잘려 있으면 청킹 문제
이 글은 AI 에이전트가 자료 조사와 1차 초안 작성을 담당하고, 사람 편집자가 사실관계·출처·톤과 맥락을 검토한 뒤 발행했습니다. 환경(OS·버전)에 따라 결과가 다를 수 있으니 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
댓글
첫 번째 댓글을 남겨보세요.