인기 문서 사이트 6곳에서 150페이지를 RAG 청크로 크롤링한 결과: 한 페이지가 토큰 예산의 절반을 차지하는 경우가 많다
요약
RAG 봇 구축 시 초기 크롤링 단계가 검색 성능을 결정합니다. 인기 문서 사이트의 단순 크롤링은 단일 페이지가 전체 토큰 예산의 상당 부분을 차지하거나, 번역본 및 변경 로그 같은 중복 청크를 대량으로 생성하여 오히려 검색 효율을 떨어뜨릴 수 있음을 보여줍니다.
핵심 포인트
- 단일 문서 페이지가 크롤링된 전체 토큰의 39%~69%까지 차지할 수 있다.
- 변경 로그나 참고표는 벡터 인덱스에서 근접 중복 청크를 생성하기 쉽다.
- 번역본을 포함한 광범위한 크롤링은 실제 답변에 도움이 안 되는 노이즈를 증가시킨다.
만약 누군가의 문서를 기반으로 RAG (Retrieval-Augmented Generation) 봇을 구축한다면, 첫 번째 크롤링이 검색기(retriever)가 무엇을 볼지 결정합니다. 저는 인기 문서 사이트들의 단순한 크롤링이 실제로 어떤 결과를 반환하는지 알고 싶었기 때문에, 2026년 11월 3일에 이들 중 여섯 곳을 대상으로 크롤러를 작동시키고 카운팅했습니다.
공개 사항: 여기에 사용된 크롤러는 제가 Apify에서 Website to LLM Markdown를 이용해 구축했습니다. 이 도구는 페이지를 깔끔한 Markdown과 토큰이 계산된 청크로 변환합니다. 설정 방법은 마지막에 있습니다.
설정
- 사이트: docs.n8n.io, fastapi.tiangolo.com, docs.stripe.com, supabase.com/docs, docs.astro.build, react.dev/learn
- 사이트당 25페이지, 시작 URL에서 너비 우선(breadth-first) 방식으로 진행, 동일 도메인만 사용, robots.txt 준수
- 보일러플레이트(내비게이션, 푸터, 쿠키 배너 등)를 제거한 후, 제목을 기준으로 최대 500 토큰 크기의 청크로 분할
- 토큰은
o200k_base토크나이저로 계산
모든 150페이지가 정상적으로 반환되었습니다. 이들을 합치면 394,230 토큰에 달하는 1,037개의 청크입니다.
결과 1: 한 페이지의 지배력
| 사이트 | 토큰 (25페이지) | 중앙값 페이지 | 가장 큰 페이지 | 가장 큰 페이지가 차지하는 비율 |
|---|---|---|---|---|
| fastapi.tiangolo.com | 194,179 | 4,051 | /release-notes/: 117,704 | 61% |
| ... |
여섯 사이트 중 네 곳에서 단일 페이지가 전체 크롤링 토큰의 39%에서 69%를 차지했습니다. 이 경우 세 가지는 지원 봇에 거의 원하지 않는 종류의 페이지입니다:
- FastAPI의 릴리스 노트: 117,704 토큰, 287개 청크. 하나의 버전 기록 페이지가 나머지 24페이지를 합친 것보다 더 많은 비중을 차지합니다.
- Stripe의 테스트 페이지: 36,764 토큰으로, 주로 긴 테스트 카드 번호와 오류 코드 테이블로 구성되어 있습니다.
- n8n의 변경 로그(changelog): 13,522 토큰, 37개 청크.
React의 큰 페이지는 단계별 튜토리얼입니다. 이 페이지는 인덱스에 포함되지만, 매우 유사한 코드로 이루어진 53개의 청크가 검색 시 다른 답변들을 압도할 수 있습니다.
이 문제의 핵심은 이러한 사이트들이 형편없이 구축되었다는 것이 아닙니다. 변경 로그(Changelogs)나 참고표(reference tables)는 인간에게 유용합니다. 하지만 벡터 인덱스(vector index)에서는 이들이 여러 쿼리에 약간씩 일치하는 근접 중복 청크(near-duplicate chunks)를 주로 추가할 뿐, 어떤 질문에도 답하지 못하게 만듭니다.
결과 2: 번역본이 크롤링 예산(crawl budget)을 소모합니다
FastAPI의 문서는 여러 언어로 번역되었으며, 홈페이지는 각 버전을 링크하고 있습니다. 따라서 너비 우선 탐색(breadth-first crawl)은 초기 단계부터 번역본에 시간을 할애하게 됩니다:
- 첫 25개의 FastAPI 페이지 중 12개는 홈페이지의 번역본이었습니다: 힌디어, 프랑스어, 독일어, 스페인어, 한국어, 일본어, 터키어, 러시아어, 포르투갈어, 중국어(간체 및 번체), 우크라이나어.
- 실제 영어 페이지는 13개에 불과했고, 실제 튜토리얼 콘텐츠는 극소수였습니다.
만약 여러분의 봇이 영어로 답변한다면, 이 페이지들은 순수한 노이즈(pure noise)일 뿐입니다. 그리고 같은 내용이라도 12개 언어로 존재하면, 검색기(retriever)가 영어 질문에 대해 일본어 버전을 반환하게 만들 수 있습니다.
결과 3: 단어당 토큰 수가 2배까지 차이 납니다
단어당 토큰 수(Tokens per word)는 사이트의 마크다운(Markdown) 밀도(
- 변경 로그 및 릴리스 노트 제외:
*/changelog*,*/release-notes*,*/releases*와 같은 패턴을 사용합니다. 사용자가 "버전 X에서 무엇이 바뀌었나요?"라고 물으면, 별도의 컬렉션으로 최근 몇 개의 버전만 인덱싱합니다. - 언어 고정:
/en/경로만 포함하거나, 언어 접두사(/de/,/ja/, ...)를 제외합니다. 또한 크롤링 후 각 페이지의language필드를 확인해야 합니다. - 페이지 크기 제한: 약 10,000 토큰을 초과하는 내용은 들어오기 전에 검토가 필요합니다. 일반적으로 변경 로그, 거대한 참조 테이블 또는 자동 생성된 API 페이지인 경우가 많습니다.
이 세 가지 필터를 사용하면 FastAPI 크롤러는 12개의 번역본과 릴리스 노트(총 25페이지 중 13페이지)를 제외하게 되며, 토큰의 절반 이상을 줄일 수 있습니다.
이를 재현하는 방법 (How to reproduce this)
아래의 각 실행은 25페이지에 대해 6초에서 14초가 소요되었으며, 컴퓨팅 자원은 매우 적게 사용했습니다:
{
"startUrls": [{ "url": "https://fastapi.tiangolo.com/" }],
"maxPages": 25,
...
}
액터는 페이지당 하나의 항목을 반환하며, 여기에는 markdown, wordCount, tokenCountEstimate, language 및 chunks 배열이 포함됩니다. 각 청크(chunk)는 headingPath, text, tokenCount와 안정적인 chunkId를 가지므로 벡터 저장소(vector store)에 바로 업서트(upsert)할 수 있습니다. 가격은 페이지당 변환 시 $0.0015이며, 실패했거나 비어 있거나 봇이 차단한 페이지는 무료입니다.
위의 분석은 데이터셋에 대한 몇 줄의 Python 코드입니다:
from collections import Counter
pages = [p for p in rows if p["status"] == "ok"]
total = sum(p["tokenCountEstimate"] for p in pages)
...
인덱싱을 시작하기 전에 한 번 실행해 보세요. 토큰이 어디로 가는지 확인하는 5분은 나중에 많은 디버깅 시간을 절약해 줍니다.
데이터: 공개 문서 사이트 6곳, 각 25페이지를 2026년 11월 3일에 크롤링했습니다. 다른 시작 URL이나 페이지 제한은 다른 페이지를 제공하므로, 여러분의 크롤링도 같은 방식으로 확인해 보세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기