🚀 Coba Zilliz Cloud, Milvus yang sepenuhnya terkelola, secara gratis—rasakan performa 10x lebih cepat! Coba Sekarang>>

milvus-logo
LFAI
Beranda
  • Integrasi
  • Home
  • Docs
  • Integrasi

  • Model Penyematan

  • BentoML

Retrieval-Augmented Generation (RAG) dengan Milvus dan BentoML

Open In Colab GitHub Repository

Pendahuluan

Panduan ini mendemonstrasikan cara menggunakan model penyematan sumber terbuka dan model bahasa besar di BentoCloud dengan basis data vektor Milvus untuk membangun aplikasi RAG (Retrieval Augmented Generation). BentoCloud adalah Platform Inferensi AI untuk tim AI yang bergerak cepat, yang menawarkan infrastruktur terkelola penuh yang disesuaikan untuk inferensi model. Platform ini bekerja bersama dengan BentoML, sebuah kerangka kerja penyajian model sumber terbuka, untuk memfasilitasi pembuatan dan penerapan layanan model berkinerja tinggi dengan mudah. Dalam demo ini, kami menggunakan Milvus Lite sebagai basis data vektor, yang merupakan versi ringan dari Milvus yang dapat disematkan ke dalam aplikasi Python Anda.

Sebelum Anda mulai

Milvus Lite tersedia di PyPI. Anda dapat menginstalnya melalui pip untuk Python 3.8+:

$ pip install -U pymilvus bentoml

Jika Anda menggunakan Google Colab, untuk mengaktifkan dependensi yang baru saja diinstal, Anda mungkin perlu memulai ulang runtime (Klik menu "Runtime" di bagian atas layar, dan pilih "Restart session" dari menu tarik-turun).

Setelah masuk ke BentoCloud, kita dapat berinteraksi dengan Layanan BentoCloud yang telah diterapkan di Deployment, dan END_POINT serta API yang sesuai berada di Playground -> Python. Anda dapat mengunduh data kota di sini.

Menyajikan Penyematan dengan BentoML/BentoCloud

Untuk menggunakan endpoint ini, impor bentoml dan siapkan klien HTTP menggunakan SyncHTTPClient dengan menentukan endpoint dan opsional token (jika Anda mengaktifkan Endpoint Authorization di BentoCloud). Sebagai alternatif, Anda dapat menggunakan model yang sama yang disajikan melalui BentoML menggunakan repositori Sentence Transformers Embeddings.

import bentoml

BENTO_EMBEDDING_MODEL_END_POINT = "BENTO_EMBEDDING_MODEL_END_POINT"
BENTO_API_TOKEN = "BENTO_API_TOKEN"

embedding_client = bentoml.SyncHTTPClient(
    BENTO_EMBEDDING_MODEL_END_POINT, token=BENTO_API_TOKEN
)

Setelah kita terhubung ke embedding_client, kita perlu memproses data kita. Kami menyediakan beberapa fungsi untuk melakukan pemisahan dan penyematan data.

Baca file dan praproses teks menjadi daftar string.

# naively chunk on newlines
def chunk_text(filename: str) -> list:
    with open(filename, "r") as f:
        text = f.read()
    sentences = text.split("\n")
    return sentences

Pertama kita perlu mengunduh data kota.

import os
import requests
import urllib.request

# set up the data source
repo = "ytang07/bento_octo_milvus_RAG"
directory = "data"
save_dir = "./city_data"
api_url = f"https://api.github.com/repos/{repo}/contents/{directory}"


response = requests.get(api_url)
data = response.json()

if not os.path.exists(save_dir):
    os.makedirs(save_dir)

for item in data:
    if item["type"] == "file":
        file_url = item["download_url"]
        file_path = os.path.join(save_dir, item["name"])
        urllib.request.urlretrieve(file_url, file_path)

Selanjutnya, kita memproses setiap file yang kita miliki.

