Cymbal Transit: نظام متعدّد الوكلاء يستخدم LangChain4J وMCP Toolbox Java SDK

1. نظرة عامة

يتوقّع المسافرون في الوقت الحالي الحصول على تجارب حوارية. بدلاً من التنقّل بين فلاتر واجهة المستخدم المعقّدة، يريدون طرح السؤال التالي: "هل يمكنني اصطحاب كلبي في حافلة الساعة 9 صباحًا إلى بوسطن؟" يتطلّب ذلك توفّر وكيل يمكنه التفكير في البيانات غير المنظَّمة (سياسات PDF) والبيانات المنظَّمة (جداول SQL).

في هذا الدرس التطبيقي، سننشئ وكيل النقل في Cymbal باستخدام:

  • LangChain4j: إطار عمل Java الأوّل لتنظيم الذكاء الاصطناعي
  • AlloyDB: هي قاعدة بيانات عالية الأداء ومتوافقة مع PostgreSQL.
  • حزمة تطوير البرامج (SDK) في Java لأداة MCP: طريقة موحّدة لربط وكلاء Java بالأدوات ومصادر البيانات الخارجية

ما ستنشئه

e68388d533c9997e.png

وكيل Cymbal Bus، وهو تطبيق Java Spring Boot يتألف من:

  1. قاعدة بيانات AlloyDB وحزمة تطوير البرامج (SDK) في Java لأدوات MCP Toolbox لتنظيم الأدوات باستخدام الوكلاء
  2. ‫Cloud Run لنشر مجموعة الأدوات والتطبيق (نشر الوكيل)
  3. مكتبة LangChain4J لإطار عمل الوكيل والنموذج اللغوي الكبير في تطبيق Spring Boot باستخدام Java 17

أهداف الدورة التعليمية

  • كيفية استخدام LangChain4J لإنشاء وكلاء متخصصين ووكلاء فرعيين يتم تنسيقهم باستخدام MCP Toolbox for Databases Java SDK
  • كيفية إعداد AlloyDB واستخدامها للبيانات والذكاء الاصطناعي
  • كيفية استخدام MCP Toolbox لربط العملاء بأدوات بيانات AlloyDB
  • كيفية نشر الحل باستخدام Cloud Run أو تشغيله محليًا

البنية

  1. AlloyDB for PostgreSQL: تعمل كقاعدة بيانات تشغيلية عالية الأداء تتضمّن سجلّات الطرق والسياسات والحجوزات. وهي تتيح البحث عن المتّجهات واسترجاعها.
  2. حزمة تطوير البرامج (SDK) المستندة إلى Java لأداة MCP Toolbox لقواعد البيانات: تعمل كـ "أداة التنسيق الرئيسية"، حيث تعرض بيانات AlloyDB كأدوات قابلة للتنفيذ يمكن أن تستدعيها البرامج.

تتيح حزمة تطوير البرامج (SDK) المستندة إلى Java في "مجموعة أدوات MCP" تنسيق الوكلاء مع أدوات قاعدة البيانات بسهولة لإنشاء تطبيقات على مستوى المؤسسة.

  1. LangChain4J: هي مكتبة Java مفتوحة المصدر تسهّل دمج النماذج اللغوية الكبيرة (LLM) في تطبيقات Java. توفّر هذه المنصة أدوات وتجريدات لإنشاء تطبيقات مستندة إلى الذكاء الاصطناعي، بما في ذلك روبوتات الدردشة والوكلاء وأنظمة التوليد المعزّز بالاسترجاع (RAG).
  2. ‫Cloud Run: هي منصة مُدارة بالكامل بدون خادم تتيح لك إنشاء التطبيقات أو المواقع الإلكترونية ونشرها بسرعة وبسهولة بأي لغة أو مكتبة أو ملف ثنائي. يمكنك كتابة الرمز باستخدام اللغة والإطار والمكتبات المفضّلة لديك، وتجميعها في حاوية، وتشغيل الأمر "gcloud run deploy"، وسيصبح تطبيقك متاحًا، مع توفير كل ما يحتاج إليه للتشغيل في مرحلة الإنتاج. إنشاء حاوية هو أمر اختياري تمامًا. إذا كنت تستخدم Go أو Node.js أو Python أو Java أو ‎.NET Core أو Ruby، يمكنك استخدام خيار النشر المستند إلى المصدر الذي ينشئ الحاوية نيابةً عنك، وذلك باستخدام أفضل الممارسات للغة التي تستخدمها.

المتطلبات

  • متصفّح، مثل Chrome أو Firefox
  • مشروع على السحابة الإلكترونية من Google Cloud تم تفعيل الفوترة فيه
  • معرفة أساسية بلغة SQL وJava

2. قبل البدء

إنشاء مشروع

  1. في Google Cloud Console، في صفحة اختيار المشروع، اختَر أو أنشِئ مشروعًا على Google Cloud.
  2. تأكَّد من تفعيل الفوترة لمشروعك على السحابة الإلكترونية. كيفية التحقّق من تفعيل الفوترة في مشروع
  1. ستستخدم Cloud Shell، وهي بيئة سطر أوامر تعمل في Google Cloud. انقر على "تفعيل Cloud Shell" في أعلى "وحدة تحكّم Google Cloud".

صورة زر تفعيل Cloud Shell

  1. بعد الاتصال بـ Cloud Shell، يمكنك التأكّد من أنّك قد تم التحقّق من هويتك وأنّه تم ضبط المشروع على رقم تعريف مشروعك باستخدام الأمر التالي:
gcloud auth list
  1. نفِّذ الأمر التالي في Cloud Shell للتأكّد من أنّ أمر gcloud يعرف مشروعك.
gcloud config list project
  1. إذا لم يتم ضبط مشروعك، استخدِم الأمر التالي لضبطه:
gcloud config set project <YOUR_PROJECT_ID>
  1. فعِّل واجهات برمجة التطبيقات المطلوبة: اتّبِع الرابط وفعِّل واجهات برمجة التطبيقات.

يمكنك بدلاً من ذلك استخدام أمر gcloud لهذا الغرض. راجِع المستندات لمعرفة أوامر gcloud وطريقة استخدامها.

المشاكل المحتملة وتحديد المشاكل وحلّها

متلازمة "المشروع الوهمي"

نفّذت الأمر gcloud config set project، ولكنّك في الواقع تنظر إلى مشروع مختلف في واجهة مستخدم "وحدة التحكّم". تحقَّق من رقم تعريف المشروع في القائمة المنسدلة أعلى يمين الصفحة.

حاجز الفوترة

لقد فعّلت المشروع، ولكن نسيت حساب الفوترة. ‫AlloyDB هو محرّك عالي الأداء، ولن يبدأ إذا كان "خزان الوقود" (الفوترة) فارغًا.

تأخُّر انتشار واجهة برمجة التطبيقات

نقرت على "تفعيل واجهات برمجة التطبيقات"، ولكن سطر الأوامر لا يزال يعرض Service Not Enabled. انتظِر لمدة 60 ثانية. تحتاج السحابة الإلكترونية إلى بضع لحظات لتنشيط الخلايا العصبية.

Quota Quags

إذا كنت تستخدم حسابًا تجريبيًا جديدًا تمامًا، قد تبلغ حصة إقليمية لمثيلات AlloyDB. إذا تعذّر تنفيذ us-central1، جرِّب us-east1.

وكيل الخدمة"مخفي"

في بعض الأحيان، لا يتم منح دور aiplatform.user تلقائيًا إلى AlloyDB Service Agent. إذا تعذّر على طلبات بحث SQL التواصل مع Gemini لاحقًا، يكون هذا هو السبب عادةً.

3- إعداد قاعدة البيانات

AlloyDB for PostgreSQL هي أساس تطبيقنا. استفدنا من إمكانات المتجهات القوية ومحرّك الأعمدة المدمج لإنشاء تضمينات لأكثر من 50,000 سجلّ من سجلّات إدارة سلسلة التوريد. يتيح ذلك إجراء تحليل متّجه في الوقت الفعلي تقريبًا، ما يسمح لبرامجنا بتحديد أيّ قيم شاذة في المستودع أو مخاطر لوجستية في مجموعات البيانات الضخمة في غضون أجزاء من الثانية.

في هذا التمرين العملي، سنستخدم AlloyDB كقاعدة بيانات لبيانات الاختبار. يستخدم المجموعات للاحتفاظ بجميع الموارد، مثل قواعد البيانات والسجلات. تحتوي كل مجموعة على مثيل أساسي يوفّر نقطة وصول إلى البيانات. ستحتوي الجداول على البيانات الفعلية.

لننشئ مجموعة ومثيل وجدول AlloyDB سيتم تحميل مجموعة البيانات الاختبارية فيه.

  1. انقر على الزر أو انسخ الرابط أدناه إلى المتصفّح الذي سجّلت فيه الدخول إلى Google Cloud Console.

بدلاً من ذلك، يمكنك الانتقال إلى "وحدة Cloud Shell" من مشروعك الذي استرددت فيه حساب الفوترة، واستنساخ مستودع github والانتقال إلى المشروع باستخدام الأوامر أدناه:

git clone https://github.com/AbiramiSukumaran/easy-alloydb-setup

cd easy-alloydb-setup
  1. بعد إكمال هذه الخطوة، سيتم استنساخ المستودع إلى محرّر Cloud Shell المحلي، وستتمكّن من تنفيذ الأمر أدناه من مجلد المشروع (من المهم التأكّد من أنّك في دليل المشروع):
sh run.sh
  1. استخدِم الآن واجهة المستخدم (من خلال النقر على الرابط في نافذة المحطة الطرفية أو على الرابط "معاينة على الويب" في نافذة المحطة الطرفية).
  2. أدخِل تفاصيل معرّف المشروع واسمَي المجموعة والآلة الافتراضية للبدء.
  3. يمكنك تناول القهوة أثناء تصفّح السجلات، ويمكنك الاطّلاع على كيفية تنفيذ ذلك وراء الكواليس هنا.

المشاكل المحتملة وتحديد المشاكل وحلّها

مشكلة "الصبر"

مجموعات قواعد البيانات هي بنية تحتية ثقيلة. إذا أعَدت تحميل الصفحة أو أغلقت جلسة Cloud Shell لأنّها "تبدو عالقة"، قد ينتهي بك الأمر إلى إنشاء آلة افتراضية "وهمية" تم توفيرها جزئيًا ولا يمكن حذفها بدون تدخّل يدوي.

عدم تطابق المنطقة

إذا فعّلت واجهات برمجة التطبيقات في us-central1 وحاولت توفير المجموعة في asia-south1، قد تواجه مشاكل في الحصة أو تأخيرات في أذونات حساب الخدمة. يجب الالتزام بمنطقة واحدة طوال فترة التدريب العملي.

مجموعات الأجهزة غير النشطة

إذا سبق لك استخدام الاسم نفسه لمجموعة ولم تحذفها، قد تشير البرمجة النصية إلى أنّ اسم المجموعة مستخدَم من قبل. يجب أن تكون أسماء المجموعات فريدة ضمن المشروع.

