Дайджесты новостей
Схема мультивекторного поиска MaxSim модели pplx-embed-v2-late по сложной таблице PDF

Поиск по сложным PDF без потери таблиц: модель pplx-embed-v2-late от Perplexity

Если ты хоть раз пытался построить систему поиска по корпоративным документам (RAG), то наверняка сталкивался с тихим ужасом: пользователь задает точный вопрос по финансовому отчету («Какова операционная маржа в третьем квартале?»), а умная языковая модель либо разводит руками, либо берет цифру с потолка.

Почему так происходит? Корень проблемы спрятан в традиционных алгоритмах векторного поиска (Dense Retrieval). Вчера мы вскользь упоминали мультимодальные эмбеддинги Perplexity pplx-embed-v2-late, а сегодня давай подробно разберем, как устроен этот механизм и почему он ломает привычный подход к извлечению данных.

Классический энкодер берет страницу сложного PDF-документа — со сносками, графиками, многоуровневыми таблицами и балансами — и пытается утрамбовать весь этот массив в один-единственный плоский вектор (обычно на 768 или 1536 чисел). В этой «усушке» неизбежно теряется геометрия: строки таблиц перемешиваются с заголовками, а мелкие цифры в сносках просто растворяются в общем шуме.

Команда Perplexity AI пошла другим путем и выложила в открытый доступ семейство моделей pplx-embed-v2-late, построенное на архитектуре позднего взаимодействия (Late-Interaction).

Как работает позднее взаимодействие и оператор MaxSim

Вместо того чтобы сплющивать документ в один вектор, pplx-embed-v2-late сохраняет для каждого токена страницы свой собственный компактный 128-мерный вектор. Если на странице 500 токенов, модель формирует матрицу из 500 векторов.

Когда ты отправляешь поисковый запрос, магия происходит на этапе расчета сходства. Модель использует оператор максимального сходства (MaxSim):

  • Каждое отдельное слово твоего запроса сравнивается со всеми токенами документа;
  • Для каждого слова запроса находится токен документа с максимальным совпадением;
  • Полученные максимумы суммируются в итоговый скор релевантности.

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

При этом модель нативно мультимодальна: страницу можно подавать не только как текст, но и как прямое изображение скана (PNG/JPEG). Модель сама выравнивает визуальные токены таблицы с текстом запроса, избавляя тебя от капризных OCR-библиотек.

Семейство моделей и асимметричная индексация

Линейка pplx-embed-v2-late включает две основные версии:

  1. pplx-embed-v2-late-0.6b (~340M активных параметров) — сверхлегкая модель, которую можно запускать локально даже на слабом GPU или CPU;
  2. pplx-embed-v2-late-9b (~7.4B активных параметров) — флагман для индексации документов экстремальной сложности.

Поскольку обе модели проецируют данные в единое 128-мерное пространство, доступен элегантный трюк: асимметричный деплой. Ты можешь предварительно проиндексировать корпоративный архив тяжелой 9B-моделью, а пользовательские запросы на лету кодировать легковесной 0.6B-версией с задержкой менее 15 миллисекунд.

Практический запуск на Python через Sentence Transformers

Благодаря поддержке в библиотеке sentence-transformers >= 6.0.0 запустить локальный инференс можно буквально в десяток строк кода:

import torch
from PIL import Image
from sentence_transformers import MultiVectorEncoder

# Загрузка легковесной модели 0.6B на локальный GPU
device = "cuda" if torch.cuda.is_available() else "cpu"
model = MultiVectorEncoder(
    "perplexity-ai/pplx-embed-v2-late-0.6b",
    device=device,
    torch_dtype=torch.float16 if device == "cuda" else torch.float32,
)

# 1. Индексация текстового фрагмента и изображения таблицы
document_text = (
    "Отчет Q3 2026: Выручка облачного сегмента составила $4.2B, "
    "показав прирост 28% YoY. Операционная маржа выросла до 31%."
)
document_image = Image.open("balance_sheet_q3.png").convert("RGB")

doc_embeddings = model.encode_document([document_text, document_image])

# 2. Кодирование пользовательского запроса
query = "Какова выручка облачного направления за третий квартал 2026 года?"
query_embedding = model.encode_query([query])

# 3. Расчет релевантности через оператор MaxSim
similarity_scores = model.similarity(query_embedding, doc_embeddings)

print(f"Релевантность текста: {similarity_scores[0][0]:.4f}")
print(f"Релевантность скана таблицы: {similarity_scores[0][1]:.4f}")

А вот как организовать потоковую конвертацию и индексацию многостраничного PDF:

from pdf2image import convert_from_path

def index_pdf_document(pdf_path: str, model: MultiVectorEncoder):
    pages = convert_from_path(pdf_path, dpi=150)
    indexed_pages = []
    for idx, page in enumerate(pages):
        page_rgb = page.convert("RGB")
        embedding = model.encode_document([page_rgb])
        indexed_pages.append({"page_number": idx + 1, "embedding": embedding})
    return indexed_pages
Лайфхак асимметричного поиска

Если база документов насчитывает миллионы страниц, не пытайся считать MaxSim в лоб по всему массиву: это потребует колоссального объема вычислений. Настрой двухэтапный поиск (Two-Stage Retrieval): сначала быстрый фильтр (BM25 или одиночный плотный вектор) отбирает 100 наиболее похожих кандидатов, а затем pplx-embed-v2-late проводит точный попиксельный и пословный скоринг первой сотни.

Обратная сторона медали: хранение индексов

Где подвох? В объеме дискового пространства. Сохранение матрицы 128-мерных векторов на каждый токен страницы раздувает векторный индекс в 20–50 раз по сравнению с привычными одиночными эмбеддингами. Для боевой эксплуатации тебе потребуется современная векторная база данных с поддержкой мультивекторного квантования (например, Qdrant или Milvus). Но если твоя задача — находить точные цифры в балансах без галлюцинаций, эта плата за надежность полностью оправдана.