إنشاء وكيل SQL مع LangGraph وMistral Medium 3 باستخدام watsonx.ai

مؤلف

Anna Gutowska

AI Engineer, Developer Advocate

IBM

في هذا البرنامج التعليمي، ستبني وكيل ذكاء اصطناعي يمكنه تنفيذ وتوليد استعلامات Python وSQL لقاعدة بيانات SQLite المخصصة لديك. سيتم بناء وكيلك من الصفر باستخدام LangGraph والنموذج اللغوي الكبير (LLM) Mistral Medium 3. تم تحسين هذا النموذج اللغوي الكبير (LLM) لحالات الاستخدام الاحترافية مثل البرمجة والفهم متعدد الوسائط، مما يجعله خيارًا ممتازًا لهذه المهمة.1 كما سنقوم باكتشاف الرسائل الضارة وحظرها باستخدام نموذج IBM® Granite® Guardian.

ما هو LangGraph؟

LangGraph، الذي طوّرته LangChain ، هو إطار عمل مفتوح المصدر لوكلاء الذكاء الاصطناعي، صُمم لبناء مهام سير العمل المعقدة لوكلاء الذكاء الاصطناعي التوليدي ونشرها وإدارتها. يوفر مجموعة من الأدوات والمكتبات التي تُمكِّن المستخدمين من إنشاء النماذج اللغوية الكبيرة (LLMs) وتشغيلها وتحسينها بصورة قابلة للتوسع وفعّالة. وفي جوهره، يستفيد LangGraph من البنى المعتمدة على الرسوم البيانية لنمذجة العلاقات المعقدة بين مكوّنات مهام سير العمل لوكلاء الذكاء الاصطناعي وإدارتها، بما في ذلك المكوّنات الموجودة في الأنظمة متعددة الوكلاء.

IBM watsonx.ai

الحصول على رؤى البيانات باستخدام LangGraph وwatsonx.ai

هل يمكن لوكيل الذكاء الاصطناعي أن يأخذ استعلام اللغة الطبيعية ويقوم بمعالجته ليقدم لنا تلك المخرجات ذات الدلالة؟ نحن نستخدم عدة أجزاء من التقنية مفتوحة المصدر وقدرات watsonx.ai لاختبار ذلك.

المتطلبات الأساسية

  1. تحتاج إلى حساب IBM Cloud لإنشاء مشروع watsonx.ai.

  2. يمكن استخدام عدة إصدارات من Python في هذا البرنامج التعليمي. وقت النشر، نوصي بتنزيل Python 3.13، وهو أحدث إصدار.

الخطوات

الخطوة 1. إعداد البيئة.

رغم توفُّر عدة أدوات للاختيار منها، يُرشدك هذا الدليل خلال خطوات إعداد حساب IBM لاستخدام Jupyter Notebook.

  1. سجِّل الدخول إلى watsonx.ai باستخدام حساب IBM Cloud الخاص بك.

  2. أنشئ مشروع watsonx.ai.

    يمكنك الحصول على معرِّف المشروع من داخل مشروعك. انقر فوق علامة التبويب إدارة . ثم انسخ معرِّف المشروع من قسم التفاصيل ( Details ) في صفحة عام ( General ). ستحتاج إلى هذا المعرِّف في هذا البرنامج التعليمي.

  3. أنشئ Jupyter Notebook.

    تفتح هذه الخطوة بيئة Jupyter Notebook حيث يمكنك نسخ تعليمات برمجية هذا البرنامج التعليمي. وبدلاً من ذلك، يمكنك تنزيل هذا الدفتر إلى جهازك ثم تحميله إلى مشروع watsonx.ai كأصل. هذا البرنامج التعليمي متاح أيضًا على GitHub.

الخطوة 2. إعداد مثيل watsonx.ai Runtime ومفتاح واجهة برمجة التطبيقات

  1. أنشئ مثيل خدمة watsonx.ai Runtime (اختَر المنطقة المناسبة لك، ثم اختَر خطة Lite، وهي مثيل مجاني).

  2. أنشئ مفتاح واجهة برمجة التطبيقات (API).

  3. اربط مثيل خدمة watsonx.ai Runtime بالمشروع الذي أنشأته في watsonx.ai.

الخطوة 3: تثبيت المكتبات ذات الصلة واستيرادها، ثم إعداد بيانات الاعتماد الخاصة بك

نحن بحاجة إلى عدد قليل من المكتبات والوحدات لهذا البرنامج التعليمي. تأكَّد من استيراد المكتبات التالية، وإذا لم تكن مثبَّتة، يمكنك تثبيتها بسرعة باستخدام pip.

#installations
%pip install -qU ibm-watsonx-ai \
    langchain-ibm \
    langgraph \
    langchain_experimental \
    tavily-python \
    langchain-community

أعد تشغيل الطرفية ثم استورد الحزم التالية.

# imports
import sqlite3
import getpass

from ibm_watsonx_ai import APIClient, Credentials
from ibm_watsonx_ai.foundation_models.moderations import Guardian
from IPython.display import Image, display
from langchain import hub  
from langchain_ibm import ChatWatsonx
from langgraph.graph.message import add_messages
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langchain_community.utilities.sql_database import SQLDatabase
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage, AIMessage
from langchain_core.tools import tool
from langchain_experimental.tools.python.tool import PythonREPLTool
from sqlalchemy import create_engine
from typing_extensions import TypedDict
from typing import Annotated

لإعداد بيانات الاعتماد الخاصة بنا، سنحتاج إلى WATSONX_APIKEY و WATSONX_PROJECT_ID اللذين أنشأتهما في الخطوة 1. سنُعيِّن أيضًا عنوان URL ليعمل كنقطة نهاية واجهة برمجة التطبيقات (API).

WATSONX_APIKEY = getpass.getpass("Please enter your watsonx.ai Runtime API key (hit enter): ")

WATSONX_PROJECT_ID = getpass.getpass("Please enter your project ID (hit enter): ")

URL = "https://us-south.ml.cloud.ibm.com"

قبل أن نتمكن من تهيئة النموذج اللغوي الكبير (LLM)، يمكننا استخدام Credentials class لتغليف بيانات اعتماد واجهة برمجة التطبيقات (API) التي نُمرِّرها.

credentials = Credentials(url=URL, api_key=WATSONX_APIKEY)

