RAG 전에 문서 정리하기

검색 증강 생성(RAG)을 위해 문서를 정리한다는 것은, 나머지 텍스트가 청크로 나뉘어 임베딩되고 벡터 인덱스에 저장되기 전에, 내용이 아닌 모든 것 — PDF가 모든 페이지에 지니고 있는 머리글, 바닥글, 페이지 번호와 반복되는 상용구 — 을 제거하는 것입니다. 그것은 RAG 파이프라인에서 가장 화려하지 않은 단계이며, 검색이 동작하는지를 조용히 결정하는 단계입니다: 정리되지 않은 텍스트로 구축된 인덱스는 같은 가구를 수백 번 저장하고 그것을 지식인 것처럼 검색합니다. 이 글은 가구가 임베딩을 왜 오염시키는지, 청킹이 실제로 어떻게 동작하는지, 중복 제거가 임베딩 전에 속하는 이유, 무엇을 벗겨내고 무엇을 남겨야 하는지, 그리고 정리가 도움이 되었는지를 어떻게 평가하는지를 설명합니다. 정리 자체를 하려면 문서 클리너를 사용하고, 이 안내와 나란히 자신의 결과를 읽으세요.

페이지 가구가 임베딩을 오염시키는 이유

임베딩 모델은 텍스트 청크를 그 청크가 무엇에 관한 것인지를 포착해야 할 벡터로 바꿉니다. 보고서 제목, 기밀 유지 바닥글과 페이지 번호가 절반인 청크를 그것에 주면, 벡터는 그것도 충실히 포착합니다 — 즉 긴 문서의 모든 청크가 같은 가구 쪽으로 표류하고, 벡터 공간에서 멀리 떨어져 있어야 할 청크들이 머리글을 공유하기 때문에 인위적으로 가깝게 끝납니다. 그러면 검색은 요청받은 그대로를 정확히 수행합니다: 환불 정책에 관한 섹션을 물으면, 그것의 가장 강한 공유 신호가 실행 머리글 안의 회사 이름인 다섯 개의 청크를 반환합니다. 아무도 모델링 실수를 하지 않았습니다. 인덱스는 모든 페이지에서 반복되는 소음으로 온전한 강도로 채워졌고, 반복되는 소음은 유사도를 세는 시스템에게는 신호와 구별할 수 없습니다.

피해는 희석보다 더 나쁩니다. 가구 청크는 검색에서 그대로 이길 수 있습니다: 바닥글처럼 표현된 질문 — 기밀 유지, 문서 통제나 버전에 관한 — 은 이백 번 임베딩된 바닥글 청크와, 그것에 실제로 답하는 단 하나의 단락보다 더 잘 일치합니다. 페이지 번호는 더 미묘한 실패를 만들어, 맨 숫자도 내용이라고 모델에게 가르치므로, “42”로 끝나는 청크가 그 숫자가 무언가를 의미하는 것처럼 인용되어 돌아올 수 있습니다. 그리고 가구 청크는 각각 유한한 top-k 결과 집합에서 한 자리를 차지해, 진정으로 관련된 청크를 모델에게 주어지는 맥락 밖으로 밀어냅니다. 따라서 정리는 겉치레 정돈이 아닙니다; 그것은 자신의 인덱스 안에서 자신의 내용에 대한 체계적인 경쟁자를 제거하는 것입니다.

청킹 기초: 크기, 겹침과 경계

청킹은 어떤 단위가 임베딩될지에 관한 결정이며, 그것에는 세 개의 조절 장치가 있습니다. 크기는 초점과 맥락을 맞바꿉니다: 작은 청크, 수백 자는, 하나의 생각을 날카롭게 임베딩하고 정확하게 검색하지만, 그 생각에 조건을 주는 문장 없이 도착할 수 있습니다; 큰 청크, 수천 자는, 맥락을 함께 지니지만 여러 생각을 하나의 평균 벡터로 섞어, 어느 것도 강하게 검색되지 않습니다. 대부분의 문서 코퍼스는 중간의 어딘가에 자리합니다 — 대략 500에서 1,000자가 합리적인 시작 영역입니다 — 그리고 올바른 답은 프레임워크 기본값에서 숫자를 복사하는 것이 아니라, 자신의 질문을 자신의 문서에 대해 테스트함으로써 결정됩니다. LangChain 텍스트 스플리터 문서는 문자 및 재귀 스플리터부터 구조를 인식하는 것까지, 스플리터 가족의 좋은 지도입니다.

