موجّه ReAct نمط يتناوب فيه النموذج اللغوي بين الاستدلال والتنفيذ: يكتب فكرة عما يجب فعله، وينفّذ إجراءً مثل بحث أو استدعاء أداة، ويقرأ النتيجة، وعندها فقط يقرر الخطوة التالية. الاسم اختصار Reason + Act (استدلل ونفّذ)، ويأتي من بحث Yao وزملائه عام 2022، "ReAct: Synergizing Reasoning and Acting in Language Models". ولا علاقة له بمكتبة React في JavaScript لبناء واجهات المستخدم.
معظم وكلاء الذكاء الاصطناعي الذين يتصفحون الويب أو يشغّلون الكود أو يعدّلون الملفات يشغّلون نسخة من هذه الحلقة. وما إن تمرّ عليها يدويًا، يصبح سلوك الوكيل أسهل بكثير في التوقع وفي تصحيح أخطائه.
حلقة Thought وAction وObservation
يطلب موجّه ReAct من النموذج أن يكتب ثلاثة أنواع من الأسطر.
- Thought (الفكرة): استدلال حول الوضع الحالي والمعلومات الناقصة.
- Action (الإجراء): استدعاء أداة واحد بصيغة ثابتة، مثل
search[query]أوread_file[path]أوfinish[answer]. - Observation (الملاحظة): نتيجة ذلك الإجراء. النموذج لا يكتب هذا السطر. برنامجك (أو أنت) ينفّذ الإجراء ويضيف المخرجات الحقيقية إلى السجل.
ثم يعود السجل كله إلى النموذج، فيكتب الفكرة التالية. تنتهي الحلقة عندما يختار النموذج إجراء الإنهاء. النموذج لا يشغّل أداة بنفسه أبدًا، بل يطلب فقط، والكود المحيط به يقرر هل ينفّذ الطلب.
لماذا يتفوق الاستدلال مع التنفيذ على كل منهما وحده
قارن البحث بين ReAct وموجّهات تستدل فقط (سلسلة التفكير) وموجّهات تنفّذ فقط (استدعاءات أدوات دون استدلال مكتوب). في الإجابة عن الأسئلة والتحقق من الحقائق باستخدام أداة بحث في ويكيبيديا، كثيرًا ما بنى الاستدلال وحده حجة واثقة على حقيقة اختلقها النموذج، بينما استطاع ReAct البحث عن الحقيقة، وجاءت أفضل نتائج الإجابة عن الأسئلة من الجمع بين ReAct وسلسلة التفكير، بالرجوع من أحدهما إلى الآخر حين لا يعطي الأول إجابة واثقة. أما التنفيذ وحده فتعثّر في تفكيك الهدف وفي جمع ما وجده في إجابة، والأفكار المكتوبة أبقت الخطة ظاهرة. وفي مهمتين تفاعليتين، لعبة منزلية نصية وموقع تسوّق محاكى، أدى ReAct بمثال أو مثالين أفضل من النماذج المدرّبة التي قارن بها المؤلفون.
الدرس العام: سلسلة التفكير تساعد النموذج على التخطيط، والأدوات تعطيه الحقائق، ولا يكفي أي منهما لمهمة تحتاج إلى الاثنين.
وكيل ReAct، دورًا بدور
المثال التالي وكيل برمجة صغير بأداتين. كل تبويب هو المحادثة نفسها بعد خطوة واحدة: أسطر Observation هي ما ألصقه البرنامج بعد تنفيذ الإجراء السابق. اقرأ الردود بالترتيب. التسميات Task: وThought: وAction: وObservation: تبقى بالإنجليزية لأن كود Python لاحقًا في هذه الصفحة يبني السجل بها ويبحث عنها.
Thought: لا أعرف أي اختبار يفشل ولا كيف. تشغيل الاختبارات سيُظهر الشرط الدقيق الذي فشل قبل أن أقرأ أي كود. Action: run_tests[tests/test_cart.py]
لاحظ أمرين. الإجراء الأول تشغيل للاختبارات، لا تخمين: جمع النموذج الأدلة قبل أن يقرأ الكود. وكل فكرة تشير إلى آخر ملاحظة، وهذا ما لا تستطيعه سلسلة التفكير.
جرّب ReAct في تطبيق محادثة
لا تحتاج إلى كود لترى الحلقة. في ChatGPT أو Claude أو Gemini يمكنك أن تكون أنت الأداة: يطلب النموذج إجراءً، فتنفّذه وتلصق النتيجة.
الفكرة: المروحة العالية في وضع الخمول تعني عادةً أن شيئًا ما يستخدم المعالج في الخلفية، أو أن المروحة تكافح للتبريد (غبار، أو فتحات تهوية مسدودة). فحص استخدام المعالج أولًا يفصل بين الحالتين.
الإجراء: افتح إدارة المهام (Ctrl+Shift+Esc في Windows) أو مراقب النشاط (Applications > Utilities في Mac). رتّب العمليات حسب استخدام المعالج، وانتظر 30 ثانية، وأخبرني بأعلى ثلاث عمليات ونسبها المئوية.
التعليمات نفسها، مع دالة حقيقية خلف كل إجراء، هي وكيل.
حلقة ReAct مصغّرة في Python
في الكود، يرسل البرنامج السجل، ويجد سطر Action في الرد، ويشغّل الدالة المطابقة، ويضيف Observation، ويكرر. يستخدم هذا المخطط مكتبة Python من OpenAI وموجّه النظام من وكيل البرمجة أعلاه.
import re
import subprocess
from pathlib import Path
from openai import OpenAI
client = OpenAI()
MODEL = "your-model-id" # e.g. from your provider's model list
PROJECT = Path.cwd().resolve()
READABLE = {".py", ".md", ".txt", ".toml", ".cfg"}
def inside_project(arg):
# The model chooses arg: resolve it and refuse anything outside the project.
path = (PROJECT / arg).resolve()
if not path.is_relative_to(PROJECT):
raise ValueError(f"{arg} is outside the project")
return path
def run_tests(arg):
path = inside_project(arg)
if not (path.is_file() and path.name.startswith("test_") and path.suffix == ".py"):
raise ValueError(f"{arg} is not a test file")
result = subprocess.run(["pytest", str(path), "-q"], capture_output=True, text=True)
return result.stdout[-2000:]
def read_file(arg):
path = inside_project(arg)
if not path.is_file() or path.suffix not in READABLE:
raise ValueError(f"{arg} is not a file this agent may read")
return path.read_text()[:20000]
TOOLS = {"run_tests": run_tests, "read_file": read_file}
def react(task, system_prompt, max_steps=8):
transcript = f"Task: {task}\n"
for _ in range(max_steps):
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": transcript},
],
temperature=0,
)
text = response.choices[0].message.content
match = re.search(r"Action: (\w+)\[(.*)\]", text)
if not match:
return text
transcript += text[: match.end()] + "\n"
tool, arg = match.groups()
if tool == "finish":
return arg
try:
observation = TOOLS[tool](arg) if tool in TOOLS else f"Unknown tool: {tool}"
except Exception as error: # a missing file becomes an observation, not a crash
observation = f"Error: {error}"
transcript += f"Observation:\n{observation}\n"
return "Stopped after max_steps without an answer."
أربعة تفاصيل مهمة. يُقطع السجل مباشرة بعد سطر Action، لأن النماذج تواصل الكتابة أحيانًا وتختلق Observation خاصة بها. والأداة الفاشلة (اسم ملف خاطئ مثلًا) تصبح Observation يستطيع النموذج التفاعل معها، بدلًا من أن توقف الحلقة. وحد الخطوات يوقف النموذج الذي يدور بلا نهاية. ومخرجات الاختبارات تُقتطع، لأن سجل اختبارات ضخمًا سيملأ نافذة السياق، وتحديد ما يدخل تلك النافذة هو هندسة السياق.
وتتحقق الأداتان أيضًا من الوسيط قبل أن تفعلا أي شيء. النموذج هو من يختار هذا الوسيط، لذا فمكان القيود هو الأداة نفسها: ترفض inside_project أي مسار ينتهي خارج مجلد المشروع (بما في ذلك حيل ../)، ولا تقبل run_tests إلا ملفات test_*.py، ولا تفتح read_file إلا أنواعًا قليلة من ملفات الشيفرة والنص وتعيد 20,000 حرف على الأكثر، فلا يصل ملف .env أو مفتاح SSH إلى الطلب التالي أبدًا. ومع ذلك فتشغيل pytest ينفّذ شيفرة مشروعك، لذا شغّل وكيلًا كهذا داخل حاوية أو نسخة مؤقتة من المشروع، ولا تشغّله أبدًا على جهاز يحمل أسرارًا.
توفر واجهات API الحالية من OpenAI وAnthropic وGoogle أيضًا استدعاء أدوات مدمجًا: تصف كل أداة باسم ومخطط JSON، ويُرجع النموذج استدعاء أداة منظمًا بدلًا من سطر Action:. الحلقة متطابقة، ولا يختفي إلا التحليل.
الأمان في حلقة ReAct
الوكيل يقرأ نصًا لم يكتبه: صفحات ويب، وملفات، ومخرجات أدوات. وأي منها قد يحتوي على تعليمات موجّهة إلى النموذج، وهذا هو حقن الموجّهات. أعطِ كل أداة أقل صلاحية تحتاجها (قراءة فقط حيثما أمكن)، واطلب تأكيدًا بشريًا لكل ما يحذف أو يرسل أو يدفع، وتعامل مع الإجراءات التي يطلبها النموذج على أنها مُدخلات غير موثوقة يجب فحصها، لا أوامر تُنفَّذ دون تفكير.
الأسئلة الشائعة
ما هو موجّه ReAct؟
ReAct (اختصار Reason + Act، أي استدلل ونفّذ) نمط في كتابة الموجّهات يكتب فيه النموذج اللغوي جزءًا قصيرًا من الاستدلال، ثم إجراءً مثل بحث أو استدعاء أداة، ثم يقرأ النتيجة قبل أن يستدل مجددًا. يأتي من بحث Yao وزملائه عام 2022 "ReAct: Synergizing Reasoning and Acting in Language Models". ولا علاقة له بمكتبة React في JavaScript.
ما هي Thought وAction وObservation في ReAct؟
Thought (الفكرة) هي استدلال النموذج حول ما يفعله بعد ذلك. وAction (الإجراء) استدعاء أداة بصيغة ثابتة، مثل search[python 3.13 release notes]. وObservation (الملاحظة) هي مخرجات الأداة، التي يشغّل برنامجك الإجراء ليحصل عليها ويضيفها إلى الموجّه. تتكرر الحلقة حتى يختار النموذج إجراء الإنهاء مع إجابته.
ما الفرق بين ReAct وسلسلة التفكير؟
سلسلة التفكير تستدل مما يعرفه النموذج أصلًا، فالحقيقة الخاطئة في بداية السلسلة تبقى خاطئة. أما ReAct فيمزج الاستدلال بإجراءات تجلب معلومات حقيقية، فيستطيع النموذج التحقق من حقيقة، أو رؤية اختبار يفشل، أو قراءة ملف قبل أن يتابع. ووجد بحث ReAct أن ربط الاستدلال بنتائج البحث قلّل الحقائق المختلقة التي كانت تنتجها سلسلة التفكير وحدها.
هل ما زال وكلاء الذكاء الاصطناعي يستخدمون ReAct؟
الحلقة، نعم. معظم الوكلاء اليوم يستدلون، ويستدعون أداة، ويقرؤون النتيجة، ويقررون من جديد، وهذه هي دورة ReAct. ما تغيّر هو الصيغة: بدلًا من استخراج أسطر Action: من النص، توفر واجهات API الحالية استدعاء أدوات مدمجًا، يُرجع فيه النموذج طلب أداة منظمًا ويرسل كودك النتيجة.
هل يمكنني استخدام ReAct في ChatGPT دون كود؟
نعم، بأن تؤدي أنت دور الأداة. اطلب من النموذج أن يرد بفكرة واحدة وإجراء واحد ثم يتوقف. أنت تنفّذ الإجراء (بحث، أو فتح ملف، أو تشغيل أمر)، وتلصق النتيجة على أنها الملاحظة، وتكرر. الطريقة بطيئة، لكنها تُظهر بالضبط كيف يقرر الوكيل ما يفعله بعد ذلك.