Дата публикации
ai_products

Amazon Nova Multimodal Embeddings: как искать по чертежам, графикам и отчётам, а не только по тексту

Что нового

Amazon запустила Amazon Nova Multimodal Embeddings (MME) в составе Amazon Bedrock и связку с Amazon S3 Vectors. Это не просто ещё один «эмбеддер», а инструмент, который умеет кодировать в один векторный простор:

  • текстовые запросы и документы;
  • отдельные изображения (CAD, фото, графики, схемы);
  • страницы PDF как цельные «document image».

Ключевые факты и цифры:

  • Один общий векторный простор для текста, картинок и страниц документов. Можно напрямую сравнивать текстовый запрос и картинку по косинусному сходству.
  • Настраиваемая размерность эмбеддингов: 256, 384, 1024 или 3072. В примере используют 1024 как баланс между качеством и стоимостью.
  • Специальный режим DOCUMENT_IMAGE для страниц с «мешаниной» из таблиц, графиков, схем и аннотаций.
  • Ассиметричные эмбеддинги по параметру embeddingPurpose:
    • GENERIC_INDEX — для индексации документов;
    • GENERIC_RETRIEVAL — для запросов.
  • Интеграция с Amazon S3 Vectors: управляемое хранилище и поиск по векторам без поднятия собственного кластера.

Amazon протестировала систему на наборе синтетических документов по аэрокосмическому производству и сравнила два пайплайна:

  1. Мультимодальный — изображения и PDF-страницы индексируются как картинки через Nova Multimodal Embeddings.
  2. Текстовый базовый — сначала OCR через Amazon Nova 2 Lite, потом эмбеддинг только текста тем же Nova MME.

Результаты по качеству:

  • Мультимодальный поиск:
    • Recall@5 — 90%;
    • Recall@10 — 96%;
    • MRR — 0,92 (релевантный документ почти всегда на первом месте).
  • Качество ответов (LLM-as-judge, шкала 1–5):
    • мультимодальный пайплайн — 4,88 / 5 (нормализовано 0,977);
    • текстовый (OCR) — 2,00 / 5 (нормализовано 0,400);
    • мультимодальный вариант даёт более высокий балл в 23 из 26 запросов.

По затратам и сложности реализации:

  • Мультимодальный пайплайн требует одного вызова модели на документ (эмбеддинг).
  • Текстовый базовый пайплайн требует двух вызовов (OCR + эмбеддинг) и дополнительных промптов для OCR.
  • В результате стоимость и сложность пайплайна для мультимодального варианта примерно в два раза ниже на этапе индексации.

Как это работает

Общая идея

Amazon Nova Multimodal Embeddings кодирует разные типы контента в один векторный простор. Это означает:

  • текстовый запрос → вектор;
  • изображение (чертёж, график, фото) → вектор;
  • страница PDF как картинка → вектор.

Дальше всё строится вокруг стандартного векторного поиска (косинусное расстояние) в Amazon S3 Vectors. Никаких специальных хаков для картинок не нужно: текст и изображение сравниваются как обычные векторы.

Мультимодальные эмбеддинги

Для картинок и страниц PDF используется один и тот же API InvokeModel в Bedrock. В запросе можно указать:

  • embeddingDimension — 256 / 384 / 1024 / 3072;
  • embeddingPurpose:
    • GENERIC_INDEX — когда вы индексируете документы;
    • GENERIC_RETRIEVAL — когда считаете эмбеддинг запроса;
  • тип входа:
    • image с detailLevel:
      • STANDARD_IMAGE — обычные изображения (CAD, фото);
      • DOCUMENT_IMAGE — страницы PDF с таблицами, графиками и подписями;
    • или text — для текстовых запросов и документов.

Пример эмбеддинга картинки (чертёж сопла двигателя):

import base64, json, boto3

bedrock_runtime = boto3.client("bedrock-runtime", region_name="us-east-1")
MODEL_ID = "amazon.nova-2-multimodal-embeddings-v1:0"

