sy/dev
Guide
19 min read

PageIndex와 Quarkify를 보며 생각한 구조형 인덱스 — Vector RAG를 대체할 수 있을까

PageIndex와 Quarkify는 문서와 코드를 chunk로 납작하게 만들지 않고 구조형 인덱스로 바꾸는 접근이다. 기존 vector RAG와 비교했을 때 무엇이 좋아지고, 대규모 데이터에서는 어디까지 통할 수 있는지 정리한다.

요즘 RAG를 만들다 보면 거의 자동으로 이런 파이프라인을 떠올린다.

문서 수집

chunking

embedding

vector DB 저장

query embedding

top-k retrieval

LLM 답변 생성

이 방식은 단순하고 강력하다. 하지만 모든 데이터를 chunk로 납작하게 만든 뒤 벡터 유사도만으로 찾는 접근에는 분명한 한계가 있다. 특히 긴 전문 문서나 대형 코드베이스처럼 원래 구조가 중요한 데이터에서는 “비슷한 문장”을 찾는 것과 “정말 답이 있는 위치”를 찾는 것이 자주 어긋난다.

최근 살펴본 두 레포가 이 문제를 다른 방식으로 건드린다.

  • PageIndex: PDF/Markdown 문서를 목차형 tree index로 바꾸고, LLM이 그 구조를 reasoning하면서 필요한 페이지를 찾는다.
  • Quarkify: 코드베이스를 file/class/function/statement 단위의 물리적 폴더 구조로 바꿔 AI coding agent가 원본 코드를 다 읽지 않고 탐색하게 한다.

둘은 대상이 다르다. PageIndex는 문서, Quarkify는 코드다. 하지만 철학은 비슷하다.

원본을 무작정 chunk로 잘라 넣지 말고, 사람이 읽는 방식에 가까운 구조 인덱스를 먼저 만들자.

이 글에서는 두 접근을 기존 vector RAG와 비교하고, 실제 대규모 데이터에서도 효과가 있을지 정리해본다.

PageIndex: 문서를 tree로 만들고 LLM이 탐색하게 하기

PageIndex는 스스로를 Vectorless, Reasoning-based RAG라고 설명한다. 핵심 아이디어는 단순하다.

긴 PDF/Markdown 문서

목차형 tree structure 생성

질문이 들어오면 LLM이 tree를 보고 관련 section/page range 선택

선택된 page content만 읽고 답변

일반 RAG가 문서를 chunk로 쪼개고 embedding similarity로 top-k chunk를 가져온다면, PageIndex는 문서를 다음과 같은 구조로 표현한다.

pageindex-tree-example.json
{
  "title": "Financial Stability",
  "node_id": "0006",
  "start_index": 21,
  "end_index": 22,
  "summary": "The Federal Reserve ...",
  "nodes": [
    {
      "title": "Monitoring Financial Vulnerabilities",
      "node_id": "0007",
      "start_index": 22,
      "end_index": 28,
      "summary": "The Federal Reserve's monitoring ..."
    }
  ]
}

Agentic 예제도 흥미롭다. PageIndex는 agent에게 복잡한 vector search tool을 주지 않는다. 대신 아래 세 도구만 준다.

get_document()
get_document_structure()
get_page_content(pages="5-7")

즉, agent는 먼저 문서 메타를 보고, 그 다음 전체 문서 구조를 훑고, 마지막으로 필요한 페이지 범위만 가져온다. 사람이 긴 보고서를 읽을 때와 비슷하다. 먼저 목차를 보고, 관련 장을 찾고, 필요한 페이지만 펼쳐 읽는다.

Quarkify: 코드를 폴더 구조로 물리화하기

Quarkify는 문서가 아니라 코드베이스를 대상으로 한다. README의 핵심 문장은 “Everything is a folder”다.

Quarkify는 소스 파일을 분석해서 아래처럼 물리적인 디렉터리 구조를 만든다.

output/
├── quark/
├── _mirror/
├── _axon/
├── index.html
└── ai_context_guide.txt

예를 들어 Spring controller를 분석하면 이런 식의 구조가 생기는 컨셉이다.

