Получите рабочий пайплайн: от установки окружения до индексации через FAISS и развёртывания простого API; время выполнения — 30–90 минут в зависимости от конфигурации. Примеры кода используют Python 3.11 и модели 2025 года.
Что вы изучите
Как сформировать эмбеддинги текста с помощью модели sentence-transformers (версия 2.3.0, релиз 2025).
Как выбрать модель для задач поиска и сравнить точность и размер (2025).
Как индексировать эмбеддинги в FAISS (faiss-cpu 1.7.4) и хранить метаданные в PostgreSQL 16.
Как выполнять семантический поиск: cosine, dot-product, L2 с примерами на Python.
Как развёртывать простой HTTP API на FastAPI 0.98 и сохранять/восстанавливать индекс.
Требования
ОС: Ubuntu 22.04 LTS или Debian 12; рабочие инструкции проверены на Ubuntu 22.04 (апрель 2026).
Минимум 4 GB RAM; рекомендовано 8 GB для моделей средней размерности (384–1024) и 2 CPU.
PostgreSQL 16 для метаданных (опционально). Порт по умолчанию 5432.
Что такое embeddings?
0
Статья была полезной?
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…
Embeddings — это векторные представления текстов или других объектов в числовом пространстве фиксированной размерности. Для семантического поиска цель — отображать близкие по смыслу тексты в соседние вектора, чтобы близость векторов отражала смысловую близость. В 2025–2026 годах распространён подход: получить эмбеддинги с предобученных трансформеров и индексировать их в быстрых индексах, таких как FAISS, для миллионий документов.
Какую модель выбрать?
Выбор модели зависит от компромисса точность/скорость/память. В 2025 году распространены семейства:
Mini/Small (например, all-MiniLM v2, 384D) — быстрые, образ ~50–150 MB, подходят для подсистем с ограниченным ресурсом, латентность <20 ms на CPU за текст ~128 токенов.
Base/Medium (768D) — лучше качество при приемлемых ресурсах, размер модели 300–800 MB, требование RAM 4–8 GB.
Large (1024–1536D и выше) — для задач высокой точности, размер 1–4 GB, GPU рекомендован; время эмбеддинга на CPU может быть >200 ms.
Практический выбор: для большинства production-цепочек в 2025 годe разумен all-MiniLM-v2 (384D) или модель 768D, если требуется более точный поиск. Всегда измеряйте точность на своей валидационной выборке.
Как измерять похожесть?
Часто используются три метрики: cosine similarity, dot-product и L2 (евклидово расстояние). Для нормированных векторов cosine и dot эквивалентны по упорядочению. Dot полезен, когда длина векторов несбалансирована. L2 применим при использовании индексирования, чувствительного к норме векторов. Важно: измерения зависят от нормализации и размерности. В примерах ниже показано, как вычислять все три для пары векторов в Python и как выбирать порог для фильтрации ответов.
Пояснение: создаётся виртуальное окружение на Python 3.11; устанавливаются ключевые пакеты (версии указаны для 2025–2026). Установка faiss-cpu занимает ~30–90 с в зависимости от сети и CPU; размер wheel ~30–60 MB.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
corpus = ['Как настроить PostgreSQL', 'Пример использования FAISS', 'Введение в embeddings']
embeddings = model.encode(corpus, convert_to_numpy=True)
print(embeddings.shape)
Пояснение: код загружает модель all-MiniLM-L6-v2 (версия модели 2023–2025, размер ~80 MB) и создаёт эмбеддинги для трёх строк. На CPU время кодирования для 3 коротких строк ~50–200 ms.
Ожидаемый вывод (успешно):
(3, 384)
Типичная ошибка и фикc:
OSError: Can't load model for 'all-MiniLM-L6-v2' from Hugging Face hub.
# fix: проверьте интернет и проброс прокси, или предварительно скачайте модель:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('/path/to/local/model')
Шаг 3: Индексация через FAISS
import faiss
import numpy as np
# embeddings - numpy array shape (N, D)
d = embeddings.shape[1]
index = faiss.IndexFlatIP(d) # для cosine предварительно нормализуем
faiss.normalize_L2(embeddings)
index.add(embeddings.astype(np.float32))
print('Indexed vectors:', index.ntotal)
Пояснение: используем IndexFlatIP (Inner Product) + нормализацию L2 для cosine-подобия. IndexFlatIP быстрый и без обучения; подходит для десятков тысяч векторов; для миллионов используйте IVF или HNSW (пример ниже). Добавление нескольких тысяч векторов занимает секунды на CPU; для 100k — минуты.
Ожидаемый вывод:
Indexed vectors: 3
Типичная ошибка и исправление:
RuntimeError: Unsupported dtype: float64
# fix: привести в numpy.float32
index.add(embeddings.astype(np.float32))
Шаг 4: Запросы и поиск по похожести
query = 'как установить faiss'
q_vec = model.encode([query], convert_to_numpy=True)
faiss.normalize_L2(q_vec)
D, I = index.search(q_vec.astype(np.float32), k=5)
print('indices:', I)
print('scores:', D)
Пояснение: поиск возвращает индексы ближайших документов и их скор (inner product после нормализации = cosine). k — число результатов. Для производительности на 10k+ документов рекомендуется batch-запросы; запрос на CPU для одного запроса ~1–10 ms для IndexFlatIP, больше для сложных индексов.
IndexError: index out of bounds
# fix: убедитесь, что k <= index.ntotal и что вектор q_vec корректной размерности
Шаг 5: Сохранение и восстановление индекса; интеграция с PostgreSQL
# Сохранение FAISS индекса
faiss.write_index(index, 'index.faiss')
# В PostgreSQL сохраняем метаданные (id -> текст)
# SQL пример:
-- CREATE TABLE documents(id SERIAL PRIMARY KEY, doc_id TEXT UNIQUE, text TEXT);
-- INSERT INTO documents(doc_id, text) VALUES ('doc-1', 'Как настроить PostgreSQL');
# Восстановление индекса
index2 = faiss.read_index('index.faiss')
print('Loaded index size:', index2.ntotal)
Пояснение: индекс сохраняется в бинарный файл ~O(N*D*4 bytes). Для 100k векторов 384D размер ≈ 100000*384*4 ≈ 153.6 MB. Метаданные лучше хранить в PostgreSQL 16, а индекс — на диске/объектном хранилище.
Ожидаемый вывод:
Loaded index size: 3
Типичная ошибка и как её исправить:
AssertionError: Error reading index: file not found
# fix: проверьте путь, права доступа, используйте полный путь и синхронизируйте файлы при развёртывании
Шаг 6: Развёртывание простого API для поиска (FastAPI)
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Query(BaseModel):
q: str
@app.post('/search')
def search(query: Query):
q_vec = model.encode([query.q], convert_to_numpy=True)
faiss.normalize_L2(q_vec)
D, I = index.search(q_vec.astype(np.float32), k=5)
# здесь запрос к PostgreSQL для метаданных по I
return {'indices': I.tolist(), 'scores': D.tolist()}
# запуск: uvicorn main:app --host 0.0.0.0 --port 8000
Пояснение: минимальный HTTP API принимает JSON {"q":"текст
Embeddings для семантического поиска на Python | KtoHto
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…