الخطوة 4. إنشاء مثيل لنموذج الدردشة

لكي تتمكن من التفاعل مع جميع الموارد المتاحة في watsonx.ai Runtime، تحتاج إلى إعداد .APIClient هنا، نُمرِّر بيانات الاعتماد الخاصة بنا و WATSONX_PROJECT_ID.

client = APIClient(credentials=credentials, project_id=WATSONX_PROJECT_ID)

في هذا البرنامج التعليمي، سنستخدم الغلاف ChatWatsonx لإعداد نموذج المحادثة الخاص بنا. يبسِّط هذا الغلاف تكامل استدعاء الأدوات والتسلسل (chaining). نوصيك بالرجوع إلى مراع واجهة برمجة التطبيقات في وثائق ChatWatsonx الرسمية للحصول على مزيد من المعلومات. يمكننا تمرير رمز model_id الخاص بنا إلى Mistral Medium 3 وإلى client في صورة متغيّرات.

ملاحظة: إذا كنت تستخدم مزوِّد واجهة برمجة تطبيقات مختلفًا، فستحتاج إلى تغيير الغلاف وفقًا لذلك. على سبيل المثال ، لاستخدام واجهة برمجة تطبيقات OpenAI للوصول إلى نماذج مثل GPT-4، ستحتاج إلى مفتاح openai_api_key بالإضافة إلى الغلاف ChatOpenAI.

model_id = "mistralai/mistral-medium-2505" 
llm = ChatWatsonx(model_id=model_id, watsonx_client=client)

الخطوة 5. إعداد قاعدة بيانات SQLite

في هذا البرنامج التعليمي، سيستخدم وكيلك الأدوات المتاحة لديه للتفاعل مع قاعدة بيانات SQLite. إذا كانت لديك بالفعل مجموعة البيانات مخزَّنة في نظام إدارة قواعد بيانات علائقية (RDBMS) مثل PostgreSQL أو SQLite، يمكنك تخطي هذه الخطوة. بخلاف ذلك، شغِّل الخلية التالية لتعيين متغير sql_script بحيث يساوي برنامجًا نصيًا يُنشئ قاعدة بيانات تحتوي على بيانات مبيعات اصطناعية لوكلاء السيارات. ستتضمن قاعدة البيانات هذه عدة جداول لتخزين بيانات الوكلاء والمبيعات والمركبات.

sql_script = """
DROP TABLE IF EXISTS [Dealerships];

DROP TABLE IF EXISTS [Cars];

DROP TABLE IF EXISTS [Sales];

CREATE TABLE [Dealerships] (
    [id] INTEGER PRIMARY KEY,
    [name] TEXT NOT NULL,
    [location] TEXT NOT NULL
);

CREATE TABLE [Cars] (
    [id] INTEGER PRIMARY KEY,
    [make] TEXT NOT NULL,
    [model] TEXT NOT NULL,
    [year] INTEGER NOT NULL,
    [color] TEXT NOT NULL
);

CREATE TABLE [Sales] (
    [id] INTEGER PRIMARY KEY,
    [car_id] INTEGER NOT NULL,
    [dealership_id] INTEGER NOT NULL,
    [sale_date] DATE NOT NULL,
    [sale_price] REAL NOT NULL,
    FOREIGN KEY ([car_id]) REFERENCES [Cars] ([id]),
    FOREIGN KEY ([dealership_id]) REFERENCES [Dealerships] ([id])
);


INSERT INTO [Dealerships] ([id], [name], [location]) VALUES
    (1, 'Dealership A', 'New York'),
    (2, 'Dealership B', 'Los Angeles'),
    (3, 'Dealership C', 'Chicago'),
    (4, 'Dealership D', 'Houston'),
    (5, 'Dealership E', 'Phoenix'),
    (6, 'Dealership F', 'Philadelphia'),
    (7, 'Dealership G', 'San Antonio'),
    (8, 'Dealership H', 'San Diego'),
    (9, 'Dealership I', 'Dallas'),
    (10, 'Dealership J', 'San Jose');

INSERT INTO [Cars] ([id], [make], [model], [year], [color]) VALUES
    (1, 'Toyota', 'Camry', 2020, 'Blue'),
    (2, 'Honda', 'Civic', 2019, 'Red'),
    (3, 'Ford', 'Mustang', 2021, 'Black'),
    (4, 'Chevrolet', 'Silverado', 2018, 'White'),
    (5, 'Nissan', 'Altima', 2020, 'Gray'),
    (6, 'Kia', 'Optima', 2020, 'Silver'),
    (7, 'Hyundai', 'Elantra', 2019, 'Black'),
    (8, 'Volkswagen', 'Golf', 2021, 'Red'),
    (9, 'BMW', '3 Series', 2018, 'White'),
    (10, 'Mercedes-Benz', 'C-Class', 2020, 'Gray'),
    (11, 'Audi', 'A4', 2019, 'Blue'),
    (12, 'Lexus', 'ES', 2021, 'Black'),
    (13, 'Toyota', 'Corolla', 2018, 'White'),
    (14, 'Honda', 'Accord', 2020, 'Gray'),
    (15, 'Ford', 'Fusion', 2019, 'Red');

INSERT INTO [Sales] ([id], [car_id], [dealership_id], [sale_date], [sale_price]) VALUES
    (1, 1, 1, '2022-01-01', 25000.0),
    (2، 2، 2، '2022-02-01'، 20000.0)،
    (3، 3، 3، '2022-03-01'، 30000.0) ،
    (4، 4، 1، '2022-04-01'، 40000.0) ،
    (5، 5، 2، '2022-05-01'، 28000.0) ،
    (6، 6، 4، '2022-06-01'، 22000.0) ،
    (7 ، 7 ، 5 ، "2022-07-01" ، 20000.0) ،
    (8، 8، 6، '2022-08-01'، 28000.0) ،
    (9، 9، 7، '2022-09-01'، 35000.0) ،
    (10 ، 10 ، 8 ، "2022-10-01" ، 32000.0) ،
    (11، 11، 9، '2022-11-01'، 30000.0) ،
    (12 ، 12 ، 10 ، "2022-12-01" ، 38000.0) ،
    (13، 13، 1، '2023-01-01'، 25000.0) ،
    (14، 14، 2، '2023-02-01'، 28000.0) ،
    (15، 15، 3، '2023-03-01'، 22000.0)؛
    
"""