with open("dataset/nozzle_assembly_diagram.png", "rb") as f:
    b64_data = base64.b64encode(f.read()).decode("utf-8")

request_body = {
    "taskType": "SINGLE_EMBEDDING",
    "singleEmbeddingParams": {
        "embeddingPurpose": "GENERIC_INDEX",
        "embeddingDimension": 1024,
        "image": {
            "format": "png",
            "detailLevel": "STANDARD_IMAGE",
            "source": {"bytes": b64_data},
        },
    },
}

response = bedrock_runtime.invoke_model(
    modelId=MODEL_ID,
    body=json.dumps(request_body),
    accept="application/json",
    contentType="application/json",
)

embedding = json.loads(response["body"].read())["embeddings"][0]["embedding"]
print(f"Embedding dimension: {len(embedding)}")  # 1024

Amazon S3 Vectors

S3 Vectors — это слой поверх S3 для хранения и поиска по векторам. Вы создаёте:

  • vector bucket — контейнер для векторов;
  • index — индекс с нужной размерностью и метрикой расстояния.

Пример создания индекса с косинусной метрикой и размерностью 1024:

s3vectors = boto3.client("s3vectors", region_name="us-east-1")

# Create vector bucket and index
s3vectors.create_vector_bucket(vectorBucketName="manufacturing-vectors")

s3vectors.create_index(
    vectorBucketName="manufacturing-vectors",
    indexName="manufacturing-multimodal",
    dataType="float32",
    dimension=1024,
    distanceMetric="cosine",
)

# Ingest a batch of embeddings with metadata
vectors = [
    {
        "key": "img-nozzle_assembly_diagram",
        "data": {"float32": embedding},
        "metadata": {
            "source_file": "nozzle_assembly_diagram.png",
            "type": "image",
        },
    }
]

s3vectors.put_vectors(
    vectorBucketName="manufacturing-vectors",
    indexName="manufacturing-multimodal",
    vectors=vectors,
)

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

Поиск по индексу

Запрос пользователя — обычный текст. Nova Multimodal Embeddings генерирует для него эмбеддинг с embeddingPurpose="GENERIC_RETRIEVAL", после чего S3 Vectors возвращает ближайшие векторы.

query = "What is the torque specification for the chamber flange bolts?"

request_body = {
    "taskType": "SINGLE_EMBEDDING",
    "singleEmbeddingParams": {
        "embeddingPurpose": "GENERIC_RETRIEVAL",
        "embeddingDimension": 1024,
        "text": {"truncationMode": "END", "value": query},
    },
}

response = bedrock_runtime.invoke_model(
    modelId=MODEL_ID,
    body=json.dumps(request_body),
    accept="application/json",
    contentType="application/json",
)

query_embedding = json.loads(response["body"].read())["embeddings"][0]["embedding"]

results = s3vectors.query_vectors(
    vectorBucketName="manufacturing-vectors",
    indexName="manufacturing-multimodal",
    queryVector={"float32": query_embedding},
    topK=5,
    returnDistance=True,
    returnMetadata=True,
)

for v in results["vectors"]:
    print(f" {v['key']} (distance: {v['distance']:.4f})")

В тесте именно этот запрос возвращает:

  • изображение с таблицей моментов затяжки;
  • схему с расположением болтов фланца.

Текстовый пайплайн с OCR попадает в эту цель только если OCR безошибочно распознал цифры и подписи на чертеже, что для сложных технических схем часто не выполняется.

Два параллельных пайплайна

Amazon сравнила два подхода на одном и том же наборе документов:

Датасет:

  • 15 одиночных технических изображений:
    • CAD-диаграммы;
    • отчёты по инспекциям с фото и разметкой;
    • графики испытаний;
    • спецификации материалов;
    • блок-схемы процессов.
  • 5 многостраничных PDF:
    • инструкции по сборке;
    • отчёты о горячих огневых испытаниях;
    • уведомления об инженерных изменениях;
    • сертификаты материалов;
    • отчёты о несоответствиях.

