1. نظرة عامة
تخيَّل أنك تدخل متجر ألعاب افتراضيًا أو حضور شخصي، حيث يمكنك العثور على الهدية المثالية بسهولة. يمكنك وصف ما تبحث عنه أو تحميل صورة للعبة أو حتى تصميم لعبتك الخاصة، وسيفهم المتجر احتياجاتك على الفور ويقدّم لك تجربة مخصّصة. هذا ليس خيالًا مستقبليًا، بل هو واقع مدعوم بالذكاء الاصطناعي وتكنولوجيا السحابة الإلكترونية ورؤية للتجارة الإلكترونية المخصَّصة.
التحدي: قد يكون من الصعب العثور على المنتج المثالي الذي يتطابق مع ما تتخيله. غالبًا ما تكون عبارات البحث العامة والكلمات الرئيسية وعمليات البحث التقريبية غير كافية، وقد يكون تصفّح صفحات لا نهاية لها أمرًا مملًا، كما أنّ التناقض بين ما تتخيله وما هو متاح قد يؤدي إلى الإحباط.
الحل: يتصدّى التطبيق التجريبي لهذا التحدي مباشرةً، إذ يستفيد من إمكانات الذكاء الاصطناعي لتقديم تجربة مخصّصة وسلسة حقًا من خلال البحث السياقي وإنشاء منتج مخصّص يتطابق مع سياق البحث.
ما ستنشئه
في هذا الدرس التطبيقي، ستنفّذ ما يلي:
- إنشاء مثيل AlloyDB وتحميل مجموعة بيانات Toys
- تفعيل إضافات pgvector ونموذج الذكاء الاصطناعي التوليدي في AlloyDB
- إنشاء تضمينات من وصف المنتج وإجراء بحث عن التشابه الجيب التمامي في الوقت الفعلي لنص بحث المستخدم
- استخدام Gemini 2.0 Flash لوصف الصورة التي حمّلها المستخدم للبحث عن ألعاب تراعي السياق
- استخدام Imagen 3 لإنشاء لعبة مخصّصة استنادًا إلى اهتمامات المستخدم
- استدعاء أداة توقّع الأسعار التي تم إنشاؤها باستخدام Gen AI Toolbox for Databases للحصول على تفاصيل أسعار اللعبة المخصّصة
- نشر الحل في "دوال Cloud Run" بدون خادم
المتطلبات
2. الهندسة المعمارية
تدفّق البيانات: لنلقِ نظرة عن كثب على كيفية انتقال البيانات عبر نظامنا:
- البحث السياقي باستخدام التوليد المعزّز بالاسترجاع (RAG) المستند إلى الذكاء الاصطناعي
فكِّر في الأمر على النحو التالي: بدلاً من البحث عن "سيارة حمراء" فقط، يفهم النظام ما يلي:
"مركبة صغيرة مناسبة لصبي يبلغ من العمر 3 سنوات"
AlloyDB كأساس: نستخدم AlloyDB، وهي قاعدة بيانات متوافقة مع PostgreSQL ومدارة بالكامل من Google Cloud، لتخزين بيانات الألعاب، بما في ذلك الأوصاف وعناوين URL للصور والسمات الأخرى ذات الصلة.
pgvector للبحث الدلالي: تتيح لنا إضافة pgvector، وهي إضافة إلى PostgreSQL، تخزين عمليات تضمين المتجهات الخاصة بأوصاف الألعاب وطلبات بحث المستخدمين. يتيح ذلك البحث الدلالي، ما يعني أنّ النظام يفهم المعنى من وراء الكلمات، وليس الكلمات الرئيسية المطابقة فقط.
تشابه جيب التمام لتحديد مدى الصلة بالموضوع: نستخدم تشابه جيب التمام لقياس التشابه الدلالي بين متجه بحث المستخدم ومتجهات وصف اللعبة، ما يؤدي إلى عرض النتائج الأكثر صلةً بالموضوع.
فهرس ScaNN لتحقيق السرعة والدقة: لضمان الحصول على نتائج سريعة ودقيقة، لا سيما مع زيادة مخزون الألعاب لدينا، ندمج فهرس ScaNN (الجيران الأقرب القابل للتوسيع). يؤدي ذلك إلى تحسين كفاءة البحث المتّجه واسترجاع النتائج بشكل كبير.
- البحث المستند إلى الصور وفهمها باستخدام نموذج 2.0 Flash من Gemini
بدلاً من كتابة السياق كنص، لنفترض أنّ المستخدم يريد تحميل صورة لعبة مألوفة يريد البحث عنها. يمكن للمستخدمين تحميل صورة للعبة تعجبهم والحصول على ميزات ذات صلة بها. نستفيد من نموذج Gemini 2.0 Flash من Google، الذي يتم استدعاؤه باستخدام LangChain4j، لتحليل الصورة واستخراج السياق المناسب، مثل لون اللعبة ومادتها ونوعها والفئة العمرية المناسبة لها.
- Building Your Dream Toy Customized with Generative AI: Imagen 3
تحدث المتعة الحقيقية عندما يقرّر المستخدمون إنشاء لعبتهم الخاصة. باستخدام Imagen 3، نسمح لهم بوصف لعبتهم المفضّلة باستخدام طلبات نصية بسيطة. تخيَّل أن تقول: "أريد تنينًا قطنيًا بأجنحة أرجوانية ووجه ودود"، ثم ترى هذا التنين يظهر على شاشتك. بعد ذلك، تنشئ Imagen 3 صورة للعبة المصمَّمة خصيصًا، ما يمنح المستخدم تصورًا واضحًا لما صنعه.
- توقّع الأسعار باستخدام "الوكلاء" وMCP Toolbox لقواعد البيانات
لقد نفّذنا ميزة توقّع الأسعار التي تقدّر تكلفة إنتاج اللعبة المصمَّمة خصيصًا. يتم ذلك من خلال وكيل يتضمّن أداة متطورة لاحتساب الأسعار.
MCP Toolbox for Databases: تم دمج هذا الوكيل بسلاسة مع قاعدة البيانات باستخدام أداة Google الجديدة مفتوحة المصدر، وهي MCP Toolbox for Databases. يتيح ذلك للوكيل الوصول إلى بيانات في الوقت الفعلي حول تكاليف المواد وعمليات التصنيع وغيرها من العوامل ذات الصلة لتقديم تقدير دقيق للسعر. يمكنك الاطّلاع على مزيد من المعلومات حول هذا الموضوع هنا.
- Java Spring Boot وGemini Code Assist وCloud Run لتطوير سلس ونشر بلا خادم
تم إنشاء التطبيق بالكامل باستخدام Java Spring Boot، وهو إطار عمل قوي وقابل للتوسيع. استفدنا من Gemini Code Assist في جميع مراحل عملية التطوير، لا سيما في تطوير الواجهة الأمامية، ما أدّى إلى تسريع دورة التطوير وتحسين جودة الرموز البرمجية بشكل كبير. استخدمنا Cloud Run لنشر التطبيق بأكمله وCloud Run Functions لنشر وظائف قاعدة البيانات والوظائف المستندة إلى الوكلاء كنقاط نهاية مستقلة.
3- قبل البدء
إنشاء مشروع
- في Google Cloud Console، ضمن صفحة اختيار المشروع، اختَر أو أنشِئ مشروعًا على Google Cloud.
- تأكَّد من تفعيل الفوترة لمشروعك على السحابة الإلكترونية. تعرَّف على كيفية التحقّق مما إذا كانت الفوترة مفعَّلة في مشروع .
- ستستخدم Cloud Shell، وهي بيئة سطر أوامر تعمل في Google Cloud ومحمّلة مسبقًا بأداة bq. انقر على "تفعيل Cloud Shell" في أعلى "وحدة تحكّم Google Cloud".