مهلة Cloud Shell

إذا استغرقت استراحة القهوة 30 دقيقة، قد ينتقل Cloud Shell إلى وضع السكون ويقطع اتصال العملية sh run.sh. يجب إبقاء علامة التبويب نشطة.

4. توفير المخطط

بعد تشغيل مجموعة AlloyDB ومثيلها، انتقِل إلى أداة تعديل SQL في AlloyDB Studio لتفعيل إضافات الذكاء الاصطناعي وتوفير المخطّط.

1e3ac974b18a8113.png

قد تحتاج إلى الانتظار إلى أن يكتمل إنشاء مثيلك. بعد ذلك، سجِّل الدخول إلى AlloyDB باستخدام بيانات الاعتماد التي أنشأتها عند إنشاء المجموعة. استخدِم البيانات التالية للمصادقة على PostgreSQL:

  • اسم المستخدم : "postgres"
  • قاعدة البيانات : "postgres"
  • كلمة المرور : "alloydb" (أو أي كلمة مرور تم ضبطها عند إنشاء الحساب)

بعد إكمال عملية المصادقة بنجاح في AlloyDB Studio، يتم إدخال أوامر SQL في "المحرّر". يمكنك إضافة نوافذ "المحرّر" متعددة باستخدام علامة الجمع على يسار النافذة الأخيرة.

28cb9a8b6aa0789f.png

ستُدخل أوامر 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;

منح الإذن

نفِّذ العبارة أدناه لمنح إذن التنفيذ على الدالة "embedding":

GRANT EXECUTE ON FUNCTION embedding TO postgres;

منح دور "مستخدم Vertex AI" لحساب خدمة AlloyDB

من وحدة تحكّم Google Cloud IAM، امنح حساب خدمة AlloyDB (الذي يبدو على النحو التالي: service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com) إذن الوصول إلى الدور "مستخدم Vertex AI". سيحتوي PROJECT_NUMBER على رقم مشروعك.

بدلاً من ذلك، يمكنك تنفيذ الأمر أدناه من "وحدة 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"

إنشاء جدول

يمكنك إنشاء جدول باستخدام عبارة DDL أدناه في AlloyDB Studio:

DROP TABLE IF EXISTS transit_policies;
DROP TABLE IF EXISTS bus_schedules;
DROP TABLE IF EXISTS bookings;

-- Table 1: Transit Policies (Unstructured Data for RAG)
CREATE TABLE transit_policies (
    policy_id SERIAL PRIMARY KEY,
    category VARCHAR(50),
    policy_text TEXT,
    policy_embedding vector(768) 
);

-- Table 2: Intercity Bus Schedules (Structured Data)
CREATE TABLE bus_schedules (
    trip_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    origin_city VARCHAR(100),
    destination_city VARCHAR(100),
    departure_time TIMESTAMP,
    arrival_time TIMESTAMP,
    available_seats INT DEFAULT 50,
    ticket_price DECIMAL(6,2)
);