겹침은 두 번째 조절 장치인 경계에 대한 보험입니다. 구조와 상관없이 800자마다 자르는 스플리터는 결국 정의를 반으로 자를 것이고, 어느 절반도 잘 검색되거나 잘 읽히지 않습니다. 경계에서 나누는 것 — 재귀 스플리터가 하는 것처럼 먼저 단락, 그다음 문장, 그다음 공백 — 은 대부분의 경우 단위를 온전하게 유지하고, 10에서 20퍼센트의 적당한 겹침은 한 청크의 가장자리를 다음 청크의 시작에 반복하므로, 그래도 일어나는 절단이 그 맥락을 고아로 만들지 않습니다. LlamaIndex 노드 파서 문서의 계층은 로더 쪽에서 같은 지점을 말합니다: 문서를 존중하는 노드로 구문 분석한 뒤 나누세요. 그러나 이 중 어느 것도 가구를 구하지 못합니다: 겹침은 머리글을 다음 청크에도 충실히 반복하므로, 정리는 청킹 전에 오며, 절대로 그 뒤에 오지 않습니다.

임베딩하기 전에 중복을 제거하세요

중복은 두 번째 체계적인 오염물질이며, 두 종류가 있습니다. 첫 번째는 문서 전체의 중복입니다: 같은 PDF가 다른 파일 이름으로 두 번 인덱싱된 것, 새 버전 옆에 남겨진 옛 버전, 공유 드라이브 사본 옆에 저장된 메일 첨부 파일. 두 번째는 문서 안에 있습니다: 제목 페이지의 면책 조항이 부록에 다시 나타나는 것, 각 장의 머리에 반복되는 요약, 본문과 부속서 양쪽에 붙여진 표. 두 종류 모두 검색에 같은 영향을 줍니다 — 중복된 텍스트는 반복해서 임베딩되므로 반복해서 검색되어, 한 구절의 사본으로 top-k를 채우는 동안 다른 구절은 절대로 떠오르지 않습니다 — 그리고 비용에도 같은 영향을 줍니다. 왜냐하면 사본마다 임베딩과 저장 비용을 내기 때문입니다.

중복 제거는 임베딩 전에, 그것이 아직 문자열 비교일 때 가장 쌉니다. 정확한 중복은 정규화로 해결됩니다: 공백을 축소하고, 이미 벗겨낸 페이지 가구를 무시하고, 결과를 해시해 사본 하나만 남기세요. 거의 중복 — 날짜가 바뀌었거나 제목 번호가 다시 매겨진 같은 단락 — 은 유사도 검사가 필요하지만, 거친 검사라도 가장 큰 피해를 주는 상용구를 잡아냅니다. 두 가지 주의가 중복 제거를 정직하게 유지합니다. 첫째, 첫 번째 출현을 남기고 사본이 어디에 있었는지 기록하세요; 두 장에 반복된 경고는 의도적인 안전 장치일 수 있으며, 그것을 기록에서 완전히 제거하는 것은 그것을 인덱스에서 제거하는 것과는 다른 결정입니다. 둘째, 중복 제거는 정리한 뒤에 하세요, 그 전이 아니라: 페이지 번호만 다른 두 페이지는 서로 다른 가구로 감싸인 내용의 중복이며, 정리된 텍스트만이 그것을 드러냅니다.

무엇을 벗겨내고 무엇을 남길 것인가

알려주지 않으면서 반복되는 것을 벗겨내세요: 실행 머리글과 바닥글, 페이지 번호, 워터마크, 기밀 유지 배너, 생성된 “인쇄 일시” 줄, 그리고 웹에서 PDF로 내보내기가 모든 페이지에 찍는 탐색 부스러기. 구조를 주는 것을 남기세요: 실제 제목, 그것들은 당신이 가진 가장 강한 청크 경계 신호이며 종종 청크 메타데이터에 속하기 때문입니다; 캡션, 그림 캡션은 그림이 무엇을 보여주는지를 말하는 유일한 텍스트인 경우가 많기 때문입니다; 표 내용, 조심스럽게 다루세요, 벗겨진 표는 그 숫자에 의미를 주는 행과 열 제목을 잃기 때문입니다; 그리고 목록, 그 항목들은 자연스러운 단위입니다. 경계 사례는 목차입니다. 청크로서는 목차 줄은 가구입니다 — 모든 쿼리와 어렴풋이 일치하고 어느 것에도 답하지 않는 제목과 페이지 번호의 목록 — 그러나 메타데이터로서는 그 같은 목차 페이지가 문서의 지도입니다. 그것을 임베딩되는 텍스트에서 벗겨내고, 코퍼스에 관한 메모에 남기세요.

