English translation is not available yet. Showing Russian content.

Как вы анализируете embedding geometry для отладки retrieval качества?

Краткий тезис

Анализ embedding geometry (геометрии эмбеддингов) — это набор методов визуализации и количественной оценки того, как векторные представления документов и запросов распределены в пространстве. Используя UMAP/t-SNE для визуализации, метрики intra-cluster vs inter-cluster distance и average pairwise similarity, можно выявить проблемы: плохую кластеризацию по темам, аномалии (выбросы), несоответствие распределений запросов и документов. Это помогает понять, почему retrieval находит нерелевантные чанки, и направить усилия на улучшение эмбеддингов, чанкинга или индексации.


1. Термин: Embedding geometry (геометрия эмбеддингов)

Embedding geometry — это пространственное расположение векторных представлений (эмбеддингов) объектов в многомерном пространстве (обычно 768–1536 измерений). Для RAG это эмбеддинги чанков документов и запросов пользователей.

Почему это важно для отладки retrieval:

  • Если эмбеддинги релевантных документов образуют плотные кластеры, а запросы попадают в те же кластеры — retrieval будет точным.
  • Если кластеры перемешаны (разные темы сливаются) или запросы оказываются далеко от релевантных документов — retrieval будет плохим.
  • Аномалии (выбросы) могут указывать на битые чанки, неправильный чанкинг или шум в данных.

Анализ геометрии позволяет визуально и количественно оценить эти свойства, не запуская полный пайплайн RAG.


2. Визуализация с UMAP/t-SNE

UMAP (Uniform Manifold Approximation and Projection) и t-SNE (t-distributed Stochastic Neighbor Embedding) — методы нелинейного снижения размерности до 2D или 3D для визуализации.

Как интерпретировать графики

  • Кластеры: точки одного цвета (одна тема) должны группироваться вместе. Если кластеры размыты или перемешаны — эмбеддинги плохо разделяют темы.
  • Аномалии: точки, изолированные от всех кластеров — возможны ошибки в данных или чанках.
  • Запросы: нанесите эмбеддинги запросов (другим маркером) и посмотрите, попадают ли они в кластеры релевантных документов.

Пример кода (Python):

import umap
import matplotlib.pyplot as plt
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')
doc_embeddings = model.encode(documents)
query_embeddings = model.encode(queries)

reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42)
all_embeddings = np.vstack([doc_embeddings, query_embeddings])
reduced = reducer.fit_transform(all_embeddings)

doc_reduced = reduced[:len(documents)]
query_reduced = reduced[len(documents):]

plt.figure(figsize=(10,8))
plt.scatter(doc_reduced[:,0], doc_reduced[:,1], c='blue', label='documents', alpha=0.6)
plt.scatter(query_reduced[:,0], query_reduced[:,1], c='red', label='queries', alpha=0.8)
plt.legend()
plt.title('UMAP projection of document and query embeddings')
plt.show()

Ограничения t-SNE сохраняет локальную структуру, но глобальные расстояния могут быть искажены. UMAP лучше сохраняет глобальную топологию и быстрее. Используйте оба для кросс-проверки.


3. Метрики внутрикластерного и межкластерного расстояния

Для количественной оценки качества кластеризации используются intra-cluster distance (среднее расстояние между точками внутри одного кластера) и inter-cluster distance (среднее расстояние между центрами кластеров).

Формулы

  • Intra-cluster distance для кластера ( C ): [ [text](/wiki/text){intra}(C) = \frac{1}{|C|(|C|-1)} \sum_{x_i \in C} \sum_{x_j \in C, j \neq i} d(x_i, x_j) ] где ( d ) — евклидово или косинусное расстояние.
  • Inter-cluster distance между кластерами ( C_i ) и ( C_j ): [ [text](/wiki/text){inter}(C_i, C_j) = d(\mu_i, \mu_j) ] где ( \mu_i ) — центроид кластера.