-- Table 3: Booking Ledger (Transactional Action Data)
CREATE TABLE bookings (
    booking_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    trip_id UUID REFERENCES bus_schedules(trip_id),
    passenger_id VARCHAR(100),
    status VARCHAR(20) DEFAULT 'CONFIRMED',
    booking_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

سيسمح عمود policy_embedding بتخزين قيم المتجهات لبعض حقول النص.

نقل البيانات

نفِّذ مجموعة عبارات SQL أدناه لإدراج السجلات بشكل مجمّع في الجداول المعنية:

  1. إدراج سياسات غير منظَّمة وإنشاء عمليات تضمين حقيقية بشكلٍ أصلي في AlloyDB
-- 1. Insert Unstructured Policies and GENERATE REAL EMBEDDINGS natively in AlloyDB

INSERT INTO transit_policies (category, policy_text, policy_embedding) 
VALUES 
('Pets', 'Service animals are always welcome. Small pets (under 25 lbs) are allowed in secure carriers for a $25 fee. Large dogs are not permitted on standard coaches.', embedding('text-embedding-005', 'Service animals are always welcome. Small pets (under 25 lbs) are allowed in secure carriers for a $25 fee. Large dogs are not permitted on standard coaches.')),
('Luggage', 'Each passenger is allowed one carry-on (up to 15 lbs) and two stowed bags (up to 50 lbs each) free of charge. Additional bags cost $15 each.', embedding('text-embedding-005', 'Each passenger is allowed one carry-on (up to 15 lbs) and two stowed bags (up to 50 lbs each) free of charge. Additional bags cost $15 each.')),
('Refunds', 'Tickets are fully refundable up to 24 hours before departure. Within 24 hours, tickets can be exchanged for travel credit only.', embedding('text-embedding-005', 'Tickets are fully refundable up to 24 hours before departure. Within 24 hours, tickets can be exchanged for travel credit only.'));
  1. إنشاء أكثر من 200 جدول زمني واقعي لمدة 7 أيام باستخدام generate_series
-- 2. Generate 200+ Realistic Schedules for the Next 7 Days using generate_series

INSERT INTO bus_schedules (origin_city, destination_city, departure_time, arrival_time, ticket_price, available_seats)
SELECT 
    origin,
    destination,
    -- Generate departures every 4 hours starting from tomorrow
    (CURRENT_DATE + 1) + (interval '4 hours' * seq) AS dep_time,
    (CURRENT_DATE + 1) + (interval '4 hours' * seq) + interval '4.5 hours' AS arr_time,
    ROUND((RANDOM() * 30 + 25)::numeric, 2) AS price, -- Random price between $25 and $55
    FLOOR(RANDOM() * 50 + 1) AS seats -- Random seats between 1 and 50
FROM 
    (VALUES 
        ('New York', 'Boston'), ('Boston', 'New York'),
        ('Philadelphia', 'Washington DC'), ('Washington DC', 'Philadelphia'),
        ('Seattle', 'Portland'), ('Portland', 'Seattle')
    ) AS routes(origin, destination)
CROSS JOIN generate_series(1, 40) AS seq; -- 6 routes * 40 time slots = 240 distinct trips ingested!

إنشاء تضمينات

يتم تلقائيًا تضمين عمليات التضمين في عبارة الإدراج في جدول transit_policies باستخدام الدالة "embedding('text-embedding-005', '<<policytext>>')".

المشاكل المحتملة وتحديد المشاكل وحلّها

حلقة "فقدان الذاكرة" بشأن كلمات المرور

إذا كنت قد استخدمت عملية الإعداد "بنقرة واحدة" ولم تتمكّن من تذكُّر كلمة المرور، انتقِل إلى صفحة "المعلومات الأساسية للمثيل" في وحدة التحكّم وانقر على "تعديل" لإعادة ضبط كلمة مرور postgres.

رسالة الخطأ "لم يتم العثور على الإضافة"

إذا تعذّر تنفيذ CREATE EXTENSION، يكون السبب غالبًا أنّ المثيل لا يزال في حالة "صيانة" أو "تحديث" منذ عملية التوفير الأولية. تحقَّق مما إذا كانت خطوة إنشاء الجهاز الافتراضي قد اكتملت وانتظِر بضع ثوانٍ إذا لزم الأمر.

مشاكل نشر نظام إدارة الهوية وإمكانية الوصول

لقد نفّذت أمر gcloud في "إدارة الهوية وإمكانية الوصول"، ولكن لا يزال SQL CALL يتعذّر تنفيذه بسبب خطأ في الأذونات. قد يستغرق نشر تغييرات "إدارة الهوية وإمكانية الوصول" (IAM) بعض الوقت من خلال البنية الأساسية لشبكة Google. خذ نفسًا عميقًا.***مهم:

  1. في بعض الأحيان، من المحتمل أن يبدو حساب خدمة AlloyDB مختلفًا عن التنسيق الحالي الذي استخدمناه في خطوة الأذونات. للتأكّد تمامًا من أنّ حساب خدمة AlloyDB لديه دور مستخدم Vertex AI: انتقِل إلى صفحة مجموعات AlloyDB في Google Cloud Console. انقر على مجموعتك، وفي علامة التبويب نظرة عامة، ابحث عن حقل يحمل اسم حساب الخدمة.
    انسخ القيمة ثم انتقِل إلى "إدارة الهوية وإمكانية الوصول" وأضِف دور مستخدم Vertex AI.
  2. بالإضافة إلى ذلك، إذا تخطّيت خطوة "تفعيل واجهة برمجة التطبيقات" في قسم "قبل البدء"، ستواجه مشاكل في الوصول إلى التضمينات من AlloyDB.

عدم تطابق أبعاد المتّجه

تم ضبط العمود policy_embedding في الجدول transit_policies على VECTOR(768). إذا حاولت استخدام نموذج مختلف (مثل نموذج 1536-dim) لاحقًا، ستنفجر عمليات الإدخال. الالتزام بـ text-embedding-005

خطأ إملائي في رقم تعريف المشروع

في استدعاء create_model، إذا تركت الأقواس « » أو أخطأت في كتابة رقم تعريف مشروعك، ستبدو عملية تسجيل النموذج ناجحة ولكنها ستفشل أثناء طلب البحث الفعلي الأول. يُرجى التحقّق من السلسلة.

5- الأدوات وإعداد صندوق الأدوات

‫MCP Toolbox for Databases هو خادم MCP مفتوح المصدر لقواعد البيانات. تتيح لك هذه الخدمة تطوير الأدوات بسهولة أكبر وبسرعة أكبر وبشكل أكثر أمانًا من خلال التعامل مع التعقيدات، مثل تجميع الاتصالات والمصادقة والمزيد. تساعدك "مجموعة الأدوات" في إنشاء أدوات الذكاء الاصطناعي التوليدي التي تتيح للوكلاء الوصول إلى البيانات في قاعدة بياناتك.

نستخدم مجموعة أدوات "بروتوكول سياق النموذج" (MCP) لقواعد البيانات كـ "موصل". وهي تعمل كبرنامج وسيط موحّد بين الوكلاء وAlloyDB. من خلال تحديد إعدادات tools.yaml، تعرض مجموعة الأدوات تلقائيًا عمليات قواعد البيانات المعقّدة كأدوات نظيفة وقابلة للتنفيذ، مثل find-bus-schedules and routes أو query-schedules for specific routes، وتنفّذ إجراءات مستقلة، مثل book-ticket. يُغنيك ذلك عن تجميع الاتصالات يدويًا أو استخدام SQL النموذجي ضمن منطق الوكيل.

تثبيت خادم "أداة التحويل"

من "وحدة طرفية Cloud Shell"، أنشئ مجلدًا لحفظ ملف yaml الخاص بالأدوات الجديدة وثنائي صندوق الأدوات:

mkdir cymbal-bus-toolbox

cd cymbal-bus-toolbox

من داخل هذا المجلد الجديد، شغِّل مجموعة الأوامر التالية:

# see releases page for other versions
export VERSION=0.27.0
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
chmod +x toolbox

بعد ذلك، أنشئ ملف tools.yaml داخل هذا المجلد الجديد من خلال الانتقال إلى "محرّر Cloud Shell" ونسخ محتوى ملف repo هذا إلى ملف tools.yaml.

... (Refer to entire file in the repo)

tools:

   find-bus-schedules:
    kind: postgres-sql
    source: alloydb
    description: Find all available bus schedules.
    statement: |
      SELECT CAST(trip_id AS TEXT) trip_id, departure_time, arrival_time, ticket_price, available_seats , origin_city, destination_city 
      FROM bus_schedules;

   query-schedules:
    kind: postgres-sql
    source: alloydb
    description: Find available bus schedules between an origin and destination city.
    parameters:
      - name: origin
        type: string
        description: The departure city name.
      - name: destination
        type: string
        description: The arrival city name.
    statement: |
      SELECT CAST(trip_id AS TEXT) trip_id, departure_time, arrival_time, ticket_price, available_seats 
      FROM bus_schedules 
      WHERE lower(origin_city) = lower($1) 
        AND lower(destination_city) = lower($2) 
        AND available_seats > 0 
      ORDER BY departure_time ASC 
      LIMIT 5;

   book-ticket:
    kind: postgres-sql
    source: alloydb
    description: Books a ticket for a specific trip, decrementing available seats and generating a confirmed booking record.
    parameters:
      - name: trip_id
        type: string
        description: The UUID of the trip schedule to book.
      - name: passenger_name
        type: string
        description: Name or ID of the passenger (Bound securely via backend or AuthToken).
        authServices:
          - name: google_auth
            field: sub
    statement: |
      WITH updated_schedule AS (
          UPDATE bus_schedules 
          SET available_seats = available_seats - 1 
          WHERE trip_id = CAST($1 AS UUID) AND available_seats > 0
          RETURNING trip_id
      )
      INSERT INTO bookings (trip_id, passenger_id)
      SELECT trip_id, $2 
      FROM updated_schedule
      RETURNING CAST(booking_id as TEXT) as booking_id, trip_id, passenger_id, status, booking_time;

   search-policies:
    kind: postgres-sql
    source: alloydb
    description: Semantic search for transit policies regarding luggage, pets, refunds, and general rules.
    parameters:
      - name: search_query
        type: string
        description: The user's question about transit policies to be embedded and searched.
    statement: |
      SELECT category, policy_text 
      FROM transit_policies 
      ORDER BY policy_embedding <=> CAST(embedding('text-embedding-005', $1) AS vector(768))
      LIMIT 2;

ملاحظة:

  1. في إعداد tools.yaml، لا تنسَ تضمين ipType: "private" في إعدادات مصدر AlloyDB.
  2. تذكَّر أيضًا تضمين عنوان URL لخدمة MCP Toolbox في المَعلمة clientId لإعداد authServices. قد يصلك الرابط بعد عملية النشر الأولية فقط، لذا عليك تنفيذ خطوات النشر مرتين للتأكّد من أنّ حالة استخدام الأدوات التي تتطلّب المصادقة تعمل بشكل سليم.
  3. لن تعمل الخيارات أدناه لاختبار مجموعة الأدوات محليًا إذا تم ضبط اتصال AlloyDB على خاص، وعليك ضبطه على عام لاختباره محليًا أو استخدام خادم وكيل للاتصال. لكن لا داعي للقلق بشأن ذلك. في حالتنا، سننشرها مباشرةً على Cloud Run ثم نختبرها.

لاختبار ملف tools.yaml في الخادم المحلي، اتّبِع الخطوات التالية:

./toolbox --tools-file "tools.yaml"

يمكنك بدلاً من ذلك اختباره في واجهة المستخدم باتّباع الخطوات التالية:

./toolbox --ui

لننشره الآن في Cloud Run على النحو التالي.

نشر Cloud Run

  1. اضبط متغيّر البيئة PROJECT_ID:
export PROJECT_ID="my-project-id"
  1. افتح gcloud CLI:
gcloud init
gcloud config set project $PROJECT_ID
  1. يجب تفعيل واجهات برمجة التطبيقات التالية:
gcloud services enable run.googleapis.com \
                       cloudbuild.googleapis.com \
                       artifactregistry.googleapis.com \
                       iam.googleapis.com \
                       secretmanager.googleapis.com
  1. أنشئ حساب خدمة للخادم الخلفي إذا لم يكن لديك حساب حاليًا:
gcloud iam service-accounts create toolbox-identity
  1. امنح الأذونات لاستخدام Secret Manager:
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/secretmanager.secretAccessor
  1. امنح حساب الخدمة أذونات إضافية خاصة بمصدر AlloyDB (الأدوار/alloydb.client والأدوار/serviceusage.serviceUsageConsumer).
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/alloydb.client


gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/serviceusage.serviceUsageConsumer
  1. حمِّل ملف tools.yaml كمفتاح سرّي:
gcloud secrets create tools-cymbal-transit --data-file=tools.yaml
  1. إذا كان لديك رمز سري حالي وأردت تعديل إصدار الرمز السري، نفِّذ ما يلي:
gcloud secrets versions add tools-cymbal-transit --data-file=tools.yaml
  1. اضبط متغيّر بيئة على صورة الحاوية التي تريد استخدامها في Cloud Run:
export IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
  1. يمكنك نشر Toolbox على Cloud Run باستخدام الأمر التالي:

إذا فعّلت الوصول العام في مثيل AlloyDB، اتّبِع الأمر أدناه للنشر على Cloud Run:

gcloud run deploy toolbox-cymbal-transit \
    --image $IMAGE \
    --service-account toolbox-identity \
    --region us-central1 \
    --set-secrets "/app/tools.yaml=tools-cymbal-transit:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --allow-unauthenticated

إذا كنت تستخدم شبكة VPC، استخدِم الأمر أدناه:

gcloud run deploy toolbox-cymbal-transit \
    --image $IMAGE \
    --service-account toolbox-identity \
    --region us-central1 \
    --set-secrets "/app/tools.yaml=tools-cymbal-transit:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --network <<YOUR_NETWORK_NAME>> \
    --subnet <<YOUR_SUBNET_NAME>> \
    --allow-unauthenticated

ملاحظة: بعد النشر، انتقِل إلى قائمة خدمات Cloud Run وتأكَّد من تحديد الخيار "السماح بالوصول العام" في علامة التبويب "الأمان" الخاصة بهذه الخدمة.

6. إعداد تطبيق الوكيل

استنسِخ هذا المستودع في مشروعك وسنستعرضه معًا.

مستودع Github

لنسخ هذا المستودع، نفِّذ الأمر التالي من "وحدة Cloud Shell الطرفية" (في الدليل الجذر أو من أي مكان تريد إنشاء هذا المشروع منه):

git clone https://github.com/googleapis/mcp-toolbox-sdk-java

يؤدي الأمر أعلاه إلى استنساخ mcp-toolbox-sdk-java بالكامل. نحتاج فقط إلى المشروع النموذجي منه. انتقِل إلى دليل جذر المشروع داخل المستودع:

cd mcp-toolbox-sdk-java/demo-applications/cymbal-transit
  1. من المفترض أن يؤدي ذلك إلى إنشاء المشروع، ويمكنك التأكّد من ذلك في "محرِّر Cloud Shell".

a494664032904c77.png

  1. افتح ملف CymbalTransitController.java واضبط متغيرات البيئة:
  2. GCP_PROJECT_ID
  3. GCP_REGION
  4. GEMINI_MODEL_NAME
  5. MCP_TOOLBOX_URL

بدلاً من ذلك (لأغراض التطوير فقط)، يمكنك أيضًا استبدال العناصر النائبة لقيمة الاحتياطية المعنية.

7. جولة تفصيلية في الرموز البرمجية

يعمل CymbalTransitController كنقطة دخول لخدمة Cloud Run. تدير هذه الخدمة سير المحادثة وتضمن وصول الوكيل إلى طلب المستخدم الحالي.

يتبع التنفيذ بنية ذات طبقات تفصل بين تنسيق الذكاء الاصطناعي وربط الأدوات والتواصل المنخفض المستوى مع MCP.

1. إعدادات وكيل الذكاء الاصطناعي (AgentConfiguration)

يستخدم هذا الصف @Configuration من Spring لتشغيل مكوّنات الذكاء الاصطناعي. يتم تهيئة VertexAiGeminiChatModel وربطها بواجهة Agent.

@Bean
ChatLanguageModel geminiChatModel() {
    return VertexAiGeminiChatModel.builder()
        .project(projectId)
        .location(region)
        .modelName(modelName)
        .build();
}

@Bean
TransitAgent transitAgent(ChatLanguageModel chatLanguageModel, TransitAgentTools tools) {
    return AiServices.builder(TransitAgent.class)
        .chatLanguageModel(chatLanguageModel)
        .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(20))
        .tools(tools) 
        .build();
}