Pipeline A — мультимодальный:

  • Каждое изображение → напрямую в Nova MME как image.
  • Каждая страница PDF → как DOCUMENT_IMAGE.
  • Эмбеддинги → в индекс Amazon S3 Vectors.

Pipeline B — текстовый базовый:

  • Каждое изображение и страница PDF → в Amazon Nova 2 Lite для OCR.
  • Промпт для OCR:
Extract ALL visible text from this image exactly as it appears. Include all numbers, labels, annotations, table contents, headers, and footnotes. Preserve the structure (tables, lists, sections) as much as possible. Return only the extracted text, no commentary.
  • Полученный текст → в Nova MME как text.
  • Эмбеддинги текста → в отдельный индекс S3 Vectors.

Дальше для обоих пайплайнов используется один и тот же генератор — Amazon Nova 2 Lite.

Оценка качества: поиск и генерация отдельно

Amazon разделила оценку на два уровня:

  1. Retrieval — находит ли поиск правильные документы.
  2. Generation — может ли LLM выдать корректный ответ, имея эти документы.

Retrieval:

  • Для каждого из 26 запросов:
    • генерируется текстовый эмбеддинг (GENERIC_RETRIEVAL);
    • выполняется поиск по мультимодальному индексу;
    • список retrieved_ids сравнивается с эталонным набором релевантных документов.

Пример:

query = "What is the torque specification for the chamber flange bolts?"

query_embed = generate_text_embedding(
    query,
    dim=1024,
    purpose="GENERIC_RETRIEVAL"
)

results = s3vectors.query_vectors(
    vectorBucketName="manufacturing-vectors",
    indexName="manufacturing-multimodal",
    queryVector={"float32": query_embed},
    topK=10,
    returnDistance=True,
    returnMetadata=True,
)

retrieved_ids = [v["key"] for v in results["vectors"]]

Считаются три метрики для K = 3, 5, 10:

  • Recall@K — доля релевантных документов в топ-K;
  • MRR — насколько высоко в списке появляется первый релевантный документ;
  • NDCG@K — качество ранжирования с учётом позиций.

Generation:

  • Оба пайплайна отдают в Nova 2 Lite топ-5 найденных документов.
  • Для мультимодального пайплайна это картинки.
  • Для текстового — текст после OCR.

Пример генерации ответа в мультимодальном варианте:

def generate_answer_multimodal(query, retrieved_keys):
    """Pass retrieved images directly as multimodal context."""
    content_blocks = []

    for key in retrieved_keys[:5]:
        img_path = vector_key_to_image_path(key)
        with open(img_path, "rb") as f:
            img_bytes = f.read()

        content_blocks.append({"text": f"Retrieved document:"})
        content_blocks.append({
            "image": {"format": "png", "source": {"bytes": img_bytes}}
        })

    content_blocks.append({
        "text": (
            f"Review each image above carefully. "
            f"Answer the following question concisely and precisely.\n\n\n"
            f"Question: {query}\n\n\n"
            f"Answer:"
        )
    })

    response = bedrock_runtime.converse(
        modelId="us.amazon.nova-2-lite-v1:0",
        messages=[{"role": "user", "content": content_blocks}],
        inferenceConfig={"maxTokens": 500, "temperature": 0.1},
    )

    return response["output"]["message"]["content"][0]["text"]

Оценка ответов — через LLM-as-judge. В роли судьи используется Anthropic Claude Sonnet 4.5, который получает вопрос, эталонный ответ и сгенерированный ответ, а затем выставляет балл от 1 до 5.

