RAG2026-5일7차시 · 텍스트 분할 이해13 / 19← 이전목차다음 →MetaContents

7차시. 텍스트 분할 이해

10. 이번 차시 완성 코드

출처: 원본 PDF 07차시_텍스트분할이해.pdf 20~21쪽 · 쪽 그림 20쪽 21쪽

6차시의 로딩과 오늘의 분할을 하나로 합칩니다. 8차시에서 이 결과를 바로 씁니다.

📝 src/prepare.py — 로딩 + 분할

Python
from langchain_text_splitters import RecursiveCharacterTextSplitter
from ingest import load_documents
CHUNK_SIZE = 100
CHUNK_OVERLAP = 20
def prepare_chunks(path: str):
    # 문서를 읽고 조각으로 나눠서 돌려준다
    docs = load_documents(path)
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=CHUNK_SIZE,
        chunk_overlap=CHUNK_OVERLAP,
        separators=["\n\n", "\n", ". ", " ", ""],
        length_function=len,
    )
    chunks = splitter.split_documents(docs)
    # 조각마다 번호를 매겨둔다 (나중에 추적용)
    for i, c in enumerate(chunks):
        c.metadata["chunk_id"] = i
    lengths = [len(c.page_content) for c in chunks]
    print(f"✓ 조각 {len(chunks)}개 생성 "
          f"(평균 {sum(lengths)//len(lengths)}자, "
          f"최소 {min(lengths)}자, 최대 {max(lengths)}자)")
    if min(lengths) < 50:
        print("⚠ 50자 미만 조각이 있습니다. chunk_size 확인 권장")
    return chunks
if __name__ == "__main__":
    chunks = prepare_chunks("data/manual.pdf")
    for c in chunks[:3]:
        print(f"\n[{c.metadata['chunk_id']}] "
              f"p.{c.metadata['page_no']}")
        print(c.page_content[:100])

실행 결과 예시 (코드를 읽고 만든 예상 화면입니다. 실제 실행 결과, 특히 모델의 답은 다를 수 있습니다)

출력
✓ 3쪽 로딩 완료 (총 1529자)
✓ 조각 21개 생성 (평균 77자, 최소 47자, 최대 99자)
⚠ 50자 미만 조각이 있습니다. chunk_size 확인 권장

[0] p.1
1
제품 사용 설명서
가정용 공기청정기 AP-3300
목차
1. 제품 개요
2. 설치 방법
3. 사용 방법
4. 환불 및 교환 규정
5. 보증 및 무상 A/S

[1] p.1
5. 보증 및 무상 A/S
6. 문제 해결(FAQ)
7. 고객센터 안내
8. 제품 사양
9. 품질보증서

[2] p.2
가정용 공기청정기 AP-3300
2
1. 제품 개요
본 제품은 가정용 공기청정기로서, 초미세먼지·유해가스·생활 악취를 효과적으로 제거합니다.

💡 chunk_id를 넣어둔 이유
나중에 "몇 번 조각이 검색됐는지" 추적할 수 있습니다.
12차시에서 RAG가 이상한 답을 할 때
"아, 17번 조각이 잘못 걸렸구나" 하고
바로 원인을 찾을 수 있게 됩니다.

실습 코드 · 07/prepare.py

실습 코드: 실습/src/07/prepare.py · 위의 원본 PDF 7차시 20~21쪽 「이번 차시 완성 코드」과 이어집니다.

Python
# ============================================================
# 7차시 | PPT: 07차시_텍스트분할이해.pptx
# 역할: 설명서를 chunk로 나누고 각 조각에 chunk_id를 붙이는 함수
# 입력: ../../data/manual.pdf
# 출력: 로딩 문장, 조각 개수, 앞 3개 본문과 chunk_id
# 흐름:
#   (import 시) manual.pdf -> load_documents
#   prepare_chuncks(경로)
#     -> load_documents -> splitter -> chunk_id 부여 -> 반환
# ============================================================
# Document: 본문(page_content)과 metadata 딕셔너리를 담는 객체
# chunk: 검색에 쓰려고 잘라 낸 문서 조각
# overlap: chunk_overlap. 이웃 조각이 이 글자 수만큼 겹칩니다.
# metadata: 본문 밖의 부가 정보. 여기서 chunk_id(조각 번호)를 추가합니다.

from langchain_community.document_loaders import PyPDFLoader
import os
import sys

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document

