Главная / Статьи

PageIndex: Безвекторный RAG, основанный на логических рассуждениях, с деревянным индексом

PageIndex заменяет векторную базу данных на деревянный индекс, управляемый LLM. Как работает этот RAG, основанный на логических рассуждениях, с примерами кода на Python, интеграцией через MCP и цифрами тестирования.

Издатель: REACTAPP.TOP14 мин чтения3118 слов

Источники: PageIndex: The RAG Framework That Threw Out Vector Databases and Still Hit 98.7% Accuracy

Представьте себе фреймворк RAG, который полностью отказывается от векторных баз данных и при этом показывает результаты тестирования, к которым ни одна система, основанная на эмбеддингах, даже близко не подходит. Это PageIndex — проект с открытым исходным кодом от VectifyAI. В FinanceBench, стандартном тесте на ответы на вопросы по финансовым документам, обычные системы RAG на основе векторов показывают результаты примерно от 30 до 50 процентов. PageIndex демонстрирует 98,7 процента. Он достиг этого не благодаря улучшенной модели эмбеддингов, а путем полного отказа от них.

Этот результат заслуживает повторного рассмотрения, поскольку обработка финансовых вопросов на основе документов SEC является одним из самых сложных тестов на поиск информации в реальных AI-системах. Этот процесс требует многократного логического анализа, перехода между разделами и использования точных чисел. Лучшая существующая система не использовала ни векторы, ни разбиение текста на части, ни векторные базы данных.

Вот что делает PageIndex, как он построен, примеры рабочего Python-кода, в чем его сильные стороны и в чем — слабые.

Стена, с которой сталкиваются длинные документы

Каждый, кто создавал системы RAG на основе материалов длиннее, чем пост в блоге, знаком с проблемами, связанными с этим. Пользователь задаёт системе, основанной на 200-страничном годовом отчёте, вопрос о том, как общий чистый доход за финансовый год 2024 года сравнивается с финансовым годом 2023 года. Стандартная процедура выглядит следующим образом:

  1. Разбиваем документ на фрагменты фиксированного размера, обычно от 300 до 500 токенов.
  2. Встраиваем каждый фрагмент с помощью модели вроде text-embedding-3-large.
  3. Храним полученные векторы в Pinecone, Weaviate, Milvus, Chroma, pgvector или аналогичных сервисах.
  4. При поступлении запроса встраиваем вопрос и находим k-фрагментов с наибольшим сходством по коэффициенту косинуса.
  5. Передаём эти фрагменты в большую языковую модель для формирования ответа.

Для коротких неструктурированных материалов, таких как посты в блогах, заявки на поддержку и документация к продуктам, такой подход отлично сработает. Однако отчёты формата 10-K разбиваются на фрагменты предсказуемым образом, что создаёт дополнительные сложности.

Запрос не похож на ответ. Метод векторного поиска предполагает, что текст, наиболее похожий на запрос, является наиболее релевантным. Однако запрос выражает намерение, а не содержимое. Вопрос о тенденциях доходов не выделяет конкретную строку в таблице на странице 47 — он выделяет все абзацы, где речь идет о доходах.

Один термин, шестьдесят мест. В длинном годовом отчете термин «операционная прибыль» встречается десятками раз в разных контекстах. Методы сравнения похожести ставят их примерно на один уровень, и абзац, который действительно отвечает на вопрос, может так и не попасть в тройку лидеров.

Разбиение на фрагменты портит таблицы. Заголовок таблицы оказывается в 14-м фрагменте, а нужная строка — в 15-м. Каждый из них сам по себе не имеет смысла. Накладные окна, семантическое разбиение и парсеры, учитывающие структуру таблиц, могут помочь, но ни один из них не устраняет основной проблемы.

Отсутствие памяти между запросами. Если в предыдущем сообщении спрашивали о активах, а в следующем — «а как насчет обязательств?», система воспринимает это как совершенно новый запрос. Ничто не указывает ей на то, что пользователь, скорее всего, имеет в виду ту же часть того же отчета.