quark/
└── file__SpringTestController.java/
    └── class__SpringTestController/
        └── fn__getUser/
            ├── annotation__GetMapping/
            │   └── arg__0____users__id_/
            └── stmt_0__try/
                ├── body/
                ├── catch___IOException_e/
                └── finally/

이러면 AI coding agent는 대형 파일을 처음부터 끝까지 읽지 않아도 된다.

# 특정 메서드 구조만 확인
tree output/quark/file__SpringTestController.java/class__SpringTestController/fn__getUser
 
# equals 호출 위치만 탐색
fd -t d "call__equals" output/quark
 
# web_endpoint 역할로 분류된 심볼 확인
ls output/_mirror/by_role/web_endpoint

PageIndex가 문서의 목차를 읽는 방식이라면, Quarkify는 코드의 AST 비슷한 구조를 파일시스템에 풀어놓는 방식이다. JSON이나 DB가 아니라 폴더 자체를 index surface로 쓰는 점이 독특하다.

둘의 공통점: chunk가 아니라 구조를 먼저 본다

PageIndex와 Quarkify는 구현은 다르지만 같은 문제의식을 공유한다.

일반 RAG는 데이터를 먼저 납작하게 만든다.

document/codebase

chunks

vectors

반면 구조형 인덱스 접근은 원래 데이터의 계층을 최대한 보존한다.

document/codebase

structure tree / topology map

reasoning-based navigation

selected page/function/section only

이 차이는 꽤 크다. chunk 기반 검색은 “이 질문과 비슷한 텍스트는 어디인가?”에 강하다. 구조 기반 검색은 “이 질문에 답하려면 어느 영역을 열어봐야 하는가?”에 강하다.

💡

Vector RAG의 기본 질문은 “무엇이 query와 embedding 공간에서 가까운가?”다. PageIndex나 Quarkify류 구조형 인덱스의 질문은 “사람이라면 이 문제를 풀기 위해 어느 구조를 먼저 펼쳐볼까?”에 가깝다.

Vector RAG의 장점은 여전히 크다

그렇다고 vector RAG가 낡았다는 뜻은 아니다. 오히려 대규모 검색의 1차 후보 선별에서는 vector RAG나 BM25가 아직 훨씬 현실적이다.

Vector RAG의 장점은 명확하다.

  • 구축 패턴이 성숙했다.
  • vector DB, hybrid search, reranker 생태계가 풍부하다.
  • query latency를 낮추기 쉽다.
  • 수백만, 수천만 chunk scale 운영 사례가 많다.
  • 짧은 문서, FAQ, 위키, support ticket 검색에 잘 맞는다.

특히 질문이 짧고 후보 문서가 매우 많을 때는 vector search가 강하다.

query: SAML SSO callback error

이런 검색은 구조 추론보다 BM25와 dense retrieval을 섞는 편이 빠르고 싸다. 제품명, 에러 코드, API 이름, 로그 메시지처럼 표면 문자열이 중요한 영역에서는 sparse retrieval도 여전히 강력하다.

PageIndex가 유리한 지점

PageIndex는 vector RAG의 약점이 잘 드러나는 긴 전문 문서에서 빛난다.

예를 들어 이런 질문을 생각해보자.

이 회사의 유동성 리스크가 작년 대비 어떻게 바뀌었나?

답은 한 chunk에 없을 수 있다. annual report의 MD&A, risk factors, cash flow statement, debt maturity footnote를 함께 봐야 할 수 있다. 단어로는 liquidity, risk, debt, cash가 흩어져 있고, 질문의 의도는 단순 유사도보다 문서 구조와 재무적 맥락을 요구한다.

이런 경우 PageIndex의 장점이 나온다.

  1. 문서 목차와 계층을 보존한다.
  2. 관련 section/page range를 추적하기 쉽다.
  3. 답변 근거를 페이지 단위로 제시하기 좋다.
  4. 여러 섹션을 단계적으로 열어보는 agentic retrieval과 잘 맞는다.
  5. chunk size와 overlap 튜닝 부담이 줄어든다.

그래서 PageIndex는 다음 영역에 잘 맞는다.

  • 재무 보고서
  • 법률 문서
  • 계약서
  • 규제 문서
  • 논문
  • 기술 매뉴얼
  • 긴 정책 문서

공통점은 명확하다. 문서가 길고, 구조가 있고, 답변의 근거 위치가 중요하다.

