🚀 جرب Zilliz Cloud، الـ Milvus المدارة بالكامل، مجاناً — تجربة أداء أسرع بـ 10 أضعاف! جرب الآن>>

milvus-logo
LFAI
الصفحة الرئيسية
  • عمليات الدمج
  • Home
  • Docs
  • عمليات الدمج

  • تضمين النماذج

  • بينتو مل

التوليد المعزز للاسترجاع (RAG) مع Milvus و BentoML

Open In Colab GitHub Repository

مقدمة

يوضح هذا الدليل كيفية استخدام نموذج التضمين مفتوح المصدر ونموذج اللغة الكبيرة على BentoCloud مع قاعدة بيانات Milvus المتجهة لبناء تطبيق RAG (التوليد المعزز للاسترجاع). BentoCloud هي منصة استدلالية للذكاء الاصطناعي لفرق الذكاء الاصطناعي سريعة الحركة، حيث تقدم بنية تحتية مُدارة بالكامل مصممة خصيصًا للاستدلال على النماذج. وهي تعمل جنباً إلى جنب مع BentoML، وهو إطار عمل مفتوح المصدر لخدمة النماذج، لتسهيل إنشاء ونشر خدمات النماذج عالية الأداء بسهولة. في هذا العرض التوضيحي، نستخدم Milvus Lite كقاعدة بيانات متجهة، وهي نسخة خفيفة الوزن من Milvus التي يمكن تضمينها في تطبيق Python الخاص بك.

قبل أن تبدأ

يتوفر Milvus Lite على PyPI. يمكنك تثبيته عبر pip لبايثون 3.8+:

$ pip install -U pymilvus bentoml

إذا كنت تستخدم Google Colab، لتمكين التبعيات المثبتة للتو، قد تحتاج إلى إعادة تشغيل وقت التشغيل (انقر على قائمة "وقت التشغيل" في أعلى الشاشة، وحدد "إعادة تشغيل الجلسة" من القائمة المنسدلة).

بعد تسجيل الدخول إلى بينتوكلاود، يمكننا التفاعل مع خدمات بينتوكلاود التي تم نشرها في عمليات النشر، وتوجد النهاية_POINT وواجهة برمجة التطبيقات المقابلة في ساحة اللعب -> بايثون. يمكنك تنزيل بيانات المدينة هنا.

خدمة التضمينات باستخدام BentoML/BentoCloud

لاستخدام نقطة النهاية هذه، قم باستيراد bentoml وقم بإعداد عميل HTTP باستخدام SyncHTTPClient من خلال تحديد نقطة النهاية واختيارياً الرمز المميز (إذا قمت بتشغيل Endpoint Authorization على BentoCloud). بدلاً من ذلك، يمكنك استخدام نفس النموذج الذي يتم تقديمه من خلال BentoML باستخدام مستودع تضمينات محولات الجمل.

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
)

بمجرد أن نتصل بعميل_التضمين_التضمين، نحتاج إلى معالجة بياناتنا. لقد وفرنا عدة وظائف لإجراء تقسيم البيانات والتضمين.

قراءة الملفات ومعالجة النص مسبقًا إلى قائمة من السلاسل.

# 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

نحتاج أولاً إلى تنزيل بيانات المدينة.

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)

بعد ذلك، نقوم بمعالجة كل ملف من الملفات التي لدينا.

# 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)

نقسّم قائمة من السلاسل إلى قائمة من التضمينات، كل منها مجمّع 25 سلسلة نصية.

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,
    )

والآن، نحتاج إلى مطابقة التضمينات والسلاسل النصية. نظرًا لأنه يجب أن تتطابق قائمة التضمينات وقائمة الجمل حسب الفهرس، يمكننا enumerate من خلال أي من القائمتين لمطابقتها.

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)

إدراج البيانات في قاعدة بيانات المتجهات لاسترجاعها

بعد إعداد التضمينات والبيانات الخاصة بنا، يمكننا إدراج المتجهات مع البيانات الوصفية في Milvus Lite للبحث عن المتجهات لاحقًا. الخطوة الأولى في هذا القسم هي بدء تشغيل عميل عن طريق الاتصال بـ Milvus Lite. نقوم ببساطة باستيراد الوحدة النمطية MilvusClient وتهيئة عميل Milvus Lite الذي يتصل بقاعدة بيانات متجهات Milvus Lite. يأتي حجم البعد من حجم نموذج التضمين، على سبيل المثال نموذج محول الجملة all-MiniLM-L6-v2 ينتج متجهات ذات أبعاد 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")

