Эмбеддинги и векторные хранилища

Урок о том, как текст становится вектором и как по векторам ищут похожее.

Embedding (эмбеддинг) — числовой вектор, в который модель превращает фрагмент текста так, что близкие по смыслу тексты дают близкие векторы.

Текст как точка в пространстве

Чтобы искать по смыслу, а не по точным словам, текст переводят в вектор чисел. Модель эмбеддингов устроена так, что семантически похожие фразы оказываются рядом в этом пространстве. Тогда «найти похожее» сводится к «найти ближайшие векторы». В LangChain за это отвечает интерфейс Embeddings.

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector = embeddings.embed_query("Что такое индекс в БД?")
print(len(vector))   # размерность вектора, напр. 1536

Близость векторов

Похожесть обычно меряют косинусной близостью. Её идею можно посчитать на чистом Python:

import math

def cosine(a, b):
    dot = sum(x * y for x, y in zip(a, b))
    na = math.sqrt(sum(x * x for x in a))
    nb = math.sqrt(sum(y * y for y in b))
    return dot / (na * nb)

q = [1, 0, 1]
docs = {"про БД": [1, 0, 1], "про погоду": [0, 1, 0]}
for name, v in docs.items():
    print(name, round(cosine(q, v), 2))

Вывод:

про БД 1.0
про погоду 0.0

Векторное хранилище

VectorStore — база, которая хранит чанки вместе с их векторами и умеет быстро находить ближайшие к запросу. В LangChain единый интерфейс поверх разных движков (FAISS, Chroma, pgvector и др.), поэтому код добавления и поиска почти не зависит от выбранного хранилища.

from langchain_community.vectorstores import FAISS

store = FAISS.from_documents(chunks, embeddings)
results = store.similarity_search("Что такое индекс?", k=3)
for doc in results:
    print(doc.page_content[:60])

Как работает под капотом

При индексации каждый чанк прогоняется через модель эмбеддингов и кладётся в хранилище вместе со своим вектором. На запросе вектор вопроса считается тем же способом, и хранилище ищет k ближайших векторов по выбранной метрике. Чтобы поиск был корректным, вопрос и документы обязаны быть закодированы одной и той же моделью эмбеддингов — иначе их векторы лежат в «разных пространствах» и близость бессмысленна.

Частые ошибки

  • Разные модели для индекса и запроса. Вектора несравнимы; всегда одна модель эмбеддингов.
  • Переиндексировать всё при каждом запуске. Эмбеддинги стоят денег; сохраняйте индекс на диск.
  • Брать слишком большое k. В контекст попадёт шум и вырастет стоимость.

Итог

  • Эмбеддинг превращает текст в вектор, близкий для похожих по смыслу фрагментов.
  • Похожесть меряют косинусной близостью векторов.
  • VectorStore хранит чанки с векторами и ищет ближайшие к запросу.
  • Индекс и запрос кодируют одной и той же моделью эмбеддингов.
Проверьте себя
1. Что такое эмбеддинг текста?
AСжатая копия файла
BЧисловой вектор, в котором близкие по смыслу тексты лежат рядом
CХэш строки для проверки целостности
DПеревод текста на английский
2. Почему вопрос и документы нужно кодировать одной моделью эмбеддингов?
AТак дешевле
BИначе их векторы окажутся в разных пространствах и близость станет бессмысленной
CЧтобы получить одинаковую длину строки
DЭто ускоряет ответ модели
3. Что делает VectorStore?
AХранит историю диалога
BХранит чанки с их векторами и ищет ближайшие к запросу
CПарсит JSON-ответы модели
DЗагружает PDF-файлы