Chunking은 RAG 시스템에서 원본 문서를 검색 가능한 단위로 분할하는 과정입니다. Chunk 크기와 분할 방식은 검색 정밀도, 응답 품질, 비용에 직접적인 영향을 미칩니다.
핵심 요약
- Chunking은 RAG 파이프라인에서 검색 품질을 결정하는 가장 중요한 단일 변수입니다.
- Chunk가 너무 작으면 문맥이 유실되고, 너무 크면 노이즈가 섞여 검색 정밀도가 떨어집니다.
- 전략 선택은 문서 구조, 질문 유형, 응답 요구사항에 따라 달라집니다.
- 운영 환경에서는 단일 전략보다 Overlap, Parent-Child, Metadata 보강을 조합하는 것이 일반적입니다.
- Chunk 크기는 이론적 정답이 없으므로, 평가 데이터셋을 기반으로 실험하고 측정하는 방식이 필요합니다.
1. 왜 Chunking이 중요한가
RAG 시스템을 구축할 때 가장 먼저 부딪히는 문제가 있습니다. 사내 기술 문서 500페이지를 벡터 저장소에 넣었는데, 질문에 엉뚱한 답변이 나오는 상황입니다.
원인을 추적하면 대부분 검색 단계에서 잘못된 문서 조각이 반환된 것입니다. 그리고 그 근본 원인은 문서를 어떻게 나눴는지에 있습니다.
예를 들어 보겠습니다.
- 10페이지짜리 장애 대응 매뉴얼을 통째로 하나의 Chunk로 만들면, "DB 장애 시 연락처가 뭐야?"라는 질문에 전체 매뉴얼이 반환됩니다. LLM은 불필요한 정보 속에서 답을 찾아야 합니다.
- 반대로 문장 단위로 잘게 나누면, "프로덕션 DB가 다운됐을 때 RTO는 얼마야?"라는 질문에 "RTO는 4시간입니다"라는 조각만 반환되고, 그 RTO가 어떤 조건에서 적용되는지의 문맥이 사라집니다.
Chunking 전략은 이 균형점을 찾는 작업입니다. 검색 정밀도(필요한 정보만 반환)와 문맥 보존(충분한 맥락 유지) 사이의 trade-off를 문서 특성에 맞게 설계해야 합니다.
2. Chunking이 RAG 성능에 미치는 영향
Chunk 설계가 영향을 미치는 영역은 크게 네 가지입니다.
2.1 검색 정밀도 (Retrieval Precision)
Chunk 크기가 크면 하나의 Chunk 안에 여러 주제가 섞입니다. 임베딩 벡터는 Chunk 전체의 평균적인 의미를 표현하므로, 특정 질문과의 유사도가 희석됩니다.
반대로 Chunk가 작으면 하나의 주제만 담기므로 의미가 명확하지만, 정보량이 부족하여 질문에 부분적으로만 관련된 조각이 검색될 수 있습니다.
2.2 응답 품질 (Generation Quality)
LLM은 전달받은 컨텍스트를 기반으로 답변을 생성합니다. 검색된 Chunk에 질문에 대한 답이 완전히 포함되어 있으면 정확한 답변이 나옵니다. 반면 답이 여러 Chunk에 걸쳐 있는데 일부만 검색되면, LLM이 불완전한 정보로 답하거나 Hallucination을 생성합니다.
2.3 비용
Chunk가 작으면 전체 Chunk 수가 많아집니다. 이는 다음 비용에 영향을 줍니다. - 임베딩 비용: Chunk 수만큼 임베딩 API를 호출합니다. - 저장소 비용: 벡터 저장소에 저장되는 레코드 수가 증가합니다. - LLM 비용: Top-K로 가져오는 Chunk 수가 동일해도, 작은 Chunk K개보다 큰 Chunk K개가 더 많은 토큰을 소비합니다.
2.4 지연 시간
Chunk 수가 많으면 벡터 검색 시 비교 대상이 많아져 검색 시간이 증가할 수 있습니다. 다만 대부분의 벡터 DB는 ANN(Approximate Nearest Neighbor) 인덱스를 사용하므로, 수백만 건 이하에서는 실질적 차이가 크지 않습니다.
3. Chunking 전략 종류