الأهمية: AiServices يربط الواجهة بنموذج اللغة الكبير. تضمن MessageWindowChatMemory أن يتذكّر الموظف الإعدادات المفضّلة للمستخدم (مثل حامل الحيوانات الأليفة المذكور سابقًا) لما يصل إلى 20 رسالة ضمن جلسة واحدة.

2. واجهة وكيل الذكاء الاصطناعي (TransitAgent)

يحدّد التعليق التوضيحي @SystemMessage "الشخصية" والقيود التشغيلية، وتحديدًا استراتيجية التوجيه.

@SystemMessage({
    "You are the Cymbal Transit Concierge.",
    "CRITICAL INSTRUCTION: On your very first interaction, you MUST use the 'findAllSchedules' tool to fetch and memorize the broad bus routes.",
    "ONLY if the user asks a specifically narrowed-down question... should you route to the specific tools like 'querySchedules', 'bookTicket', 'searchPolicies'.",
    "Don't show any asterisks while listing results. Keep it formatted and numbered or bulleted."
})
String chat(@MemoryId String sessionId, @UserMessage String userMessage);

الأهمية: تقلّل هذه الاستراتيجية من وقت الاستجابة. من خلال جلب بيانات واسعة النطاق أولاً، يمكن للوكيل الإجابة عن أسئلة التوجيه العامة باستخدام السياق الداخلي بدون إجراء طلبات غير ضرورية من الخلفية.

