Сравнение 1: поиск по словам vs по смыслу
🟡 Поверхностный (TF-IDF / ключевые слова)
# Сравнивает символы/слова, НЕ смысл
similarity("латте", "капучино") # ≈ 0 — буквы разные
# «отзыв о кофе» не найдётся,
# если в нём нет слова «кофе»
Подходит для точных совпадений, опечаток, коротких строк. Смысла не понимает.
🟢 Семантический (эмбеддинги)
# Сравнивает векторы смысла
emb("латте") ↔ emb("капучино") # близки!
# «Мне нравится латте» найдёт
# отзывы про кофе без слова «кофе»
Понимает близость по смыслу: синонимы, перефразировки, разные языки.
Сравнение 2: запрос без защиты vs устойчивый
🟡 Хрупкий запрос
r = client.models.generate_content(
model="gemini-2.0-flash",
contents=[prompt])
print(r.text)
# зависнет при перегрузке;
# упадёт на первой ошибке 429/500
🟢 Устойчивый запрос
@retry(stop=stop_after_attempt(3),
wait=wait_exponential(min=2, max=10))
def ask(prompt):
return client.models.generate_content(
model="gemini-2.0-flash",
contents=[prompt]).text
# таймаут на клиенте + 3 попытки
Сравнение 3: L2 vs косинус (best practice)
🟡 Как в лекции (L2)
index = faiss.IndexFlatL2(dim)
index.add(embeddings)
# евклидово расстояние;
# чувствительно к длине вектора
🟢 Косинусная близость
faiss.normalize_L2(embeddings) # нормализуем
index = faiss.IndexFlatIP(dim) # скалярное произв.
index.add(embeddings)
# = косинус: сравнивает «направление» смысла
⚠️ Для текстовых эмбеддингов косинусная близость обычно предпочтительнее евклидовой. Способ нормализации и тип индекса зависят от версии FAISS — сверяйтесь с документацией.