Кросс-ссылки остаются скрытыми. Предположим, страница 12 направляет читателей на Приложение G, а это приложение находится на странице 87. Текст приложения не имеет семантического совпадения с первоначальным вопросом, поэтому технология RAG никогда не будет следовать за этой ссылкой. Введение метаданных кросс-ссылок в фрагменты текста — это временное решение, но оно нестабильно и не позволяет масштабироваться.

Это не редкие крайние случаи — они являются следствием самой архитектуры. Как отметил сооснователь VectifyAI Минтянь Чжан в объявлении о проекте, для эффективного поиска действительно необходима релевантность, а релевантность требует использования логических рассуждений.

Что такое PageIndex

PageIndex — это безвекторная платформа на основе логического анализа для работы с RAG, выпущенная компанией VectifyAI в сентябре 2025 года; её создателями являются Чжан и Юй Тан. Она распространяется под лицензией MIT, и количество репозиториев с этим проектом быстро росло: к концу марта 2026 года их количество превысило 23 000, а количество копий — почти 2 000.

Основная идея этой платформы заимствована из AlphaGo. Вместо того чтобы полностью сканировать всё пространство данных и сравнивать каждый фрагмент с помощью векторного сходства, здесь используется выученная стратегия для интеллектуального навигирования в этих данных. PageIndex применяет этот принцип к документам, обладая тремя ключевыми особенностями:

  • Отсутствие векторной базы данных. Структура документов и процесс логического анализа с помощью больших языковых моделей заменяют поиск по сходству, поэтому здесь нет таких сервисов, как Pinecone или Chroma, а также нет векторных представлений.
  • Отсутствие разбиения на фрагменты. Документы сохраняют свою структуру в виде естественных разделов, глав, абзацев и таблиц, а не произвольных окон длиной 500 токенов.
  • Навигация в стиле человека. Она работает как человек, который вручную ищет информацию в документе: смотрит оглавление, находит раздел, который, скорее всего, содержит ответ, и читает его.

Метод состоит из двух шагов.

Шаг 1: иерархический деревянный индекс

При обработке документа не создаются никакие векторные представления. PageIndex анализирует структуру документа и формирует иерархическое дерево, которое по сути является оглавлением, подходящим для использования с большими языковыми моделями. Каждый узел содержит название, краткое описание раздела, диапазон страниц и дочерние узлы для подразделов, которые могут быть вложены на любую глубину.

Документ SEC объемом 50 страниц может дать дерево из 30–50 узлов, сохраняемое в виде одного JSON-объекта. Ничего не хранится в векторной базе данных — там только JSON. Весь объект помещается в одно окно контекста большой языковой модели, и вы можете открыть любой узел и прочитать его. Узел выглядит так:

{
  "node_id": "0006",
  "title": "Financial Stability",
  "start_index": 21,
  "end_index": 22,
  "summary": "Covers the Federal Reserve's financial stability oversight...",
  "sub_nodes": [
    {
      "node_id": "0007",
      "title": "Monitoring Financial Vulnerabilities",
      "start_index": 22,
      "end_index": 28,
      "summary": "Describes the Fed's vulnerability monitoring framework..."
    },
    {
      "node_id": "0008",
      "title": "Domestic and International Cooperation",
      "start_index": 28,
      "end_index": 31,
      "summary": "Federal Reserve collaboration with international bodies..."
    }
  ]
}

Каждый node_id указывает на необработанный контент соответствующего раздела: текст, таблицы и изображения. Языковая модель может запрашивать содержимое любого узла по мере необходимости.

Ключевая особенность архитектуры заключается в местоположении этого индекса. База данных векторов хранит отдельный, статический индекс эмбеддингов вне самой модели. Здесь же дерево JSON находится в активном контексте языковой модели во время выполнения задачи. VectifyAI называет это индексом внутри контекста, причем модель не просто запрашивает его данные, а анализирует их в реальном времени.

Шаг 2: поиск в дереве на основе логических рассуждений

Когда поступает вопрос, PageIndex передаёт большой языковой модели дерево, содержащее только заголовки и краткое содержание без самого текста, фактически задавая вопрос о том, где искать ответ с учётом этой структуры и вопроса. Модель читает заголовки и краткое содержание узлов, определяет, какие разделы, скорее всего, содержат ответ, и возвращает список идентификаторов узлов. Затем система загружает реальный контент этих узлов.