3. The Toolbox Bridge (TransitAgentTools)

تعمل هذه الخدمة كـ "أيدي" الوكيل، حيث تحوّل طلبات أدوات LangChain4j إلى منطق تنفيذي.

@Tool("Fetches the initial, broad dataset of all available bus schedules and routes.")
public String findAllSchedules() {
    return mcpService.findAllSchedules().join();
}


@Tool("Book a ticket for a passenger using a specific trip ID.")
public String bookTicket(String tripId, String passengerName) {
    return mcpService.bookTicket(tripId, passengerName).join();
}

التنفيذ المتزامن: على الرغم من أنّ طلبات MCP غير متزامنة (تعرض CompletableFuture)، يتطلّب النموذج اللغوي الكبير نتيجة قبل أن يتمكّن من مواصلة عملية "التفكير". نستخدم .join() لتقديم نتائج متزامنة إلى الوكيل.

4. خدمة "مجموعة أدوات MCP" (McpToolboxService)

هذه هي طبقة الاتصال التي تستخدم حزمة تطوير البرامج (SDK) المستندة إلى Java في MCP Toolbox للتفاعل مع الخلفية في AlloyDB.

// Identity Management: Fetching OIDC ID Token for Auth
GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
this.idToken = ((IdTokenProvider) credentials)
    .idTokenWithAudience(targetUrl, Collections.emptyList())
    .getTokenValue();

