في هذا البرنامج التعليمي، سنرى في هذا البرنامج التعليمي كيفية تنفيذ وكيل يستفيد من SQL باستخدام smolagents
.
دعونا نبدأ بالسؤال الذهبي: لماذا لا نبقي الأمر بسيطًا ونستخدم خط أنابيب قياسي لتحويل النص إلى SQL؟
يعتبر خط أنابيب تحويل النص إلى معادلة قياسي هشًا، نظرًا لأن استعلام SQL الذي تم إنشاؤه يمكن أن يكون غير صحيح. بل والأسوأ من ذلك، يمكن أن يكون الاستعلام غير صحيح، ولكن لا يثير خطأً، وبدلاً من ذلك يعطي بعض المخرجات غير الصحيحة/غير المفيدة دون أن يثير إنذارًا.
👉 بدلاً من ذلك، يستطيع نظام الوكيل فحص المخرجات بشكل نقدي وتحديد ما إذا كان الاستعلام يحتاج إلى تغيير أم لا، مما يمنحه دفعة كبيرة في الأداء.
دعونا نبني هذا الوكيل! 💪
أولاً، نقوم بإعداد بيئة SQL:
تم النسخ
من sqlalalchemy استيراد ( create_engine, MetaData, جدول, عمود, سلسلة, عدد صحيح, عائم, إدراج, فحص, نص, ) المحرك = إنشاء_محرك ("sqlite:////:الذاكرة:") metadata_obj = MetaData() # إنشاء جدول SQL المدينة الجدول_الاسم = "الإيصالات" الإيصالات = جدول( table_name, metadata_obj, العمود("receipt_id"، عدد صحيح، مفتاح أساسي=صحيح), العمود("اسم_العميل"، سلسلة (16)، مفتاح أساسي=صحيح), العمود("السعر"، عائم), العمود("إكرامية"، عائم), ) metadata_obj.create_all(المحرك) الصفوف = [ {"receipt_id": 1, "اسم_العميل": "Alan Payne"، "السعر": 12.06، "الإكرامية": 1.20}, {"receipt_id": 2, "اسم_العميل": "أليكس ماسون"، "السعر": 23.86، "إكرامية": 0.24}, {"receipt_id": 3, "اسم_العميل": "وودرو ويلسون"، "السعر": 53.43، "إكرامية": 5.43}, {"receipt_id": 4, "اسم_العميل": "مارجريت جيمس"، "السعر": 21.11، "إكرامية": 1.00}, ] للصف في الصفوف stmt = إدراج (الإيصالات).القيم (** صف) مع engine.begin() كاتصال المؤشر = connection.execute.execute(stmt)
بناء وكيلنا #
والآن لنجعل جدول SQL الخاص بنا قابلاً للاسترجاع بواسطة أداة.
سيتم تضمين سمة وصف الأداة في موجه الأداة LLM بواسطة نظام الوكيل: فهي تعطي LLM معلومات حول كيفية استخدام الأداة. هذا هو المكان الذي نريد وصف جدول SQL.
تم النسخ
المفتش = فحص (المحرك) الأعمدة_المعلومات = [(عمود ["الاسم"]، عمود ["النوع"]) ل col في inspector.get_columns("الإيصالات")] table_description = "الأعمدة: \n" + "\n".join([f" - {الاسم}: {col_type}" للاسم، col_type في columns_info]) طباعة(table_description)
تم النسخ
الأعمدة: - receipt_id: INTEGER - اسم_العميل: VARCHAR(16) - السعر: مسطح: FLOAT - الإكرامية: FLOAT
الآن دعونا نبني أداتنا. تحتاج إلى ما يلي: (اقرأ مستند الأدوات لمزيد من التفاصيل)
- سلسلة مستند مع
الأوامر:
جزء سرد الحجج. - اكتب تلميحات على كل من المدخلات والمخرجات.
تم النسخ
من أداة الاستيراد smolagents @أداة def sql_engine(استعلام: str) -> str: """ يسمح لك بإجراء استعلامات SQL على الجدول. يُرجع تمثيل سلسلة للنتيجة. يُسمى الجدول "إيصالات". وصفه كالتالي: الأعمدة: - receipt_id: INTEGER - اسم_العميل: VARCHAR(16) - السعر: مسطح: FLOAT - الإكرامية: FLOAT الأوامر: استعلام: الاستعلام المطلوب تنفيذه. يجب أن يكون هذا SQL صحيحًا. """ الإخراج = "" مع engine.connect() كـ con: الصفوف = con.execute(text(query)) للصف في الصفوف الإخراج += "\n" + str(صف) إرجاع الإخراج
الآن دعنا ننشئ الآن عاملاً يستفيد من هذه الأداة.
نحن نستخدم CodeAgent
وهي فئة الوكيل الرئيسية في smolagents: وكيل يكتب الإجراءات في التعليمات البرمجية ويمكنه تكرار المخرجات السابقة وفقًا لإطار عمل ReAct.
النموذج هو LLM الذي يشغل نظام الوكيل. يسمح لك HfApiModel باستدعاء LLMs باستخدام واجهة برمجة تطبيقات الاستدلال الخاصة بـ HF، إما عبر نقطة نهاية بدون خادم أو نقطة نهاية مخصصة، ولكن يمكنك أيضًا استخدام أي واجهة برمجة تطبيقات خاصة.
تم النسخ
من smolagents smolagents استيراد CodeAgent, HfApiModel وكيل = CodeAgent( الأدوات=[sql_engine], model=HfApiModel("meta-llama/Meta-Llama-3.1-8B-Instruct"), ) agent.run("هل يمكنك إعطائي اسم العميل الذي حصل على أغلى إيصال؟")
المستوى 2: وصلات الطاولة #
والآن لنجعل الأمر أكثر صعوبة! نريد أن يتعامل وكيلنا مع الوصلات عبر جداول متعددة.
لذلك دعونا نصنع جدولاً ثانياً يسجل أسماء النوادل لكل إيصال_أيدي!
تم النسخ
الجدول_الاسم = "النوادل" الإيصالات = جدول( table_name, metadata_obj, العمود("receipt_id"، عدد صحيح، مفتاح_أساسي=صحيح), العمود("اسم_النادل"، سلسلة (16)، مفتاح_أساسي=صحيح), ) metadata_obj.create_all(المحرك) الصفوف = [ {"receipt_id": 1, "waiter_name": "كوري جونسون"}, {"receipt_id": 2, "اسم_النادل": "مايكل واتس"}, {"receipt_id": 3، "اسم_النادل": "مايكل واتس"}, {"receipt_id": 4, "اسم_النادل": "مارجريت جيمس"}, ] للصف في الصفوف stmt = إدراج (إيصالات).القيم (**صف) مع engine.begin() كاتصال المؤشر = connection.execute.execute(stmt)
بما أننا قمنا بتغيير الجدول، فإننا نقوم بتحديث أداة SQLExecutorTool
مع وصف هذا الجدول للسماح لـ LLM بالاستفادة من المعلومات من هذا الجدول بشكل صحيح.
تم النسخ
تحديث_الوصف = """"يتيح لك تنفيذ استعلامات SQL على الجدول. انتبه إلى أن مخرجات هذه الأداة عبارة عن تمثيل سلسل لمخرجات التنفيذ. يمكنه استخدام الجداول التالية: """"" مفتش = فحص(محرك) بالنسبة للجدول في ["الإيصالات"، "الناظرون"]: الأعمدة_info = [(عمود ["الاسم"]، عمود ["النوع"]) لـ col في inspector.get_columns(الجدول)] الجدول_وصف الجدول = f"الجدول '{طاولة}':\n" table_description += "الأعمدة:\n" + "\n".join([f" - {اسم}: {col_type}" للاسم، نوع_العمود في الأعمدة_info]) تحديث_الوصف += "\n\n" + وصف_الجدول_ن طباعة(update_description)
نظرًا لأن هذا الطلب أصعب قليلًا من الطلب السابق، سنقوم بتبديل محرك LLM لاستخدام Qwen/Qwen2.5-Coder-32B-Instructer!
تم النسخ
وصف محرك sql_engine.description = updated_description الوكيل = CodeAgent( الأدوات=[sql_engine], model=HfApiModel("Qwen/Qwen2.5-Coder-32B-Instruct"), ) agent.run("أي نادل حصل على إجمالي أموال أكثر من البقشيش؟")
إنه يعمل مباشرةً! كان الإعداد بسيطاً بشكل مدهش، أليس كذلك؟
تم الانتهاء من هذا المثال! لقد تطرقنا إلى هذه المفاهيم:
- بناء أدوات جديدة.
- تحديث وصف الأداة.
- يساعد التحويل إلى LLM أقوى في مساعدة الوكيل على التفكير المنطقي.
✅ الآن يمكنك الذهاب لبناء نظام تحويل النص إلى SQL الذي طالما حلمت به! ✨