Процесс поиска представляет собой цикл:

  1. Проанализируйте оглавление, чтобы понять структуру и выделить возможные разделы.
  2. Выберите раздел, который с наибольшей вероятностью содержит необходимую информацию.
  3. Прочитайте его, извлекая сырой текст из соответствующего узла.
  4. Проверьте, достаточно ли этого. Если да, запишите ответ. Если нет, вернитесь к первому шагу и попробуйте другой раздел.

Это другая парадигма по сравнению с векторным поиском. Векторная база данных параллельно вычисляет косинусное сходство для каждого фрагмента, что делает процесс быстрым, но поверхностным. PageIndex же использует ИИ-модель для анализа того, где, вероятно, находится ответ. При этом модель может определять перекрестные ссылки, понимать, что вопрос, касающийся данных из приложения, относится к соответствующему узлу, и осознавать, что многокомпонентный вопрос требует информации из двух разделов. Каждый шаг также оставляет след рассуждений, что позволяет увидеть, какие узлы были посещены и почему. Таким образом, процесс поиска перестаёт быть «чёрным ящиком».

Пример из Приложения G

Демонстрация, созданная с использованием интеграции MCP от VectifyAI, показывает, почему это важно. Кто-то спрашивает о сумме отсроченных активов в годовом отчете Федерального резерва. Основная часть отчета на страницах с 75 по 82 рассматривает изменения в отсроченных активах, но так и не указывает их общую сумму. Однако на странице 77 приводится предложение о том, что в таблице 5.3 обобщены доходы, расходы и распределения, а в приложении G приводится более подробная информация.

Vector RAG застревает на этом этапе. Приложение G представляет собой таблицу чисел, не имеющую семантической связи с вопросом об отсроченных активах, поэтому база данных игнорирует его. PageIndex работает иначе: большая языковая модель читает структуру отчета, переходит в финансовый раздел, находит ссылку на приложение G, следует по ней внутри структуры, извлекает нужную таблицу и возвращает точное значение, при этом отслеживается каждый шаг рассуждений.

Python, от начала до конца

Приведённый ниже код взят из официальной книги рецептов PageIndex, с комментариями, объясняющими его работу. Начните с установки:

pip install pageindex openai

Импорт:

import os
import json
import asyncio
from pageindex import PageIndexClient
from openai import AsyncOpenAI

Затем учетные данные и клиенты. Ключ API получается с панели управления PageIndex:

# Grab an API key from https://dash.pageindex.ai/api-keys
PAGEINDEX_API_KEY = os.environ["PAGEINDEX_API_KEY"]
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]pi_client = PageIndexClient(api_key=PAGEINDEX_API_KEY)
openai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)

Создание дерева

Импортируем утилиты:

import pageindex.utils as utils

Загрузите PDF, и PageIndex сгенерирует дерево. Индексация занимает некоторое время, поэтому скрипт будет проверять статус до тех пор, пока всё не будет готово, после чего выведет результат:

# Upload a PDF; PageIndex handles the tree generation
doc = pi_client.upload("annual_report_2024.pdf")
doc_id = doc["doc_id"]# Tree generation takes a bit, so we poll
while not pi_client.is_retrieval_ready(doc_id):
    print("Still indexing...")
    import time; time.sleep(5)# Grab the tree and take a look
tree = pi_client.get_tree(doc_id, node_summary=True)["result"]
print("Document Tree:")
utils.print_tree(tree)

В отчете отображаются все разделы, подразделы и диапазоны страниц, что позволяет сразу понять, была ли структура корректно скопирована.

Позвольте большой языковой модели искать в структуре

Это ключевой шаг. Функция принимает структуру и запрос:

async def find_relevant_nodes(tree: dict, query: str) -> list:
    """LLM reasons over tree structure to identify relevant nodes."""

