**Короткая версия: **EmbeddingGemma — открытая embedding-модель от Google DeepMind на 308M параметров. 768-мерные векторы с MRL-усечением до 128, контекст 2048 токенов, 100+ языков, помещается в ~200 МБ RAM. Лучший дефолт, когда embedding нужен прямо на устройстве пользователя или на слабом VPS, куда BGE-M3 уже не влезает по экономике.

Если BAAI/bge-m3 — это добротный грузовик для self-hosted RAG, то EmbeddingGemma — маленький электрический скутер. Грузит меньше, едет быстрее, помещается в карман и работает там, где сервер поставить просто негде.

В этом справочнике разбираемся, что это за модель, когда она реально уместна и как собрать с ней рабочий embedding-контур: поднять локально, выбрать размерность, подключить к существующему RAG-пайплайну и не нарваться на типичные грабли.

Что это

EmbeddingGemma — open-source embedding-модель от Google DeepMind, выпущенная в сентябре 2025 года. Под капотом — архитектура Gemma 3 на 300M параметров, адаптированная из decoder-only в encoder-only по рецепту T5Gemma. Проще говоря, взяли мозги Gemma 3, отрезали генеративную голову и оставили только ту часть, которая умеет превращать текст в вектор.

Модель построена на той же исследовательской базе, что и Gemini, и занимает первое место на бенчмарке MTEB среди открытых мультиязычных моделей размером до 500M параметров.

Главная идея — on-device. EmbeddingGemma спроектирована так, чтобы запускаться на телефоне, ноутбуке или дешёвом VPS без GPU. Эмбеддинг на EdgeTPU считается меньше чем за 22 мс, а вся модель с квантизацией помещается в 200 МБ RAM. Это совсем другой класс задач, чем у BGE-M3 или OpenAI — там, где раньше не было RAG, теперь он возможен.

Термин: on-device — модель работает прямо на устройстве пользователя, без похода в облако. Данные не уходят на сторонние серверы, интернет не нужен, latency минимальный. Для приватности и офлайн-сценариев — это всё.

Ключевые характеристики

ПараметрЗначение
РазработчикGoogle DeepMind
ЛицензияGemma Terms of Use (коммерческое использование разрешено)
АрхитектураEncoder-only на базе Gemma 3 (T5Gemma-инициализация)
Параметров308M (≈100M backbone + ≈200M embeddings)
RAM при инференсе~200 МБ с квантизацией, ~1.2 ГБ в full precision
Размерность dense-вектора768 (с MRL-усечением до 512, 256 или 128)
Максимальный контекст2048 токенов
Языки100+, тренировалась на данных Gemini-уровня
Latency на EdgeTPU~22 мс на запрос
Latency на среднем CPU~30–80 мс на чанк

Как устроено

Matryoshka Representation Learning — главная фича

MRL — это технология, при которой внутри большого вектора уже «живут» меньшие. У EmbeddingGemma полный эмбеддинг — 768-мерный, но вы можете честно обрезать его до первых 512, 256 или 128 измерений — и это по-прежнему будет качественное представление текста, а не обрубок.

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

РазмерностьРазмер индекса (на 1M чанков)Типичный сценарий
768~3 ГБМаксимальное качество, серверный RAG
512~2 ГББаланс качества и места
256~1 ГБМобильный RAG, быстрый поиск
128~0.5 ГБПрекоммутация, кеш, дешёвый retrieval

Практический приём — двухэтапный поиск: сначала по 128-мерным векторам быстро отбираете top-200 кандидатов, потом пересчитываете их 768-мерными и ранжируете. Индекс в 6 раз меньше, а качество на выдаче — как у полного вектора.

**Компромисс: **на 128 измерениях семантическая точность всё-таки просаживается на 2–5%. Для дедупа и классификации — нормально. Для юридических или медицинских текстов, где цена ошибки высокая, лучше держать 512 или 768.

Зачем нужно

  • Мобильные приложения с RAG. Поиск по заметкам, чатам, документам прямо на телефоне. Без интернета, без облака, без утечек.
  • Приватный офлайн-поиск. На ноутбуке или корпоративном десктопе, где данные не должны покидать устройство.
  • Слабый VPS без GPU. Там, где BGE-M3 уже начинает кряхтеть. EmbeddingGemma на 200 МБ RAM и CPU — это другая экономика хостинга.
  • Высоконагруженный API. Когда надо считать миллионы эмбеддингов в сутки, и каждые 10 мс на запрос превращаются в реальные деньги.
  • Короткие запросы и короткие документы. Сниппеты, сообщения, заголовки, подписи. Контекст 2048 токенов здесь избыточен, а скорость решает.