3.1 Fixed-size Chunking (고정 크기 분할)
가장 단순한 방식입니다. 문서를 고정된 토큰 수 또는 문자 수로 균일하게 나눕니다.
# LangChain 예시
from langchain.text_splitter import CharacterTextSplitter
splitter = CharacterTextSplitter(
chunk_size=500, # 500자 단위
chunk_overlap=50, # 50자 겹침
separator="\n" # 줄바꿈 기준 분할
)
chunks = splitter.split_text(document)
| 장점 | 단점 |
|---|---|
| 구현이 단순하고 예측 가능 | 문장이나 문단 중간에서 잘릴 수 있음 |
| Chunk 크기가 균일하여 임베딩 품질이 일정 | 의미 단위를 무시하므로 문맥이 끊길 수 있음 |
| 어떤 문서에도 적용 가능 | 최적의 크기를 찾기 위한 실험이 필요 |
적합한 경우: 문서 구조가 불규칙하거나, 빠르게 프로토타입을 만들어야 할 때. 로그 파일, 채팅 이력처럼 구조가 없는 텍스트에도 사용합니다.
3.2 Recursive Character Splitting (재귀적 분할)
LangChain에서 기본으로 권장하는 방식입니다. 여러 단계의 구분자를 우선순위대로 적용하여 가능한 한 의미 있는 단위를 유지합니다.
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", ". ", " ", ""] # 우선순위 순
)
chunks = splitter.split_text(document)
분할 순서: 1. 먼저 \n\n(빈 줄, 문단 구분)으로 나눕니다. 2. 결과가 chunk_size보다 크면 \n(줄바꿈)으로 나눕니다. 3. 그래도 크면 .(문장 끝)으로 나눕니다. 4. 마지막으로 공백, 문자 단위로 나눕니다.
| 장점 | 단점 |
|---|---|
| 문단/문장 경계를 존중하므로 문맥 유지가 나음 | 구분자 우선순위 설정에 문서 이해가 필요 |
| Fixed-size보다 자연스러운 분할 | 마크다운, HTML 등 포맷에 따라 구분자 조정 필요 |
| 범용적으로 사용 가능 | Chunk 크기가 불균일할 수 있음 |
적합한 경우: 마크다운 문서, 기술 문서, 블로그 글 등 문단 구조가 있는 일반 텍스트. 대부분의 경우 첫 번째 선택지로 적합합니다.
3.3 Semantic Chunking (의미 기반 분할)
문서의 의미적 연관성을 기반으로 분할합니다. 인접 문장들의 임베딩 유사도를 계산하여, 유사도가 급격히 떨어지는 지점을 Chunk 경계로 설정합니다.
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings
splitter = SemanticChunker(
embeddings=OpenAIEmbeddings(),
breakpoint_threshold_type="percentile", # 분할 기준
breakpoint_threshold_amount=95 # 상위 5% 변화점에서 분할
)
chunks = splitter.create_documents([document])
동작 원리: 1. 문서를 문장 단위로 분리합니다. 2. 각 문장을 임베딩합니다. 3. 인접 문장 간 코사인 유사도를 계산합니다. 4. 유사도가 임계값 이하로 떨어지는 지점에서 Chunk를 분리합니다.
| 장점 | 단점 |
|---|---|
| 의미 단위로 분할하므로 검색 정밀도가 높음 | 임베딩 API 호출이 문장마다 필요 (비용 증가) |
| 주제 전환 지점을 자동으로 감지 | 처리 시간이 다른 전략보다 길음 |
| 문서 구조에 의존하지 않음 | 임계값 설정에 따라 결과 변동이 큼 |
적합한 경우: 문서 구조가 불규칙하지만 주제별로 내용이 묶이는 경우. 회의록, 인터뷰 전사본, 긴 이메일 스레드 등에 효과적입니다.
3.4 Document Structure-based Chunking (문서 구조 기반 분할)
마크다운 헤딩, HTML 태그, PDF 섹션 등 문서 자체의 구조를 활용하여 분할합니다.
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers_to_split_on = [
("#", "Header 1"),
("##", "Header 2"),
("###", "Header 3"),
]
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=headers_to_split_on
)
chunks = splitter.split_text(markdown_document)
| 장점 | 단점 |
|---|---|
| 문서 작성자의 의도대로 구조를 유지 | 문서에 구조가 없으면 사용 불가 |
| 헤딩 정보를 메타데이터로 보존 가능 | 섹션 크기가 불균일 (한 섹션이 매우 클 수 있음) |
| 검색 시 섹션 컨텍스트를 함께 제공 | 구조 파싱 로직이 문서 포맷마다 다름 |
적합한 경우: 마크다운/HTML로 작성된 기술 문서, API 문서, 위키 페이지. 구조가 명확한 공식 문서에 효과적입니다.
3.5 Parent-Child Chunking (계층적 분할)
검색과 응답 생성에 서로 다른 크기의 Chunk를 사용하는 전략입니다. 작은 Chunk(Child)로 정밀하게 검색하고, 검색된 Child의 상위 Chunk(Parent)를 LLM에 전달합니다.
[Parent Chunk: 2000 토큰]
├── [Child Chunk 1: 300 토큰] ← 검색 대상
├── [Child Chunk 2: 300 토큰] ← 검색 대상
├── [Child Chunk 3: 300 토큰] ← 검색 대상
└── ...
동작 방식: 1. 문서를 큰 Parent Chunk로 먼저 나눕니다 (1000~2000 토큰). 2. 각 Parent를 작은 Child Chunk로 다시 나눕니다 (200~400 토큰). 3. Child Chunk만 임베딩하여 벡터 저장소에 저장합니다. 4. 검색 시 Child로 검색하되, 반환할 때는 해당 Child의 Parent를 반환합니다.
| 장점 | 단점 |
|---|---|
| 검색 정밀도와 문맥 보존을 동시에 확보 | 구현 복잡도가 높음 |
| Small-to-big 검색으로 노이즈 감소 | Parent-Child 관계를 별도로 관리해야 함 |
| LLM이 충분한 컨텍스트를 받을 수 있음 | 저장소 용량이 증가 (Child + Parent 모두 저장) |
적합한 경우: 검색 정밀도와 응답 품질을 모두 높여야 하는 프로덕션 환경. 특히 긴 문서에서 특정 세부 정보를 정확히 찾아야 하는 경우에 효과적입니다.
4. Chunk 크기가 성능에 미치는 영향
4.1 크기별 특성
| Chunk 크기 | 검색 정밀도 | 문맥 보존 | 비용 효율 | 적합한 질문 유형 |
|---|---|---|---|---|
| 100~200 토큰 | 높음 | 낮음 | 높음 (Chunk 수 많음) | 사실 확인형 ("X의 값은?") |
| 300~500 토큰 | 중간~높음 | 중간 | 균형 | 일반적인 질문 |
| 500~1000 토큰 | 중간 | 높음 | 낮음 (토큰 소비 많음) | 맥락 필요형 ("왜 X를 선택했나?") |
| 1000+ 토큰 | 낮음 | 매우 높음 | 낮음 | 요약/분석형 |
4.2 실무 기준
운영 환경에서 일반적으로 사용되는 기준입니다.
- 시작점: 300~500 토큰으로 시작하여 평가 결과를 보고 조정합니다.
- Overlap: Chunk 크기의 10~15%를 겹침으로 설정합니다 (예: 500 토큰 Chunk → 50~75 토큰 Overlap).
- 최소 크기: 50 토큰 미만의 Chunk는 의미 있는 정보를 담기 어려우므로 필터링합니다.
- 최대 크기: 임베딩 모델의 최대 토큰 한계를 초과하면 잘리므로, 모델별 한계를 확인합니다.
4.3 임베딩 모델별 토큰 한계
| 모델 | 최대 토큰 | 차원 수 | 비고 |
|---|---|---|---|
| OpenAI text-embedding-3-small | 8,191 | 1,536 | 비용 대비 성능 균형 |
| OpenAI text-embedding-3-large | 8,191 | 3,072 | 높은 정밀도 필요 시 |
| Cohere embed-v4 | 128,000 | 256~1,536 (설정 가능) | 멀티모달 지원, 긴 문서 처리 가능 |
| Amazon Titan Embeddings V2 | 8,192 | 1,024 | AWS 생태계 통합 |
5. Overlap (겹침) 전략
Chunk 간 겹침(Overlap)은 분할 지점에서 발생하는 문맥 유실을 보완합니다.
5.1 왜 Overlap이 필요한가
문서에서 중요한 정보가 Chunk 경계에 걸쳐 있을 수 있습니다.
[Chunk 1]
... RTO는 프로덕션 환경 기준 4시간이며,
[Chunk 2]
이 기준은 단일 AZ 장애 시에만 적용됩니다. Multi-AZ 장애의 경우 ...
Overlap 없이 분할하면, "프로덕션 RTO가 4시간인 조건은?"이라는 질문에 Chunk 1만 검색되어 조건 정보가 누락됩니다.
5.2 Overlap 크기 가이드라인
| Chunk 크기 | 권장 Overlap | 비율 |
|---|---|---|
| 200 토큰 | 20~30 토큰 | 10~15% |
| 500 토큰 | 50~75 토큰 | 10~15% |
| 1000 토큰 | 100~150 토큰 | 10~15% |
Overlap이 너무 크면 중복 정보로 인해 검색 시 동일한 내용이 여러 Chunk에서 반환됩니다. 이 경우 LLM이 소비하는 토큰이 늘어나고, 비용이 증가합니다.
6. 실무 시나리오별 전략 선택
시나리오 1: 사내 기술 문서 검색 시스템
상황: Confluence에 작성된 기술 문서 300개를 RAG로 검색합니다. 문서는 마크다운 형식이며, 헤딩으로 구조화되어 있습니다.
선택 전략: Document Structure-based + Recursive 조합
# 1단계: 마크다운 헤딩으로 1차 분할
header_splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[("#", "H1"), ("##", "H2"), ("###", "H3")]
)
sections = header_splitter.split_text(document)
# 2단계: 큰 섹션은 Recursive로 재분할
recursive_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50
)
final_chunks = []
for section in sections:
if len(section.page_content) > 500:
sub_chunks = recursive_splitter.split_text(section.page_content)
final_chunks.extend(sub_chunks)
else:
final_chunks.append(section.page_content)
이유: 기술 문서는 섹션 구조가 의미 단위와 일치하는 경우가 많습니다. 헤딩 기반으로 먼저 나누면 주제별 분리가 자연스럽고, 너무 긴 섹션만 추가 분할합니다.
시나리오 2: 법률/계약서 검색 시스템
상황: 계약서, 약관, 규정 문서를 검색합니다. 조항 번호가 있으며, 하나의 조항이 여러 하위 항목을 포함합니다.
선택 전략: Parent-Child + 조항 단위 분할
이유: 법률 문서는 조항 간 참조가 많고, 하나의 조항 내 하위 항목이 서로 의존합니다. Child로 정밀 검색하되, Parent로 충분한 맥락을 제공하여 "제3조 2항에 따라"와 같은 참조를 해석할 수 있게 합니다.
시나리오 3: 고객 지원 FAQ
상황: Q&A 쌍으로 구성된 FAQ 문서를 검색합니다. 각 Q&A가 독립적입니다.
선택 전략: Q&A 쌍 단위 분할 (하나의 질문-답변을 하나의 Chunk로)
이유: FAQ는 각 항목이 독립적인 의미 단위입니다. Q&A를 합쳐서 하나의 Chunk로 만들면, 질문의 의미와 답변의 내용이 모두 임베딩에 반영되어 검색 정밀도가 높아집니다.
시나리오 4: 코드 문서 + API 레퍼런스
상황: 함수 설명, 파라미터 목록, 예제 코드가 포함된 API 문서를 검색합니다.
선택 전략: 코드 전용 Splitter + 함수/클래스 단위 분할
from langchain.text_splitter import Language, RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON,
chunk_size=1000,
chunk_overlap=100
)
이유: 코드는 함수/클래스 경계가 의미 단위입니다. 일반 텍스트 구분자로 나누면 함수 중간에서 잘릴 수 있습니다. 언어별 Splitter는 함수 정의, 클래스 정의 경계를 인식합니다.
7. Metadata 보강 전략
Chunk를 나눈 후 메타데이터를 추가하면 검색 시 필터링과 맥락 복원에 도움이 됩니다.
7.1 필수 메타데이터
| 메타데이터 | 용도 | 예시 |
|---|---|---|
| source | 원본 문서 식별 | confluence/architecture/vpc-design.md |
| section_title | 해당 Chunk의 섹션 제목 | "3.2 보안 그룹 설계" |
| chunk_index | 문서 내 순서 | 5 (5번째 Chunk) |
| created_at | 문서 생성/수정 일자 | "2026-05-15" |
| access_level | 접근 권한 | "team-infra" |
7.2 Contextual Chunk Header
Chunk 앞에 상위 문맥 정보를 텍스트로 추가하는 방식입니다. 임베딩 시 이 헤더도 함께 인코딩되어, 검색 정밀도가 향상됩니다.
[문서: VPC 설계 가이드 | 섹션: 3.2 보안 그룹 설계]
보안 그룹은 인스턴스 레벨에서 인바운드/아웃바운드 트래픽을 제어합니다.
Stateful 특성으로 인해 응답 트래픽은 자동 허용됩니다...
이 방식은 Chunk만으로는 알 수 없는 "이 내용이 어떤 문서의 어떤 섹션에 속하는지"를 임베딩에 반영합니다.
8. 평가와 최적화
8.1 평가 기준
Chunking 전략의 효과를 측정하기 위한 지표입니다.
| 지표 | 설명 | 측정 방법 |
|---|---|---|
| Retrieval Precision@K | Top-K 결과 중 관련 문서 비율 | 평가 데이터셋 기반 |
| Retrieval Recall@K | 전체 관련 문서 중 Top-K에 포함된 비율 | 평가 데이터셋 기반 |
| Context Relevance | LLM에 전달된 컨텍스트의 관련성 | LLM-as-Judge 또는 수동 평가 |
| Faithfulness | 응답이 검색된 문서에 근거하는 정도 | RAGAS, LLM-as-Judge |
| Answer Correctness | 최종 응답의 정확도 | Ground Truth 비교 |
8.2 실험 방법
- 평가 데이터셋 구성: 실제 사용자 질문 50~100개와 정답(Ground Truth)을 준비합니다.
- 전략별 비교: 동일 문서에 대해 서로 다른 Chunking 전략을 적용하고, 동일 질문으로 검색 품질을 비교합니다.
- 크기 변화 실험: 같은 전략 내에서 Chunk 크기를 200, 300, 500, 800 토큰으로 변경하며 성능 변화를 측정합니다.
- Overlap 실험: 0%, 10%, 20%, 30% Overlap에서의 검색 결과를 비교합니다.
8.3 평가 도구
| 도구 | 특징 |
|---|---|
| RAGAS | RAG 파이프라인 전체 품질 평가 (Faithfulness, Relevancy 등) |
| LangSmith | LangChain 기반 평가 및 트레이싱 |
| Phoenix (Arize) | RAG 성능 모니터링 및 디버깅 |
| Custom Eval | 도메인 특화 평가 스크립트 직접 작성 |
9. 자주 하는 실수
- 하나의 Chunk 크기를 모든 문서에 동일하게 적용: 기술 문서, FAQ, 계약서는 구조가 다릅니다. 문서 유형별로 전략을 분리해야 합니다.
- Overlap 없이 분할: Chunk 경계에서 문맥이 유실됩니다. 10~15% Overlap은 기본으로 적용하는 것이 안전합니다.
- Chunk 크기만 조정하고 전략은 변경하지 않음: Fixed-size에서 크기만 바꾸는 것보다, Recursive나 Semantic으로 전략 자체를 변경하는 것이 더 큰 효과를 줄 수 있습니다.
- 메타데이터를 저장하지 않음: 검색 후 "이 정보가 어디서 왔는지" 추적할 수 없으면 디버깅과 권한 관리가 불가능합니다.
- 평가 없이 프로덕션 배포: Chunking 변경이 검색 품질에 어떤 영향을 미쳤는지 측정하지 않으면, 개선인지 퇴보인지 알 수 없습니다.
- 짧은 Chunk에 긴 메타데이터 헤더를 추가: 헤더가 Chunk 본문보다 길면 임베딩이 메타데이터 의미에 치우칩니다. 헤더는 간결하게 유지합니다.
10. 비용/운영 고려사항
10.1 전략별 비용 영향
| 전략 | 임베딩 비용 | 저장소 비용 | 구현 복잡도 |
|---|---|---|---|
| Fixed-size | 보통 | 보통 | 낮음 |
| Recursive | 보통 | 보통 | 낮음 |
| Semantic | 높음 (문장마다 임베딩) | 보통 | 중간 |
| Structure-based | 보통 | 보통 | 중간 |
| Parent-Child | 높음 (Child 임베딩) | 높음 (Parent + Child 저장) | 높음 |
10.2 운영 시 고려사항
- 문서 업데이트 시 재분할: 원본 문서가 수정되면 해당 문서의 Chunk를 삭제하고 다시 분할/임베딩해야 합니다. 변경 감지와 증분 처리 파이프라인이 필요합니다.
- Chunk ID 관리: 문서 업데이트 시 기존 Chunk를 식별하여 교체하려면, 문서 + 순서 기반의 결정적(Deterministic) ID 체계가 필요합니다.
- A/B 테스트: Chunking 전략을 변경할 때, 기존 인덱스와 새 인덱스를 병렬로 운영하며 품질을 비교한 후 전환합니다.
- 모니터링: 검색 결과의 평균 유사도 점수, Top-K 결과의 분산 등을 모니터링하여 품질 저하를 조기에 감지합니다.
11. 정리
- Chunking은 RAG 성능의 핵심 변수입니다. "검색이 안 되면 응답도 안 된다"는 원칙을 기억해야 합니다.
- Fixed-size는 시작점으로 적합하지만, 프로덕션에서는 문서 구조와 질문 유형에 맞는 전략으로 전환해야 합니다.
- Parent-Child Chunking은 검색 정밀도와 문맥 보존을 동시에 달성하는 효과적인 방식이지만, 구현 복잡도가 높습니다.
- Chunk 크기는 300~500 토큰에서 시작하여, 평가 데이터셋 기반으로 실험하며 조정합니다.
- Metadata 보강과 Contextual Header는 적은 비용으로 검색 품질을 높일 수 있는 방법입니다.
- 전략 선택보다 중요한 것은 평가 체계를 먼저 구축하는 것입니다. 측정할 수 없으면 개선할 수 없습니다.
참고 문서
'AI' 카테고리의 다른 글
| Azure OpenAI 기반 사내 문서 검색 시스템 구성 방식: AI Search, Private Endpoint, 보안까지 (0) | 2026.06.07 |
|---|---|
| Vector DB 비교: Pinecone, Weaviate, pgvector, OpenSearch 선택 기준 (0) | 2026.06.06 |
| RAG와 Fine-tuning 차이: LLM 커스터마이징 전략 선택 기준 (0) | 2026.05.31 |
| AWS Bedrock 기반 RAG 챗봇 아키텍처 설계: Knowledge Bases, Agent, 보안까지 (0) | 2026.05.31 |
| AI 애플리케이션 보안 리스크: Prompt Injection과 데이터 유출 (0) | 2026.05.31 |