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