Хорошее разделение низкое intra (точки плотно) и высокое inter (кластеры далеко). Плохое — высокое intra и низкое inter.

Пример расчёта

from sklearn.metrics import pairwise_distances
import numpy as np

def intra_cluster_distance(embeddings, labels):
    unique_labels = np.unique(labels)
    intra_dists = []
    for label in unique_labels:
        cluster_emb = embeddings[labels == label]
        if len(cluster_emb) > 1:
            dists = pairwise_distances(cluster_emb, metric='cosine')
            intra_dists.append(np.mean(dists[np.triu_indices_from(dists, k=1)]))
    return np.mean(intra_dists) if intra_dists else 0

def inter_cluster_distance(embeddings, labels):
    unique_labels = np.unique(labels)
    centroids = np.array([embeddings[labels == l].mean(axis=0) for l in unique_labels])
    if len(centroids) > 1:
        dists = pairwise_distances(centroids, metric='cosine')
        return np.mean(dists[np.triu_indices_from(dists, k=1)])
    return 0

Интерпретация

  • Если intra ≈ inter — кластеры не разделены, эмбеддинги неинформативны.
  • Если intra << inter — хорошая кластеризация.

4. Average pairwise similarity в кластерах

Average pairwise similarity — средняя косинусная схожесть между всеми парами документов внутри одного кластера. Высокая схожесть (близкая к 1) означает, что документы очень похожи — это хорошо для релевантности, но может указывать на избыточность (дубликаты). Низкая схожесть (<0.5) — кластер слишком разнороден.

Сравнение с межкластерной схожестью

  • Внутрикластерная схожесть должна быть значительно выше, чем средняя схожесть между документами из разных кластеров.
  • Если разница мала — эмбеддинги не различают темы.

Пример:

def average_pairwise_similarity(embeddings, labels):
    from sklearn.metrics.pairwise import cosine_similarity
    unique_labels = np.unique(labels)
    sims = []
    for label in unique_labels:
        cluster_emb = embeddings[labels == label]
        if len(cluster_emb) > 1:
            sim_matrix = cosine_similarity(cluster_emb)
            # берём верхний треугольник без диагонали
            sims.append(np.mean(sim_matrix[np.triu_indices_from(sim_matrix, k=1)]))
    return np.mean(sims) if sims else 0

5. Анализ распределения запросов относительно документов

Визуализация запросов на UMAP вместе с документами — ключевой шаг. Если запросы систематически попадают в «пустые» области или в кластеры нерелевантных тем, это указывает на mismatch между энкодером запроса и энкодером документа (например, разные модели или несоответствие предобработки).

Метрика query-document alignment

  • Для каждого запроса найдите его k ближайших соседей среди документов (по косинусной схожести).
  • Посчитайте долю соседей, которые действительно релевантны (по gold standard). Это precision@k для геометрии.
  • Если precision@k низкая, но intra-cluster distances хорошие — проблема в том, что запросы «не туда» попадают.

Пример:

from sklearn.neighbors import NearestNeighbors

nn = NearestNeighbors(n_neighbors=10, metric='cosine')
nn.fit(doc_embeddings)
distances, indices = nn.kneighbors(query_embeddings)
# далее сравнить indices с gold_standard_relevant_ids

6. Выявление аномалий и выбросов

Аномалии — точки, которые находятся далеко от всех кластеров. Они могут быть:

  • Битые чанки (пустые, мусорные данные).
  • Чанки на другом языке.
  • Выбросы из-за ошибок чанкинга (например, обрезанные предложения).

Методы обнаружения

  • Расстояние до k-го ближайшего соседа: если оно аномально велико (например, >95 перцентиля) — точка-выброс.
  • Isolation Forest: unsupervised метод, основанный на случайных деревьях.
  • LOF (Local Outlier Factor): оценивает локальную плотность.

Пример с Isolation Forest

from sklearn.ensemble import IsolationForest

iso_forest = IsolationForest(contamination=0.05, random_state=42)
outlier_labels = iso_forest.fit_predict(doc_embeddings)
outliers = documents[outlier_labels == -1]

