PageIndex
프레임워크VectifyAI/PageIndex
벡터 없는 추론 기반 RAG 시스템으로, 계층적 트리 인덱스를 사용하여 인간과 유사한 검색을 구현합니다.
개요
PageIndex는 벡터를 사용하지 않는 추론 기반 RAG 시스템으로, 긴 문서에서 계층적 트리 인덱스를 구축합니다. LLM을 활용하여 맥락을 인식하는 인간과 유사한 검색을 수행함으로써 기존의 벡터 유사도 검색을 대체합니다. FinanceBench와 같은 전문 문서 분석 벤치마크에서 최고 수준의 정확도를 달성했습니다.
README 미리보기
\n \n\n \n\n\n\n\n\n\n \n\n\n# PageIndex: Vectorless, Reasoning-based RAG\n\nReasoning-based RAG ◦ No Vector DB or Chunking ◦ Context-Aware ◦ Human-like Retrieval\n\n\n 🌐 Homepage • \n 🖥️ Chat Platform • \n 🔌 MCP & API • \n 📖 Docs • \n 💬 Discord • \n ✉️ Contact \n\n \n\n\n\n\n📢 Updates\n\n- 🔥 [**Agentic Vectorless RAG**](https://github.com/VectifyAI/PageIndex/blob/main/examples/agentic_vectorless_rag_demo.py) — A simple *agentic, vectorless RAG* [example](#agentic-vectorless-rag-an-example) with self-hosted PageIndex, using OpenAI Agents SDK.\n- [**Scale PageIndex to Millions of Documents**](https://pageindex.ai/blog/pageindex-filesystem) — *PageIndex File System* is a file-level tree layer that lets PageIndex reason over an entire corpus, not just a single document, enabling massive-scale document search.\n- [PageIndex Chat](https://chat.pageindex.ai) — Human-like document analysis agent [platform](https://chat.pageindex.ai) for professional long documents. Also available via [MCP](https://pageindex.ai/developer) or [API](https://pageindex.ai/developer).\n- [PageIndex Framework](https://pageindex.ai/blog/pageindex-intro) — Deep dive into PageIndex: an *agentic, in-context tree index* that enables LLMs to perform *reasoning-based, context-aware retrieval* over long documents.\n\n \n\n\n\n---\n\n# 📑 Introduction to PageIndex\n\nAre you frustrated with vector database retrieval accuracy for long professional documents? Traditional vector-based RAG relies on semantic *similarity* rather than true *relevance*. But **similarity ≠ relevance** — what we truly need in retrieval is **relevance**, and that requires **reasoning**. When working with professional documents that demand domain expertise and multi-step reasoning, similarity search often falls short.\n\nInspired by AlphaGo, we propose **[PageIndex](https://vectify.ai/pageindex)** — a **vectorless**,
FAQ (5)
문제 해결TOC 처리 중 process_none_page_numbers에서 "KeyError: 'page'" 오류를 어떻게 수정하나요?
안전하지 않은 키 삭제를 pop()과 기본값으로 교체하세요. pageindex/page_index.py(또는 pageindex/page_index_classic.py)에서 다음을 변경하세요:
del item_copy['page']
del item['page']
다음과 같이 변경합니다:
item_copy.pop('page', None)
item.pop('page', None)
이렇게 하면 키가 존재할 때 해당 키를 제거하고, TOC 항목에 page 필드가 없는 경우 KeyError를 발생시키는 대신 None을 반환합니다. 레거시 TOC 경로가 추가적인 검증, 정리, 재시도 및 오류 처리로 대체되었으므로 최신 릴리스로 업그레이드하는 것도 문제를 해결할 수 있습니다.
문제 해결TOC 항목에 페이지 번호가 없을 때 process_none_page_numbers에서 발생하는 KeyError: 'page'를 어떻게 수정하나요?
del을 사용하는 대신 키 제거를 안전하게 처리하세요. pageindex/page_index.py 또는 pageindex/page_index_classic.py에서 다음을:
del item['page']
del item_copy['page']
다음과 같이 교체하세요:
item.pop('page', None)
item_copy.pop('page', None)
이렇게 하면 page가 존재할 때만 안전하게 제거됩니다. 설치된 릴리스를 실행 중이라면 최신 버전으로 업그레이드하세요. 레거시 TOC 경로는 이후 파서 검증 및 오류 처리 변경으로 대체되거나 처리되었습니다. 오류가 계속되면 입력 형태, 모델/제공자, 패키지 버전 및 트레이스백을 보고하세요.
문제 해결LLM이 잘못된 형식의 JSON을 반환할 때 AttributeError: 'str' object has no attribute 'get' 또는 'dict' object has no attribute 'extend' 오류를 해결하는 방법은?
JSON 폴백을 수정하고 런타임 타입 검증을 추가하세요. pageindex/utils.py에서 파싱에 실패할 때 extract_json()이 {} 대신 []을 반환하도록 수정하세요. ToC 호출자는 dict의 리스트를 기대하기 때문입니다:
def extract_json(text):
try:
data = json.loads(text)
except (json.JSONDecodeError, TypeError):
return []
return data if isinstance(data, list) else []
LLM 출력을 사용하기 전에 정규화하세요:
def normalize_toc_items(data):
if not isinstance(data, list):
return []
return [item for item in data if isinstance(item, dict)]
meta_processor에서 .get()을 호출하기 전에 dict 항목만 필터링하세요:
toc_with_page_number = normalize_toc_items(toc_with_page_number)
toc_with_page_number = [
item for item in toc_with_page_number
if item.get("physical_index") is not None
]
process_no_toc에서 .extend()를 호출하기 전에 두 값이 모두 리스트인지 확인하세요:
toc_with_page_number = normalize_toc_items(
generate_toc_init(group_texts[0], model)
)
for group_text in group_texts[1:]:
additional = normalize_toc_items(
generate_toc_continue(toc_with_page_number, group_text, model)
)
toc_with_page_number.extend(additional)
또는 PR #210, #217의 잘못된 형식의 JSON 크래시 방지 처리나 issue #199에서 참조된 포괄적인 수정 사항이 포함된 릴리스로 업데이트하세요.
문제 해결PageIndex 실행 시 convert_physical_index_to_int에서 발생하는 KeyError: 'physical_index' 오류를 해결하는 방법
이 문제는 파싱된 PDF 항목 중 일부에 physical_index 필드가 누락된 초기 버전 버그로 인해 발생했습니다. 수정 사항과 회귀 테스트가 포함된 최신 버전으로 PageIndex를 업데이트하세요:
cd PageIndex
git pull
pip install -r requirements.txt
그런 다음 원래 실행했던 PageIndex 명령을 다시 실행하세요. Python 3.9는 원인으로 확인되지 않았습니다. 오래되었거나 복잡한 PDF에서 오류나 인식 문제가 계속 발생하는 경우 PyPDF가 해당 파일을 안정적으로 파싱하지 못할 수 있습니다. 이 경우 해결 방법으로, OCR을 사용하여 이러한 PDF를 더 잘 처리할 수 있는 호스티드 PageIndex API를 사용하세요.
문제 해결동시 LLM 요청으로 tree index를 생성할 때 HTTP 429 rate-limit 오류와 이어서 발생하는 KeyError 'toc_detected' 오류는 어떻게 수정할 수 있나요?
클라이언트 측 속도 제한, 제한된 동시성, Retry-After 처리, 지터를 포함한 지수 백오프, 그리고 잘못된 형식의 LLM JSON 응답에 대한 검증이 추가된 최신 pageindex 릴리스로 업그레이드하세요:
python -m pip install -U pageindex litellm
업그레이드 후에는 동시 호출이 더 이상 asyncio.gather를 통해 한꺼번에 몰리지 않으며, {}['toc_detected']에 접근하는 대신 비어 있거나 실패한 LLM 응답이 처리됩니다.
즉시 업그레이드할 수 없는 경우 다음 해결 방법을 적용하세요:
1. 세마포어로 LLM 동시성을 제한하세요:
sem = asyncio.Semaphore(2) # 제공업체의 RPM/TPM 등급에 맞게 조정하세요
async def guarded_llm_call(coro):
async with sem:
return await coro
await asyncio.gather(*(guarded_llm_call(task) for task in tasks))
2. 고정된 1초 재시도를 지수 백오프, 지터, Retry-After 지원으로 교체하세요:
import asyncio, random
delay = min(60, (2 ** attempt) + random.random())
retry_after = getattr(exc, "response", None)
if retry_after is not None:
delay = float(retry_after.headers.get("Retry-After", delay))
await asyncio.sleep(delay)
3. 키에 직접 접근하기 전에 파싱된 JSON을 검증하세요:
json_content = extract_json(response)
if not json_content or "toc_detected" not in json_content:
raise RuntimeError("LLM returned an invalid or empty JSON response")
return json_content["toc_detected"]
TOC 완료 검사에서 completed와 같은 필드에도 동일한 키 존재 여부 검사를 적용하세요.