- بعد الاتصال بـ Cloud Shell، يمكنك التأكّد من أنّك قد أثبتّ هويتك وأنّ المشروع مضبوط على رقم تعريف مشروعك باستخدام الأمر التالي:
gcloud auth list
- نفِّذ الأمر التالي في Cloud Shell للتأكّد من أنّ أمر gcloud يعرف مشروعك.
gcloud config list project
- إذا لم يتم ضبط مشروعك، استخدِم الأمر التالي لضبطه:
gcloud config set project <YOUR_PROJECT_ID>
- فعِّل واجهات برمجة التطبيقات المطلوبة من خلال تنفيذ الأوامر التالية واحدًا تلو الآخر في "وحدة Cloud Shell الطرفية":
يتوفّر أيضًا أمر واحد لتنفيذ ما يلي، ولكن إذا كنت تستخدم حسابًا تجريبيًا، قد تواجه مشاكل في الحصة عند محاولة تفعيل هذه الميزات بشكل مجمّع. لهذا السبب، يتم تحديد الأوامر بشكل منفرد في كل سطر.
gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable servicenetworking.googleapis.com
gcloud services enable run.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable cloudfunctions.googleapis.com
gcloud services enable aiplatform.googleapis.com
يمكنك بدلاً من استخدام أمر gcloud، البحث عن كل منتج في وحدة التحكّم أو استخدام هذا الرابط.
في حال عدم توفّر أي واجهة برمجة تطبيقات، يمكنك تفعيلها في أي وقت أثناء عملية التنفيذ.
راجِع المستندات لمعرفة أوامر gcloud وطريقة استخدامها.
4. إعداد قاعدة البيانات
في هذا التمرين العملي، سنستخدم AlloyDB كقاعدة بيانات لتخزين بيانات متجر الألعاب. يستخدم المجموعات للاحتفاظ بجميع الموارد، مثل قواعد البيانات والسجلات. تحتوي كل مجموعة على مثيل أساسي يوفّر نقطة وصول إلى البيانات. ستحتوي الجداول على البيانات الفعلية.
لننشئ مجموعة ومثيل وجدول AlloyDB حيث سيتم تحميل مجموعة بيانات التجارة الإلكترونية.
إنشاء مجموعة ومثيل
- انتقِل إلى صفحة AlloyDB في Cloud Console. تتمثّل إحدى الطرق السهلة للعثور على معظم الصفحات في Cloud Console في البحث عنها باستخدام شريط البحث في وحدة التحكّم.
- اختَر إنشاء مجموعة من تلك الصفحة:

- ستظهر لك شاشة مشابهة للشاشة أدناه. أنشئ مجموعة ومثيل بالقيم التالية (تأكَّد من تطابق القيم في حال استنساخ الرمز البرمجي للتطبيق من المستودع):
- معرّف المجموعة: "
vector-cluster" - كلمة المرور: "
alloydb" - متوافق مع PostgreSQL 15
- المنطقة: "
us-central1" - الشبكات: "
default"