# please upload your data directory under this file's folder
cities = os.listdir("city_data")
# store chunked text for each of the cities in a list of dicts
city_chunks = []
for city in cities:
    chunked = chunk_text(f"city_data/{city}")
    cleaned = []
    for chunk in chunked:
        if len(chunk) > 7:
            cleaned.append(chunk)
    mapped = {"city_name": city.split(".")[0], "chunks": cleaned}
    city_chunks.append(mapped)

Membagi daftar string menjadi daftar embedding, masing-masing mengelompokkan 25 string teks.

def get_embeddings(texts: list) -> list:
    if len(texts) > 25:
        splits = [texts[x : x + 25] for x in range(0, len(texts), 25)]
        embeddings = []
        for split in splits:
            embedding_split = embedding_client.encode(sentences=split)
            embeddings += embedding_split
        return embeddings
    return embedding_client.encode(
        sentences=texts,
    )

Sekarang, kita perlu mencocokkan embedding dan potongan teks. Karena daftar sematan dan daftar kalimat harus sesuai dengan indeks, kita dapat enumerate melalui kedua daftar tersebut untuk mencocokkannya.

entries = []
for city_dict in city_chunks:
    # No need for the embeddings list if get_embeddings already returns a list of lists
    embedding_list = get_embeddings(city_dict["chunks"])  # returns a list of lists
    # Now match texts with embeddings and city name
    for i, embedding in enumerate(embedding_list):
        entry = {
            "embedding": embedding,
            "sentence": city_dict["chunks"][
                i
            ],  # Assume "chunks" has the corresponding texts for the embeddings
            "city": city_dict["city_name"],
        }
        entries.append(entry)
    print(entries)

Memasukkan Data ke dalam Basis Data Vektor untuk Pengambilan

Dengan penyematan dan data yang telah disiapkan, kita dapat memasukkan vektor bersama dengan metadata ke dalam Milvus Lite untuk pencarian vektor nantinya. Langkah pertama pada bagian ini adalah memulai sebuah klien dengan menghubungkan ke Milvus Lite. Kita cukup mengimpor modul MilvusClient dan menginisialisasi klien Milvus Lite yang terhubung ke basis data vektor Milvus Lite Anda. Ukuran dimensi berasal dari ukuran model embedding, contohnya model Sentence Transformer all-MiniLM-L6-v2 menghasilkan vektor berdimensi 384.

from pymilvus import MilvusClient

COLLECTION_NAME = "Bento_Milvus_RAG"  # random name for your collection
DIMENSION = 384

# Initialize a Milvus Lite client
milvus_client = MilvusClient("milvus_demo.db")

Sedangkan untuk argumen MilvusClient:

  • Mengatur uri sebagai file lokal, misalnya./milvus.db, adalah metode yang paling mudah, karena secara otomatis menggunakan Milvus Lite untuk menyimpan semua data dalam file ini.
  • Jika Anda memiliki data dalam skala besar, Anda dapat mengatur server Milvus yang lebih berkinerja pada docker atau kubernetes. Dalam pengaturan ini, silakan gunakan uri server, misalnyahttp://localhost:19530, sebagai uri.
  • Jika Anda ingin menggunakan Zilliz Cloud, layanan cloud yang dikelola sepenuhnya untuk Milvus, sesuaikan uri dan token, yang sesuai dengan kunci Public Endpoint dan Api di Zilliz Cloud.

Atau dengan koneksi lama.connect API (tidak disarankan):

from pymilvus import connections

connections.connect(uri="milvus_demo.db")

Membuat Koleksi Milvus Lite Anda

Membuat koleksi menggunakan Milvus Lite melibatkan dua langkah: pertama, mendefinisikan skema, dan kedua, mendefinisikan indeks. Untuk bagian ini, kita membutuhkan satu modul: DataType memberi tahu kita jenis data apa yang akan ada di dalam sebuah field. Kita juga perlu menggunakan dua fungsi untuk membuat skema dan menambahkan field. create_schema(): membuat skema koleksi, add_field(): menambahkan sebuah field ke dalam skema koleksi.