После выявления аномалий нужно проверить исходные документы и, возможно, удалить или перечанковать их.


7. Инструменты и библиотеки

ИнструментНазначение
sentence-transformersПолучение эмбеддингов
umap-learnUMAP для визуализации
scikit-learnt-SNE, метрики, Isolation Forest, NearestNeighbors
matplotlib / plotlyПостроение графиков
faissБыстрый поиск ближайших соседей для больших коллекций
numpy / scipyРасчёты расстояний

Рекомендация для больших датасетов (>100k чанков) используйте faiss вместо sklearn.neighbors из-за скорости.


8. Интерпретация результатов и действия

НаблюдениеВероятная причинаДействие
Кластеры плохо разделены (intra ≈ inter)Модель эмбеддингов не подходит для доменаСменить модель (например, bge-large-en-v1.5), дообучить (fine-tune)
Запросы не попадают в кластеры релевантных документовЭнкодер запроса не согласован с энкодером документаИспользовать одну модель для обоих, проверить предобработку
Высокая внутрикластерная схожесть (>0.95)Избыточность чанков (дубликаты)Дедупликация, увеличение размера чанка
Аномалии (выбросы)Битые данные, шумОчистка данных, улучшение чанкинга
Кластеры есть, но запросы попадают в несколько кластеровЗапросы многозначные или широкиеИспользовать query rewriting или multi-vector retrieval

9. Связь с другими аспектами RAG

  • Качество чанкинга: плохой чанкинг (слишком короткие/длинные чанки) приводит к размытым кластерам.
  • Выбор модели эмбеддингов: разные модели дают разную геометрию. Анализ помогает выбрать лучшую.
  • Настройка индекса (HNSW, IVF): параметры индекса влияют на recall, но геометрия остаётся той же. Анализ геометрии помогает понять, стоит ли менять индекс.
  • Влияние на финальный ответ LLM: если геометрия плохая, LLM получит нерелевантный контекст → ответ будет плохим.

10. Пет-проект для закрепления

Задача Проанализировать геометрию эмбеддингов для датасета из 5000 документов (например, статьи Wikipedia по 5 темам) и 100 запросов. Визуализировать, посчитать метрики, выявить аномалии, сделать выводы.

Инструменты Python, sentence-transformers, umap-learn, scikit-learn, matplotlib, numpy.

Шаги:

  1. Загрузить датасет (можно взять wikipedia из datasets или сгенерировать синтетические тексты по темам).
  2. Разбить на чанки по 512 токенов (например, RecursiveCharacterTextSplitter).
  3. Получить эмбеддинги чанков с помощью all-MiniLM-L6-v2.
  4. Применить UMAP (n_neighbors=15, min_dist=0.1) для снижения размерности.
  5. Построить scatter plot, раскрасив точки по темам.
  6. Рассчитать intra-cluster и inter-cluster distances (по темам как кластеры).
  7. Рассчитать average pairwise similarity внутри каждой темы.
  8. Нанести запросы на тот же UMAP, оценить визуально.
  9. Использовать Isolation Forest для поиска аномалий, вывести 10 самых подозрительных чанков.
  10. Написать отчёт: графики, метрики, интерпретация, рекомендации.

Ожидаемый результат Отчёт (Jupyter notebook) с визуализациями, таблицами метрик и выводами. Например: «Кластеры тем хорошо разделены (intra=0.3, inter=0.8), но запросы по теме «физика» частично попадают в кластер «математика» — требуется fine-tune энкодера запросов».


11. Связь с другими вопросами

ВопросТема
5Как вы оцениваете качество retrieval'а в RAG-системе?
6Как выбрать модель эмбеддингов для RAG?
7Как уменьшить latency RAG-системы?
8Как обрабатывать запросы, на которые нет ответа в документах?
9Как обновлять документы в существующей RAG-системе?
10Что такое Self-RAG и когда его использовать?

12. Навигация


Навигация