База знаний

EmbeddingGemma (Gemma 3) — компактная embedding-модель от Google для on-device RAG

Открытая embedding-модель от Google на базе Gemma 3: 308M параметров, 100+ языков, контекст 2048 токенов, 768-мерные векторы с MRL-усечением до 128. Работает на 200 МБ RAM, считает эмбеддинг на CPU за десятки миллисекунд. Когда брать вместо BGE-M3, как поднять локально и во что упереться.

Опубликовано

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

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

Что это вообще такое

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.

Когда EmbeddingGemma — правильный выбор

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

Когда лучше взять что-то другое

  • Длинные документы. Контекст 2048 против 8192 у BGE-M3 — это реальный разрыв. Если вы эмбеддите статьи или PDF целиком, EmbeddingGemma заставит вас резать на чанки агрессивнее.
  • Максимальное качество на русском в сложных задачах. BGE-M3 на MIRACL по-прежнему сильнее в нишевых мультиязычных бенчмарках. Для RAG по русско-английской базе знаний BGE-M3 остаётся дефолтом.
  • Гибридный поиск dense + sparse в одной модели. У EmbeddingGemma только dense-режим. Sparse придётся брать отдельной моделью или BM25.
  • Эмбеддинги для кода. Специализированные модели (voyage-code-2, jina-embeddings-v2-code) дадут заметно лучший результат.

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

МодельПараметровКонтекстРазмерность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. Это не конкуренты — это инструменты под разные задачи.


Поднимаем локально

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

  • 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
# 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 с загрузкой весовПрогревать фиктивным запросом при старте сервиса

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

  • Брать EmbeddingGemma для документов по 10 000 токенов. Контекст 2048 — это реальный потолок. Для длинных текстов либо чанкуйте агрессивно, либо берите BGE-M3.
  • Эмбеддить запросы и документы одинаковым prompt-именем. Модель тренировалась на асимметричных префиксах, и она это помнит. Симметрия ломает качество.
  • Мешать в одном индексе векторы от EmbeddingGemma и любой другой модели. Даже одинаковая размерность не делает их сопоставимыми. Поиск сломается тихо и бесповоротно.
  • Хранить 768-мерные векторы, когда хватает 256. Индекс раздувается в 3 раза без повода. MRL существует ровно для того, чтобы этого не делать.
  • Тестировать качество на английском и переносить выводы на русский. Мультиязычность у модели есть, но языки ведут себя по-разному. Меряйте на своих данных.

Полезные ссылки


По теме

Если выбираете embedding-модель под свою задачу и не уверены, чем EmbeddingGemma отличается от BGE-M3 на практике — давайте обсудим, что лучше сядет под вашу нагрузку и инфраструктуру.