// Dynamic Invocation: Executing a tool by name
public CompletableFuture<String> findAllSchedules() {
    return mcpClient.invokeTool("find-bus-schedules", Collections.emptyMap()).thenApply(result -> {
        return result.content().stream()
            .map(content -> content.text())
            .collect(Collectors.joining(", ", "[", "]"));
    });
}

الأهمية: تتولّى McpToolboxClient المهام الصعبة المتعلقة بالتواصل عبر JSON-RPC. تعرض الطريقة bookTicket على وجه التحديد قدرة حزمة تطوير البرامج (SDK) على ربط المَعلمات المعقّدة بشكلٍ ديناميكي.

5. وحدة التحكّم REST (TransitAgentController)

تم تبسيط نقطة النهاية النهائية بشكل كبير لأنّ LangChain4j تدير الحالة والمنطق.

@PostMapping("/chat")
public ResponseEntity<String> handleUserChat(@RequestBody String userMessage, HttpSession session) {
    String sessionId = session.getId();
    String agentResponse = transitAgent.chat(sessionId, userMessage);
    return ResponseEntity.ok(agentResponse);
}

الأهمية: من خلال ربط معرّف HttpSession بـ @MemoryId، نضمن عدم الخلط بين خطط السفر الخاصة بالمستخدمين المختلفين، مع الحفاظ على رمز وحدة التحكّم نظيفًا وسهل القراءة.

8. مجموعة أدوات MCP: الدلالة وحزمة تطوير البرامج (SDK) بلغة Java

ما هي "منصة الشركاء المتعدّدين"؟

يمكن اعتبار بروتوكول سياق النموذج (MCP) بمثابة مترجم عالمي للذكاء الاصطناعي. تم إنشاء بروتوكول MCP لتوحيد طريقة ربط نماذج الذكاء الاصطناعي بالأدوات ومجموعات البيانات الخارجية، وهو يحلّ محلّ النصوص البرمجية المخصّصة والمجزّأة للدمج من خلال بروتوكول آمن وعالمي. سواء كان الوكيل بحاجة إلى تنفيذ طلب بحث SQL خاص بمعاملة أو البحث في آلاف مستندات السياسات أو تشغيل واجهة برمجة تطبيقات REST، يوفّر MCP واجهة واحدة موحّدة.

مجموعة أدوات MCP لقواعد البيانات

تتجاوز فِرق الهندسة روبوتات الدردشة البسيطة لإنشاء أنظمة وكيل تتفاعل مباشرةً مع قواعد البيانات المهمة. ومع ذلك، غالبًا ما يعني إنشاء وكلاء المؤسسات هذه مواجهة صعوبات في الدمج بسبب رمز الربط المخصّص وواجهات برمجة التطبيقات الهشة ومنطق قاعدة البيانات المعقّد.

لإزالة هذه الاختناقات المضمّنة في الرمز البرمجي واستبدالها بلوحة تحكّم آمنة وموحّدة، يسعدنا الإعلان عن حزمة تطوير البرامج (SDK) بلغة Java لأداة Model Context Protocol (MCP) Toolbox لقواعد البيانات. يوفّر هذا الإصدار تنسيقًا من الدرجة الأولى للوكلاء آمنًا من حيث الأنواع في نظام المؤسسات المتكامل الأكثر استخدامًا في العالم. تم تصميم بنية Java المتطورة خصيصًا لتلبية هذه المتطلبات الصارمة، ما يوفّر التزامن العالي وسلامة المعاملات الصارمة وإدارة الحالة القوية اللازمة لتوسيع نطاق تطبيقات الذكاء الاصطناعي المهمة بشكل آمن في مرحلة الإنتاج.

لماذا حزمة تطوير البرامج (SDK) بلغة Java؟

تتيح حزمة MCP Toolbox Java SDK لمطوّري Java تنفيذ ما يلي:

  1. استخدام الأدوات: يمكنك الاتصال بخادم MCP (مثل MCP Toolbox for AlloyDB) وتحويل إمكاناته تلقائيًا إلى طرق Java تفهمها LangChain4j.
  2. أمان الأنواع: يمكنك الاستفادة من ميزة تحديد الأنواع القوية في Java لمعلمات الأدوات، ما يقلّل من أخطاء "الهلوسة" أثناء وقت التشغيل في طلبات الأدوات.
  3. التوافق مع المؤسسات: يمكنك الدمج بسهولة مع Spring Boot وQuarkus وMicronaut وما إلى ذلك.
  4. الاتصال بسهولة: تجنَّب كتابة رمز JSON-RPC المتكرّر.
  5. توحيد المصادقة: يضمن التوافق الأصلي مع رموز OIDC في Google Cloud تنفيذ الأدوات بشكل آمن.

والمزيد غير ذلك.

التبعيات: إعداد pom.xml

