Векторные БД vs Точность — часть 2

В первой части из тестов стало понятно, что с в векторном поиске с терминами что-то не так. И точность достаточно низкая для корректной работы RAG (retrieval augmentation generation)

В случае с толковым словарем Ожегова, может быть 2 типа вопросов:

  1. По содержимому или значению найти термин

  2. Найти термин, что он обозначает

Проблема во втором типе вопросов, когда на входе термин. Да, это не работает. И цифры это подтверждают. Теперь цель найти решение, для таких кейсов. А не наступать на мои грабли)

Одним из вариантов решения — использовать гибридный поиск, не все векторные БД его поддерживают:

  1. Chroma — в процессе реализации

  2. Pinecone — public preview — нету в Docker — запрос фичи

  3. Milvus — в процессе реализации

  4. Weaviate — поддерживает

  5. Qdrant — поддерживает

  6. Elasticsearch — поддерживает

  7. Opensearch — поддерживает

Так как Chroma, Pinecone, Milvus гибридный поиск пока отсутствует, то выбор пал на Weaviate.

Weaviate

Быстро пробежавшись по документации, вроде как все просто и понятно — надо брать в тест.

Поднимаем контейнер Weaviate с помощью docker-compose.yaml

version: '3.4'
services:
  weaviate:
    command:
    - --host
    - 0.0.0.0
    - --port
    - '8080'
    - --scheme
    - http
    image: cr.weaviate.io/semitechnologies/weaviate:1.24.11
    ports:
    - 8080:8080
    - 50051:50051
    volumes:
    - weaviate_data:/var/lib/weaviate
    restart: on-failure:0
    environment:
      QUERY_DEFAULTS_LIMIT: 25
      AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
      PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
      #Hugginface usage
      DEFAULT_VECTORIZER_MODULE: text2vec-huggingface
      HUGGINGFACE_APIKEY: hf_****************************
      #Dafault usage
      #DEFAULT_VECTORIZER_MODULE: 'none'
      ENABLE_MODULES: 'text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai'
      CLUSTER_HOSTNAME: 'node1'
volumes:
  weaviate_data:

Ставим зависимости

%pip install -U sentence-transformers ipywidgets weaviate-client chardet charset-normalizer

Грузим датасет, также как и в первой части точь-в-точь.

Тянем список моделей, как в предыдущем тесте, чтобы потом сравнить

from weaviate.classes.config import VectorDistances
models = [
    "intfloat/multilingual-e5-large",
    "sentence-transformers/paraphrase-multilingual-mpnet-base-v2",
    "symanto/sn-xlm-roberta-base-snli-mnli-anli-xnli",
    "cointegrated/LaBSE-en-ru",
    "sentence-transformers/LaBSE"
]

distances = [
    VectorDistances.L2_SQUARED,
    VectorDistances.DOT,
    VectorDistances.COSINE
]

Далее как и предыдущем тесте создаем коллекцию и грузим данные в БД согласно документации.

from tqdm import tqdm 
from weaviate.classes.config import Configure, Property, DataType, Tokenization, VectorDistances

def create_collection(client, model_name, distance):
    
    client.collections.create(
        "title",
        vectorizer_config=[
            Configure.NamedVectors.text2vec_huggingface(
                name="title_vector",
                source_properties=["title"],
                model=model_name,
                vector_index_config=Configure.VectorIndex.hnsw(distance_metric=distance)
            )
        ]
    )

    collection = client.collections.get("title")
    
    with collection.batch.dynamic() as batch:
        for i, data in tqdm(dataset.iterrows()):
            obj = {
                "title": data["title"]
            }
            batch.add_object(
                properties = obj
            )

    if len(collection.batch.failed_objects) > 0:
         print(collection.batch.failed_objects)

def delete_collection(client):
    client.collections.delete("title")

Грузим для одной модели, чтобы проверить корректность кода

delete_collection(client)
create_collection(client, "cointegrated/LaBSE-en-ru", VectorDistances.COSINE)