def judge_correctness(query, generated_answer, ground_truth):
    prompt = (
        "You are an evaluation judge. Score the generated answer compared "
        "to the ground truth on a scale of 1-5.\n\n\n"
        "1 = Completely wrong or irrelevant\n"
        "2 = Partially relevant but mostly incorrect\n"
        "3 = Somewhat correct but missing key information\n"
        "4 = Mostly correct with minor omissions\n"
        "5 = Fully correct and complete\n\n\n"
        f"Question: {query}\n"
        f"Ground Truth: {ground_truth}\n"
        f"Generated Answer: {generated_answer}\n\n\n"
        'Respond with ONLY a JSON object: '
        '{"score": <1-5>, "reason": "<brief explanation>"}'
    )

    response = bedrock_runtime.converse(
        modelId="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
        messages=[{"role": "user", "content": [{"text": prompt}]}],
        inferenceConfig={"maxTokens": 200, "temperature": 0.0},
    )

    return response["output"]["message"]["content"][0]["text"]

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

Очистка ресурсов

После экспериментов авторы удаляют индексы и bucket, чтобы не платить за хранение:

# Delete indexes
s3vectors.delete_index(vectorBucketName=S3_VECTOR_BUCKET, indexName=MME_INDEX)
s3vectors.delete_index(vectorBucketName=S3_VECTOR_BUCKET, indexName=TEXT_ONLY_INDEX)

# Delete vector bucket
s3vectors.delete_vector_bucket(vectorBucketName=S3_VECTOR_BUCKET)

Инференс эмбеддингов в Amazon Bedrock тарифицируется «по запросу» — без постоянной инфраструктуры.

Что это значит для вас

Где это реально полезно

Если вы работаете с технической документацией, где критичные данные часто живут на картинках, Nova Multimodal Embeddings сильно меняет правила игры. Типичные сценарии:

  1. Промышленность и инжиниринг:

    • аэрокосмика, автопром, тяжёлое машиностроение;
    • поиск по чертежам, схемам, графикам испытаний, отчётам по инспекциям;
    • пример из статьи: вопрос про максимальную температуру стенки в горловине сопла — ответ находится на тепловой карте, а не в тексте.
  2. Контроль качества и инспекции:

    • отчёты с рентгенограммами сварных швов;
    • фото дефектов с аннотациями;
    • визуальные маркеры «pass/fail» на схемах.
  3. Материалы и испытания:

    • S-N кривые усталости (как в примере с Inconel 718);
    • графики нагрузка–деформация;
    • диаграммы предельных состояний.
  4. Бизнес-процессы и операционные документы:

    • блок-схемы производственных процессов с «quality hold points»;
    • диаграммы с цветовой кодировкой этапов и временных затрат;
    • схемы P&ID, где тип подшипника или клапана указан только подписью на рисунке.

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

Мультимодальные эмбеддинги решают именно эту проблему:

  • вы ищете текстом;
  • система находит картинки и страницы PDF по смыслу, а не по распознанному тексту;
  • генератор (Nova 2 Lite) смотрит на оригинальное изображение и сам читает подписи, значения на графиках и структуру схемы.

Где это не даст большого выигрыша

Если ваши документы почти полностью текстовые и хорошо структурированы:

  • юридические документы;
  • обычные отчёты в PDF с копируемым текстом;
  • документация в Confluence/Notion;

то мультимодальный подход не принесёт драматического улучшения. В этих сценариях обычный текстовый RAG с качественным эмбеддером и поиском по тексту работает достаточно хорошо, а OCR не сильно портит картину.

Ограничения и организационные моменты

  • Доступность. Amazon Bedrock и Amazon S3 Vectors работают в регионах AWS, в примере используется us-east-1. Прямой доступ из России может требовать VPN и аккаунт AWS с включённым доступом к конкретным моделям:
    • amazon.nova-2-multimodal-embeddings-v1:0;
    • us.amazon.nova-2-lite-v1:0;
    • us.anthropic.claude-sonnet-4-5-20250929-v1:0 (для LLM-as-judge).
  • Подготовка данных. Вам всё равно нужно:
    • собрать и структурировать изображения и PDF;
    • нарезать многостраничные документы по страницам или логическим фрагментам;
    • продумать схему метаданных (ID документа, версия, тип, дата и т.д.).
  • Размер эмбеддингов. 3072-мерные векторы лучше отражают нюансы, но дороже по хранению и вычислениям. Для большинства задач разумный старт — 1024, как в примере.