- عند اختيار الشبكة الافتراضية، ستظهر لك شاشة مثل الشاشة أدناه.
انقر على إعداد الاتصال.
- من هناك، اختَر استخدام نطاق عناوين IP تم تخصيصه تلقائيًا وانقر على "متابعة". بعد مراجعة المعلومات، انقر على "إنشاء ربط".

- بعد إعداد شبكتك، يمكنك مواصلة إنشاء مجموعتك. انقر على إنشاء مجموعة لإكمال عملية إعداد المجموعة كما هو موضّح أدناه:

احرص على تغيير معرّف المثيل إلى
vector-instance
إذا تعذّر عليك تغييرها، تذكَّر تغيير معرّف المثيل في جميع المراجع القادمة.
يُرجى العِلم أنّ إنشاء المجموعة سيستغرق حوالي 10 دقائق. بعد إتمام العملية بنجاح، من المفترض أن تظهر لك شاشة تعرض نظرة عامة على المجموعة التي أنشأتها للتو.
5- نقل البيانات
حان الوقت الآن لإضافة جدول يتضمّن بيانات حول المتجر. انتقِل إلى AlloyDB، واختَر المجموعة الأساسية، ثم AlloyDB Studio:

قد تحتاج إلى الانتظار إلى أن يكتمل إنشاء الجهاز الظاهري. بعد ذلك، سجِّل الدخول إلى AlloyDB باستخدام بيانات الاعتماد التي أنشأتها عند إنشاء المجموعة. استخدِم البيانات التالية للمصادقة على PostgreSQL:
- اسم المستخدم : "
postgres" - قاعدة البيانات : "
postgres" - كلمة المرور : "
alloydb"
بعد إكمال عملية المصادقة بنجاح في AlloyDB Studio، يتم إدخال أوامر SQL في "المحرّر". يمكنك إضافة نوافذ "المحرّر" متعددة باستخدام علامة الجمع على يسار النافذة الأخيرة.

ستُدخل أوامر AlloyDB في نوافذ المحرّر، باستخدام الخيارات "تشغيل" و"تنسيق" و"محو" حسب الحاجة.
تفعيل الإضافات
لإنشاء هذا التطبيق، سنستخدم الإضافتين pgvector وgoogle_ml_integration. تتيح لك إضافة pgvector تخزين عمليات التضمين المتجهة والبحث عنها. توفّر إضافة google_ml_integration دوال يمكنك استخدامها للوصول إلى نقاط نهاية التوقّع في Vertex AI من أجل الحصول على توقّعات في SQL. فعِّل هذه الإضافات من خلال تنفيذ تعريفات البيانات التالية:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
إذا أردت التحقّق من الإضافات التي تم تفعيلها في قاعدة البيانات، نفِّذ أمر SQL التالي:
select extname, extversion from pg_extension;
إنشاء جدول
أنشئ جدولاً باستخدام عبارة DDL أدناه:
CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;
بعد تنفيذ الأمر أعلاه بنجاح، يجب أن تتمكّن من عرض الجدول في قاعدة البيانات.
نقل البيانات
في هذا التمرين العملي، لدينا بيانات اختبار تتضمّن حوالي 72 سجلاً في ملف SQL هذا. يحتوي على الحقول id, name, description, quantity, price, image_url. سيتم ملء الحقول الأخرى لاحقًا في الدرس التطبيقي.
انسخ الأسطر/عبارات الإدراج الخمسة الأولى فقط من هناك، ثم الصِق هذه الأسطر في علامة تبويب فارغة للمحرّر وانقر على "تنفيذ". إذا لم يكن لديك حساب فوترة تجريبي، يمكنك على الأرجح نسخ جميع عبارات الإدراج وتشغيلها.
للاطّلاع على محتوى الجدول، وسِّع قسم "المستكشف" إلى أن يظهر الجدول باسم "الملابس". انقر على رمز النقاط الثلاث العمودية (⋮) للاطّلاع على خيار "طلب البحث في الجدول". سيتم فتح عبارة SELECT في علامة تبويب "المحرّر" جديدة.

منح الإذن
نفِّذ العبارة أدناه لمنح حقوق التنفيذ على الدالة embedding للمستخدم postgres:
GRANT EXECUTE ON FUNCTION embedding TO postgres;
منح دور "مستخدم Vertex AI" لحساب خدمة AlloyDB
انتقِل إلى وحدة Cloud Shell الطرفية وأدخِل الأمر التالي:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
6. إنشاء تضمينات للسياق
فمن الأسهل على أجهزة الكمبيوتر معالجة الأرقام مقارنةً بمعالجة النصوص. يحوّل نظام التضمين النص إلى سلسلة من الأرقام النقطية العائمة التي من المفترض أن تمثّل النص، بغض النظر عن صياغته أو اللغة المستخدَمة فيه أو غير ذلك.
يمكنك وصف موقع جغرافي على شاطئ البحر. قد يُطلق عليها "على الماء" أو "على شاطئ البحر" أو "يمكنك المشي من غرفتك إلى المحيط" أو "sur la mer" أو "на берегу океана" وما إلى ذلك. تبدو هذه العبارات مختلفة، ولكن يجب أن يكون معناها الدلالي أو تضميناتها في مصطلحات تعلُّم الآلة متقاربة جدًا.
بعد أن أصبحت البيانات والسياق جاهزين، سننفّذ طلب SQL لإضافة تضمينات وصف المنتج إلى الجدول في الحقل embedding. تتوفّر مجموعة متنوعة من نماذج التضمين التي يمكنك استخدامها. نحن نستخدم text-embedding-005 من Vertex AI. احرص على استخدام نموذج التضمين نفسه طوال مدة المشروع.
ملاحظة: إذا كنت تستخدم مشروعًا حاليًا على Google Cloud تم إنشاؤه منذ فترة، قد تحتاج إلى مواصلة استخدام إصدارات قديمة من نموذج تضمين النص، مثل textembedding-gecko.
ارجع إلى علامة التبويب AlloyDB Studio واكتب عبارة DML التالية:
UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);
انظر إلى جدول toys مرة أخرى للاطّلاع على بعض التضمينات. احرص على إعادة تنفيذ عبارة SELECT للاطّلاع على التغييرات.
SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;
من المفترض أن يعرض هذا الطلب متّجه التضمين الذي يبدو كصفيف من الأرقام العشرية، لوصف اللعبة كما هو موضّح أدناه:

ملاحظة: قد تواجه مشاريع Google Cloud التي تم إنشاؤها حديثًا ضمن الإصدار المجاني مشاكل في الحصة عندما يتعلق الأمر بعدد طلبات التضمين المسموح بها في الثانية لنماذج التضمين. نقترح استخدام طلب بحث فلترة للمعرّف ثم اختيار 1 إلى 5 سجلّات بشكل انتقائي وهكذا، أثناء إنشاء التضمين.
7. إجراء بحث عن المتّجهات
بعد أن أصبح الجدول والبيانات والتضمينات جاهزة، لننفّذ الآن البحث المتّجه في الوقت الفعلي عن نص بحث المستخدم.
لنفترض أنّ المستخدم يسأل:
"I want a white plush teddy bear toy with a floral pattern".
يمكنك العثور على نتائج مطابقة لذلك من خلال تنفيذ طلب البحث أدناه:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 2;
لنلقِ نظرة على هذا الاستعلام بالتفصيل:
في هذا الاستعلام،
- نص البحث الذي أدخله المستخدم هو: "
I want a white plush teddy bear toy with a floral pattern." - نحن نحولها إلى تضمينات باستخدام الطريقة
embedding()والنموذجtext-embedding-005. من المفترض أن تكون هذه الخطوة مألوفة بعد الخطوة الأخيرة، حيث طبّقنا دالة التضمين على جميع العناصر في الجدول. - يمثّل "
<=>" استخدام طريقة قياس المسافة COSINE SIMILARITY. يمكنك العثور على جميع مقاييس التشابه المتاحة في مستندات pgvector. - نحوّل نتيجة طريقة التضمين إلى نوع متّجه لجعلها متوافقة مع المتّجهات المخزّنة في قاعدة البيانات.
- يشير LIMIT 5 إلى أنّنا نريد استخراج 5 جيران أقرب لنص البحث.
تبدو النتيجة على النحو التالي:

كما تلاحظ في نتائجك، تكون المطابقات قريبة جدًا من نص البحث. جرِّب تغيير النص لمعرفة كيف تتغير النتائج.
ملاحظة مهمة:
لنفترض الآن أنّنا نريد تحسين أداء نتيجة "البحث المتّجه" هذه (وقت طلب البحث) وكفاءتها ودقتها باستخدام فهرس ScaNN. يُرجى قراءة الخطوات الواردة في هذه المدونة لمقارنة الفرق في النتائج مع الفهرس وبدونه.
خطوة اختيارية: تحسين الكفاءة والاسترجاع باستخدام فهرس ScaNN
تجاهل هذه الخطوة إذا كان عدد السجلات أقل من 100.
في ما يلي خطوات إنشاء الفهرس لتسهيل الأمر عليك:
- بما أنّ لدينا المجموعة والنموذج والسياق والتضمينات التي تم إنشاؤها، ما علينا سوى تثبيت إضافة ScaNN باستخدام العبارة التالية:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- بعد ذلك، سننشئ الفهرس (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);
في تعريف البيانات أعلاه، apparel_index هو اسم الفهرس
"ألعاب" هي جدولي
"scann" هي طريقة الفهرسة
"التضمين" هو العمود في الجدول الذي أريد فهرسته
"cosine" هي طريقة قياس المسافة التي أريد استخدامها مع الفهرس
"8" هو عدد الأقسام التي سيتم تطبيقها على هذا الفهرس. اضبط القيمة على أي رقم بين 1 و1048576. لمزيد من المعلومات حول كيفية تحديد هذه القيمة، اطّلِع على ضبط فهرس ScaNN.
استخدمت الجذر التربيعي لعدد نقاط البيانات كما هو مقترَح في مستودع ScaNN (عند التقسيم، يجب أن يكون عدد الأوراق مساويًا تقريبًا للجذر التربيعي لعدد نقاط البيانات).
- تحقَّق مما إذا كان الفهرس قد تم إنشاؤه باستخدام طلب البحث التالي:
SELECT * FROM pg_stat_ann_indexes;
- نفِّذ "البحث المتّجهي" باستخدام طلب البحث نفسه الذي استخدمناه بدون الفهرس:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;
طلب البحث أعلاه هو نفسه الذي استخدمناه في المختبر في الخطوة 8. ومع ذلك، تم الآن فهرسة الحقل.
- اختبِر باستخدام طلب بحث بسيط مع الفهرس وبدونه (عن طريق حذف الفهرس):
لا تحتوي حالة الاستخدام هذه إلا على 72 سجلاً، لذا لا يسري الفهرس فعليًا. بالنسبة إلى اختبار تم إجراؤه في حالة استخدام أخرى، تكون النتائج على النحو التالي:
يؤدي طلب البحث نفسه في Vector Search على بيانات التضمينات المفهرسة إلى الحصول على نتائج بحث عالية الجودة وتحقيق الكفاءة. تتحسّن الكفاءة بشكل كبير (من حيث وقت التنفيذ: 10.37 ملي ثانية بدون ScaNN و0.87 ملي ثانية باستخدام ScaNN) مع الفهرس. لمزيد من المعلومات حول هذا الموضوع، يُرجى الاطّلاع على هذه المدونة.
8. مطابقة بيانات التحقّق مع النموذج اللغوي الكبير
قبل المتابعة وإنشاء خدمة لعرض أفضل النتائج المطابقة لتطبيق، لنستخدِم نموذج ذكاء اصطناعي توليدي للتحقّق مما إذا كانت هذه الردود المحتملة مناسبة وآمنة حقًا لمشاركتها مع المستخدم.
التأكّد من إعداد المثيل لاستخدام Gemini
تحقَّق أولاً مما إذا كانت ميزة "دمج تعلُّم الآلة من Google" مفعَّلة في مجموعتك ومثيلك. في AlloyDB Studio، أدخِل الأمر التالي:
show google_ml_integration.enable_model_support;
إذا كانت القيمة معروضة على أنّها "مفعّلة"، يمكنك تخطّي الخطوتَين التاليتَين والانتقال مباشرةً إلى إعداد عملية دمج AlloyDB وVertex AI Model.
- انتقِل إلى الآلة الافتراضية الأساسية لمجموعة AlloyDB وانقر على "تعديل الآلة الافتراضية الأساسية" (EDIT PRIMARY INSTANCE).

