В первой части из тестов стало понятно, что с в векторном поиске с терминами что-то не так. И точность достаточно низкая для корректной работы RAG (retrieval augmentation generation)
В случае с толковым словарем Ожегова, может быть 2 типа вопросов:
По содержимому или значению найти термин
Найти термин, что он обозначает
Проблема во втором типе вопросов, когда на входе термин. Да, это не работает. И цифры это подтверждают. Теперь цель найти решение, для таких кейсов. А не наступать на мои грабли)
Одним из вариантов решения - использовать гибридный поиск, не все векторные БД его поддерживают:
Pinecone - public preview - нету в Docker - запрос фичи
Так как 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.

Можно использовать локально модели, но их нужно заворачивать в 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 достаточно гибкая, но чтобы использовать нужно обладать определённой экспертизой и уметь её правильно варить.
Поэтому выбор векторной БД зависит от уровня экспертизы, условий и области применения. Каждая хороша по своему.
