بناء RAG باستخدام Milvus وFeast
في هذا البرنامج التعليمي، سنقوم في هذا البرنامج التعليمي ببناء خط أنابيب توليد الاسترجاع المعزز (RAG) باستخدام Feast و Milvus. Feast هو مخزن ميزات مفتوح المصدر يعمل على تبسيط إدارة الميزات للتعلم الآلي، مما يتيح تخزين واسترجاع البيانات المنظمة بكفاءة لكل من التدريب والاستدلال في الوقت الفعلي. Milvus عبارة عن قاعدة بيانات متجهة عالية الأداء مصممة للبحث السريع عن التشابه، مما يجعلها مثالية لاسترجاع المستندات ذات الصلة في عمليات سير عمل RAG.
بشكل أساسي، سنستخدم Feast لحقن المستندات والبيانات المهيكلة (أي الميزات) في سياق نموذج اللغة الكبيرة (LLM) لتشغيل تطبيق RAG (استرجاع الجيل المعزز) مع Milvus كقاعدة بيانات متجهة عبر الإنترنت.
لماذا العيد؟
يحل Feast العديد من المشكلات الشائعة في هذا التدفق:
- الاسترجاع عبر الإنترنت: في وقت الاستنتاج، غالبًا ما تحتاج تطبيقات التوليد المعزز للاسترجاع عبر الإنترنت إلى الوصول إلى بيانات غير متاحة بسهولة وتحتاج إلى حسابها مسبقًا من مصادر بيانات أخرى.
- يدير Feast النشر إلى مجموعة متنوعة من المتاجر عبر الإنترنت (مثل Milvus وDynamoDB وRedis وGoogle Cloud Datastore) ويضمن توفر الميزات الضرورية باستمرار وحسابها حديثًا في وقت الاستدلال.
- البحث عن المتجهات: قام Feast ببناء دعم للبحث عن التشابه المتجه الذي يمكن تهيئته بسهولة بشكل معلن حتى يتمكن المستخدمون من التركيز على تطبيقاتهم. يوفر ميلفوس قدرات بحث قوية وفعالة في البحث عن التشابه المتجهي.
- بيانات منظمة أكثر ثراءً: إلى جانب البحث المتجه، يمكن للمستخدمين الاستعلام عن الحقول المهيكلة القياسية لإدخالها في سياق LLM للحصول على تجارب مستخدم أفضل.
- الميزة/السياق والإصدار: غالبًا ما تكون الفرق المختلفة داخل المؤسسة غير قادرة على إعادة استخدام البيانات عبر المشاريع والخدمات، مما يؤدي إلى تكرار منطق التطبيق. تحتوي النماذج على تبعيات البيانات التي تحتاج إلى إصدارها، على سبيل المثال عند إجراء اختبارات A/B على إصدارات النماذج/المطالبات.
- يمكّن Feast من اكتشاف المستندات والميزات المستخدمة سابقًا والتعاون بشأنها، كما يتيح إمكانية إصدار مجموعات من البيانات.
سنقوم بـ
- نشر مخزن ميزات محلي مع مخزن ملف باركيه غير متصل بالإنترنت ومخزن ميلفوس على الإنترنت.
- كتابة/إضفاء الطابع المادي على البيانات (أي قيم الميزات) من المخزن غير المتصل (ملف باركيه) إلى المخزن عبر الإنترنت (ملف باركيه).
- تقديم الميزات باستخدام مجموعة أدوات تطوير البرمجيات الخاصة بـ Feast SDK مع إمكانيات البحث المتجه في Milvus
- حقن المستند في سياق LLM للإجابة على الأسئلة
يعتمد هذا البرنامج التعليمي على دليل التكامل الرسمي لـ Milvus من مستودع Feast. في حين أننا نسعى جاهدين للحفاظ على تحديث هذا البرنامج التعليمي، إذا واجهت أي تناقضات، يرجى الرجوع إلى الدليل الرسمي ولا تتردد في فتح مشكلة في مستودعنا للحصول على أي تحديثات ضرورية.
التحضير
التبعيات
$ pip install 'feast[milvus]' openai -U -q
إذا كنت تستخدم Google Colab، لتمكين التبعيات المثبتة للتو، قد تحتاج إلى إعادة تشغيل وقت التشغيل (انقر على قائمة "وقت التشغيل" في أعلى الشاشة، وحدد "إعادة تشغيل الجلسة" من القائمة المنسدلة).
سنستخدم OpenAI كموفر LLM الخاص بنا. يمكنك تسجيل الدخول إلى موقعه الرسمي وإعداد OPENAI_API_KEY كمتغير بيئة.
import os
from openai import OpenAI
os.environ["OPENAI_API_KEY"] = "sk-**************"
llm_client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY"),
)
إعداد البيانات
سنستخدم البيانات من المجلد التالي كمثال لدينا:
Feast RAG Feature Repo
بعد تنزيل البيانات، ستجد الملفات التالية:
feature_repo/
│── data/ # Contains pre-processed Wikipedia city data in Parquet format
│── example_repo.py # Defines feature views and entities for the city data
│── feature_store.yaml # Configures Milvus and feature store settings
│── test_workflow.py # Example workflow for Feast operations
ملفات تكوين المفاتيح
1. feature_store.yaml
يقوم هذا الملف بتكوين البنية التحتية لمخزن الميزات:
project: rag
provider: local
registry: data/registry.db
online_store:
type: milvus # Uses Milvus for vector storage
path: data/online_store.db
vector_enabled: true # Enables vector similarity search
embedding_dim: 384 # Dimension of our embeddings
index_type: "FLAT" # Vector index type
metric_type: "COSINE" # Similarity metric
offline_store:
type: file # Uses file-based offline storage
يؤسس هذا التكوين:
- Milvus كمخزن على الإنترنت لاسترجاع المتجهات السريعة
- تخزين الملفات دون اتصال بالإنترنت لمعالجة البيانات التاريخية
- إمكانيات البحث عن المتجهات مع تشابه COSINE
2. example_repo.py
يحتوي على تعريفات الميزات لبيانات مدينتنا، بما في ذلك:
- تعريفات الكيانات للمدن
- طرق عرض الميزات لمعلومات المدينة والتضمينات
- مواصفات المخطط لقاعدة بيانات المتجهات
3. دليل البيانات
يحتوي على بيانات مدن ويكيبيديا المعالجة مسبقًا مع:
- أوصاف المدن وملخصاتها
- التضمينات المحسوبة مسبقاً (متجهات 384 بُعداً)
- البيانات الوصفية المرتبطة مثل أسماء المدن والولايات
تعمل هذه الملفات معًا لإنشاء مخزن ميزات يجمع بين إمكانيات البحث المتجهية في ميلفوس وإدارة ميزات فيست، مما يتيح استرجاع معلومات المدينة ذات الصلة بكفاءة لتطبيق RAG الخاص بنا.
فحص البيانات
يتم تخزين بيانات الميزات الأولية التي لدينا في هذا العرض التوضيحي في ملف باركيه محلي. تحتوي مجموعة البيانات على ملخصات ويكيبيديا للمدن المختلفة. دعونا نفحص البيانات أولاً.
import pandas as pd
df = pd.read_parquet(
"/path/to/feature_repo/data/city_wikipedia_summaries_with_embeddings.parquet"
)
df["vector"] = df["vector"].apply(lambda x: x.tolist())
embedding_length = len(df["vector"][0])
print(f"embedding length = {embedding_length}")
embedding length = 384
from IPython.display import display
display(df.head())
| المعرف | العنصر_المعرف | الطابع الزمني للحدث | الحالة | ملخص_ويكي | أجزاء_الجملة | المتجه | |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 2025-01-09 13:36:59.280589 | نيويورك، نيويورك | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، وغالبًا ما تسمى مدينة نيويورك أو ببساطة... | [0.1465730518102646, -0.07317650318145752, 0.0... |
| 1 | 1 | 1 | 2025-01-09 13:36:59.280589 | نيويورك، نيويورك | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة مدينة نيويورك... | تتألف المدينة من خمسة أحياء، كل منها... | [0.05218901485204697, -0.08449874818325043, 0.... |
| 2 | 2 | 2 | 2025-01-09 13:36:59.280589 | نيويورك، نيويورك | نيويورك، وغالباً ما يطلق عليها اسم مدينة نيويورك أو ببساطة... | نيويورك هي مركز عالمي للتمويل والتجارة... | [0.06769222766160965, -0.07371102273464203, -0... |
| 3 | 3 | 3 | 2025-01-09 13:36:59.280589 | نيويورك، نيويورك | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة ... | مدينة نيويورك هي بؤرة العالم في العالم ... | [0.12095861881971359, -0.04279915615916252, 0.... |
| 4 | 4 | 4 | 2025-01-09 13:36:59.280589 | نيويورك، نيويورك | نيويورك، وغالباً ما يطلق عليها اسم مدينة نيويورك أو ببساطة... | يُقدر عدد سكانها في عام 2022 بـ 8,335 نسمة... | [0.17943550646305084, -0.09458263963460922, 0.... |
تسجيل تعريفات الميزات ونشر مخزن الميزات
بعد تنزيل feature_repo ، نحتاج إلى تشغيل feast apply لتسجيل طرق عرض الميزات والكيانات المحددة في example_repo.py ، وإعداد Milvus كجداول المتجر عبر الإنترنت.
تأكد من أنك قمت بالتسجيل في الدليل feature_repo قبل تشغيل الأمر.
feast apply
تحميل الميزات في ملفوس
الآن نقوم بتحميل الميزات إلى ملفوس. تتضمن هذه الخطوة تسلسل قيم الميزات من المخزن غير المتصل وكتابتها في ملفوس.
from datetime import datetime
from feast import FeatureStore
import warnings
warnings.filterwarnings("ignore")
store = FeatureStore(repo_path="/path/to/feature_repo")
store.write_to_online_store(feature_view_name="city_embeddings", df=df)
Connecting to Milvus in local mode using /Users/jinhonglin/Desktop/feature_repo/data/online_store.db
لاحظ أنه يوجد الآن online_store.db و registry.db ، اللذان يخزنان الميزات المتجسدة ومعلومات المخطط، على التوالي. يمكننا إلقاء نظرة على الملف online_store.db.
pymilvus_client = store._provider._online_store._connect(store.config)
COLLECTION_NAME = pymilvus_client.list_collections()[0]
milvus_query_result = pymilvus_client.query(
collection_name=COLLECTION_NAME,
filter="item_id == '0'",
)
pd.DataFrame(milvus_query_result[0]).head()
| item_id_pk | تم إنشاؤه_ت | event_ts | العنصر_المعرف | أجزاء_الجملة | الحالة | المتجه | ويكي_ملخص | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0100000002000000070000006974656d5f696404000000... | 0 | 1736447819280589 | 0 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، نيويورك | 0.146573 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة مدينة... |
| 1 | 0100000002000000070000006974656d5f696404000000... | 0 | 1736447819280589 | 0 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، نيويورك | -0.073177 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة مدينة... |
| 2 | 0100000002000000070000006974656d5f696404000000... | 0 | 1736447819280589 | 0 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، نيويورك | 0.052114 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... |
| 3 | 0100000002000000070000006974656d5f696404000000... | 0 | 1736447819280589 | 0 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، نيويورك | 0.033187 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... |
| 4 | 0100000002000000070000006974656d5f696404000000... | 0 | 1736447819280589 | 0 | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، نيويورك | 0.012013 | نيويورك، غالباً ما تسمى مدينة نيويورك أو ببساطة... |
بناء RAG
1. تضمين استعلام باستخدام PyTorch ومحولات الجمل
أثناء الاستدلال (على سبيل المثال، أثناء إرسال المستخدم لرسالة دردشة) نحتاج إلى تضمين نص الإدخال. يمكن اعتبار ذلك بمثابة تحويل ميزة لبيانات الإدخال. في هذا المثال، سنقوم بذلك باستخدام محول جملة صغير من Hugging Face.
import torch
import torch.nn.functional as F
from feast import FeatureStore
from pymilvus import MilvusClient, DataType, FieldSchema
from transformers import AutoTokenizer, AutoModel
from example_repo import city_embeddings_feature_view, item
TOKENIZER = "sentence-transformers/all-MiniLM-L6-v2"
MODEL = "sentence-transformers/all-MiniLM-L6-v2"
def mean_pooling(model_output, attention_mask):
token_embeddings = model_output[
0
] # First element of model_output contains all token embeddings
input_mask_expanded = (
attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
)
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(
input_mask_expanded.sum(1), min=1e-9
)
def run_model(sentences, tokenizer, model):
encoded_input = tokenizer(
sentences, padding=True, truncation=True, return_tensors="pt"
)
# Compute token embeddings
with torch.no_grad():
model_output = model(**encoded_input)
sentence_embeddings = mean_pooling(model_output, encoded_input["attention_mask"])
sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
return sentence_embeddings
2. جلب المتجهات والبيانات في الوقت الحقيقي للاستدلال عبر الإنترنت
بمجرد تحويل الاستعلام إلى تضمين، فإن الخطوة التالية هي استرداد المستندات ذات الصلة من مخزن المتجهات. في وقت الاستدلال، نستفيد من البحث عن تشابه المتجهات للعثور على تضمينات المستندات الأكثر صلة المخزنة في مخزن الميزات عبر الإنترنت، باستخدام retrieve_online_documents_v2(). يمكن بعد ذلك إدخال متجهات الميزات هذه في سياق LLM.
question = "Which city has the largest population in New York?"
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER)
model = AutoModel.from_pretrained(MODEL)
query_embedding = run_model(question, tokenizer, model)
query = query_embedding.detach().cpu().numpy().tolist()[0]
from IPython.display import display
# Retrieve top k documents
context_data = store.retrieve_online_documents_v2(
features=[
"city_embeddings:vector",
"city_embeddings:item_id",
"city_embeddings:state",
"city_embeddings:sentence_chunks",
"city_embeddings:wiki_summary",
],
query=query,
top_k=3,
distance_metric="COSINE",
).to_df()
display(context_data)
| المتجه | العنصر_المعرف | الحالة | أجزاء_الجملة | ملخص_ويكي | المسافة | |
|---|---|---|---|---|---|---|
| 0 | [0.15548758208751678, -0.08017724752426147, -0... | 0 | نيويورك، نيويورك | نيويورك، غالباً ما تسمى مدينة نيويورك أو ببساطة... | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | 0.743023 |
| 1 | [0.15548758208751678, -0.08017724752426147, -0... | 6 | نيويورك، نيويورك | نيويورك هي المدينة الجغرافية والديموغرافية... | نيويورك، وغالباً ما تسمى مدينة نيويورك أو ببساطة... | 0.739733 |
| 2 | [0.15548758208751678, -0.08017724752426147, -0... | 7 | نيويورك، نيويورك | يبلغ عدد سكانها أكثر من 20.1 مليون نسمة... | نيويورك، وغالباً ما يطلق عليها اسم مدينة نيويورك أو ببساطة... | 0.728218 |
3. تنسيق المستندات المسترجعة لسياق RAG
بعد استرجاع المستندات ذات الصلة، نحتاج إلى تنسيق البيانات في سياق منظم يمكن استخدامه بكفاءة في التطبيقات النهائية. تضمن هذه الخطوة أن تكون المعلومات المستخرجة نظيفة ومنظمة وجاهزة للاندماج في خط أنابيب RAG.
def format_documents(context_df):
output_context = ""
unique_documents = context_df.drop_duplicates().apply(
lambda x: "City & State = {"
+ x["state"]
+ "}\nSummary = {"
+ x["wiki_summary"].strip()
+ "}",
axis=1,
)
for i, document_text in enumerate(unique_documents):
output_context += f"****START DOCUMENT {i}****\n{document_text.strip()}\n****END DOCUMENT {i}****"
return output_context
RAG_CONTEXT = format_documents(context_data[["state", "wiki_summary"]])
print(RAG_CONTEXT)
****START DOCUMENT 0****
City & State = {New York, New York}
Summary = {New York, often called New York City or simply NYC, is the most populous city in the United States, located at the southern tip of New York State on one of the world's largest natural harbors. The city comprises five boroughs, each of which is coextensive with a respective county. New York is a global center of finance and commerce, culture and technology, entertainment and media, academics and scientific output, and the arts and fashion, and, as home to the headquarters of the United Nations, is an important center for international diplomacy. New York City is the epicenter of the world's principal metropolitan economy.
With an estimated population in 2022 of 8,335,897 distributed over 300.46 square miles (778.2 km2), the city is the most densely populated major city in the United States. New York has more than double the population of Los Angeles, the nation's second-most populous city. New York is the geographical and demographic center of both the Northeast megalopolis and the New York metropolitan area, the largest metropolitan area in the U.S. by both population and urban area. With more than 20.1 million people in its metropolitan statistical area and 23.5 million in its combined statistical area as of 2020, New York City is one of the world's most populous megacities. The city and its metropolitan area are the premier gateway for legal immigration to the United States. As many as 800 languages are spoken in New York, making it the most linguistically diverse city in the world. In 2021, the city was home to nearly 3.1 million residents born outside the U.S., the largest foreign-born population of any city in the world.
New York City traces its origins to Fort Amsterdam and a trading post founded on the southern tip of Manhattan Island by Dutch colonists in approximately 1624. The settlement was named New Amsterdam (Dutch: Nieuw Amsterdam) in 1626 and was chartered as a city in 1653. The city came under English control in 1664 and was temporarily renamed New York after King Charles II granted the lands to his brother, the Duke of York. before being permanently renamed New York in November 1674. New York City was the capital of the United States from 1785 until 1790. The modern city was formed by the 1898 consolidation of its five boroughs: Manhattan, Brooklyn, Queens, The Bronx, and Staten Island, and has been the largest U.S. city ever since.
Anchored by Wall Street in the Financial District of Lower Manhattan, New York City has been called both the world's premier financial and fintech center and the most economically powerful city in the world. As of 2022, the New York metropolitan area is the largest metropolitan economy in the world with a gross metropolitan product of over US$2.16 trillion. If the New York metropolitan area were its own country, it would have the tenth-largest economy in the world. The city is home to the world's two largest stock exchanges by market capitalization of their listed companies: the New York Stock Exchange and Nasdaq. New York City is an established safe haven for global investors. As of 2023, New York City is the most expensive city in the world for expatriates to live. New York City is home to the highest number of billionaires, individuals of ultra-high net worth (greater than US$30 million), and millionaires of any city in the world.}
****END DOCUMENT 0****
4. توليد الاستجابات باستخدام السياق المستخرج
الآن بعد أن قمنا بتنسيق المستندات المسترجعة، يمكننا دمجها في موجه منظم لتوليد الردود. تضمن هذه الخطوة أن المساعد يعتمد فقط على المعلومات المسترجعة ويتجنب الهلوسة في الردود.
FULL_PROMPT = f"""
You are an assistant for answering questions about states. You will be provided documentation from Wikipedia. Provide a conversational answer.
If you don't know the answer, just say "I do not know." Don't make up an answer.
Here are document(s) you should use when answer the users question:
{RAG_CONTEXT}
"""
response = llm_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": FULL_PROMPT},
{"role": "user", "content": question},
],
)
print("\n".join([c.message.content for c in response.choices]))
The city with the largest population in New York is New York City itself, often referred to as NYC. It is the most populous city in the United States, with an estimated population of about 8.3 million in 2022.