Quarkify가 유리한 지점

Quarkify는 코드베이스 onboarding과 AI coding agent의 scope narrowing에 유리하다.

대형 repo에서 coding agent가 실패하는 흔한 이유 중 하나는 너무 많은 파일을 읽거나, 반대로 중요한 함수를 못 찾는 것이다. agent에게 repo 전체를 던지면 context가 터지고, 적당히 grep만 시키면 구조를 놓친다.

Quarkify식 접근은 다음 질문에 빠르게 답하려고 한다.

이 repo에 어떤 class/function이 있나?
특정 API call은 어디서 호출되나?
Spring endpoint는 어떤 method와 연결되나?
try/catch 같은 control flow는 어디에 있나?
CUDA/PTX 코드에서 어떤 opcode나 kernel이 보이나?

이런 구조가 미리 만들어져 있으면 agent는 원본 파일을 열기 전에 탐색 범위를 좁힐 수 있다.

전체 코드 읽기

관련 파일 추측

수정

대신 이렇게 바꿀 수 있다.

quark/_mirror/_axon 탐색

관련 function/class 후보 선택

원본 파일의 필요한 부분만 확인

수정

대형 코드베이스에서 이 차이는 token cost와 latency에 직접 영향을 준다.

하지만 둘 다 공짜는 아니다

구조형 인덱스의 가장 큰 비용은 index construction이다.

PageIndex는 tree를 만들기 위해 LLM을 많이 호출한다. 코드를 보면 TOC 감지, TOC 추출, page index 매핑, title 검증, 잘못된 TOC 수정, 큰 node 재귀 분할, summary 생성 같은 단계가 있다. 일반 embedding pipeline보다 비싸고 느릴 수밖에 없다.

Quarkify는 LLM 호출보다 parser 유지보수가 비용이다. 현재 구현은 tree-sitter 같은 정식 AST parser라기보다는 regex와 hand-written parser 조합에 가깝다. Java, Python, JS/TS, CUDA, PTX, Metal까지 넓게 지원하려면 edge case가 계속 생긴다.

정리하면 이렇다.

항목PageIndexQuarkify
대상PDF/Markdown 문서코드베이스
인덱스JSON tree물리적 folder topology
비용LLM 기반 tree 생성 비용parser 정확도와 유지보수 비용
강점긴 문서 내부 reasoning retrievalAI coding agent의 scope narrowing
약점latency/cost, 구조 품질 의존언어별 syntax edge case

대규모 데이터에서도 통할까?

여기서 중요한 구분이 있다. “대규모”는 두 가지로 나뉜다.

A. 문서 하나가 매우 길다
B. 문서 수가 매우 많다

PageIndex와 Quarkify류 구조형 인덱스는 A에 강하다. 긴 문서 하나, 큰 코드 repo 하나, 복잡한 매뉴얼 하나를 구조적으로 탐색하는 데 좋다.

하지만 B, 즉 수백만 문서 전체 검색에서는 이야기가 달라진다.

PageIndex README와 블로그는 PageIndex File System을 통해 millions of documents scale을 말한다. 다만 open-source repo 기준으로 보면 기본 client/workspace는 문서별 JSON과 _meta.json 중심이다. 즉, doc_id를 알고 있을 때 문서 구조와 page content를 가져오는 데는 적합하지만, 수백만 문서 중 먼저 어떤 문서를 열지 고르는 global retrieval layer는 별도로 필요해 보인다.

그래서 현실적인 대규모 설계는 PageIndex 단독이 아니라 hybrid가 맞다.

사용자 질문

metadata filter / permission filter

BM25 + vector search로 후보 문서 10~100개 선택

각 후보 문서 내부에서 PageIndex tree search

관련 page evidence 추출

LLM answer synthesis

코드베이스도 비슷하다.

사용자 작업 요청

repo metadata / file path / symbol search / git history로 후보 좁히기

Quarkify topology로 class/function/call 관계 확인

원본 코드 최소 범위 읽기

수정 및 테스트

즉, 구조형 인덱스는 대규모 시스템에서 first-stage retriever라기보다 second-stage reasoner에 가깝다.