- انتقِل إلى قسم "العلامات" في "خيارات الإعداد المتقدّمة". وتأكَّد من ضبط
google_ml_integration.enable_model_support flagعلى "on" كما هو موضّح أدناه:

إذا لم يكن الخيار مضبوطًا على "مفعّل"، اضبطه على "مفعّل" ثم انقر على الزر تعديل الجهاز الافتراضي. ستستغرق هذه الخطوة بضع دقائق.
دمج AlloyDB مع نماذج Vertex AI
يمكنك الآن الاتصال بـ AlloyDB Studio وتنفيذ عبارة DML التالية لإعداد إذن الوصول إلى نموذج Gemini من AlloyDB، وذلك باستخدام رقم تعريف مشروعك حيثما يُشار إليه. قد يتم تحذيرك من خطأ في البنية قبل تنفيذ الأمر، ولكن من المفترض أن يتم تنفيذه بشكلٍ سليم.
أولاً، ننشئ اتصال نموذج Gemini 1.5 كما هو موضّح أدناه. تذكَّر استبدال $PROJECT_ID في الأمر أدناه برقم تعريف مشروع Google Cloud.
CALL
google_ml.create_model( model_id => 'gemini-1.5',
model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
model_provider => 'google',
model_auth_type => 'alloydb_service_agent_iam');
يمكنك التحقّق من النماذج التي تم ضبطها للوصول إليها باستخدام الأمر التالي في AlloyDB Studio:
select model_id,model_type from google_ml.model_info_view;
أخيرًا، علينا منح مستخدمي قاعدة البيانات الإذن بتنفيذ الدالة ml_predict_row لتشغيل التوقعات من خلال نماذج Google Vertex AI. نفِّذ الأمر التالي:
GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;
ملاحظة: إذا كنت تستخدم مشروعًا حاليًا على Google Cloud ومجموعة/مثيل حالي من AlloyDB تم إنشاؤه منذ فترة، قد تحتاج إلى حذف المراجع القديمة لنموذج gemini-1.5 وإعادة إنشائها باستخدام عبارة CALL أعلاه، وتشغيل grant execute على الوظيفة ml_predict_row مرة أخرى في حال واجهت مشاكل في عمليات استدعاء gemini-1.5 القادمة.
تقييم الردود
مع أنّنا سنستخدم طلب بحث كبيرًا واحدًا في القسم التالي لضمان أن تكون الردود من طلب البحث معقولة، قد يكون من الصعب فهم طلب البحث. سنتعرّف الآن على الأجزاء وكيفية عملها معًا في غضون بضع دقائق.
- أولاً، سنرسل طلبًا إلى قاعدة البيانات للحصول على 10 نتائج مطابقة لطلب بحث المستخدم.
- لتحديد مدى صحة الردود، سنستخدم طلب بحث خارجيًا نشرح فيه كيفية تقييم الردود. يستخدم هذا المثال الحقل
recommended_textالذي يمثّل نص البحث والحقلcontent(الذي يمثّل حقل وصف اللعبة) من الجدول الداخلي كجزء من طلب البحث. - باستخدام هذه البيانات، سنراجع مدى "جودة" الردود التي تم عرضها.
- تعرض الدالة
predict_rowالنتيجة بتنسيق JSON. يُستخدم الرمز "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"" لاستخراج النص الفعلي من ملف JSON. للاطّلاع على ملف JSON الفعلي الذي يتم عرضه، يمكنك إزالة هذه التعليمة البرمجية. - أخيرًا، للحصول على ردّ النموذج اللغوي الكبير، نستخرجه باستخدام
REGEXP_REPLACE(gemini_validation,'[^a-zA-Z,: ]','','g')
SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ', recommended_text, '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ', content, '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
FROM (SELECT id,
name,
description AS content,
quantity,
price,
image_url,
'Pink panther standing' AS recommended_text
FROM toys
ORDER BY text_embeddings <=> embedding('text-embedding-005',
'Pink panther standing')::VECTOR
LIMIT 1) AS xyz) AS X
GROUP BY id,
name,
content,
quantity,
price,
image_url,
recommended_text) AS final_matches
-- WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';
على الرغم من أنّ ذلك قد يبدو شاقًا، نأمل أن تتمكّن من فهمه بشكل أفضل. توضّح النتائج ما إذا كان هناك تطابق أم لا، والنسبة المئوية للتطابق، وبعض التفسيرات حول التقييم.
لاحظ أنّ نموذج Gemini يتيح البث تلقائيًا، لذا يتم عرض الرد الفعلي على عدة أسطر:

9- نقل تطبيق "البحث عن الألعاب" إلى السحابة الإلكترونية بدون خادم
هل أنت مستعد لنقل هذا التطبيق إلى الويب؟ اتّبِع الخطوات التالية لجعل Knowledge Engine Serverless متوافقًا مع "وظائف Cloud Run":
- انتقِل إلى "وظائف Cloud Run" في Google Cloud Console لإنشاء وظيفة Cloud Run جديدة أو استخدِم الرابط: https://console.cloud.google.com/functions/add.
- اختَر البيئة على أنّها "دالة Cloud Run". قدِّم اسم الدالة get-toys-alloydb واختَر المنطقة us-central1. اضبط المصادقة على "السماح باستدعاءات غير مصادَق عليها" وانقر على التالي. اختَر Java 17 كوقت تشغيل وأداة التعديل المضمّنة للرمز المصدر.
- سيتم ضبط نقطة الدخول تلقائيًا على "
gcfv2.HelloHttpFunction". استبدِل الرمز النائب فيHelloHttpFunction.javaوpom.xmlمن دالة Cloud Run بالرمز من HelloHttpFunction.java وpom.xml على التوالي. - تذكَّر تغيير العنصر النائب <<YOUR_PROJECT>> وبيانات اعتماد الاتصال بـ AlloyDB بالقيم الخاصة بك في ملف Java. بيانات اعتماد AlloyDB هي تلك التي استخدمناها في بداية هذا الدرس العملي. إذا كنت قد استخدمت قيمًا مختلفة، يُرجى تعديلها في ملف Java.
- انقر على نشر.
بعد نشر Cloud Function، سننشئ موصّل VPC للسماح لوظيفة Cloud Function بالوصول إلى مثيل قاعدة بيانات AlloyDB.
خطوة مهمة:
بعد الانتهاء من عملية النشر، من المفترض أن تتمكّن من رؤية الدوال في وحدة تحكّم وظائف Cloud Run من Google. ابحث عن الدالة التي تم إنشاؤها حديثًا (get-toys-alloydb)، وانقر عليها، ثم انقر على تعديل وغيِّر ما يلي:
- الانتقال إلى إعدادات وقت التشغيل والإنشاء والاتصالات والأمان
- زيادة المهلة إلى 180 ثانية
- انتقِل إلى علامة التبويب "عمليات الربط":

- ضِمن إعدادات Ingress، تأكَّد من اختيار "السماح بكل الزيارات".
- ضمن إعدادات Egress، انقر على القائمة المنسدلة "الشبكة" (Network) واختَر الخيار "إضافة موصّل VPC جديد" (Add New VPC Connector) واتّبِع التعليمات التي تظهر في مربّع الحوار المنبثق:

- أدخِل اسمًا لموصِّل VPC وتأكَّد من أنّ المنطقة هي نفسها منطقة مثيلك. اترك قيمة "الشبكة" كما هي تلقائية واضبط "الشبكة الفرعية" على "نطاق IP مخصّص" مع نطاق IP 10.8.0.0 أو نطاق مشابه متوفّر.
- وسِّع SHOW SCALING SETTINGS وتأكَّد من ضبط الإعدادات على ما يلي بالضبط:

- انقر على "إنشاء"، ومن المفترض أن يظهر هذا الرابط في إعدادات الخروج الآن.
- اختَر الموصّل الذي تم إنشاؤه حديثًا
- اختَر توجيه كل حركة البيانات من خلال موصّل شبكة VPC هذا.
- انقر على التالي ثم على نشر.
10. اختبار دالة Cloud Run
بعد نشر Cloud Function المعدَّلة، من المفترض أن تظهر نقطة النهاية التي تم إنشاؤها. انسخ ذلك النص واستبدله في الأمر التالي:
بدلاً من ذلك، يمكنك اختبار وظيفة Cloud Run على النحو التالي:
PROJECT_ID=$(gcloud config get-value project)
curl -X POST <<YOUR_ENDPOINT>> \
-H 'Content-Type: application/json' \
-d '{"search":"I want a standing pink panther toy"}' \
| jq .
والنتيجة هي:

هذا كل شيء! بهذه البساطة يمكنك إجراء بحث عن المتّجهات المتشابهة باستخدام نموذج Embeddings على بيانات AlloyDB.
11. إنشاء تطبيق العميل على الويب
في هذا الجزء، سننشئ تطبيق ويب يتيح للمستخدم التفاعل والعثور على ألعاب مطابقة استنادًا إلى النص والصورة، وحتى إنشاء لعبة جديدة استنادًا إلى احتياجاته. بما أنّ التطبيق قد تم إنشاؤه بالفعل، يمكنك اتّباع الخطوات أدناه لنسخه إلى بيئة التطوير المتكاملة (IDE) وتشغيل التطبيق.
- بما أنّنا نستخدم Gemini 2.0 Flash لوصف الصورة التي قد يحمّلها المستخدم للعثور على ألعاب مطابقة، علينا الحصول على مفتاح واجهة برمجة التطبيقات لهذا التطبيق. لإجراء ذلك، انتقِل إلى https://aistudio.google.com/apikey واحصل على مفتاح واجهة برمجة التطبيقات لمشروعك النشط على Google Cloud الذي تنفّذ فيه هذا التطبيق، ثم احفظ المفتاح في مكان ما:

- الانتقال إلى "وحدة طرفية Cloud Shell"
- استنسِخ المستودع باستخدام الأمر التالي:
git clone https://github.com/AbiramiSukumaran/toysearch
cd toysearch
- بعد استنساخ المستودع، من المفترض أن تتمكّن من الوصول إلى المشروع من محرّر Cloud Shell.
- عليك حذف المجلّدَين "get-toys-alloydb" و "toolbox-toys" من المشروع المستنسخ لأنّ هذين المجلّدَين هما رمز Cloud Run Functions الذي يمكن الرجوع إليه من المستودع عند الحاجة.
- انتقِل إلى GenerateToy.java في مجلد الويب وابحث عن السطر التالي وأزِله لأنّ السماح بالمحتوى المخصّص للبالغين قد يتطلّب إذنًا خاصًا قد لا يكون متاحًا لبعض حسابات الفوترة التجريبية:
paramsMap.put("personGeneration", "allow_adult");
- تأكَّد من ضبط جميع متغيرات البيئة اللازمة قبل إنشاء التطبيق ونشره. انتقِل إلى "وحدة Cloud Shell الطرفية" ونفِّذ ما يلي:
PROJECT_ID=$(gcloud config get-value project)
export PROJECT_ID=$PROJECT_ID
export GOOGLE_API_KEY=<YOUR API KEY that you saved>
- إنشاء التطبيق وتشغيله على الجهاز المحلي:
تأكَّد من أنّك في دليل المشروع، ثم نفِّذ الأوامر التالية:
mvn package
mvn spring-boot:run
- النشر على Cloud Run
gcloud run deploy --source .
12. فهم تفاصيل الذكاء الاصطناعي التوليدي
لا يلزم اتخاذ أي إجراء. للتوضيح فقط:
بعد أن حصلت على التطبيق لتفعيله، ننصحك بأخذ بعض الوقت لفهم كيفية تنفيذ البحث (النص والصورة) والإنشاء.
- البحث عن المتّجهات استنادًا إلى نص المستخدم:
تمت معالجة هذه المشكلة بالفعل في دوال Cloud Run التي نشرناها في قسم "إنشاء تطبيق ويب للبحث عن المتّجهات".
- البحث المتّجه المستند إلى تحميل الصور:
بدلاً من كتابة السياق كنص، لنفترض أنّ المستخدم يريد تحميل صورة لعبة مألوفة يريد البحث عنها. يمكن للمستخدمين تحميل صورة للعبة تعجبهم والحصول على ميزات ذات صلة بها.
نستفيد من نموذج Gemini 2.0 Flash من Google، الذي يتم استدعاؤه باستخدام LangChain4j، لتحليل الصورة واستخراج السياق المناسب، مثل لون اللعبة ومادتها ونوعها والفئة العمرية المناسبة لها.
في 5 خطوات فقط، تمكّنا من تحويل إدخال البيانات المتعدّدة الوسائط من المستخدم إلى نتائج مطابقة باستخدام استدعاء نموذج لغوي كبير من خلال إطار عمل مفتوح المصدر. تعرف على كيفية إجراء ذلك:
package cloudcode.helloworld.web;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import java.util.Base64;
import java.util.Optional;
public class GeminiCall {
public String imageToBase64String(byte[] imageBytes) {
String base64Img = Base64.getEncoder().encodeToString(imageBytes);
return base64Img;
}
public String callGemini(String base64ImgWithPrefix) throws Exception {
String searchText = "";
// 1. Remove the prefix
String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");
// 2. Decode base64 to bytes
byte[] imageBytes = Base64.getDecoder().decode(base64Img);
String image = imageToBase64String(imageBytes);
// 3. Get API key from environment variable
String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
.orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));
// 4. Invoke Gemini 2.0
ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
.apiKey(apiKey)
.modelName("gemini-2.0-flash-001")
.build();
Response<AiMessage> response = gemini.generate(
UserMessage.from(
ImageContent.from(image, "image/jpeg"),
TextContent.from(
"The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send response stating that no toy is found in the input image.")));
// 5. Get the text from the response and send it back to the controller
searchText = response.content().text().trim();
System.out.println("searchText inside Geminicall: " + searchText);
return searchText;
}
}
- تعرَّف على كيفية استخدام Imagen 3 لإنشاء لعبة مخصّصة استنادًا إلى طلب المستخدم باستخدام الذكاء الاصطناعي التوليدي.
بعد ذلك، تنشئ Imagen 3 صورة للعبة المصمَّمة خصيصًا، ما يمنح المستخدم تصورًا واضحًا لما صنعه. إليك الخطوات الخمس التي اتّبعناها:
// Generate an image using a text prompt using an Imagen model
public String generateImage(String projectId, String location, String prompt)
throws ApiException, IOException {
final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
PredictionServiceSettings predictionServiceSettings =
PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
// 1. Set up the context and prompt
String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
prompt = context + prompt;
// 2. Initialize a client that will be used to send requests. This client only needs to be created
// once, and can be reused for multiple requests.
try (PredictionServiceClient predictionServiceClient =
PredictionServiceClient.create(predictionServiceSettings)) {
// 3. Invoke Imagen 3
final EndpointName endpointName =
EndpointName.ofProjectLocationPublisherModelName(
projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
Map<String, Object> instancesMap = new HashMap<>();
instancesMap.put("prompt", prompt);
Value instances = mapToValue(instancesMap);
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("sampleCount", 1);
paramsMap.put("aspectRatio", "1:1");
paramsMap.put("safetyFilterLevel", "block_few");
paramsMap.put("personGeneration", "allow_adult");
paramsMap.put("guidanceScale", 21);
paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
Value parameters = mapToValue(paramsMap);
// 4. Get prediction response image
PredictResponse predictResponse =
predictionServiceClient.predict(
endpointName, Collections.singletonList(instances), parameters);
// 5. Return the Base64 Encoded String to the controller
for (Value prediction : predictResponse.getPredictionsList()) {
Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
if (fieldsMap.containsKey("bytesBase64Encoded")) {
bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
}
}
return bytesBase64EncodedOuput.toString();
}
}
توقّع الأسعار
في القسم السابق أعلاه، ناقشنا كيف تنشئ Imagen صورة للعبة يريد المستخدم تصميمها بنفسه. ولكي يتمكّن المستخدم من شراء اللعبة، يجب أن يحدّد التطبيق سعرًا لها، وقد استخدمنا منطقًا بديهيًا لتحديد سعر اللعبة المخصّصة المصنوعة حسب الطلب. تعتمد هذه العملية على استخدام متوسط سعر أفضل 5 ألعاب تتطابق مع تصميم المستخدم (من حيث الوصف).
يُعدّ توقّع سعر اللعبة التي تم إنشاؤها جزءًا مهمًا من هذا التطبيق، وقد استخدمنا نهجًا قائمًا على الوكلاء لإنشاء هذا التوقّع. نقدّم لك Gen AI Toolbox for Databases.
13. Gen AI Toolbox for Databases
Gen AI Toolbox for Databases هو خادم مفتوح المصدر من Google يسهّل إنشاء أدوات الذكاء الاصطناعي التوليدي للتفاعل مع قواعد البيانات. تتيح لك هذه الخدمة تطوير الأدوات بسهولة أكبر وبسرعة أكبر وبشكل أكثر أمانًا من خلال التعامل مع التعقيدات، مثل تجميع الاتصالات والمصادقة وغير ذلك. تساعدك هذه الأداة في إنشاء أدوات الذكاء الاصطناعي التوليدي التي تتيح للوكلاء الوصول إلى البيانات في قاعدة بياناتك.
في ما يلي الخطوات التي يجب اتّباعها لإعداد هذه الميزة وتجهيز أداتك وجعل تطبيقنا يعمل بشكل مستقل: رابط إلى Codelab الخاص بـ "مجموعة الأدوات"
يمكن لتطبيقك الآن استخدام نقطة نهاية Cloud Run Function التي تم نشرها لملء السعر مع نتيجة Imagen التي تم إنشاؤها لصورة اللعبة المخصّصة المصنوعة حسب الطلب.
14. اختبار تطبيق الويب
بعد إنشاء جميع مكوّنات تطبيقك ونشرها، يصبح التطبيق جاهزًا للعرض على السحابة الإلكترونية. اختبِر تطبيقك في جميع السيناريوهات. إليك رابط فيديو يوضّح ما يمكن توقّعه:
https://www.youtube.com/shorts/ZMqUAWsghYQ
إليك الشكل الذي تبدو عليه الصفحة المقصودة:

15. تَنظيم
لتجنُّب تحمّل رسوم في حسابك على Google Cloud مقابل الموارد المستخدَمة في هذه المشاركة، اتّبِع الخطوات التالية:
- في Google Cloud Console، انتقِل إلى صفحة إدارة الموارد.
- في قائمة المشاريع، اختَر المشروع الذي تريد حذفه، ثم انقر على حذف.
- في مربّع الحوار، اكتب رقم تعريف المشروع، ثم انقر على إيقاف لحذف المشروع.
16. تهانينا
تهانينا! لقد نفّذت بنجاح عملية بحث سياقي وإنشاء في Toystore باستخدام AlloyDB وpgvector وImagen وGemini 2.0 مع الاستفادة من مكتبات مفتوحة المصدر لإنشاء عمليات دمج قوية. من خلال الجمع بين إمكانات AlloyDB وVertex AI وVector Search، حقّقنا تقدّمًا كبيرًا في إتاحة عمليات البحث السياقي والمتّجهي، وجعلها فعّالة ومستندة إلى المعنى.