أضِف الاعتمادية التالية إلى مشروع Maven لتضمين أحدث إصدار من حزمة تطوير البرامج (SDK) بلغة Java لأداة MCP Toolbox:

   <dependency>
        <groupId>com.google.cloud.mcp</groupId>
        <artifactId>mcp-toolbox-sdk-java</artifactId>
        <version>0.2.0</version>
    </dependency>

أضِف التبعية التالية إلى مشروع Maven لتضمين عنصر LangChain4j:

     <!-- LangChain4j Core & Gemini -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>0.35.0</version>
    </dependency>

هذا كل ما في الأمر!!! لقد استنسخنا المشروع بنجاح وتعرّفنا على تفاصيل الوكيل وMCP Toolbox Java SDK والسياق.

9- التشغيل محليًا

لاختبار الوكيل على جهازك، عليك توجيهه إلى خادم MCP Toolbox الذي تم نشره.

  1. اضبط متغيّرات البيئة:
export GCP_PROJECT_ID="<<YOUR_PROJECT_ID>>"
export GCP_REGION="us-central1"
export GEMINI_MODEL_NAME="gemini-2.5-flash"
export MCP_TOOLBOX_URL="<<YOUR_TOOLBOX_ENDPOINT_URL>>/mcp"
  1. تشغيل Maven:
mvn compile

mvn spring-boot:run

من المفترض أن يؤدي ذلك إلى بدء تشغيل البرنامج محليًا وأن تتمكّن من اختباره.

10. لننشره على Cloud Run

يمكنك نشرها على Cloud Run من خلال تنفيذ الأمر التالي من "وحدة Cloud Shell الطرفية" حيث يتم استنساخ المشروع والتأكّد من أنّك داخل المجلد الجذر للمشروع.

إذا لم تكن في المجلد الجذر لمشروعنا الحالي، نفِّذ ما يلي في نافذة Cloud Shell:

cd cymbal-transit

إذا كنت في جذر cymbal-transit، نفِّذ الأمر أدناه لنشر التطبيق مباشرةً على Cloud Run:

gcloud run deploy cymbal-transit --source . --set-env-vars GCP_PROJECT_ID=<<YOUR_PROJECT_ID>>,GCP_REGION=us-central1,GEMINI_MODEL_NAME=gemini-2.5-flash,MCP_TOOLBOX_URL=<<YOUR_MCP_TOOLBOX_URL>> --allow-unauthenticated

استبدِل قيم العناصر النائبة <<YOUR_PROJECT>> and <<YOUR_MCP_TOOLBOX_URL>>

بعد انتهاء الأمر، سيتم عرض عنوان URL للخدمة. انسخها.

امنح دور عميل AlloyDB لحساب خدمة Cloud Run.يتيح ذلك لتطبيقك الذي لا يحتاج إلى خادم إنشاء نفق آمن إلى قاعدة البيانات.

نفِّذ ما يلي في وحدة Cloud Shell الطرفية:

# 1. Get your Project ID and Project Number
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")

# 2. Grant the AlloyDB Client role
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
--role="roles/alloydb.client"

ملاحظة: بعد النشر، انتقِل إلى قائمة خدمات Cloud Run وتأكَّد من تحديد الخيار "السماح بالوصول العام" في علامة التبويب "الأمان" الخاصة بهذه الخدمة.

استخدِم الآن عنوان URL للخدمة (نقطة نهاية Cloud Run التي نسختها سابقًا) واختبِر التطبيق.

ملاحظة: إذا واجهت مشكلة في الخدمة، وتم ذكر الذاكرة كسبب، جرِّب زيادة الحدّ الأقصى للذاكرة المخصّصة إلى 1 غيغابايت لاختبارها.

11. عرض توضيحي

اطرح السؤال على موظف الدعم: "أريد الذهاب من نيويورك إلى بوسطن صباح الغد. هل يمكنني اصطحاب كلبي من سلالة "المسترد الذهبي"؟" لاحظ كيف يقوم الوكيل بما يلي:

  1. يبحث هذا المعامل عن سياسات الكلاب الكبيرة.
  2. للعثور على جداول زمنية محدّدة
  3. تلخّص هذه السمة أسرع رحلة باستخدام معرّف الرحلة.
  4. يحجز أيضًا تذكرة إذا تابعت طلب الإجراء هذا.

aa0408a81074d0fc.png

12. تَنظيم

بعد الانتهاء من هذا المختبر، لا تنسَ حذف مجموعة AlloyDB ونسختها.

يجب أن يؤدي ذلك إلى تنظيف المجموعة مع مثيلاتها.

13. تهانينا

لقد أنشأت بنجاح وكيل نقل متطوّرًا يستند إلى Java. من خلال الاستفادة من LangChain4j للتنسيق وMCP Toolbox Java SDK لربط البيانات، أنشأت نظامًا يمكنه التفكير في الوكلاء والأدوات ومصادر البيانات. إذا أردت البدء في تنسيق تطبيقاتك المستندة إلى الوكلاء باستخدام MCP Toolbox for Databases على مستوى قواعد بيانات متعددة، حتى على مستوى منصات مختلفة، يمكنك البدء باستخدام حزمة تطوير البرامج (SDK) الخاصة بلغة Java اليوم. إليك مدوّنة إعلان الإطلاق التي تقدّم معلومات أكثر تفصيلاً حول المكتبة. إذا أردت إنشاء المزيد من هذه التطبيقات بشكل عملي ومجاني وبالسرعة التي تناسبك وبإشراف مدرّب، يمكنك الاشتراك في Code Vipassana على الرابط https://codevipassana.dev.