수백만 문서에서는 “어떤 문서를 볼까?”와 “그 문서 안에서 어디를 볼까?”를 분리하는 편이 안전하다. 전자는 BM25/vector/metadata filter가, 후자는 PageIndex 같은 tree search가 잘한다.

언제 vector RAG를 쓰고, 언제 구조형 인덱스를 쓸까

실무적으로는 아래 기준이 가장 간단하다.

Vector RAG가 더 좋은 경우

  • 짧은 문서가 많다.
  • 빠른 검색 latency가 중요하다.
  • 후보가 수백만 개 이상이다.
  • FAQ, ticket, wiki, product doc처럼 chunk 단위 답변이 충분하다.
  • 업데이트가 잦고, 인덱싱 비용을 낮춰야 한다.
  • keyword, 고유명사, 에러 코드 검색이 중요하다.

PageIndex가 더 좋은 경우

  • 문서 하나가 길고 복잡하다.
  • 목차, chapter, section 구조가 중요하다.
  • 답이 여러 섹션에 흩어져 있다.
  • 근거 page나 section citation이 중요하다.
  • 법률/재무/논문/매뉴얼처럼 전문 문서다.
  • 질문마다 reasoning을 통해 읽을 범위를 정해야 한다.

Quarkify가 더 좋은 경우

  • AI coding agent가 대형 repo를 탐색해야 한다.
  • class/function/call/control flow 단위의 scope narrowing이 중요하다.
  • 코드 구조를 CLI로 빠르게 훑고 싶다.
  • 원본 파일 전체를 context에 넣는 비용을 줄이고 싶다.
  • repo onboarding, impact analysis, targeted edit workflow를 만들고 싶다.

내가 쓴다면 어떤 구조로 쓸까

내가 production RAG나 agent 시스템에 적용한다면 단독 대체보다는 조합으로 쓸 것 같다.

문서 RAG라면:

1. 문서 ingest
2. metadata extraction
3. BM25/vector hybrid index 생성
4. 긴 전문 문서에 대해서만 PageIndex tree 생성
5. query 시 coarse retrieval로 후보 문서 선택
6. 후보 내부를 PageIndex로 탐색
7. page-level citation과 함께 답변

코드 agent라면:

1. repo checkout
2. symbol index / grep / language server / git history 준비
3. Quarkify topology 생성
4. issue나 작업 요청을 symbol/file 후보로 매핑
5. topology로 관련 함수와 호출 관계 확인
6. 원본 코드는 마지막에 필요한 범위만 읽기

이렇게 보면 구조형 인덱스는 vector DB의 경쟁자라기보다, agent runtime의 navigation layer에 가깝다.

결론: RAG의 다음 단계는 “더 좋은 벡터”만은 아니다

RAG 성능을 올린다고 하면 보통 embedding model, chunk size, reranker, vector DB 튜닝을 떠올린다. 물론 중요하다. 하지만 PageIndex와 Quarkify가 보여주는 방향은 조금 다르다.

데이터가 원래 가지고 있던 구조를 보존하고, agent가 그 구조를 탐색하게 하자.

문서에는 목차와 section이 있다. 코드에는 file, class, function, call graph가 있다. 계약서에는 조항과 cross-reference가 있다. 재무보고서에는 footnote와 table이 있다. 이런 구조를 무시하고 전부 chunk로 납작하게 만들면 검색은 단순해지지만, reasoning할 단서가 사라진다.

그래서 내 결론은 이렇다.

  • PageIndex는 긴 전문 문서 내부 retrieval에 강하다.
  • Quarkify는 AI coding agent의 코드 탐색 범위 축소에 유용하다.
  • Vector RAG는 여전히 대규모 후보 검색과 빠른 recall에 강하다.
  • 대규모 시스템에서는 구조형 인덱스 단독보다 hybrid 설계가 현실적이다.

한 줄로 줄이면:

Vector RAG는 “비슷한 조각”을 빠르게 찾고, 구조형 인덱스는 “어디를 열어봐야 하는지”를 더 잘 설명한다.

앞으로 agentic RAG나 coding agent를 설계할 때는 vector DB만 볼 게 아니라, 데이터별 구조 인덱스를 어떻게 만들고 탐색 도구로 노출할지가 점점 중요해질 것 같다.

참고 자료

Comments