RAG(검색 증강 생성)를 만들어 보신 분들은 다 아시겠지만, 답변 품질의 절반은 청크를 어떻게 나누느냐에서 결정돼요. 특히 한국 공공·금융 문서처럼 표가 많은 문서에서는 더 그래요. 오늘은 저희가 한글 파서 위에서 청크를 나누는 방식을 공유할게요.
글자 수로 자르면 생기는 일
제일 흔한 방법이 "500자씩, 50자 겹치게" 자르는 거예요. 이렇게 하면 이런 일이 생겨요.
- 표가 중간에서 잘려요. 앞 청크엔 헤더와 첫 두 행, 뒤 청크엔 나머지 행만 있어요. 뒤 청크는 헤더가 없어서 "이 숫자가 뭔지" 알 수 없는 조각이 돼요.
- 조항 제목과 본문이 따로 놀아요. "제12조(환급)" 은 앞 청크 끝에, 내용은 뒤 청크에 있어요. "환급 조건"을 검색하면 제목만 있는 청크가 걸려요.
- 각주가 본문에서 떨어져요. 각주 번호만 본문에 남고 내용은 문서 끝 청크에 가 있어요.
이게 다 문서 구조를 모르고 자르기 때문이에요.
구조 단위로 먼저 나눠요
저희는 1월에 소개한 중간 표현(IR)에서 시작해요. IR에는 헤딩, 문단, 표, 리스트, 각주가 블록으로 구분돼 있고 각 블록에 원본 위치가 있어요. 청크를 나누는 규칙은 이래요.
1. 표는 하나의 청크예요. 아무리 길어도 안 잘라요. 너무 길면(토큰 한도를 넘으면) 헤더 행을 복제해서 나눠요. 뒤쪽 조각에도 헤더가 붙어 있어야 혼자서도 읽혀요.
2. 헤딩은 아래 본문에 붙여요. 헤딩 블록 단독 청크는 안 만들어요. 그리고 상위 헤딩 경로를 청크 앞에 붙여요. "제3장 보험금 지급 > 제12조 환급 > 본문..." 이런 식으로요. 이걸 "브레드크럼"이라고 부르는데, 검색 적중률에 제일 효과가 컸어요.
3. 표 앞 문단은 표와 묶어요. 표 바로 앞 문단은 보통 "다음 표는 ~를 나타낸다" 같은 설명이에요. 표 청크에 같이 넣어요. 표 뒤의 "주)" 문단도 같이요.
4. 각주는 참조한 문단에 넣어요. 문서 끝에 모으지 않고, 각주를 참조하는 문단 청크 안에 인라인으로 붙여요.
5. 그 다음에 크기를 맞춰요. 위 규칙으로 묶은 덩어리가 너무 크면 문단 경계에서 나누고, 너무 작으면 이웃이랑 합쳐요. 크기 조정은 마지막이에요.
표를 청크에 넣을 때의 형식
표를 Markdown으로 넣느냐, 문장으로 풀어서 넣느냐도 고민이었어요. 저희 결론은 둘 다 넣는 거예요.
[표: 보험료 납입 기간별 환급률]
| 경과 기간 | 환급률 |
| 1년 미만 | 50% |
| 1년 이상 3년 미만 | 70% |
(풀어쓰기) 경과 기간 1년 미만은 환급률 50%, 1년 이상 3년 미만은 환급률 70%.
Markdown 표는 LLM이 답변할 때 구조를 보기 좋고, 풀어쓴 문장은 임베딩 검색에 잘 걸려요. "3년 미만 환급률"이라고 검색하면 표만 있을 때보다 풀어쓴 문장이 있을 때 훨씬 잘 찾혀요. 토큰이 두 배 들긴 하지만 그만한 가치가 있었어요. 큰 표는 풀어쓰기를 행 단위로 요약해서 길이를 줄여요.
메타데이터를 꼭 붙이세요
청크 텍스트만 벡터 DB에 넣지 마시고, 이런 걸 같이 넣으세요.
- 문서 ID, 페이지, 원본 블록 위치 (답변에 "어디서 왔는지" 보여 주려면 필수예요)
- 헤딩 경로 (브레드크럼)
- 블록 종류 (표/문단/리스트) — "표에서만 검색" 같은 필터에 써요
- 문서 종류와 날짜 — 개정 전후 문서가 섞여 있을 때 최신 것만 보게요
효과는 어땠냐면요
저희 내부 평가셋(공개 약관·규정 문서에 질문-정답 쌍을 만든 것)에서, 글자 수 자르기 대비 구조 기반 청크로 바꿨을 때 정답 청크가 상위 5개 안에 들어오는 비율이 눈에 띄게 올랐어요. 특히 표 안의 값을 묻는 질문에서 차이가 컸어요. 정확한 숫자는 평가셋 구성에 너무 좌우돼서 여기 쓰진 않을게요. 직접 해 보시면 체감이 되실 거예요.
정리
- 글자 수로 자르지 마세요. 구조 단위로 묶은 다음 크기를 맞추세요.
- 표는 안 자르고, 자를 수밖에 없으면 헤더를 복제하세요.
- 헤딩 경로를 청크에 붙이세요. 효과 대비 비용이 제일 좋아요.
- 표는 Markdown과 풀어쓰기를 같이 넣으세요.
다음 주부터 두 주 동안은 배포 이야기예요. 폐쇄망에 설치할 때 챙겨야 하는 것들을 체크리스트로 정리할게요.