Внутри сырой текст удаляется для экономии токенов, поскольку модели нужны только заголовки и краткое содержание. В промпте модель представляется как эксперт по поиску документов, ей указывается следовать перекрестным ссылкам, и запрашивается JSON с её обоснованием и списком идентификаторов узлов:

    # Strip raw text to save tokens; the LLM only needs titles and summaries
    tree_without_text = utils.remove_fields(
        tree.copy(), fields=["text"]
    )    search_prompt = f"""
    You are a document retrieval expert. Given a question and
    a hierarchical tree structure of a document, identify all
    nodes likely to contain the answer.    Each node has a node_id, title, and summary.
    Follow cross-references if a section mentions another.    Question: {query}    Document tree structure:
    {json.dumps(tree_without_text, indent=2)}    Reply in this JSON format only:
    {{
        "thinking": "<reasoning about which nodes are relevant>",
        "node_list": ["node_id_1", "node_id_2"]
    }}
    """    response = await openai_client.chat.completions.create(
        model="gpt-4.1",
        messages=[{"role": "user", "content": search_prompt}],
        temperature=0,
        response_format={"type": "json_object"},
    )    result = json.loads(response.choices[0].message.content)
    print(f"LLM reasoning: {result['thinking']}")
    return result["node_list"]

Загрузка контента и ответ

Следующая функция собирает необработанный текст для выбранных узлов:

def collect_node_content(tree: dict, node_ids: list) -> str:
    """Pull raw text from the nodes the LLM selected."""
    all_nodes = utils.flatten_tree(tree)
    context_parts = []

Затем тело цикла собирает контекст, причем каждый раздел обозначается заголовком и диапазоном страниц, а вся структура обрабатывает его: выбираются узлы, загружается контент, генерируется ответ с цитатами, и ответ вместе с использованными узлами возвращается.

    for node in all_nodes:
        if node["node_id"] in node_ids:
            title = node.get("title", "Untitled")
            pages = f"pages {node.get('start_index', '?')}-{node.get('end_index', '?')}"
            text = node.get("text", "")
            context_parts.append(
                f"[{title} | {pages}]\n{text}"
            )
    return "\n\n---\n\n".join(context_parts)
async def answer_query(tree: dict, query: str) -> dict:
    """Full vectorless RAG pipeline: tree search + answer generation."""    # Step 1: LLM picks the nodes
    node_ids = await find_relevant_nodes(tree, query)    # Step 2: Fetch content from those nodes
    context = collect_node_content(tree, node_ids)    # Step 3: Generate answer with citations
    answer_prompt = f"""
    Answer the question using only the provided context.
    Cite specific pages and sections in your answer.    Context:
    {context}    Question: {query}
    """    response = await openai_client.chat.completions.create(
        model="gpt-4.1",
        messages=[{"role": "user", "content": answer_prompt}],
        temperature=0,
    )    return {
        "answer": response.choices[0].message.content,
        "retrieved_nodes": node_ids,
        "context_length": len(context),
    }
# Run it
query = "What was the total value of deferred assets in 2023?"
result = asyncio.run(answer_query(tree, query))
print(result["answer"])
print(f"Nodes used: {result['retrieved_nodes']}")

Подключение к MCP

Для Claude, Cursor или любого агента, совместимого с MCP, PageIndex подключается напрямую через хостинговый сервер:

{
  "mcpServers": {
    "pageindex": {
      "type": "http",
      "url": "https://api.pageindex.ai/mcp",
      "headers": {
        "Authorization": "Bearer your_api_key"
      }
    }
  }
}

Также существует локальный сервер MCP для загрузки файлов с диска, и для его работы требуется Node.js 18 или новее:

{
  "mcpServers": {
    "pageindex": {
      "command": "npx",
      "args": ["-y", "@pageindex/mcp"]
    }
  }
}

Цифры в контексте

Основная цифра взята из FinanceBench, который использует реальные документы, подаваемые в SEC, включая 10-K, 10-Q и 8-K, и принимает только точные ответы. Агент финансового анализа Mafin 2.5 от VectifyAI, разработанный на основе PageIndex, был протестирован на всем наборе данных. Уровень точности:

Система Точность Охват эталонов
Mafin 2.5 (PageIndex) 98,7% 100%
Традиционный векторный RAG примерно 50% различается
GPT-4o без RAG примерно 31% 100%
Perplexity примерно 45% различается

Разница в примерно 49 процентных пунктов по сравнению с традиционным векторным RAG — это не незначительное улучшение. Это совершенно другой уровень результатов. Всегда выделяются три фактора:

  • Перекрестные ссылки. Внутридокументовые указатели вроде «см. Приложение G» обрабатываются с помощью дерева структуры. Поиск по сходству не учитывает их.
  • Сохранение структуры. Таблицы содержат заголовки, сноски и взаимосвязи между ячейками.PageIndex сохраняет их в виде узлов дерева, тогда как разбиение на части уничтожает эти связи.
  • Многократные вычисления. Вопросы, сравнивающие финансовый год 2023 с финансовым годом 2024 и упомянутые в разных разделах документа, естественным образом обрабатываются с помощью итеративных циклов.

Какие у него недостатки

PageIndex впечатляет в своей нише, но он не может заменить векторные решения типа RAG во всех случаях.

  • Он медленнее. Каждая операция поиска включает несколько вызовов больших языковых моделей: чтение индекса, анализ узлов, загрузка контента, проверка достаточности информации, возможно, повторный цикл. Vector RAG отвечает за миллисекунды, а PageIndex — за секунды. Сооснователь отметил, что поскольку поиск происходит непосредственно в процессе генерации, время получения первого токена может сравниться с временем обычного вызова большой языковой модели, однако общая задержка всё равно выше.
  • Это дороже. На каждый запрос требуется несколько операций инференса вместо одного поиска в эмбеддингах. При большом объёме данных расчёты становятся крайне затратными.
  • Он разработан для глубины, а не для ширины. Он отлично справляется с глубоким извлечением информации из одного длинного документа. Поиск 10 000 коротких документов одновременно — это сфера применения векторных баз данных, а создание и анализ деревьев для каждого из них не является практичным решением.
  • Структура имеет большое значение. Аккуратно оформленная заявка в SEC формирует отличную иерархическую структуру. Плохо сформатированный скан без логических разделов приводит к неудовлетворительному оглавлению, из-за чего страдает вся последующая информация. Для подобных случаев существует режим работы на основе визуального анализа, но структурированные документы по-прежнему остаются оптимальным вариантом.
  • Логика ИИ-моделей также несовершенна. Метод Vector RAG дает ошибки, поскольку векторные представления лишь приблизительно отражают смысл текста. Система PageIndex тоже допускает ошибки, когда логика рассуждений является приблизительной: модель может перейти к неверному разделу, неправильно прочитать краткое содержание или пропустить важный подузел. Эти сбои легче интерпретировать и, пожалуй, проще отлаживать, но они всё равно происходят.
  • Один показатель качества. FinanceBench оценивает качество проверки на хорошо структурированных документах, подаваемых в SEC. Результаты работы с неструктурированными, многодоменными, неоднозначными запросами к совершенно разным типам документов не были независимо проверены в такой же степени. 98,7 процента — это реальное значение, но важно понимать, что именно оно измеряет.
  • Когда использовать его

    Используйте PageIndex в следующих случаях:

    • документы длинные, структурированные и профессиональные: годовые отчеты, контракты, регуляторные документы, технические руководства
    • точность важнее скорости, например, когда неверный ответ приводит к финансовым потерям или рискам соблюдения нормативов
    • запросы требуют многократных вычислений или перехода между разделами
    • вам нужны записи аудита, поскольку каждый ответ сопровождается хронологией выводов и ссылками на элементы структуры, что ценится в регулируемых отраслях

    Используйте векторный RAG в следующих случаях:

    • вам нужны ответы за доли секунды при высокой нагрузке на поисковые запросы
    • вы ищете в большом корпусе кратких документов
    • документы неструктурированы или имеют разговорный формат
    • точность в 90 процентов уже считается достаточной
    • основным ограничением является стоимость одного запроса

    Гибридный подход, вероятно, недостаточно изучен. Используйте векторный поиск, чтобы определить, какой документ в большом корпусе имеет значение, а затем передайте его в PageIndex для более глубокой обработки.

    Что нового с момента запуска

    С сентября 2025 года проект развивается очень быстро.

    Агентный векторный RAG. Новейшее обновление позволяет интегрировать самостоятельно размещённый PageIndex в SDK OpenAI Agents. Агенту предоставляются три инструмента (get_document(), get_document_structure() и get_page_content()), и он самостоятельно анализирует структуру, вызывая соответствующие инструменты и получая содержимое без необходимости вручную выбирать узлы. Это пример, с которого следует начинать при создании агентных рабочих процессов:

    pip install openai-agents
    python3 examples/agentic_vectorless_rag_demo.py
    

    Режим, основанный на визуальном анализе без OCR. Теперь специализированный поток обработки данных полностью исключает использование OCR. Изображения страниц напрямую передаются в модель, способную анализировать визуальную информацию, а структура дерева формируется на основе того, что видит эта модель на странице. Это критически важно для финансовых документов, где формат отчета имеет такое же значение, как и текст. Диаграммы, таблицы с объединенными ячейками и сноски остаются нетронутыми, поскольку ничто не преобразуется сначала в текст.

    SDK на TypeScript pageindex-js-sdk появился в начале 2026 года для интеграции с Node.js и веб-инструментами для обработки документов. Расширение для рабочего стола .mcpb одним кликом устанавливает PageIndex в Claude Desktop с автоматической обработкой OAuth. ChatIndex, отдельный репозиторий с января 2026 года, применяет ту же концепцию индексации деревьев к длинным историям чатов.

    Более широкие тенденции

    PageIndex отражает более широкий сдвиг от пассивного поиска, который извлекает всё, что выглядит похоже, к активному, основанному на логических рассуждениях поиску, который определяет, где искать. Это уже заметно в инструментах для программирования: Claude Code и Cursor отошли от использования векторных технологий RAG для кода в пользу активного исследования кодовой базы, и команда PageIndex ожидает, что документы последуют этому примеру. Для структурированных документов такое прогнозирование кажется разумным.

    Векторные базы данных не исчезнут. Они быстрые, дешевые и достаточно хороши для решения огромного количества задач. Однако там, где точность, прозрачность и глубокое понимание документов являются абсолютно необходимыми, как в финансовых аудитах, юридических исследованиях, медицинских записях и соблюдении нормативов, поиск, основанный на логических рассуждениях, является гораздо более подходящим решением.

    Код и документация доступны по адресу https://github.com/VectifyAI/PageIndex, а документация — по адресу https://docs.pageindex.ai/.

    Связанная литература

  • pgvector или SQL Server 2025 в качестве векторного хранилища для RAG: настройка, запросы и особенности — Использование PostgreSQL с pgvector и встроенных векторов SQL Server 2025 для RAG: настройка, поиск по коэффициенту косинуса, объединение с бизнес-данными, а также шесть особенностей предварительной версии SQL Server, которых следует избегать.
  • Разбиение на части «родитель-дочерний» и иерархическое индексирование для улучшения поиска в RAG — Почему маленькие части помогают в поиске, но мешают получению ответа, и как разбиение на части «родитель-дочерний», удаление дубликатов и иерархическое индексирование восстанавливают контекст при поиске в RAG.
  • Как работает RAG: эмбеддинги, векторные базы данных и чанкинг — Проследите за одним фрагментом текста от токенизации через объединение данных до поиска с использованием косинусного сходства и поймите, почему процесс чанкинга и использование моделей эмбеддингов определяют качество RAG.
  • RAG без векторов с PageIndex: поиск на основе логических рассуждений вместо векторов — Как PageIndex заменяет эмбеддинги и чанкинг деревом документов, управляемым большой языковой моделью, с пошаговым примером на Python и рекомендациями относительно ситуаций, когда векторный RAG всё ещё предпочтительнее.
  • RAG без фреймворка: чанки, оценка, бюджет, промпт — объяснение концепции RAG через простой выбор токенов: краткий пример на Python с оценкой перекрытия слов, механизмом контроля бюджета токенов и тем, что на самом деле улучшают эмбеддинги и хранилища векторов.