لتشغيل هذا البرنامج النصي وإنشاء قاعدة بيانات SQLite محلية، نحتاج إلى إعداد كائن اتصال بقاعدة البيانات. من خلال تمرير اسم المسار ":memory:"، يمكننا الاتصال بقاعدة بيانات مؤقتة داخل الذاكرة (in-memory).

connection = sqlite3.connect(":memory:")

بعد ذلك، يمكننا استخدام الدالة executescript لإنشاء مؤشر قاعدة بيانات (Cursor) وتشغيل برنامج SQL النصي. يتيح لنا الكائن Cursor تنفيذ هذا النوع من البرامج النصية.

connection.executescript(sql_script)

المخرجات:

<sqlite3.Cursor at 0x30c511240>

أخيرًا، شغِّل الأمر التالي لإنشاء مثيل من SQLAlchemy Engine مع اتصال بملف قاعدة البيانات في دليل العمل لديك. يجب أن يحمل الملف الاسم نفسه لملف Jupyter Notebook لديك، مع إضافة امتداد ملف قاعدة البيانات. يمكننا ترك عنوان URL فارغًا بحيث يتم إنشاء الاتصال بقاعدة بيانات SQLite المحلية. يمكننا توفير كائن Connection في متغير Creator. هذا المتغير مسؤول عن إنشاء الاتصال بقاعدة البيانات.

engine = create_engine(
    "sqlite://",
    creator=lambda: connection
)

إذا كنت تفضل استخدام قاعدة بيانات بديلة لهذا الدرس غير مخزنة محليا، ببساطة استبدل المسار الفارغ بما يلي "sqlite:///Chinook.db" للوصول إلى قاعدة بيانات نموذجية لمخزن الوسائط الرقمية.

الخطوة 6. إعداد الأدوات

يستخدم هذا البرنامج التعليمي SQLDatabaseToolkit الجاهزة من LangChain. تتطلب مجموعة الأدوات كائنًا من النوع SQLDatabase، والذي يستقبل SQLAlchemy Engine كمتغيّر، بالإضافة إلى النموذج اللغوي الكبير (LLM) الذي تختاره. بعد إنشاء مثيل من مجموعة الأدوات، يمكننا استرجاع الأدوات التي توفرها. لنطبع الأدوات لعرض مزيد من التفاصيل.

db = SQLDatabase(engine)
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
tools = toolkit.get_tools()
الأدوات

المخرجات:

[QuerySQLDatabaseTool(description="Input to this tool is a detailed and correct SQL query, output is a result from the database. If the query is not correct, an error message will be returned. If an error is returned, rewrite the query, check the query, and try again. If you encounter an issue with Unknown column 'xxxx' in 'field list', use sql_db_schema to query the correct table fields.", db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x30c3ecd10>),
InfoSQLDatabaseTool(description='Input to this tool is a comma-separated list of tables, output is the schema and sample rows for those tables. Be sure that the tables actually exist by calling sql_db_list_tables first! Example Input: table1, table2, table3', db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x30c3ecd10>),
ListSQLDatabaseTool(db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x30c3ecd10>),
QuerySQLCheckerTool(description='Use this tool to double check if your query is correct before executing it. Always use this tool before executing a query with sql_db_query!', db=<langchain_community.utilities.sql_database.SQLDatabase object at 0x30c3ecd10>, llm=ChatWatsonx(model_id='mistralai/mistral-medium-2505', apikey=SecretStr('**********'), params={}, watsonx_model=<ibm_watsonx_ai.foundation_models.inference.model_inference.ModelInference object at 0x309c34690>, watsonx_client=<ibm_watsonx_ai.client.APIClient object at 0x30c3e3250>), llm_chain=LLMChain(verbose=False, prompt=PromptTemplate(input_variables=['dialect', 'query'], input_types={}, partial_variables={}, template='\n{query}\nDouble check the {dialect} query above for common mistakes, including:\n- Using NOT IN with NULL values\n- Using UNION when UNION ALL should have been used\n- Using BETWEEN for exclusive ranges\n- Data type mismatch in predicates\n- Properly quoting identifiers\n- Using the correct number of arguments for functions\n- Casting to the correct data type\n- Using the proper columns for joins\n\nIf there are any of the above mistakes, rewrite the query. If there are no mistakes, just reproduce the original query.\n\nOutput the final SQL query only.\n\nSQL Query: '), llm=ChatWatsonx(model_id='mistralai/mistral-medium-2505', apikey=SecretStr('**********'), params={}, watsonx_model=<ibm_watsonx_ai.foundation_models.inference.model_inference.ModelInference object at 0x309c34690>, watsonx_client=<ibm_watsonx_ai.client.APIClient object at 0x30c3e3250>), output_parser=StrOutputParser(), llm_kwargs={}))]

يمكننا أن نرى أن هناك 4 أدوات متاحة كجزء من مجموعة الأدوات. تخدم كل أداة غرضًا محددًا، كما توضحه أوصاف الأدوات. تم تصميم هذه الأدوات لسرد قواعد البيانات، وتشغيل الاستعلامات، وإرجاع مخططات الجداول (schema)، والتحقق من استعلامات SQL قبل تشغيلها.

لتزويد وكيلنا بالقدرة على توليد وتنفيذ تعليمات Python، يمكننا الاستفادة من PythonREPLTool class في LangChain. تقوم هذه التعليمات بإعداد أداة Python REPL (Read-Eval-Print Loop)، وتحديد وظائفها، ثم إلحاقها بقائمة الأدوات لاستخدامها لاحقًا

python_repl = PythonREPLTool()
tools.append(python_repl)

ولضمان تزويد وكيلنا بموجِّه نظام (System Prompt) مُصمَّم خصيصًا لأدوات SQL وقواعد البيانات، يمكننا سحب موجِّه جاهز من LangChain Hub. لنطبع system_message للاطّلاع على الموجِّه بالتفصيل.

chatprompttemplate = hub.pull("langchain-ai/sql-agent-system-prompt")  
system_message = chatprompttemplate.format(dialect="SQLite", top_k=5)  
print(system_message)

المخرجات:

System: You are an agent designed to interact with a SQL database.
Given an input question, create a syntactically correct SQLite query to run, then look at the results of the query and return the answer.
Unless the user specifies a specific number of examples they wish to obtain, always limit your query to at most 5 results.
You can order the results by a relevant column to return the most interesting examples in the database.
Never query for all the columns from a specific table, only ask for the relevant columns given the question.
You have access to tools for interacting with the database.
Only use the below tools. Only use the information returned by the below tools to construct your final answer.
You MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.
    
DO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database.
    
To start you should ALWAYS look at the tables in the database to see what you can query.
Do NOT skip this step.
Then you should query the schema of the most relevant tables.

الخطوة 7. تحديد حالة الوكيل

تتوفر دالة create_react_agent مُعدة مسبقًا في LangGraph، وتقوم بإنشاء مخطط وكيل (agent graph) يتبع بنية ReAct (reasoning and action). تتيح هذه البنية للوكيل استدعاء الأدوات بشكل تكراري داخل حلقة إلى أن يتحقق شرط الإيقاف.

مخطط تدفق عامل التفاعل تدفق وكيل ReAct

ولاتباع نهج عملي أكثر، سنقوم ببناء وكيل ReAct من الصفر في هذا البرنامج التعليمي كخطوة أولى، يمكننا إنشاء AgentState class لتخزين سياق الرسائل الواردة من المستخدم، والأدوات، والوكيل نفسه. تُستخدم TypedDict class في Python هنا للمساعدة على ضمان أن تكون الرسائل بالصيغة المناسبة (dictionary format). يمكننا أيضًا استخدام دالة add_messages في LangGraph لإلحاق أي رسالة جديدة بقائمة الرسائل الموجودة.

class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

الخطوة 8. تعريف ReActAgent class

بعد ذلك ، يمكننا إنشاء ReActAgent class. توفر ReActAgent class بنية أساسية لإنشاء وكلاء يمكنهم التفاعل مع التغييرات في محيطهم. تسمح الدوال في ReActAgent class باستدعاء الأداة التكرارية استجابةً لحالة الرسم البياني.

تعمل الدالة __init__ على تهيئة صفات class باستخدام النموذج اللغوي الكبير والأدوات ورسالة النظام كمتغيرات. يعمل هذا المُنشئ (constructor) على إنشاء رسم بياني للحالة (State Graph) يحتوي على عقد خاصة بنموذج الحارس (Guardian)، والنموذج اللغوي الكبير، والأدوات. يبدأ الرسم البياني من عقدة guardian، والتي تستدعي الدالة guardian_moderation لاكتشاف المحتوى الضار قبل أن يصل إلى النموذج اللغوي الكبير وقاعدة البيانات. تقوم الحافة الشرطية بين عقدتي guardian و llm بتوجيه حالة الرسم البياني إما إلى عقدة llm أو إلى النهاية. ويتم تحديد ذلك بناءً على ناتج دالة guardian_moderation. يتم تمرير الرسائل الآمنة إلى عقدة llm، التي تنفذ دالة call_llm. كما نضيف حافة شرطية بين عقدتي llm و tools لتوجيه الرسائل بالشكل المناسب. إذا أعاد النموذج اللغوي الكبير استدعاء أداة، فإن الدالة should_call_tools تُرجع القيمة المنطقية True. وبخلاف ذلك ،تُرجع الدالة القيمة False ويتّجه الرسم البياني إلى النهاية. تُعد هذه الخطوة جزءًا من بنية وكيل ReAct، حيث نريد أن يستقبل الوكيل ناتج الأداة ثم يتفاعل مع تغيّر الحالة لتحديد الإجراء التالي.

بعد ذلك، يمكننا تجميع الرسم البياني، مما يتيح لنا استدعاء الوكيل في خطوة لاحقة. وللاحتفاظ بالرسائل عبر الحالات المختلفة، يمكننا استخدام أداة MemorySaver كنقطة حفظ (checkpointer). السطران الأخيران من هذه الطريقة يقومان بتهيئة سمات tools و llm الخاصة بمثيل class. سمة tools هي قاموس يربط أسماء الأدوات بكائنات الأدوات. سمة llm هي النموذج اللغوي الكبير (LLM)، والذي يتم ربطه بالأدوات باستخدام الدالة bind_tools.

class ReActAgent:
    
    def __init__(self, llm, tools, system_message=""):
        memory = MemorySaver()
        graph = StateGraph(AgentState)
        graph.add_node("guardian", self.guardian_moderation)
        graph.add_node("llm", self.call_llm)
        graph.add_node("tools", self.call_tools)
        graph.add_node("block_message", self.block_message)
        graph.add_conditional_edges(
            "guardian",
            lambda state: state["moderation_verdict"],  
            {
                "inappropriate": "block_message",  
                "safe": "llm"           
            }
        )
        graph.add_edge("block_message", END)
        graph.add_conditional_edges(
            "llm",
            self.should_call_tools,
            ["tools", END]
        )
        graph.add_edge("tools", "llm")
        graph.add_edge(START, "guardian")
        self.system_message = system_message
        self.graph = graph.compile(checkpointer=memory)
        self.tools = {t.name: t for t in tools}
        self.llm = llm.bind_tools(tools)

الدالة التالية في ReActAgent class هي call_llm. تستدعي هذه الدالة النموذج اللغوي الكبير (LLM) من خلال استرجاع الرسائل من الحالة (state). إذا كانت رسالة النظام موجودة، فإن الدالة تضيفها إلى بداية قائمة الرسائل. بعد ذلك يتم استدعاء النموذج اللغوي الكبير باستخدام الرسائل، ويتم إرجاع حالة جديدة تحتوي على استجابة النموذج.

def call_llm(self, state: AgentState):
    messages = state['messages']
    if self.system_message:
        messages = [SystemMessage(content=self.system_message)] + messages
    message = self.llm.invoke(messages)
    return {'messages': [message]}

الدالة call_tools هي التالية في ReActAgent class. تقوم هذه الدالة باستخراج استدعاءات الأدوات من آخر رسالة في الحالة، ثم تكرارها واستدعاء كل أداة باستخدام الوسيطات المحددة. بعد ذلك يتم تخزين نتائج كل استدعاء أداة في قائمة تُسمى results. أخيرًا، يتم إرجاع الحالة الجديدة على شكل قاموس، حيث يشير المفتاح messages إلى قائمة results.