Когда использовать

СитуацияПодходитПочему
On-device RAG на телефоне или ноутбукеEmbeddingGemmaПомещается в 200 МБ, не нужен интернет, latency <30 мс
RAG по русско-английской базе знаний на сервереBAAI/bge-m3Контекст 8192, лучше держит сложные русскоязычные запросы
Гибридный dense + sparse в одной моделиBGE-M3 или связка с BM25У EmbeddingGemma только dense-режим, sparse придётся брать отдельно
Эмбеддинги для кодаvoyage-code-2 или jina-embeddings-v2-codeСпециализированные модели заметно точнее на кодовых корпусах
Миллионы эмбеддингов в сутки на дешёвом железеEmbeddingGemmaНагрузка CPU, без GPU, минимальная стоимость инфраструктуры
Максимальное качество на русскомBGE-M3 или OpenAI text-embedding-3-largeНа мультиязычных бенчмарках они по-прежнему лидируют
Прекоммутация больших массивовEmbeddingGemma 128-мернаяMRL-усечение + двухэтапный поиск дают качество 768 за память 128

Сравнение с альтернативами

МодельПараметровКонтекстРазмерностьRAM
EmbeddingGemma308M2048768 (MRL до 128)~200 МБ
BAAI/bge-m3567M81921024~1 ГБ
bge-small-en33M512384~150 МБ
multilingual-e5-large560M5121024~1 ГБ
OpenAI text-embedding-3-small— (API)81911536 (truncatable)— (API)

Если сравнивать «в лоб» с BGE-M3: EmbeddingGemma проигрывает в размере контекста, но выигрывает в скорости, размере индекса и пригодности для on-device. Это не конкуренты — это инструменты под разные задачи.

Пример

Два основных способа поднять EmbeddingGemma локально. Первый — быстрый старт за пять минут, второй — для тонкой интеграции в свой backend.

Минимальные требования

  • **CPU: **любой современный x86_64 или ARM (в т.ч. Apple Silicon, Raspberry Pi 5).
  • **RAM: **от 512 МБ с квантизацией, от 2 ГБ в full precision.
  • **Диск: **~1 ГБ под веса.
  • **Python: **3.10+.
  • GPU не нужен. Это принципиально: модель проектировалась для CPU.

Вариант 1: Ollama (самый быстрый старт)

ollama pull embeddinggemma
ollama serve

# Проверка:
curl http://localhost:11434/api/embeddings \
  -d '{"model": "embeddinggemma", "prompt": "Привет, мир"}'

Ollama поднимает OpenAI-совместимый endpoint на /v1/embeddings — можно сразу подключать к LiteLLM, LangChain, LlamaIndex без единой строки кода.

Вариант 2: sentence-transformers (тонкий контроль)

Установка:

pip install -U sentence-transformers

OpenAI-совместимый embeddings-сервер:

# server.py — OpenAI-compatible embeddings server на EmbeddingGemma
from fastapi import FastAPI
from pydantic import BaseModel
from sentence_transformers import SentenceTransformer
from typing import List, Union, Optional

# Загружаем модель один раз при старте
model = SentenceTransformer("google/embeddinggemma-300m")

app = FastAPI()

class EmbeddingRequest(BaseModel):
    input: Union[str, List[str]]
    model: str = "embeddinggemma"
    dimensions: Optional[int] = None  # 128, 256, 512 или 768

@app.post("/v1/embeddings")
def embeddings(req: EmbeddingRequest):
    texts = [req.input] if isinstance(req.input, str) else req.input
    # EmbeddingGemma ожидает task-специфичные префиксы
    vectors = model.encode(
        texts,
        prompt_name="Retrieval-document",
        normalize_embeddings=True,
    )
    # MRL-усечение: берём первые N измерений и ренормализуем
    if req.dimensions and req.dimensions < 768:
        import numpy as np
        vectors = vectors[:, :req.dimensions]
        vectors = vectors / np.linalg.norm(vectors, axis=1, keepdims=True)
    return {
        "object": "list",
        "model": req.model,
        "data": [
            {
                "object": "embedding",
                "index": i,
                "embedding": v.tolist()
            }
            for i, v in enumerate(vectors)
        ],
        "usage": {"prompt_tokens": 0, "total_tokens": 0},
    }

