AI-инжиниринг
Embeddings: превращаем текст в векторы для поиска и сравнения
Цели урока
- Понять что такое embeddings и как текст превращается в вектор чисел
- Сравнить embedding-модели и выбрать подходящую для задачи
- Освоить cosine similarity и другие метрики расстояния между векторами
- Научиться генерировать embeddings через API с batch-оптимизацией
- Применять embeddings для search, дедупликации, классификации и anomaly detection
Netflix хранит каждый фильм как вектор из 128 чисел. Spotify - каждую песню. Tinder - каждого человека. Одна математика, три домена, миллиарды матчей. 'king - man + woman = queen' возникает не из правил - из сжатия 300 миллиардов слов в 1536 чисел. Это не магия. Это побочный эффект линейной алгебры на масштабе.
- GitHub Copilot использует embeddings для поиска релевантного кода из репозитория - каждый файл превращается в вектор, поиск работает через cosine similarity
- Notion AI строит семантический индекс всех страниц пользователя через embeddings - поиск по базе знаний без ключевых слов
- Intercom классифицирует 500K+ тикетов в день через embedding-сравнение (0.00002/тикет) - в 500 раз дешевле GPT-4o
- Stack Overflow использует embeddings для поиска дубликатов вопросов - 'уже спрашивали' срабатывает по смыслу, а не по словам
Эволюция embedding-технологии
**Word2Vec (Mikolov, Google, 2013)** - первая модель, показавшая что слова можно представить как векторы со структурой. Тогда же возникло знаменитое 'king - man + woman ≈ queen' - не запрограммированное явно, а вылезшее из геометрии. **GloVe (Stanford, 2014)** - улучшил подход через глобальную статистику совстречаемости слов. **BERT embeddings (Devlin, Google, 2018)** - переход от слов к контексту: один токен получает разный вектор в зависимости от предложения. **OpenAI text-embedding-ada-002 (2022)** - коммерциализация: высокое качество через простой API-вызов. **text-embedding-3-small/large (2024)** - гибкая размерность, 5x дешевле ada-002 при лучшем качестве.
Предварительные знания
Что такое embeddings и зачем они нужны
Netflix хранит каждый фильм как вектор из 128 чисел. Spotify - каждую песню. Tinder - каждого человека. Одна математика, три домена, миллиарды матчей.
Вектор из чисел - и вдруг алгоритм знает, что 'Крёстный отец' ближе к 'Однажды в Америке', чем к 'Шрек 2'. Откуда? Не из явных правил - из структуры данных. Это и есть embedding: **сжатие смысла в координаты многомерного пространства**.
Каждое из 1536 измерений кодирует какой-то аспект смысла. Не 'тема' или 'тональность' напрямую - это абстрактные признаки, выученные моделью из сотен миллиардов слов. Но эффект наглядный: семантически похожие тексты получают похожие координаты.
Word2Vec (Mikolov, Google, 2013) - первая модель, которая показала это свойство. Тогда же появилось знаменитое: **king - man + woman ≈ queen**. Не запрограммировано явно - вылезло из геометрии векторного пространства. GloVe (2014, Stanford) закрепил подход. BERT embeddings (2018) перенесли его на контекст целых предложений. OpenAI text-embedding-ada-002 (2022) сделал всё это доступным через один API-вызов.
**GPS-аналогия:** широта и долгота кодируют положение на карте двумя числами. Embedding кодирует положение текста в 'пространстве смыслов' - только измерений не 2, а 1536. И расстояние между точками - это семантическая близость.
Для backend-разработчика embeddings - фундамент целого класса задач:
- **Semantic Search** - поиск документов по смыслу, не по ключевым словам
- **RAG (Retrieval-Augmented Generation)** - подача релевантного контекста в LLM
- **Дедупликация** - нахождение семантических дубликатов в базе
- **Кластеризация** - автоматическая группировка тикетов, отзывов, сообщений
- **Рекомендации** - 'похожие статьи', 'похожие товары' по смыслу описания
- **Anomaly Detection** - обнаружение текстов, сильно отличающихся от остальных
Embedding текста - это:
Модели для создания embeddings
Embedding-модели - отдельный класс. Они не генерируют текст - они **сжимают смысл в вектор**. Обучаются иначе: задача не 'предскажи следующий токен', а 'сделай похожие тексты близкими в пространстве'. Выбор модели влияет на качество поиска, скорость и стоимость.
| Модель | Размерность | Цена / 1M tokens | Особенности |
|---|---|---|---|
| text-embedding-3-small (OpenAI) | 1536 | 0.02 | Лучший баланс цена/качество, гибкая размерность |
| text-embedding-3-large (OpenAI) | 3072 | 0.13 | Максимальное качество OpenAI, поддержка dimensions |
| embed-v4.0 (Cohere) | 1024 | 0.10 | Мультиязычность, input_type для разных задач |
| voyage-3 (Voyage AI) | 1024 | 0.06 | Лучший для code retrieval |
| nomic-embed-text (open-source) | 768 | бесплатно | Запуск локально, Ollama-совместим |
| BGE-M3 (BAAI, open-source) | 1024 | бесплатно | Мультиязычный, dense + sparse embeddings |
Качество моделей измеряют через **MTEB benchmark** (Massive Text Embedding Benchmark) - стандарт индустрии. text-embedding-3-small стабильно в топ-15, BGE-M3 конкурирует с платными решениями для мультиязычных задач.
OpenAI text-embedding-3 поддерживает **гибкую размерность**: можно запросить вектор короче (256, 512) с минимальной потерей качества - и сэкономить на памяти и скорости поиска в Qdrant/pgvector.
**Критически важно:** embedding-модель нельзя менять после построения индекса. База построена на text-embedding-3-small - нельзя искать вектором от text-embedding-3-large. Пространства несовместимы. Миграция = пересчёт всех embeddings.
Для большинства backend-задач text-embedding-3-small - оптимальный выбор. Обработка 1 миллиона документов средней длины (500 токенов) стоит ~`10.` Это разовая операция - вектор пересчитывается только при изменении текста.
Почему нельзя заменить embedding-модель после построения индекса без пересчёта?
Cosine similarity: как измерить близость векторов
Embeddings превращают текст в вектор. Следующий шаг - **сравнить** два вектора. Интуитивный ответ: вычислить расстояние между точками. Но это ловушка.
Embedding-модели возвращают векторы разной длины для разных текстов. Длинный документ будет иметь большую норму, чем короткая фраза - даже если смысл идентичен. Евклидово расстояние это не учтёт.
**Cosine similarity** измеряет не расстояние - а **угол между векторами**. Длина векторов не важна. Важно только направление. Результат - число от -1 до 1:
- **1.0** - векторы сонаправлены (идентичный смысл)
- **0.0** - векторы ортогональны (никакой связи)
- **-1.0** - векторы противоположны (на практике с текстами почти не встречается)
| Метрика | Формула | Когда использовать |
|---|---|---|
| Cosine Similarity | cos(θ) = dot(A,B) / (‖A‖ × ‖B‖) | Стандартный выбор для текстовых embeddings |
| Euclidean (L2) | ‖A - B‖₂ | Когда важна абсолютная величина вектора |
| Dot Product | A · B | Для нормализованных векторов (эквивалентен cosine) |
| Manhattan (L1) | Σ|Aᵢ - Bᵢ| | Разреженные данные, менее чувствителен к выбросам |
**Практический момент:** OpenAI text-embedding-3 возвращает уже **нормализованные** векторы (длина = 1). Для нормализованных векторов cosine similarity = dot product. Dot product - одна операция вместо трёх. Именно поэтому Qdrant, pgvector и другие vector databases используют dot product внутри при нормализованных векторах.
Cosine similarity между двумя embeddings равен 0.92. Это означает:
Генерация embeddings: API, batch-обработка и оптимизация
В production нужно генерировать embeddings для тысяч и миллионов документов. Наивный подход - один запрос на документ. 10 000 документов × 200ms = 33 минуты. Это не production, это ожидание.
**Batch processing** - одним запросом до 2048 текстов. Те же 10 000 документов = 5 запросов ≈ 5 секунд. Разница в 400 раз.
| Параметр | text-embedding-3-small | text-embedding-3-large |
|---|---|---|
| Макс. токенов на вход | 8191 | 8191 |
| Макс. текстов в batch | 2048 | 2048 |
| Rate limit (tier 1) | 3,000 RPM / 1M TPM | 3,000 RPM / 1M TPM |
| Размерность вектора | 1536 (по умолч.) | 3072 (по умолч.) |
| Минимальная размерность | 256 | 256 |
Для кластеризации и дедупликации (сравнение текстов между собой) - dimensions: 256 или 512 достаточно. Для semantic search и RAG рекомендуется полная размерность: качество заметно падает на коротких текстах.
**Текст длиннее 8191 токенов обрезается без ошибки.** API не бросит exception - просто проигнорирует хвост. Перед отправкой нужно проверять длину и при необходимости разбивать текст на чанки (chunking - тема отдельного урока).
Если нужно сгенерировать embeddings для 10,000 документов через OpenAI API с batch size 2048, сколько минимум API-запросов потребуется?
Практические применения embeddings в backend
Embeddings - не академическая концепция. Это рабочий инструмент, который уже сейчас решает конкретные задачи дешевле и быстрее LLM. Пять паттернов - с кодом.
1. Semantic Search
Keyword search ищет совпадения слов. Semantic search находит документы по **смыслу** - даже если ни одно слово не совпадает с запросом. Запрос 'приложение тормозит на старых телефонах' находит 'Оптимизация производительности для low-end устройств' - ни одного общего слова.
2. Дедупликация контента
3. Anomaly Detection
Если embedding нового текста далёк от всех остальных - это аномалия. Полезно для фильтрации спама, обнаружения нерелевантного контента, мониторинга.
4. Кластеризация
Embeddings позволяют автоматически группировать контент без ручных правил. Достаточно кластеризовать векторы - тексты одной темы окажутся в одном кластере. Именно так работают Spotify плейлисты по настроению и похожие видео на YouTube.
5. Классификация по примерам (Few-shot)
**Embedding-классификация vs LLM-классификация:** Embedding-подход стоит `0.00002 USD` за тикет и работает за 50ms. LLM-подход (GPT-4o) стоит `0.01 USD` за тикет и работает за 500ms. Для high-volume задач (тысячи тикетов в день) embeddings выгоднее в 500 раз.
Для классификации 50,000 тикетов поддержки в день по 5 категориям оптимальный подход:
Cosine similarity = расстояние между векторами
Cosine similarity - это угол между векторами, не расстояние. Высокий cosine не гарантирует семантическую близость в out-of-domain задачах
Cosine similarity измеряет cos(θ) - угол между направлениями. Два вектора могут быть 'близкими по направлению' (score 0.85), но при этом представлять тексты из разных доменов, где эта близость бессмысленна. Score 0.8 для текстов о кулинарии и score 0.8 для юридических документов - это разные вещи. Порог нужно калибровать под домен.
Embedding-модель можно выбрать и поменять потом - это просто API
Смена модели = пересчёт всего индекса. Разные модели создают несовместимые векторные пространства
text-embedding-3-small и text-embedding-3-large - разные пространства, даже если размерность совпадает после параметра dimensions. Один и тот же текст получит разные координаты в разных пространствах. Сравнивать вектор из одной модели с вектором из другой - всё равно что сравнивать GPS-координаты с пикселями на экране.
Ключевые выводы
- Embedding - вектор из 1536 чисел, кодирующий смысл. Восходит к Word2Vec 2013 - принцип тот же, качество несравнимо лучше
- text-embedding-3-small: 0.02/1M tokens, 1536 dim - оптимальный выбор для большинства backend-задач
- Cosine similarity - угол между векторами, не расстояние. Высокий score нужно калибровать под домен
- Batch processing до 2048 текстов за запрос - ускорение в 400 раз по сравнению с наивным подходом
- Embedding-модель выбирается один раз. Смена = пересчёт всего индекса
- Netflix, Spotify, Tinder - одна математика, разные домены. Embedding-классификация в 500 раз дешевле LLM для high-volume задач
Вопросы для размышления
- Netflix хранит фильм как вектор из 128 чисел. Какие 'измерения' могут кодироваться в этом векторе? Жанр? Темп? Настроение? Что ещё?
- Cosine similarity возвращает 0.87 для двух тикетов поддержки. Порог дедупликации - 0.92. Что нужно знать о домене, прежде чем менять порог?
- 1 миллион документов × 500 токенов × 0.02/1M tokens = сколько стоит построить индекс? Это разовая стоимость или регулярная?
Что дальше
Embeddings генерировать научились. Теперь нужно место для хранения и быстрого поиска по миллионам векторов. Обычная SQL-база не справится с поиском ближайших соседей в 1536-мерном пространстве за миллисекунды - нужен специализированный инструмент.
- Vector Databases — Хранение и поиск по миллионам embeddings - pgvector, Pinecone, Qdrant
- Document Processing — Извлечение текста из PDF, DOCX, HTML перед генерацией embeddings
Связанные уроки
- aie-03-llm-fundamentals — Эмбеддинги берутся из тех же внутренностей трансформера
- aie-10-vector-databases — Эмбеддингам нужно векторное хранилище для масштабного поиска
- aie-12-rag-fundamentals — Эмбеддинги это основа поиска в RAG
- ml-35-word-embeddings — Современные текстовые эмбеддинги расширяют идеи word2vec
- la-02-dot-product — Косинусная близость это нормализованное скалярное произведение
- alg-10-binary-search
- db-30-vector