def call_tools(self, state: AgentState):
    tool_calls = state['messages'][-1].tool_calls
    results = []
    for t in tool_calls:
        result = self.tools[t['name']].invoke(t['args'])
        results.append(ToolMessage(tool_call_id=t['id'], 
                                    name=t['name'], 
                                    content=str(result)))
    return {'messages': results}

الدالة التالية في ReActAgent class هي should_call_tools. تُحدِّد هذه الدالة ما إذا كان يجب استدعاء الأدوات اعتمادًا على الحالة، وذلك من خلال استرجاع استجابة النموذج اللغوي الكبير السابقة من الحالة والتحقق مما إذا كانت تحتوي على أي استدعاءات أدوات.

def should_call_tools(self, state: AgentState):
    result = state['messages'][-1]
    return "tools" if len(result.tool_calls) > 0 else END

تم تصميم الدالة guardian_moderation، التي يتم تنفيذها في عقدة guardian، للإشراف على الرسائل باستخدام نظام Guardian، بهدف اكتشاف المحتوى غير المرغوب فيه أو الحساس وحظره. أولًا، يتم استرجاع الرسالة الأخيرة. بعد ذلك، يتم تعريف قاموس باسم detectors يحتوي على إعدادات الكواشف وقيمها الحدّية. تعمل هذه الكواشف على تحديد أنواع محددة من المحتوى في الرسائل، مثل معلومات التعريف الشخصية (PII)، إضافة إلى خطاب الكراهية واللغة المسيئة والألفاظ النابية (HAP). بعد ذلك، يتم إنشاء مثيل من فئة Guardian، مع تمرير كائن api_client المسمى client وقاموس detectors. يتم بعد ذلك استدعاء دالة detect الخاصة بمثيل Guardian، مع تمرير محتوى الرسالة الأخيرة وقاموس detectors. بعدها تُعيد الدالة قاموسًا يحتوي المفتاح moderation_verdict على قيمة إما "safe" أو "inappropriate"، وذلك اعتمادًا على مخرجات نموذج Granite Guardian.

def guardian_moderation(self, state: AgentState):
    message = state['messages'][-1]  
    detectors = {
        "granite_guardian": {"threshold": 0.4},
        "hap": {"threshold": 0.4},
        "pii": {},
    }
    guardian = Guardian(
        api_client=client,  
        detectors=detectors 
    )
    response = guardian.detect(
        text=message.content,
        detectors=detectors
    )
    if len(response['detections']) != 0 and response['detections'][0]['detection'] == "Yes":
        return {"moderation_verdict": "inappropriate"}
    else:
        return {"moderation_verdict": "safe"}

تعمل الدالة block_message كآلية إشعار، حيث تُعلِم المستخدم بأن استعلام الإدخال الخاص به يحتوي على محتوى غير مناسب وقد تم حظره.

def block_message(self, state: AgentState):
    return {"messages": [AIMessage(content="This message has been blocked due to inappropriate content.")]}

يمكننا الآن تجميع كل هذه التعليمات البرمجية معًا وتشغيل الخلية التالية.

class ReActAgent:
    
    def __init__(self, llm, tools, system_message=""):
        memory = MemorySaver()
        graph = StateGraph(AgentState)
        graph.add_node("guardian", self.guardian_moderation)
        graph.add_node("llm", self.call_llm)
        graph.add_node("tools", self.call_tools)
        graph.add_node("block_message", self.block_message)
        graph.add_conditional_edges(
            "guardian",
            lambda state: state["moderation_verdict"],  
            {
                "inappropriate": "block_message",  
                "safe": "llm"           
            }
        )
        graph.add_edge("block_message", END)
        graph.add_conditional_edges(
            "llm",
            self.should_call_tools,
            ["tools", END]
        )
        graph.add_edge("tools", "llm")
        graph.add_edge(START, "guardian")
        self.system_message = system_message
        self.graph = graph.compile(checkpointer=memory)
        self.tools = {t.name: t for t in tools}
        self.llm = llm.bind_tools(tools)
    
    def call_llm(self, state: AgentState):
        messages = state['messages']
        if self.system_message:
            messages = [SystemMessage(content=self.system_message)] + messages
        message = self.llm.invoke(messages)
        return {'messages': [message]}
    
    def call_tools(self, state: AgentState):
        tool_calls = state['messages'][-1].tool_calls
        results = []
        for t in tool_calls:
            result = self.tools[t['name']].invoke(t['args'])
            results.append(ToolMessage(tool_call_id=t['id'], 
                                       name=t['name'], 
                                       content=str(result)))
        return {'messages': results}
    
    def should_call_tools(self, state: AgentState):
        result = state['messages'][-1]
        return "tools" if len(result.tool_calls) > 0 else END
    
    def guardian_moderation(self, state: AgentState):
        message = state['messages'][-1]  
        detectors = {
            "granite_guardian": {"threshold": 0.4},
            "hap": {"threshold": 0.4},
            "pii": {},
        }
        guardian = Guardian(
            api_client=client,  
            detectors=detectors 
        )
        response = guardian.detect(
            text=message.content,
            detectors=detectors
        )
        if len(response['detections']) != 0 and response['detections'][0]['detection'] == "Yes":
            return {"moderation_verdict": "inappropriate"}
        else:
            return {"moderation_verdict": "safe"}
        
    def block_message(self, state: AgentState):
        return {"messages": [AIMessage(content="This message has been blocked due to inappropriate content.")]}

الخطوة 9. إنشاء كائن ReActAgent واستدعاؤه

يُنشئ السطر الأول في كتلة التعليمات البرمجية التالية مثيلًا من ReActAgent class، مع تمرير النموذج اللغوي الكبير (LLM)، وأدوات SQL، ورسالة النظام كمعلمات. بعد ذلك، نحدد سلسلة محادثة (thread) لتخزين حالات الرسم البياني في الذاكرة. يمكن اعتبار كل thread_id بمثابة نافذة دردشة جديدة. كما يمكننا تحديد إدخال المستخدم بأي نص نختاره. بعد ذلك، نقوم بتمرير قائمة تحتوي على إدخال المستخدم من نوع HumanMessage لاستدعاء الوكيل.

أولاً، لنجرب الموجِّه الذي يجب أن يحظره نموذج Granite Guardian.

agent = ReActAgent(llm, tools, system_message=system_message)