같은 판단은 문서 클리너 자체 안에도 적용됩니다: 가구와 페이지 번호는 제거하는 것이 거의 항상 안전하므로 기본으로 체크되고, 중복 단락은 반복이 때로는 목적 자체이므로 절대로 기본으로 체크되지 않습니다. 여기서는 추출의 정직함도 중요합니다. PDF는 구조화된 형식입니다 — ISO PDF 표준인 ISO 32000은 페이지를 흐르는 텍스트가 아니라 그리기와 텍스트 연산의 콘텐츠 스트림으로 정의합니다 — 따라서 모든 추출기는 읽기 순서를 근사하며, 스캔된 PDF는 OCR이 텍스트 레이어를 줄 때까지 텍스트 레이어가 전혀 없습니다. 원본 문서가 다른 이유로도 중요하다면, 당신의 PDF가 웹사이트 접근성의 일부라는 것에 관한 동반 글은 화면 읽기 프로그램과 추출기 양쪽을 돕는 태그 구조를 다룹니다.

정리한 뒤 검색을 평가하기

정리는 가설입니다 — 검색이 좋아질 것이라는 — 그리고 검색 품질에 관한 가설은 부끄러울 만큼 적은 기계로 테스트할 수 있습니다. 사용자들이 실제로 묻는 진짜 질문을 스무 개에서 쉰 개 모으고, 각각에 답해야 할 구절을 손으로 기록하세요. 같은 리트리버, 같은 청크 설정과 같은 top-k로 정리되지 않은 인덱스와 정리된 인덱스에 대해 그것들을 실행하고, 두 가지를 비교하세요: 올바른 구절이 결과에 아예 나타나는 빈도와, 나타났을 때 얼마나 높이 순위가 매겨지는지. 그 쌍 — 재현율과 순위 — 이 스코어보드입니다. 정리가 동작하고 있다면, 가구 청크는 결과에 나타나는 것을 멈추고, 올바른 구절은 올라가며, 바닥글이 답을 앞질러서 예전에는 실패하던 질문이 통과하기 시작합니다.

그런 다음 실패를 읽으세요, 숫자만으로는 당신에게 아첨할 것이기 때문입니다. 정리된 인덱스는 재현율을 얻으면서, 당신이 중복 제거해 버린 반복 요약 안에 그 답이 진정으로 살고 있던 질문이나, 모든 청크가 필요로 했던 제품 이름을 지니고 있던 머리글을 잃어, 질문 하나를 놓칠 수 있습니다. 그런 손실은 정보입니다: 그것들은 그 요소를 메타데이터로 남기거나, 문서 제목을 이백 번 우연히 임베딩하는 대신 각 청크 앞에 의도적으로 붙이라고 말해줍니다. 코퍼스, 스플리터나 임베딩 모델이 바뀔 때마다 평가를 다시 실행하고, 질문 집합을 인덱스와 나란히 버전 관리하세요. RAG 품질은 출시의 특성이 아닙니다; 그것은 유지보수의 특성이며, 작은 고정 테스트 집합이 바로 “더 좋아진 느낌”을 방어할 수 있는 것으로 바꾸는 것입니다.

출처와 더 읽을거리

자주 묻는 질문

정리는 실제로 검색을 얼마나 좋아지게 하나요?

그것은 당신의 문서가 가구에 얼마나 무거운지에 달려 있으며, 그것은 측정할 수 있습니다: 정리하기 전에 페이지를 가로질러 반복되는 줄을 세고, 고정된 진짜 질문 집합을 인덱스의 전후로 테스트하세요. 가구가 각 청크의 10분의 1 이상을 차지할 수 있으므로, 강한 실행 머리글을 가진 긴 보고서가 가장 많이 얻습니다; 짧고 깨끗한 문서는 거의 얻지 못할 수 있습니다. 정직한 방법은 마지막 섹션의 전후 평가이며, 약속된 백분율이 아닙니다.

정리는 청킹 전에 해야 하나요, 그 뒤에 해야 하나요?

항상 전에 하세요. 정리되지 않은 문서를 청크로 나누면 가구가 모든 청크에 임베딩되고, 다음 청크에 겹쳐지며, 페이지 번호가 인덱스 전체에 흩어져, 이후의 어떤 단계도 그것들을 확실하게 제거할 수 없게 됩니다. 먼저 추출된 텍스트를 정리한 뒤 결과를 청크로 나누세요 — 문서 클리너는 바로 이 이유로 그 순서로 정리된 텍스트와 준비된 JSONL 청크를 만듭니다.

어떤 청크 크기와 겹침으로 시작해야 하나요?

단락 경계에서 나누고 적당한 겹침을 갖춘 약 800자로 시작하고, 그다음 자신의 질문 집합에 맞춰 조정하세요. 작은 청크는 더 정확하게 검색하지만 맥락이 적고, 큰 청크는 그 반대입니다. 출처에 연결된 LangChain 텍스트 스플리터 문서와 같은 프레임워크 안내는 스플리터 가족을 설명하지만, 당신의 코퍼스에 맞는 숫자는 기본값이 아니라 평가에서 옵니다.