Семантический поиск с помощью Milvus и VoyageAI
В этом руководстве показано, как можно использовать VoyageAI's Embedding API с векторной базой данных Milvus для проведения семантического поиска по тексту.
Начало работы
Прежде чем начать, убедитесь, что у вас готов ключ Voyage API, или получите его на сайте VoyageAI.
В этом примере используются данные о названиях книг. Вы можете скачать набор данных здесь и поместить его в ту же директорию, где вы запускаете следующий код.
Сначала установите пакет для Milvus и Voyage AI:
$ pip install --upgrade voyageai pymilvus
Если вы используете Google Colab, для включения только что установленных зависимостей вам, возможно, потребуется перезапустить среду выполнения. (Нажмите на меню "Runtime" в верхней части экрана и выберите "Restart session" из выпадающего меню).
После этого мы готовы к генерации вкраплений и использованию векторной базы данных для семантического поиска.
Поиск названий книг с помощью VoyageAI и Milvus
В следующем примере мы загружаем данные о названиях книг из загруженного CSV-файла, используем модель встраивания Voyage AI для генерации векторных представлений и сохраняем их в векторной базе данных Milvus для семантического поиска.
import voyageai
from pymilvus import MilvusClient
MODEL_NAME = "voyage-law-2" # Which model to use, please check https://docs.voyageai.com/docs/embeddings for available models
DIMENSION = 1024 # Dimension of vector embedding
# Connect to VoyageAI with API Key.
voyage_client = voyageai.Client(api_key="<YOUR_VOYAGEAI_API_KEY>")
docs = [
"Artificial intelligence was founded as an academic discipline in 1956.",
"Alan Turing was the first person to conduct substantial research in AI.",
"Born in Maida Vale, London, Turing was raised in southern England.",
]
vectors = voyage_client.embed(texts=docs, model=MODEL_NAME, truncation=False).embeddings
# Prepare data to be stored in Milvus vector database.
# We can store the id, vector representation, raw text and labels such as "subject" in this case in Milvus.
data = [
{"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
for i in range(len(docs))
]
# Connect to Milvus, all data is stored in a local file named "milvus_voyage_demo.db"
# in current directory. You can also connect to a remote Milvus server following this
# instruction: https://milvus.io/docs/install_standalone-docker.md.
milvus_client = MilvusClient(uri="milvus_voyage_demo.db")
COLLECTION_NAME = "demo_collection" # Milvus collection name
# Create a collection to store the vectors and text.
if milvus_client.has_collection(collection_name=COLLECTION_NAME):
milvus_client.drop_collection(collection_name=COLLECTION_NAME)
milvus_client.create_collection(collection_name=COLLECTION_NAME, dimension=DIMENSION)
# Insert all data into Milvus vector database.
res = milvus_client.insert(collection_name="demo_collection", data=data)
print(res["insert_count"])
Что касается аргумента MilvusClient
:
- Установка
uri
в качестве локального файла, например./milvus.db
, является наиболее удобным методом, поскольку он автоматически использует Milvus Lite для хранения всех данных в этом файле. - Если у вас большой объем данных, вы можете настроить более производительный сервер Milvus на docker или kubernetes. В этом случае используйте ури сервера, например
http://localhost:19530
, в качествеuri
. - Если вы хотите использовать Zilliz Cloud, полностью управляемый облачный сервис для Milvus, настройте
uri
иtoken
, которые соответствуют публичной конечной точке и ключу Api в Zilliz Cloud.
Теперь, имея все данные в векторной базе Milvus, мы можем выполнять семантический поиск, генерируя векторные вкрапления для запроса и осуществляя векторный поиск.
queries = ["When was artificial intelligence founded?"]
query_vectors = voyage_client.embed(
texts=queries, model=MODEL_NAME, truncation=False
).embeddings
res = milvus_client.search(
collection_name=COLLECTION_NAME, # target collection
data=query_vectors, # query vectors
limit=2, # number of returned entities
output_fields=["text", "subject"], # specifies fields to be returned
)
for q in queries:
print("Query:", q)
for result in res:
print(result)
print("\n")
Query: When was artificial intelligence founded?
[{'id': 0, 'distance': 0.7196218371391296, 'entity': {'text': 'Artificial intelligence was founded as an academic discipline in 1956.', 'subject': 'history'}}, {'id': 1, 'distance': 0.6297335028648376, 'entity': {'text': 'Alan Turing was the first person to conduct substantial research in AI.', 'subject': 'history'}}]
Поиск изображений с помощью VoyageAI и Milvus
import base64
import voyageai
from pymilvus import MilvusClient
import urllib.request
import matplotlib.pyplot as plt
from io import BytesIO
import urllib.request
import fitz # PyMuPDF
from PIL import Image
def pdf_url_to_screenshots(url: str, zoom: float = 1.0) -> list[Image]:
# Ensure that the URL is valid
if not url.startswith("http") and url.endswith(".pdf"):
raise ValueError("Invalid URL")
# Read the PDF from the specified URL
with urllib.request.urlopen(url) as response:
pdf_data = response.read()
pdf_stream = BytesIO(pdf_data)
pdf = fitz.open(stream=pdf_stream, filetype="pdf")
images = []
# Loop through each page, render as pixmap, and convert to PIL Image
mat = fitz.Matrix(zoom, zoom)
for n in range(pdf.page_count):
pix = pdf[n].get_pixmap(matrix=mat)
# Convert pixmap to PIL Image
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
images.append(img)
# Close the document
pdf.close()
return images
def image_to_base64(image):
buffered = BytesIO()
image.save(buffered, format="JPEG")
img_str = base64.b64encode(buffered.getvalue())
return img_str.decode("utf-8")
DIMENSION = 1024 # Dimension of vector embedding
Затем нам нужно подготовить входные данные для Milvus. Воспользуемся клиентом VoyageAI, который мы создали в предыдущей главе. Доступную модель мультимодального встраивания VoyageAI смотрите на этой странице.
pages = pdf_url_to_screenshots("https://www.fdrlibrary.org/documents/356632/390886/readingcopy.pdf", zoom=3.0)
inputs = [[img] for img in pages]
vectors = client.multimodal_embed(inputs, model="voyage-multimodal-3")
inputs = [i[0] if isinstance(i[0], str) else image_to_base64(i[0]) for i in inputs]
# Prepare data to be stored in Milvus vector database.
# We can store the id, vector representation, raw text and labels such as "subject" in this case in Milvus.
data = [
{"id": i, "vector": vectors.embeddings[i], "data": inputs[i], "subject": "fruits"}
for i in range(len(inputs))
]
Далее мы создадим соединение с базой данных Milvus и вставим в нее эмбеддинги.
milvus_client = MilvusClient(uri="milvus_voyage_multi_demo.db")
COLLECTION_NAME = "demo_collection" # Milvus collection name
# Create a collection to store the vectors and text.
if milvus_client.has_collection(collection_name=COLLECTION_NAME):
milvus_client.drop_collection(collection_name=COLLECTION_NAME)
milvus_client.create_collection(collection_name=COLLECTION_NAME, dimension=DIMENSION)
# Insert all data into Milvus vector database.
res = milvus_client.insert(collection_name="demo_collection", data=data)
print(res["insert_count"])
Теперь мы готовы к поиску изображений. Здесь запрос - это строка, но мы можем запрашивать и изображения. (Мы используем matplotlib для отображения результатов.
queries = [["The consequences of a dictator's peace"]]
query_vectors = client.multimodal_embed(
inputs=queries, model="voyage-multimodal-3", truncation=False
).embeddings
res = milvus_client.search(
collection_name=COLLECTION_NAME, # target collection
data=query_vectors, # query vectors
limit=4, # number of returned entities
output_fields=["data", "subject"], # specifies fields to be returned
)
for q in queries:
print("Query:", q)
for result in res:
fig, axes = plt.subplots(1, len(result), figsize=(66, 6))
for n, page in enumerate(result):
page_num = page['id']
axes[n].imshow(pages[page_num])
axes[n].axis("off")
plt.tight_layout()
plt.show()