from pymilvus import MilvusClient, DataType, Collection

# Create schema
schema = MilvusClient.create_schema(
    auto_id=True,
    enable_dynamic_field=True,
)

# 3.2. Add fields to schema
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=DIMENSION)

Sekarang kita telah membuat skema dan berhasil mendefinisikan field data, kita perlu mendefinisikan indeks. Dalam hal pencarian, sebuah "indeks" mendefinisikan bagaimana kita akan memetakan data kita untuk diambil. Kita menggunakan pilihan default AUTOINDEX untuk mengindeks data kita untuk proyek ini.

Selanjutnya, kita membuat koleksi dengan nama, skema, dan indeks yang telah diberikan sebelumnya. Terakhir, kita memasukkan data yang telah diproses sebelumnya.

# prepare index parameters
index_params = milvus_client.prepare_index_params()

# add index
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",  # use autoindex instead of other complex indexing method
    metric_type="COSINE",  # L2, COSINE, or IP
)

# create collection
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, schema=schema, index_params=index_params
)

# Outside the loop, now you upsert all the entries at once
milvus_client.insert(collection_name=COLLECTION_NAME, data=entries)

Menyiapkan LLM Anda untuk RAG

Untuk membangun aplikasi RAG, kita perlu menerapkan LLM di BentoCloud. Mari kita gunakan LLM Llama3 terbaru. Setelah aktif dan berjalan, cukup salin titik akhir dan token layanan model ini dan siapkan klien untuknya.

BENTO_LLM_END_POINT = "BENTO_LLM_END_POINT"

llm_client = bentoml.SyncHTTPClient(BENTO_LLM_END_POINT, token=BENTO_API_TOKEN)

Petunjuk LLM

Sekarang, kita menyiapkan instruksi LLM dengan prompt, konteks, dan pertanyaan. Berikut ini adalah fungsi yang berperilaku sebagai LLM dan kemudian mengembalikan keluaran dari klien dalam format string.

def dorag(question: str, context: str):

    prompt = (
        f"You are a helpful assistant. The user has a question. Answer the user question based only on the context: {context}. \n"
        f"The user question is {question}"
    )

    results = llm_client.generate(
        max_tokens=1024,
        prompt=prompt,
    )

    res = ""
    for result in results:
        res += result

    return res

Contoh RAG

Sekarang kita siap untuk mengajukan pertanyaan. Fungsi ini hanya mengambil sebuah pertanyaan dan kemudian melakukan RAG untuk menghasilkan konteks yang relevan dari informasi latar belakang. Kemudian, kita mengoper konteks dan pertanyaan ke dorag() dan mendapatkan hasilnya.

question = "What state is Cambridge in?"


def ask_a_question(question):
    embeddings = get_embeddings([question])
    res = milvus_client.search(
        collection_name=COLLECTION_NAME,
        data=embeddings,  # search for the one (1) embedding returned as a list of lists
        anns_field="embedding",  # Search across embeddings
        limit=5,  # get me the top 5 results
        output_fields=["sentence"],  # get the sentence/chunk and city
    )

    sentences = []
    for hits in res:
        for hit in hits:
            print(hit)
            sentences.append(hit["entity"]["sentence"])
    context = ". ".join(sentences)
    return context


context = ask_a_question(question=question)
print(context)

Menerapkan RAG

print(dorag(question=question, context=context))

Untuk contoh pertanyaan yang menanyakan di negara bagian mana Cambridge berada, kita dapat mencetak seluruh respons dari BentoML. Namun, jika kita meluangkan waktu untuk menguraikannya, hasilnya akan terlihat lebih baik, dan akan memberi tahu kita bahwa Cambridge terletak di Massachusetts.

Coba Milvus yang Dikelola secara Gratis

Zilliz Cloud bebas masalah, didukung oleh Milvus dan 10x lebih cepat.

Mulai
Umpan balik

Apakah halaman ini bermanfaat?