config = {"configurable": {"thread_id": "1"}}

user_input = "What is the home address of the customer who purchased the most expensive car last month?"

result = agent.graph.invoke({'messages': [HumanMessage(content=user_input)]}, config)

for message in result["messages"]:
    message.pretty_print()

المخرجات:

    ================================ [1m Human Message  [0m=================================
    
    What is the home address of the customer who purchased the most expensive car last month?
    ================================== [1m Ai Message  [0m==================================
    
    This message has been blocked due to inappropriate content.

تمكّن نموذج Granite Guardian من منع المستخدم بنجاح من طلب معلومات العميل الحساسة. يمكننا أن نرى أن الرسم البياني لم يصل إلى عقدة النموذج اللغوي الكبير قبل إنهاء المحادثة. وبعد ذلك، لنطرح سؤالاً مناسبًا في سلسلة مختلفة. على سبيل المثال، قد يكون إدخال المستخدم "ما إجمالي إيرادات المبيعات لأفضل 5 وكلاء أداءً في عام 2022؟".

user_input = "What is the total sales revenue for the top 5 performing dealerships in the year 2022?"

config2 = {"configurable": {"thread_id": "2"}}

result = agent.graph.invoke({'messages': [HumanMessage(content=user_input)]}, config2)

for message in result["messages"]:
    message.pretty_print()

المخرجات:

    ================================ [1m Human Message  [0m=================================
    
    What is the total sales revenue for the top 5 performing dealerships in the year 2022?
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_list_tables (H2irrlsPM)
     Call ID: H2irrlsPM
      Args:
        tool_input:
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_list_tables
    
    Cars, Dealerships, Sales
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_schema (ILZWiZvGX)
     Call ID: ILZWiZvGX
      Args:
        table_names: Cars, Dealerships, Sales
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_schema
    
    
    CREATE TABLE "Cars" (
    	id INTEGER, 
    	make TEXT NOT NULL, 
    	model TEXT NOT NULL, 
    	year INTEGER NOT NULL, 
    	color TEXT NOT NULL, 
    	PRIMARY KEY (id)
    )
    
    /*
    3 rows from Cars table:
    id	make	model	year	color
    1	Toyota	Camry	2020	Blue
    2	Honda	Civic	2019	Red
    3	Ford	Mustang	2021	Black
    */
    
    
    CREATE TABLE "Dealerships" (
    	id INTEGER, 
    	name TEXT NOT NULL, 
    	location TEXT NOT NULL, 
    	PRIMARY KEY (id)
    )
    
    /*
    3 rows from Dealerships table:
    id	name	location
    1	Dealership A	New York
    2	Dealership B	Los Angeles
    3	Dealership C	Chicago
    */
    
    
    CREATE TABLE "Sales" (
    	id INTEGER, 
    	car_id INTEGER NOT NULL, 
    	dealership_id INTEGER NOT NULL, 
    	sale_date DATE NOT NULL, 
    	sale_price REAL NOT NULL, 
    	PRIMARY KEY (id), 
    	FOREIGN KEY(dealership_id) REFERENCES "Dealerships" (id), 
    	FOREIGN KEY(car_id) REFERENCES "Cars" (id)
    )
    
    /*
    3 rows from Sales table:
    id	car_id	dealership_id	sale_date	sale_price
    1	1	1	2022-01-01	25000.0
    2	2	2	2022-02-01	20000.0
    3	3	3	2022-03-01	30000.0
    */
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_query_checker (yIZ0tk4VP)
     Call ID: yIZ0tk4VP
      Args:
        query: SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue FROM Dealerships INNER JOIN Sales ON Dealerships.id = Sales.dealership_id WHERE strftime('%Y', Sales.sale_date) = '2022' GROUP BY Dealerships.id ORDER BY total_sales_revenue DESC LIMIT 5;
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_query_checker
    
    SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue
    FROM Dealerships
    INNER JOIN Sales ON Dealerships.id = Sales.dealership_id
    WHERE strftime('%Y', Sales.sale_date) = '2022'
    GROUP BY Dealerships.id
    ORDER BY total_sales_revenue DESC
    LIMIT 5;
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_query (cTzJFfvTl)
     Call ID: cTzJFfvTl
      Args:
        query: SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue FROM Dealerships INNER JOIN Sales ON Dealerships.id = Sales.dealership_id WHERE strftime('%Y', Sales.sale_date) = '2022' GROUP BY Dealerships.id ORDER BY total_sales_revenue DESC LIMIT 5;
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_query
    
    [('Dealership A', 65000.0), ('Dealership B', 48000.0), ('Dealership J', 38000.0), ('Dealership G', 35000.0), ('Dealership H', 32000.0)]
    ================================== [1m Ai Message  [0m==================================
    
    The total sales revenue for the top 5 performing dealerships in the year 2022 are:
    
    1. Dealership A: $65,000
    2. Dealership B: $48,000
    3. Dealership J: $38,000
    4. Dealership G: $35,000
    5. Dealership H: $32,000

    ================================ [1m Human Message  [0m=================================
    
    What is the total sales revenue for the top 5 performing dealerships in the year 2022?
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_list_tables (H2irrlsPM)
     Call ID: H2irrlsPM
      Args:
        tool_input:
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_list_tables
    
    Cars, Dealerships, Sales
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_schema (ILZWiZvGX)
     Call ID: ILZWiZvGX
      Args:
        table_names: Cars, Dealerships, Sales
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_schema
    
    
    CREATE TABLE "Cars" (
    	id INTEGER, 
    	make TEXT NOT NULL, 
    	model TEXT NOT NULL, 
    	year INTEGER NOT NULL, 
    	color TEXT NOT NULL, 
    	PRIMARY KEY (id)
    )
    
    /*
    3 rows from Cars table:
    id	make	model	year	color
    1	Toyota	Camry	2020	Blue
    2	Honda	Civic	2019	Red
    3	Ford	Mustang	2021	Black
    */
    
    
    CREATE TABLE "Dealerships" (
    	id INTEGER, 
    	name TEXT NOT NULL, 
    	location TEXT NOT NULL, 
    	PRIMARY KEY (id)
    )
    
    /*
    3 rows from Dealerships table:
    id	name	location
    1	Dealership A	New York
    2	Dealership B	Los Angeles
    3	Dealership C	Chicago
    */
    
    
    CREATE TABLE "Sales" (
    	id INTEGER, 
    	car_id INTEGER NOT NULL, 
    	dealership_id INTEGER NOT NULL, 
    	sale_date DATE NOT NULL, 
    	sale_price REAL NOT NULL, 
    	PRIMARY KEY (id), 
    	FOREIGN KEY(dealership_id) REFERENCES "Dealerships" (id), 
    	FOREIGN KEY(car_id) REFERENCES "Cars" (id)
    )
    
    /*
    3 rows from Sales table:
    id	car_id	dealership_id	sale_date	sale_price
    1	1	1	2022-01-01	25000.0
    2	2	2	2022-02-01	20000.0
    3	3	3	2022-03-01	30000.0
    */
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_query_checker (yIZ0tk4VP)
     Call ID: yIZ0tk4VP
      Args:
        query: SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue FROM Dealerships INNER JOIN Sales ON Dealerships.id = Sales.dealership_id WHERE strftime('%Y', Sales.sale_date) = '2022' GROUP BY Dealerships.id ORDER BY total_sales_revenue DESC LIMIT 5;
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_query_checker
    
    SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue
    FROM Dealerships
    INNER JOIN Sales ON Dealerships.id = Sales.dealership_id
    WHERE strftime('%Y', Sales.sale_date) = '2022'
    GROUP BY Dealerships.id
    ORDER BY total_sales_revenue DESC
    LIMIT 5;
    ================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_query (cTzJFfvTl)
     Call ID: cTzJFfvTl
      Args:
        query: SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue FROM Dealerships INNER JOIN Sales ON Dealerships.id = Sales.dealership_id WHERE strftime('%Y', Sales.sale_date) = '2022' GROUP BY Dealerships.id ORDER BY total_sales_revenue DESC LIMIT 5;
    ================================= [1m Tool Message  [0m=================================
    Name: sql_db_query
    
    [('Dealership A', 65000.0), ('Dealership B', 48000.0), ('Dealership J', 38000.0), ('Dealership G', 35000.0), ('Dealership H', 32000.0)]
    ================================== [1m Ai Message  [0m==================================
    
    The total sales revenue for the top 5 performing dealerships in the year 2022 are:
    
    1. Dealership A: $65,000
    2. Dealership B: $48,000
    3. Dealership J: $38,000
    4. Dealership G: $35,000
    5. Dealership H: $32,000
```

رائع! نجح الوكيل في تنفيذ سلسلة من المهام، بما في ذلك استدعاء عدة أدوات لاستخراج مخطط جدول SQL وتوليد استعلامات SQL جديدة والتحقق من صحتها قبل تنفيذها. ونتيجة لذلك، يقوم الوكيل بإرجاع إجمالي إيرادات المبيعات الصحيحة لأفضل 5 وكلاء سيارات أداءً في قاعدة بياناتنا في عام 2022. يمكننا رؤية الاستدلال متعدد الخطوات للوكيل أثناء قيامه بطباعة كل استعلام SQL تم إنشاؤه. في الرد، نرى أيضًا أن نموذج Granite Guardian حدد أن استعلام المستخدم مناسب.

دعنا نطرح سؤال متابعة. هذه المرة، دعنا نطلب من الوكيل توليد وتنفيذ تعليمات برمجية بلغة Python لعرض تمثيل بياني شريطي للنتائج. يجب على الوكيل استرجاع الرسائل السابقة لأننا نستخدم thread_id نفسه.

user_input = "Write Python code to plot these results on a bar graph. Then, you must execute the code and display the bar graph."

result = agent.graph.invoke({'messages': [HumanMessage(content=user_input)]}, config2)

for message in result["messages"]:
    message.pretty_print()

المخرجات:

================================ [1m Human Message  [0m=================================
    
    What is the total sales revenue for the top 5 performing dealerships in the year 2022?
================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_list_tables (H2irrlsPM)
     Call ID: H2irrlsPM
      Args:
        tool_input:
================================= [1m Tool Message  [0m=================================
    Name: sql_db_list_tables
    
    Cars, Dealerships, Sales
================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_schema (ILZWiZvGX)
     Call ID: ILZWiZvGX
      Args:
        table_names: Cars, Dealerships, Sales
================================= [1m Tool Message  [0m=================================
    Name: sql_db_schema
    
    
    CREATE TABLE "Cars" (
    	id INTEGER, 
    	make TEXT NOT NULL, 
    	model TEXT NOT NULL, 
    	year INTEGER NOT NULL, 
    	color TEXT NOT NULL, 
    	PRIMARY KEY (id)
    )
    
    /*
    3 rows from Cars table:
    id	make	model	year	color
    1	Toyota	Camry	2020	Blue
    2	Honda	Civic	2019	Red
    3	Ford	Mustang	2021	Black
    */
    
    
    CREATE TABLE "Dealerships" (
    	id INTEGER, 
    	name TEXT NOT NULL, 
    	location TEXT NOT NULL, 
    	PRIMARY KEY (id)
    )
    
    /*
    3 rows from Dealerships table:
    id	name	location
    1	Dealership A	New York
    2	Dealership B	Los Angeles
    3	Dealership C	Chicago
    */
    
    CREATE TABLE "Sales" (
    	id INTEGER, 
    	car_id INTEGER NOT NULL, 
    	dealership_id INTEGER NOT NULL, 
    	sale_date DATE NOT NULL, 
    	sale_price REAL NOT NULL, 
    	PRIMARY KEY (id), 
    	FOREIGN KEY(dealership_id) REFERENCES "Dealerships" (id), 
    	FOREIGN KEY(car_id) REFERENCES "Cars" (id)
    )
    
    /*
    3 rows from Sales table:
    id	car_id	dealership_id	sale_date	sale_price
    1	1	1	2022-01-01	25000.0
    2	2	2	2022-02-01	20000.0
    3	3	3	2022-03-01	30000.0
    */
================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_query_checker (yIZ0tk4VP)
     Call ID: yIZ0tk4VP
      Args:
        query: SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue FROM Dealerships INNER JOIN Sales ON Dealerships.id = Sales.dealership_id WHERE strftime('%Y', Sales.sale_date) = '2022' GROUP BY Dealerships.id ORDER BY total_sales_revenue DESC LIMIT 5;
================================= [1m Tool Message  [0m=================================
    Name: sql_db_query_checker
    
    SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue
    FROM Dealerships
    INNER JOIN Sales ON Dealerships.id = Sales.dealership_id
    WHERE strftime('%Y', Sales.sale_date) = '2022'
    GROUP BY Dealerships.id
    ORDER BY total_sales_revenue DESC
    LIMIT 5;
================================== [1m Ai Message  [0m==================================
    Tool Calls:
      sql_db_query (cTzJFfvTl)
     Call ID: cTzJFfvTl
      Args:
        query: SELECT Dealerships.name, SUM(Sales.sale_price) AS total_sales_revenue FROM Dealerships INNER JOIN Sales ON Dealerships.id = Sales.dealership_id WHERE strftime('%Y', Sales.sale_date) = '2022' GROUP BY Dealerships.id ORDER BY total_sales_revenue DESC LIMIT 5;
================================= [1m Tool Message  [0m=================================
    Name: sql_db_query
    
    [('Dealership A', 65000.0), ('Dealership B', 48000.0), ('Dealership J', 38000.0), ('Dealership G', 35000.0), ('Dealership H', 32000.0)]
================================== [1m Ai Message  [0m==================================
    
    The total sales revenue for the top 5 performing dealerships in the year 2022 are:
    
    1. Dealership A: $65,000
    2. Dealership B: $48,000
    3. Dealership J: $38,000
    4. Dealership G: $35,000
    5. Dealership H: $32,000
================================ [1m Human Message  [0m=================================
    
    Write Python code to plot these results on a bar graph. Then, you must execute the code and display the bar graph.
================================== [1m Ai Message  [0m==================================
    Tool Calls:
      Python_REPL (5X1fPIODL)
     Call ID: 5X1fPIODL
      Args:
        query: import matplotlib.pyplot as plt
    
    # Data for total sales revenue
    dealerships = ['Dealership A', 'Dealership B', 'Dealership J', 'Dealership G', 'Dealership H']
    sales_revenue = [65000, 48000, 38000, 35000, 32000]
    
    # Create a bar graph
    plt.bar(dealerships, sales_revenue, color='blue')
    
    # Customize the plot
    plt.title('Total Sales Revenue for Top 5 Performing Dealerships in 2022')
    plt.xlabel('Dealerships')
    plt.ylabel('Total Sales Revenue ($)')
    plt.xticks(rotation=45)
    plt.grid(axis='y')
    
    # Display the plot
    plt.tight_layout()
    plt.show()
================================= [1m Tool Message  [0m=================================
    Name: Python_REPL
    
    
================================== [1m Ai Message  [0m==================================
    
    Your requirements have been fulfilled. Code has been executed in repl.
    The bar graph has been plotted and shown in the python REPL.
    The graph can also be seen below:
إجمالي إيرادات المبيعات لأفضل 5 وكلاء أداء في عام 2022

كما هو متوقّع، نجح الوكيل في استدعاء أداة python_repl لتوليد وتنفيذ تعليمات برمجية بلغة Python، مما أدى إلى إنشاء تمثيل رسومي للنتائج. لاحظ أن الوكيل تمكّن أيضًا من تحديد قيم المحور السيني والمحور الصادي المناسبة، إلى جانب التسميات والعنوان. يُبرز هذا الاستدلال الوكيلي الذي يميّز وكلاء الذكاء الاصطناعي عن روبوتات المحادثة التقليدية المعتمدة على النماذج اللغوية الكبيرة.

للحصول على تمثيل مرئي لرسم بياني للوكيل، يمكننا عرض تدفق الرسم البياني.

display(Image(agent.graph.get_graph().draw_mermaid_png()))

المخرجات:

مخطط تصور الرسم البياني للوكيل عرض توضيحي مرئي للرسم البياني لوكيل LangGraph

ملخص

في هذا البرنامج التعليمي، استكشفنا كيفية بناء وكيل ReAct من النص إلى SQL باستخدام LangGraph. وبدلًا من استخدام دالة تنفيذ الوكيل الجاهزة create_react_agent، قمنا ببناء الوكيل من الصفر. بعد تحليل سؤال المستخدم باللغة الطبيعية، يستخدم وكيل الذكاء الاصطناعي أدواته لتوليد استعلامات SQL والتحقق منها وتنفيذها، مظهرًا كفاءة في كلٍّ من SQL وPython. وبالاعتماد على فئة PythonREPLTool من LangChain، يصبح الوكيل قادرًا ليس فقط على توليد تعليمات برمجية بلغة Python، بل أيضًا على تنفيذها. وقد شاهدنا التنفيذ الناجح لهذه الأداة عند مطالبة الوكيل بتقديم تمثيل رسومي لاستجابته. تُمكّن الحلقة الشرطية بين عُقدة النموذج اللغوي الكبير (LLM) وعُقد الأدوات بنية وكيل ReAct. من خلال هذا البرنامج التعليمي، استعرضنا قدرات البرمجة والتفكير متعدد الوسائط في Mistral Medium 3. وكخطوة تالية، يُنصَح بتجربة إضافة عُقد وحواف إضافية إلى الرسم البياني.

حلول ذات صلة
تطوير وكلاء الذكاء الاصطناعي من IBM 

تمكين المطورين من إنشاء وكلاء الذكاء الاصطناعي ونشرهم ومراقبتهم باستخدام استوديو IBM watsonx.ai.

 

استكشف watsonx.ai
حلول الذكاء الاصطناعي

استفد من الذكاء الاصطناعي في عملك بالاستعانة بخبرة IBM الرائدة في مجال الذكاء الاصطناعي ومحفظة حلولها المتوفرة لك.

استكشف حلول الذكاء الاصطناعي
الاستشارات والخدمات المتعلقة بالذكاء الاصطناعي

أعدّ ابتكار عمليات ومهام سير العمل الحساسة بإضافة الذكاء الاصطناعي لتعزيز التجارب وصنع القرارات في الوقت الفعلي والقيمة التجارية.

استكشف خدمات الذكاء الاصطناعي
اتخِذ الخطوة التالية

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

استكشف watsonx Orchestrate استكشف watsonx.ai
الحواشي

1 “Medium Is the New Large.” Mistral.ai, 7 May 2025, mistral.ai/news/mistral-medium-3.