@app.get("/health")
def health():
    return {"status": "ok", "model": "embeddinggemma-300m"}

Запуск:

uvicorn server:app --host 127.0.0.1 --port 8080

**Важно про префиксы. **EmbeddingGemma обучалась с task-специфичными инструкциями. Для запросов — Retrieval-query: <текст>, для документов — title: none | text: <текст>. В sentence-transformers они подставляются через prompt\_name. Если эмбеддить всё голым текстом — потеряете несколько процентов качества.

Systemd-юнит для автозапуска

# /etc/systemd/system/embeddinggemma.service
[Unit]
Description=EmbeddingGemma Embeddings Server
After=network.target

[Service]
Type=simple
User=embeddings
WorkingDirectory=/opt/embeddinggemma
Environment="PATH=/opt/embeddinggemma/.venv/bin"
ExecStart=/opt/embeddinggemma/.venv/bin/uvicorn server:app --host 127.0.0.1 --port 8080
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Активация:

sudo systemctl daemon-reload
sudo systemctl enable --now embeddinggemma
sudo systemctl status embeddinggemma

**Безопасность: **биндите сервис на 127.0.0.1 или на интерфейс Tailscale. Лицензия Gemma разрешает коммерческое использование, но не разрешает сторонним ботам жечь ваш CPU. Авторизация из коробки не встроена.

Когда это особенно выстреливает

On-device RAG в мобильном приложении

  • Модель в квантизации до 200 МБ помещается в iOS/Android бандл.
  • База знаний пользователя (заметки, чаты, файлы) индексируется локально, один раз.
  • Запрос → эмбеддинг за 30 мс → поиск в локальной SQLite+vector-extension → ответ. Интернет не нужен.
  • Данные никуда не утекают — вся приватность соблюдена технически, а не на бумаге.

Двухэтапный поиск на большой базе

  • Индексируете документы в 128-мерных векторах (экономия памяти в 6 раз).
  • На запрос считаете 128-мерный эмбеддинг, достаёте top-500 кандидатов.
  • Пересчитываете эти 500 текстов в 768-мерных векторах и ранжируете ещё раз.
  • Получаете качество 768-мерного поиска при затратах памяти 128-мерного.

Семантический дедуп входящих сообщений

  • Порог cosine > 0.90 — дубль.
  • 0.75–0.90 — похожая тема, кандидат на объединение.
  • Считается настолько быстро, что можно запускать inline при каждом новом сообщении.

Классификация без разметки (zero-shot)

  • Создаёте эмбеддинг для каждой категории (описываете её короткой фразой).
  • Входящий текст эмбеддите тоже.
  • Побеждает та категория, у которой cosine с текстом максимальный.
  • Работает удивительно хорошо для типовых задач вроде «спам / не спам», «запрос / жалоба / благодарность».

Типичные ошибки и как их чинить

СимптомПричинаРешение
Низкое качество retrievalНе используются task-специфичные префиксыПередавать prompt_name=“Retrieval-query” для запросов и “Retrieval-document” для документов
MRL-эмбеддинги не сравниваются между собойПосле обрезки забыли ренормализовать векторПосле vectors[:, :N] делать vectors / np.linalg.norm(…)
Тексты длиннее 2048 токенов молча обрезаютсяКонтекст модели — всего 2048Резать на чанки 300–800 токенов с overlap, эмбеддить по отдельности
Cross-lingual similarity низкаяСмешаны префиксы для query и documentДля query и document использовать разные prompt-имена, это важно
Модель медленно стартуетCold start с загрузкой весовПрогревать фиктивным запросом при старте сервиса

Ограничения

Ограничения

Что учитывать

Контекст 2048 токенов — жёсткий потолок.

Длинные документы надо резать на чанки или брать BGE-M3 с его 8192.

Только dense-режим.

Sparse-представления и гибридный поиск «из коробки» не поддерживаются. Для BM25-составляющей нужна отдельная модель или индекс.

