기술 블로그

RAG Engineering

RAG 청킹: 원문 위치를 보존하고 검색 단위를 검증하기

원문 오프셋을 유지하는 Python 분할 예제와 표·문맥·문서 버전·토큰 제한을 다루는 청킹 검증 절차입니다.

RAGO-X작성 수정
#RAG#Chunking#Architecture
RAG 청킹: 검색 가능한 문서 단위 만들기 개념도

문서를 일정 길이로 나눴다고 검색 가능한 근거가 완성되는 것은 아닙니다. “전원을 끈 후 덮개를 여세요”에서 조건과 행동이 서로 다른 청크로 분리되면, 검색 결과에 행동만 남을 수 있습니다. 청킹의 목표는 작은 조각을 많이 만드는 것이 아니라, 질문에 답할 수 있는 문맥과 원문 위치를 함께 보존하는 것입니다.

이 글은 Python 3으로 실행할 수 있는 문자 단위 기준선을 만들고 그 한계를 검사하는 방법을 설명합니다. 아래 크기와 겹침은 실험용 값이며 RAGO-X의 운영 기본값이 아닙니다.

분할 전에 추출 결과부터 확인하기

PDF의 다단 편집, 반복 머리말, 표 셀 순서가 추출 과정에서 무너지면 청크 크기를 바꿔도 원문 의미는 돌아오지 않습니다. 실제 문서에서 제목, 본문, 표, 각주가 올바른 순서인지 먼저 확인하세요. 가능하면 제목 경로와 문단을 기본 단위로 삼고, 긴 문단에만 추가 분할을 적용합니다.

표는 행에 열 이름과 단위가 함께 있어야 이해할 수 있습니다. 표가 길다면 제목과 열 머리글을 각 조각에 연결하고 페이지 경계를 기록하세요. 머리글을 덧붙이는 경우 원문 그대로의 구간과 검색을 위해 추가한 문맥을 구분해서 저장해야 합니다.

원문 오프셋을 유지하는 기준선

아래를 chunk_demo.py로 저장하고 python3 chunk_demo.py로 실행하세요. 반열린 구간 [start, end)를 사용하므로 text[start:end]가 청크 본문과 같습니다.

python
def split_text(text, size=80, overlap=15):
    if size <= 0 or not 0 <= overlap < size:
        raise ValueError("require size > 0 and 0 <= overlap < size")
    start = 0
    while start < len(text):
        end = min(start + size, len(text))
        yield {"start": start, "end": end, "text": text[start:end]}
        if end == len(text):
            break
        start = end - overlap


text = "Pump X17: disconnect power. Wait 30 seconds. Check the inlet filter."
chunks = list(split_text(text, size=40, overlap=10))
print([(c["start"], c["end"]) for c in chunks])
assert [(c["start"], c["end"]) for c in chunks] == [(0, 40), (30, 68)]
assert all(text[c["start"]:c["end"]] == c["text"] for c in chunks)
assert set().union(*(set(range(c["start"], c["end"])) for c in chunks)) == set(range(len(text)))
assert list(split_text("")) == []

출력은 [(0, 40), (30, 68)]입니다. 두 구간은 10문자가 겹치며 원문 전체를 덮습니다. 빈 입력은 청크를 만들지 않고, 잘못된 겹침 값은 오류를 냅니다. 원문을 미리 strip()하거나 공백을 바꾸지 않아 위치 비교를 유지합니다.

이 함수의 단위는 Python 문자열의 문자 수입니다. 바이트, 화면상 글자 묶음, 모델의 토큰 수와 같지 않습니다. 실제 모델 입력 한도는 사용하는 토크나이저로 별도 계산해야 합니다. 제목이나 문장 경계도 인식하지 않으므로 이 기준선 자체를 최종 분할기로 간주하면 안 됩니다.

검색용 메타데이터 설계

정보 보존하는 이유
문서 ID와 개정 버전 같은 문서의 이전 내용과 구분
청크 ID와 분할 설정 버전 재처리한 청크를 추적
페이지·절·시작/끝 위치 사용자가 원문 근거를 확인
조직·문서함·접근 범위 허용된 문서만 검색
원문 구간과 추가 문맥 인용문과 검색 보조 텍스트를 구분

원문 오프셋은 어떤 추출 텍스트 버전을 기준으로 하는지도 필요합니다. OCR이나 공백 정규화가 바뀌면 같은 위치가 다른 내용을 가리킬 수 있습니다. 문서를 교체할 때는 새 청크와 검색 인덱스를 일관되게 전환하고, 이전 버전이 함께 검색되지 않는지 확인하세요. 위 표는 설계 항목이며 공개 API의 필드 계약을 의미하지 않습니다.

크기를 바꾸기 전에 정답 근거를 정하기

실제 질문에 대해 답이 있는 원문 구간을 표시한 뒤 두 가지 분할 설정을 비교하세요. 상위 검색 결과가 정답 구간을 포함하는지, 예외 조건까지 포함하는지, 출처를 열면 같은 버전이 보이는지 확인합니다. 청크 수나 답변 길이만 늘어난 것을 품질 개선으로 보지 마세요.

관찰한 문제 먼저 시도할 변경
조건과 결론이 분리됨 문단·문장 경계를 우선하고 필요한 인접 문맥 추가
큰 청크에 여러 주제가 섞임 제목별 분리 후 검색 결과 비교
중복 근거가 문맥 창을 차지함 겹침을 줄이거나 인접 후보 중복 정리
표의 숫자를 오해함 열 머리글·단위·각주 연결
출처 위치가 어긋남 추출 텍스트 버전과 위치 매핑 확인

겹침은 경계 손실을 줄일 수 있지만 저장량과 중복 후보도 늘립니다. 고정된 최적 크기는 없으므로 질문 집합, 입력 토큰 수, 처리 시간, 인용 정확도를 함께 기록하세요. 다음 단계는 하이브리드 검색 비교근거에서 답변까지의 설계입니다.