왜 문서를 잘게 잘라야 하나 — 청킹
한 줄 요약
문서를 500자짜리 조각으로 자르고, 50자씩 겹치게 합니다. 조각 크기를 정하는 것은 검색 정확도와 근거의 양 사이에서 균형을 잡는 일이고, 사람이 판단하는 자리입니다.
1. 왜 자르나
이유가 셋 있습니다.
① 통째로 보내면 낭비다
우리 문서는 8쪽 5,526자입니다. "반품 기간"을 물었는데 로봇청소기 매뉴얼까지 다 보낼 이유가 없습니다.
② 관련 없는 내용이 섞이면 답이 흐려진다
LLM에게 A4 10장을 주고 "여기서 반품 기간 찾아 줘"라고 하면, 엉뚱한 문장을 근거로 삼기도 합니다. 필요한 조각만 주면 그럴 여지가 줄어듭니다.
③ 어디서 나왔는지 밝혀야 한다
조각 단위로 관리해야 "환불교환정책.pdf 1쪽" 이라고 출처를 붙일 수 있습니다.
2. 로드 — PDF 읽기
아래는 4절에서 만들 code/ch06_rag_agent.py 의 일부를 미리 보는 것입니다 — 지금 붙여 넣지 않아도 됩니다.
from langchain_community.document_loaders import PyPDFLoader
pages = PyPDFLoader(str(path)).load()
한 쪽이 하나의 Document 가 됩니다. 각 Document 에는 두 가지가 들어 있습니다.
| 무엇 | |
|---|---|
page_content |
그 쪽의 텍스트 |
metadata |
어디서 왔는지 (source, page) |
우리 문서를 읽으면 이렇습니다.
환불교환정책.pdf 2쪽 1694자
멤버십정책.pdf 1쪽 864자
직원핸드북.pdf 2쪽 1164자
제품매뉴얼_스마트워치.pdf 1쪽 753자
제품매뉴얼_로봇청소기.pdf 2쪽 1051자
─────────────
총 8쪽 5,526자
출처를 정리해 둡니다
아래는 4절에서 만들 code/ch06_rag_agent.py 의 일부를 미리 보는 것입니다 — 지금 붙여 넣지 않아도 됩니다.
for d in pages:
d.metadata["source"] = name # 전체 경로 대신 파일명만
PyPDFLoader 는 source 에 전체 경로(/Users/.../data/docs/환불교환정책.pdf)를 넣습니다. 화면에 보여 줄 때 지저분하므로 파일명만 남깁니다.
나중에 출처를 표시할 때 여기가 쓰입니다. 미리 정리해 두는 것이 사람의 일입니다.
3. 청킹 — 자르기
아래는 4절에서 만들 code/ch06_rag_agent.py 의 일부를 미리 보는 것입니다 — 지금 붙여 넣지 않아도 됩니다.
from langchain_text_splitters import RecursiveCharacterTextSplitter
chunks = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50).split_documents(docs)
8쪽이 15조각이 됩니다.
잘라 낸 조각 하나를 청크(chunk)라고 부릅니다. 자르는 일이 청킹(chunking) 이고요. 이 교재에서는 "조각"으로 쓰고, 코드의
chunk_size·chunk_overlap이 그 조각의 크기와 겹침입니다. 혼자 검색할 때는 "청크"라는 말로 찾으면 됩니다.
| 인자 | 뜻 | 우리 값 |
|---|---|---|
chunk_size |
조각 하나의 최대 글자 수 | 500 |
chunk_overlap |
이웃 조각끼리 겹치는 글자 수 | 50 |
두 값이 각각 어디를 가리키는 길이인지 그림으로 보세요.
겹치는 50자는 두 조각 모두에 들어갑니다. 어느 쪽이 검색되든 그 부분을 볼 수 있게요.
그래서 조각이 500자보다 짧을 수 있습니다. 6번에서 다시 다룹니다.
4. chunk_size — 조각 크기에 따른 장단점
작으면 좋을까요, 크면 좋을까요? 둘 다 문제가 있습니다.
[너무 작다 — 100자]
✓ 검색이 정확하다 (조각 하나에 한 가지 내용만)
✗ 근거가 부족하다 ("30일 이내"만 나오고 무엇의 30일인지 안 보임)
[적당하다 — 500자]
✓ 한 조항 정도가 통째로 들어간다
✓ 검색도 그럭저럭 정확하다
[너무 크다 — 3000자]
✓ 근거가 충분하다
✗ 검색이 부정확하다 (여러 주제가 섞여 무엇과 비슷한지 흐려짐)
✗ 토큰이 많이 든다
500은 어떻게 나온 숫자인가 — 정답이 있는 건 아닙니다. 다만 감을 잡는 기준은 있습니다.
"답 하나가 들어갈 만한 크기" 로 잡습니다. 규정 문서라면 조항 하나, 매뉴얼이라면 항목 하나, 논문이라면 문단 하나. 우리 정책 문서는 조항 하나가 300~500자쯤이라 500이 맞습니다.
문서 종류에 따라 달라집니다.
| 문서 | 권장 |
|---|---|
| 규정·정책 (조항 단위) | 300~500 |
| 매뉴얼·설명서 | 500~800 |
| 논문·보고서 | 800~1500 |
| 대화 기록·로그 | 200~400 |
5. chunk_overlap — 왜 겹치나
문장이 조각 경계에서 잘리는 것을 막기 위해서입니다.
겹치는 부분이 안전망입니다. 어느 조각이 검색되든 뜻이 통합니다.
보통 chunk_size 의 10~20% 로 잡습니다. 500의 10%면 50이죠.
너무 크게 잡으면 같은 내용이 여러 조각에 중복 저장돼 낭비입니다.
6. Recursive 가 뜻하는 것
RecursiveCharacterTextSplitter — 이름이 긴데, 자르는 방식이 이름에 들어 있습니다.
무조건 500자에서 뚝 자르는 게 아닙니다. 순서대로 시도합니다.
① 문단 경계(\n\n)에서 자를 수 있나? → 된다면 거기서
② 안 되면 줄바꿈(\n)에서
③ 안 되면 공백에서
④ 그래도 안 되면 글자 단위로
최대한 자연스러운 경계에서 자릅니다. 그래서 조각이 500자보다 짧을 수도 있습니다.
이게 왜 중요한가 — 문장 한가운데를 자르면 조각의 뜻이 망가지고, 임베딩도 엉뚱해집니다. 문단 경계에서 자르면 조각 하나가 하나의 완결된 이야기가 됩니다. 검색 정확도가 올라갑니다.
7. 잘린 결과 보기
우리 문서의 첫 조각입니다.
(주)승승장구 SEUNGSEUNG COMMERCE
CS-POL-2026-014
대외 공개 · 무단 배포 금지
- 1 -
고객지원본부
환불·교환·반품 운영 정책
Return, Exchange & Refund Policy — 승승장구몰 고객지원본부
문서번호 CS-POL-2026-014
제·개정일 2026-05-01
관리부서 고객지원본부
시행일 2026-05-15
문서등급 대외 공개
버전 v3.2
본 정책은 「전자상거래 등에서의 소비자보호에 관한 법률」에 근거하여
승승장구몰(이하 '회사')이 판매하는 상품의 환불·교환·반품 ...
머리말과 문서 정보가 한 조각을 차지했습니다. 실제 규정 내용은 다음 조각부터입니다.
PDF에서 뽑은 텍스트는 지저분합니다. 표가 줄줄이 풀리고, 쪽번호(
- 1 -)가 섞이고, 줄바꿈이 이상합니다. 실무에서는 이런 것을 정리(전처리) 하는 데 시간을 꽤 씁니다. 이 과정에서는 그냥 두고 갑니다 — 어차피 검색은 됩니다. 다만 "PDF 텍스트는 원래 이렇다"는 것은 알아 두세요.
8. 정리 — AI가 한 것과 사람이 한 것
| 누가 | 무엇 |
|---|---|
| 라이브러리 | PDF 읽기, 자르기 |
| 사람 | 어떤 문서를 넣을지 |
| 사람 | chunk_size 를 몇으로 할지 |
| 사람 | chunk_overlap 을 몇으로 할지 |
| 사람 | 출처를 파일명으로 정리 |
AI는 아직 등장하지도 않았습니다. 여기까지는 전부 평범한 텍스트 처리입니다.
스스로 해 보기
먼저 4절에서 실습 파일을 만든 뒤에 해 보세요. chunk_size 를 바꿔 조각 수가 어떻게 달라지는지 확인합니다.
직접 고쳐 보기 — 4절에서 만든
agentic_ai/code/ch06_rag_agent.py를 열어 아래처럼 바꾸거나 덧붙인 뒤 다시 실행하세요.
for size in [200, 500, 1000, 2000]:
ch = RecursiveCharacterTextSplitter(chunk_size=size, chunk_overlap=50).split_documents(docs)
print(f"chunk_size={size:5d} → {len(ch):3d}조각")
그리고 각 설정으로 만든 인덱스에서 같은 질문을 던져 검색 결과가 어떻게 달라지는지 비교해 보세요.
인덱스를 다시 만들려면
data/policy_index폴더를 지워야 합니다. 다음 절에서 이유를 설명합니다.
핵심 정리
- 문서를 자르는 이유 셋 — 비용 · 정확도 · 출처 표시.
PyPDFLoader로 읽으면 한 쪽이 하나의Document가 되고,metadata에 출처가 들어갑니다.chunk_size=500— 조각 크기는 검색 정확도와 근거의 양 사이에서 균형을 잡는 값입니다.- 기준은 "답 하나가 들어갈 만한 크기" 입니다. 규정이면 조항 하나, 매뉴얼이면 항목 하나.
chunk_overlap=50— 문장이 경계에서 잘려도 뜻이 남게 하는 안전망입니다. 보통chunk_size의 10~20%.Recursive는 문단 → 줄 → 공백 순으로 자연스러운 경계를 찾아 자른다는 뜻입니다.- 우리 문서는 8쪽 → 15조각이 됩니다.
- 조각 하나를 청크(chunk), 자르는 일을 청킹(chunking) 이라고 부릅니다. 이 교재는 "조각" 으로 씁니다.
- 여기까지는 AI가 등장하지 않습니다. 평범한 텍스트 처리입니다.