أما بالنسبة للوسيطة MilvusClient:

  • يعد تعيين uri كملف محلي، على سبيل المثال./milvus.db ، هو الطريقة الأكثر ملاءمة، حيث يستخدم تلقائيًا ملف Milvus Lite لتخزين جميع البيانات في هذا الملف.
  • إذا كان لديك حجم كبير من البيانات، يمكنك إعداد خادم Milvus أكثر أداءً على docker أو kubernetes. في هذا الإعداد، يُرجى استخدام الخادم uri، على سبيل المثالhttp://localhost:19530 ، كـ uri.
  • إذا كنت ترغب في استخدام Zilliz Cloud، الخدمة السحابية المدارة بالكامل لـ Milvus، اضبط uri و token ، والتي تتوافق مع نقطة النهاية العامة ومفتاح Api في Zilliz Cloud.

أو مع واجهة برمجة التطبيقات القديمة للاتصالات.connect.API (غير مستحسن):

from pymilvus import connections

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

إنشاء مجموعة ميلفوس لايت الخاصة بك

يتضمن إنشاء مجموعة باستخدام Milvus Lite خطوتين: أولاً، تحديد المخطط، وثانياً، تحديد الفهرس. في هذا القسم، نحتاج إلى وحدة واحدة: DataType تخبرنا بنوع البيانات التي ستكون في الحقل. نحتاج أيضًا إلى استخدام دالتين لإنشاء مخطط وإضافة حقول. create_schema(): إنشاء مخطط مجموعة، و add_field(): إضافة حقل إلى مخطط المجموعة.

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)

الآن بعد أن أنشأنا المخطط وحددنا حقل البيانات بنجاح، نحتاج إلى تحديد الفهرس. فيما يتعلق بالبحث، يحدد "الفهرس" كيف سنقوم بتعيين بياناتنا لاسترجاعها. نستخدم الخيار الافتراضي AUTOINDEX لفهرسة بياناتنا لهذا المشروع.

بعد ذلك، ننشئ المجموعة بالاسم والمخطط والفهرس المعطى مسبقًا. أخيرًا، نقوم بإدراج البيانات التي تمت معالجتها مسبقًا.

# 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)

إعداد LLM الخاص بك لـ RAG

لإنشاء تطبيق RAG، نحتاج إلى نشر LLM على BentoCloud. دعنا نستخدم أحدث Llama3 LLM. بمجرد تشغيله وتشغيله، ما عليك سوى نسخ نقطة النهاية والرمز المميز لهذه الخدمة النموذجية وإعداد عميل لها.

BENTO_LLM_END_POINT = "BENTO_LLM_END_POINT"

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

تعليمات LLM

والآن، سنقوم بإعداد تعليمات LLM مع المطالبة والسياق والسؤال. هذه هي الدالة التي تتصرف كـ LLM ثم تقوم بإرجاع المخرجات من العميل بتنسيق سلسلة.

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

مثال RAG

نحن الآن جاهزون لطرح سؤال. تأخذ هذه الدالة ببساطة سؤالًا ثم تقوم بعمل RAG لتوليد السياق ذي الصلة من المعلومات الأساسية. ثم نمرر السياق والسؤال إلى dorag() ونحصل على النتيجة.

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)

تنفيذ RAG

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

بالنسبة لمثال السؤال الذي يسأل عن الحالة التي تتواجد فيها كامبريدج، يمكننا طباعة الإجابة كاملةً من BentoML. ومع ذلك، إذا أخذنا الوقت الكافي لتحليله، سيبدو الأمر أجمل، وسيخبرنا أن كامبريدج تقع في ماساتشوستس.

جرب Managed Milvus مجاناً

Zilliz Cloud خالي من المتاعب، ويعمل بواسطة Milvus ويعمل بسرعة 10 أضعاف.

ابدأ
التعليقات

هل كانت هذه الصفحة مفيدة؟