# split_basic.py와 같은 방법으로 06 폴더의 ingest.py를 찾게 합니다.
CURRENT_DIR = os.path.dirname(__file__)
INGEST_DIR = os.path.join(CURRENT_DIR, "..", "06")
sys.path.insert(0, INGEST_DIR)

from ingest import load_documents

# 이 모듈을 import하기만 해도 아래 한 줄이 실행되어 PDF를 한 번 읽습니다.
docs = load_documents("../../data/manual.pdf")

# 값을 맨 위 상수로 빼 두면, 비교 실험 때 이 두 줄만 고치면 됩니다.
CHUNK_SIZE = 200
CHUNK_OVERLAP = 50

def prepare_chuncks(path):
    # 함수 안에서도 같은 로더로 다시 읽습니다. 이름 철자는 chuncks입니다.
    docs = load_documents(path)

    # 자르는 기준은 split_basic.py와 같고, 크기와 겹침만 상수에서 가져옵니다.
    splitter = RecursiveCharacterTextSplitter(
        chunk_size = CHUNK_SIZE,
        chunk_overlap = CHUNK_OVERLAP,
        separators=["\n\n", "\n", ". ", " ", ""],
        length_function = len,
    )

    chunks = splitter.split_documents(docs)

    # 0부터 번호를 매겨 metadata에 넣습니다. 검색 결과를 구분할 때 씁니다.
    for index, chunk in enumerate(chunks):
        chunk.metadata["chunk_id"] = index

    print(f"{len(chunks)} 개")

    return chunks

# 직접 실행할 때만 아래가 돕니다. 위의 docs 줄 때문에 로딩 문장은 두 번 찍힙니다.
if __name__ == "__main__":
    chunks = prepare_chuncks("../../data/manual.pdf")
    # 전체 대신 앞 3개만 출력합니다.
    for chunk in chunks[:3]:
        print(chunk.page_content)
        print(chunk.metadata["chunk_id"])
        print()

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/07
      python prepare.py
3쪽 로딩 완료 (총 1529 자)
3쪽 로딩 완료 (총 1529 자)
11 개
1
제품 사용 설명서
가정용 공기청정기 AP-3300
목차
1. 제품 개요
2. 설치 방법
3. 사용 방법
4. 환불 및 교환 규정
5. 보증 및 무상 A/S
6. 문제 해결(FAQ)
7. 고객센터 안내
8. 제품 사양
9. 품질보증서
0

가정용 공기청정기 AP-3300
2
1. 제품 개요
본 제품은 가정용 공기청정기로서, 초미세먼지·유해가스·생활 악취를 효과적으로 제거합니다.
HEPA 13 등급 필터와 활성탄 필터를 함께 사용하여 실내 공기질을 쾌적하게 유지합니다.
권장 사용 면적은 33㎡ 이내이며, 저소음 설계로 취침 시에도 사용할 수 있습니다.
2. 설치 방법
1

2. 설치 방법
벽면에서 30cm 이상 떨어진 곳에 제품을 설치해 주세요.
바닥이 평평하고 통풍이 잘 되는 곳에 두시는 것이 좋습니다.
전원 코드는 접지가 된 콘센트에 연결해 주세요.
커튼이나 가구 등으로 흡입구·배출구가 가려지지 않도록 주의해 주세요.
3. 사용 방법
전원 버튼을 눌러 제품을 켜고, 원하는 풍량 단계(약/중/강/자동)를 선택하세요.
2

코드 해설

설명서를 chunk로 나누고 각 조각에 chunk_id를 붙이는 함수입니다. 입력은 ../../data/manual.pdf이고, 출력은 로딩 문장, 조각 개수, 앞 3개 본문과 chunk_id입니다.

주석에 적힌 흐름입니다.

출력
(import 시) manual.pdf -> load_documents
prepare_chuncks(경로)
-> load_documents -> splitter -> chunk_id 부여 -> 반환

코드 앞에서 고정해 두는 말입니다.

  • Document: 본문(page_content)과 metadata 딕셔너리를 담는 객체
  • chunk: 검색에 쓰려고 잘라 낸 문서 조각
  • overlap: chunk_overlap. 이웃 조각이 이 글자 수만큼 겹칩니다.
  • metadata: 본문 밖의 부가 정보. 여기서 chunk_id(조각 번호)를 추가합니다.

함수와 클래스로 나누어 읽습니다.

  • prepare_chuncks: 이름 그대로 한 가지 일만 합니다. 본문 주석을 같이 읽습니다.

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

← 이전 절7차시 · 9. 자주 겪는 문제와 해결법다음 절 →7차시 · 체크리스트와 과제