Вот тут произошло НО :(

1000it [00:04, 204.12it/s]
[ErrorObject(message='vectorize target vector title_vector: update vector: failed with status: 429 error: Rate limit reached. 
You reached free usage limit (reset hourly). Please subscribe to a plan at https://huggingface.co/pricing to use the API at this rate'...

Оказывается, что Weviate использует Huggingface не для того, чтобы скачать модель локально, как делают другие БД при создании коллекции. А использует модель на стороне инфраструктуры hugginface через API.

Схема работы Weaviate и huggingface

Схема работы Weaviate и huggingface

Можно использовать локально модели, но их нужно заворачивать в Docker образ и потом коннектить к Weaviate.

Решил не продолжать тест, так как он выбивается за рамки «по-быстрому» + хочется использовать локально модели. Поэтому переходим к Qdrant.

Qdrant

Поднимаем Docker-образ согласно документации

docker run -p 6333:6333 -v $PWD/qdrant_storage:/qdrant/storage qdrant/qdrant

Ставим нужные пакеты

%pip install -U qdrant-client

Грузим датасет, также как и в первой части точь-в-точь.

Тянем список моделей, как в предыдущем тесте + sentence-transformers/all-MiniLM-L6-v2 и sentence-transformers/paraphrase-multilingual-MiniLM-L12-v. Добавил моделей, так как FastEmbed из коробки ограничен список поддерживаемых моделей, который использует qdrant. Поэтому при создании коллекции, в некоторых будем ловить ошибку «Unsupported embedding model…»

Создаем коллекцию и грузим данные, согласно документации

from qdrant_client import QdrantClient, models as qdrant_models

client = QdrantClient(url="http://localhost:6333")
COLLECTION_NAME="termins"

def create_collection(client, model_name):
    client.set_model(model_name)
    client.create_collection(
        collection_name=COLLECTION_NAME,
        vectors_config=client.get_fastembed_vector_params()
    )
    add_data()

def add_data():
    ids = list(map(int, dataset.index.values.tolist()))

    client.add(
        collection_name=COLLECTION_NAME,
        ids = ids, documents=dataset["title"].tolist(), batch_size=2, parallel=0
    )


def delete_collection():
    client.delete_collection(collection_name=COLLECTION_NAME)

В функция поиска ответа в БД особо не отличается от предыдущих. Но мы забираем с максимально высокой оценкой, так как в qdrant оценка, а не расстояние как в Chroma.

Запускаем тест ииии…

found

model_name

100

intfloat/multilingual-e5-large

100

sentence-transformers/paraphrase-multilingual-mpnet-base-v2

100

sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2

0

symanto/sn-xlm-roberta-base-snli-mnli-anli-xnli

100

sentence-transformers/all-MiniLM-L6-v2

0

cointegrated/LaBSE-en-ru

0

sentence-transformers/LaBSE

Получаем 100% попадание, там где 0 — это «Unsupported embedding model».

Интересно, а точно дело в гибридном поиске?

Давайте попробуем просто векторный поиск использовать в Qdrant

found

model_name

100

intfloat/multilingual-e5-large

100

sentence-transformers/paraphrase-multilingual-…

100

sentence-transformers/paraphrase-multilingual-…

100

sentence-transformers/all-MiniLM-L6-v2

Хм…и снова 100%

В этот момент меня начали одолевать сомнения, правильно ли я использовал Chroma, перепроверил код и запустил еще раз тест.

found

model_name

22

intfloat/multilingual-e5-large

23

sentence-transformers/paraphrase-multilingual-mpnet-base-v2

21

sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2

18

sentence-transformers/all-MiniLM-L6-v2

Исходный код

Заключение

Для RAG с моим кейсом и «по-быстрому» — используйте Qdrant и будет вам точность. Так как под капотом он работает фундаментально по-другому.

С другой стороны Chroma достаточно гибкая, но чтобы использовать нужно обладать определённой экспертизой и уметь её правильно варить.

Поэтому выбор векторной БД зависит от уровня экспертизы, условий и области применения. Каждая хороша по своему.

Which Vector Database Should You Use? Choosing the Best One for Your Needs | by Plaban Nayak | The AI Forum | Apr, 2024 | Medium

© Habrahabr.ru