Multilingual ≠ одинаково силён на всех языках.

100+ языков — это заявленное покрытие, а не гарантия качества. BGE-M3 на русском и английском по-прежнему выигрывает в нишевых мультиязычных бенчмарках.

На 128 измерениях точность просаживается на 2–5%.

Для дедупа и zero-shot-классификации незаметно, для юридических или медицинских задач — критично. Держите 512–768, если цена ошибки высокая.

MRL-обрезку нужно ренормализовать.

После vectors\[:, :N\] обязательно делить на np.linalg.norm(...) — иначе косинусное сходство между полным и обрезанным вектором будет некорректным.

Нет встроенной авторизации.

HTTP-эндпоинт по умолчанию открыт всем, кто до него дошёл. Биндите на 127.0.0.1, ставьте обратный прокси или Tailscale.

Cold start в ~1–2 секунды.

На EdgeTPU почти незаметно, на CPU при первом запросе — ощутимо. Прогревайте модель фиктивным запросом при старте сервиса.

Антипаттерны

Антипаттерны

Чего не делать

Брать EmbeddingGemma для документов по 10 000 токенов.

Контекст 2048 — это реальный потолок. Для длинных текстов либо чанкуйте агрессивно, либо берите BGE-M3.

Эмбеддить запросы и документы одинаковым prompt-именем.

Модель тренировалась на асимметричных префиксах, и она это помнит. Симметрия ломает качество.

Мешать в одном индексе векторы от EmbeddingGemma и любой другой модели.

Даже одинаковая размерность не делает их сопоставимыми. Поиск сломается тихо и бесповоротно.

Хранить 768-мерные векторы, когда хватает 256.

Индекс раздувается в 3 раза без повода. MRL существует ровно для того, чтобы этого не делать.

Тестировать качество на английском и переносить выводы на русский.

Мультиязычность у модели есть, но языки ведут себя по-разному. Меряйте на своих данных.

Открывать embeddings-эндпоинт в интернет без авторизации.

Сторонний трафик за минуты сожжёт вам CPU и лимиты памяти. Сервис публичного API — только с ключом и rate limit.

Чеклист

Чеклист

Проверка перед запуском

Цель определена.

Понятно, что важнее — качество retrieval (тогда 768), экономия памяти (тогда 128/256 + двухэтапный поиск) или on-device (тогда ~200 МБ с квантизацией).

Префиксы настроены.

Retrieval-query для запросов, Retrieval-document для документов. Без них — потеря качества.

MRL-усечение ренормализовано.

После vectors\[:, :N\] стоит vectors / np.linalg.norm(...) — иначе косинус считается криво.

Размер чанков выбран под контекст 2048.

300–800 токенов с overlap — рабочий дефолт. Всё, что длиннее — молча обрежется и потеряет хвост.

Эндпоинт защищён.

Бинд на 127.0.0.1, reverse proxy с авторизацией или Tailscale. Без этого сервис сожгут за минуты.

Cold start прогрет.

На CPU первый запрос — это 1–2 секунды на загрузку весов. Сервисный фиктивный запрос при старте снимает проблему.

Совместимость индексов проверена.

Все векторы в индексе — от одной модели. Смешение моделей ломает поиск без явной ошибки.

Bench-замеры на своих данных.

Качество retrieval замеряется на доменном корпусе, а не общими бенчмарками. Промпт-префиксы, язык, длина чанков — всё влияет.

Ссылки

Ссылки

  • Модель на HuggingFace: google/embeddinggemma-300m открытые веса, карточка модели, license Gemma Terms of Use.
  • Документация на ai.google.dev: EmbeddingGemma overview официальный гайд по архитектуре, префиксам и ограничениям.
  • Анонс от Google DeepMind: Introducing EmbeddingGemma что именно они выпустили и какие бенчмарки взяли.
  • Разбор архитектуры: Gemma explained: EmbeddingGemma architecture and recipe как из Gemma 3 получился encoder, и зачем нужна T5Gemma-инициализация.
  • Технический отчёт (arXiv:2509.20354): EmbeddingGemma paper академическое описание модели с цифрами по бенчмаркам.
  • Ollama: embeddinggemma самый быстрый способ развернуть модель локально.
  • Лидерборд MTEB: MTEB Leaderboard место EmbeddingGemma среди открытых моделей до 500M.