Практический совет по внедрению

  1. Начните с пилота на узком наборе документов:

    • выберите 50–200 файлов, где много графики и схем;
    • сделайте два индекса: мультимодальный и текстовый через OCR;
    • соберите 20–30 реальных запросов от инженеров.
  2. Оцените качество так же, как в статье:

    • посмотрите, какие документы попадают в топ-5 для каждого запроса;
    • попросите инженеров оценить ответы LLM по шкале 1–5.
  3. Решите, где мультимодальность даёт максимальный выигрыш:

    • возможно, имеет смысл индексировать мультимодально только чертежи, графики и отчёты по испытаниям;
    • а текстовые спецификации и инструкции оставить в обычном текстовом пайплайне.
  4. Продумайте стоимость:

    • мультимодальный вариант дешевле текстового+OCR по числу вызовов моделей;
    • но хранение векторов для тысяч высокодетализированных страниц всё равно потребует бюджета.

Если вы в России и у вас нет прямого доступа к AWS, эту архитектуру можно использовать как эталон для выбора аналогов: локальный векторный стор, мультимодальный эмбеддер, LLM с поддержкой картинок.

Место на рынке

Прямых численных сравнений с GPT-4o, Claude 3.5 или другими мультимодальными эмбеддерами Amazon не приводит. Зато хорошо видна позиция продукта по архитектуре и целям.

  • Фокус — не чат-бот, а именно инфраструктура для мультимодального RAG:
    • единый векторный простор для текста и картинок;
    • tight-интеграция с S3 Vectors для хранения и поиска;
    • ассиметричные эмбеддинги для улучшения поиска.
  • По сравнению с классическим стеком "OCR + текстовый эмбеддер":
    • лучшее качество ответов на визуально-зависимых запросах (4,88/5 против 2,00/5);
    • меньше вызовов моделей → ниже стоимость индексации;
    • меньше кода и промптов: не нужен отдельный слой OCR.

Если у вас уже есть пайплайн на GPT-4o или Claude 3.5 с собственным векторным хранилищем, Nova Multimodal Embeddings и S3 Vectors можно рассматривать как альтернативный стек под AWS:

  • эмбеддер и стор из одной экосистемы;
  • нет необходимости администрировать векторный кластер;
  • легко подключить Nova 2 Lite как генератор ответов.

Чётких цифр по скорости, стоимости на 1K токенов или сравнению с GPT-4o/Claude 3.5 в материалах нет, поэтому выбор между ними придётся делать по экосистеме и требованиям к размещению данных: если вы уже живёте в AWS, Nova MME + S3 Vectors выглядит логичным вариантом.

Как запустить

Предварительные требования

Для воспроизведения примера вам понадобится:

  • аккаунт AWS с доступом к Amazon Bedrock в регионе us-east-1;
  • включённый доступ к моделям:
    • amazon.nova-2-multimodal-embeddings-v1:0;
    • us.amazon.nova-2-lite-v1:0;
    • us.anthropic.claude-sonnet-4-5-20250929-v1:0 (если нужен LLM-as-judge);
  • среда разработки:
    • Amazon SageMaker AI Notebook Instance или локальное окружение Python;
  • Python 3.10+ с пакетами:
    • boto3, numpy, pandas, matplotlib, Pillow, pdf2image, tqdm;
  • IAM-права на:
    • bedrock:InvokeModel;
    • операции с Amazon S3;
    • операции с Amazon S3 Vectors.

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

Базовый скелет пайплайна

  1. Собрать датасет: изображения и PDF в S3 или локально.
  2. Сгенерировать эмбеддинги через Nova MME:
    • для изображений — STANDARD_IMAGE;
    • для страниц PDF — DOCUMENT_IMAGE.
  3. Создать bucket и индекс в S3 Vectors.
  4. Загрузить векторы с метаданными.
  5. Реализовать поиск: текст → эмбеддинг → query_vectors.
  6. Подключить генератор (Nova 2 Lite) и передавать ему найденные изображения или текст.

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


Читайте также