بناء وكلاء الذكاء الاصطناعي من الصفر باستخدام TypeScript: إتقان نمط ReAct مع Vercel AI SDK

AI Bot
بواسطة AI Bot ·

جاري تحميل مشغل تحويل النص إلى كلام الصوتي...

كل مختبر رئيسي للذكاء الاصطناعي يراهن على الوكلاء. OpenAI وAnthropic وGoogle جميعها تتسابق لإطلاق نماذج لا تكتفي بالإجابة على الأسئلة — بل تستدل وتتصرف وتكرر حتى يُنجَز العمل. لكن خلف كل وكيل متطور يكمن نمط بسيط بشكل مخادع: ReAct.

في هذا الدليل التعليمي، ستبني وكلاء ذكاء اصطناعي من الصفر باستخدام TypeScript. ستبدأ بحلقة استدلال خام، ثم تضيف تدريجيًا الأدوات، والتنفيذ متعدد الخطوات، وضمانات الإنتاج — كل ذلك بدعم من Vercel AI SDK.

لماذا يُعتبر نمط ReAct مهمًا في 2026: أفادت Gartner بارتفاع بنسبة 1,445% في الاستفسارات حول الأنظمة متعددة الوكلاء من الربع الأول 2024 إلى الربع الثاني 2025. فهم نمط ReAct الأساسي هو الركيزة لبناء أي نظام وكلاء — من المساعدين البسيطين إلى التنسيقات المعقدة متعددة الوكلاء.

ماذا ستتعلم

بنهاية هذا الدليل التعليمي، ستكون قادرًا على:

  • فهم نمط ReAct (الاستدلال + التصرف) ولماذا يُعد العمود الفقري لوكلاء الذكاء الاصطناعي الحديثين
  • بناء حلقة وكيل يدوية باستخدام generateText لرؤية كيفية عمل الوكلاء بدقة
  • تعريف أدوات آمنة النوع مع مخططات Zod يمكن لنماذج اللغة الكبيرة استدعاؤها
  • استخدام ToolLoopAgent لتنسيق وكلاء جاهزين للإنتاج
  • تطبيق تحكم متقدم في الحلقات: حدود الخطوات، وميزانيات التكلفة، وأنماط الأدوات الإجبارية
  • بناء وكيل بحث عملي يبحث ويحلل ويجمع المعلومات

كيف تعمل وكلاء الذكاء الاصطناعي فعليًا

قبل كتابة الكود، دعنا نفهم النموذج الذهني. استدعاء نموذج لغة كبير تقليدي هو دورة واحدة:

الأمر → نموذج اللغة الكبير → الاستجابة

أما الوكيل فهو نموذج لغة كبير في حلقة. في كل تكرار، يمكن للنموذج إما الاستجابة بنص (إنهاء الحلقة) أو استدعاء أداة (متابعة الحلقة):

الأمر → نموذج اللغة الكبير → "أحتاج للبحث عن هذا" → يستدعي أداة البحث
                                                    ↓
         نموذج اللغة الكبير ← نتيجة الأداة ← تنفيذ البحث
          ↓
         نموذج اللغة الكبير → "الآن أحتاج للحساب" → يستدعي أداة الحاسبة
                                                    ↓
         نموذج اللغة الكبير ← نتيجة الأداة ← تنفيذ الحاسبة
          ↓
         نموذج اللغة الكبير → "إليك الإجابة: ..." → استجابة نصية (تنتهي الحلقة)

هذا هو نمط ReAct: يقوم النموذج بـالاستدلال (Re) حول ما يجب فعله، ثم يتصرف (Act) باستدعاء أداة. تتكرر الحلقة حتى يقرر النموذج أن لديه معلومات كافية للاستجابة.

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

قبل البدء، تأكد من توفر:

  • Node.js 20+ مثبت
  • مفتاح API لـ OpenAI (أو أي مزود متوافق مع AI SDK)
  • معرفة أساسية بـ TypeScript
  • إلمام بـ async/await ومخططات Zod
  • محرر أكواد (يُنصح بـ VS Code)

مرونة المزود: يدعم Vercel AI SDK كلًا من OpenAI وAnthropic وGoogle وMistral والعديد من المزودين الآخرين. سنستخدم OpenAI في هذا الدليل، لكن يمكنك تبديل النموذج بتغيير سطر واحد فقط.

الخطوة 1: إعداد المشروع

أنشئ مشروع TypeScript جديدًا وثبّت التبعيات:

mkdir ai-agent-tutorial && cd ai-agent-tutorial
npm init -y
npm install ai @ai-sdk/openai zod dotenv
npm install -D typescript tsx @types/node

قم بتهيئة TypeScript:

npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext --outDir dist

أنشئ ملف .env لمفتاح API الخاص بك:

OPENAI_API_KEY=sk-your-key-here

يجب أن تبدو بنية مشروعك هكذا:

ai-agent-tutorial/
├── .env
├── package.json
├── tsconfig.json
└── src/
    ├── 01-basic-tool-call.ts
    ├── 02-manual-agent-loop.ts
    ├── 03-tool-loop-agent.ts
    ├── 04-forced-tool-pattern.ts
    └── 05-research-agent.ts

الخطوة 2: أول استدعاء أداة

قبل بناء وكيل كامل، دعنا نفهم الوحدة الأساسية: استدعاء أداة واحد. أنشئ src/01-basic-tool-call.ts:

import "dotenv/config";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
 
const result = await generateText({
  model: openai("gpt-4o"),
  tools: {
    weather: tool({
      description: "الحصول على حالة الطقس الحالية في موقع ما",
      inputSchema: z.object({
        location: z.string().describe("اسم المدينة، مثل: سان فرانسيسكو"),
      }),
      execute: async ({ location }) => {
        // في الإنتاج، استدعِ واجهة برمجة طقس حقيقية
        const conditions = ["sunny", "cloudy", "rainy", "windy"];
        return {
          location,
          temperature: Math.round(15 + Math.random() * 20),
          condition: conditions[Math.floor(Math.random() * conditions.length)],
          unit: "celsius",
        };
      },
    }),
  },
  prompt: "What's the weather like in Tokyo?",
});
 
console.log("الاستجابة:", result.text);
console.log("استدعاءات الأدوات:", JSON.stringify(result.toolCalls, null, 2));
console.log("نتائج الأدوات:", JSON.stringify(result.toolResults, null, 2));

شغّله:

npx tsx src/01-basic-tool-call.ts

لاحظ أن النموذج استدعى أداة weather مع { location: "Tokyo" }. قام AI SDK تلقائيًا بتنفيذ الأداة وإعادة النتيجة إلى النموذج، الذي أنشأ بعدها استجابة بلغة طبيعية. لكن هذه كانت رحلة ذهاب وإياب واحدة — ليست وكيلًا بعد.

الخطوة 3: بناء حلقة وكيل يدوية

الآن دعنا نبني حلقة وكيل حقيقية من الصفر. هذا هو نمط ReAct الخام — بدون تجريدات، فقط المنطق الأساسي. أنشئ src/02-manual-agent-loop.ts:

import "dotenv/config";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
import type { ModelMessage } from "ai";
 
// تعريف الأدوات
const tools = {
  search: tool({
    description: "البحث عن معلومات حول موضوع ما. يُرجع حقائق ذات صلة.",
    inputSchema: z.object({
      query: z.string().describe("استعلام البحث"),
    }),
    execute: async ({ query }) => {
      console.log(`  🔍 جارٍ البحث: "${query}"`);
      // نتائج بحث محاكاة
      const results: Record<string, string> = {
        typescript:
          "TypeScript 5.7 released in 2025. Features include improved inference, decorator metadata, and faster compilation.",
        "ai agents":
          "AI agents market projected to reach $50B by 2030. Key frameworks: Vercel AI SDK, LangChain, CrewAI.",
        "react pattern":
          "ReAct (Reasoning + Acting) proposed by Yao et al. 2022. Combines chain-of-thought with tool use for grounded reasoning.",
      };
      const key = Object.keys(results).find((k) =>
        query.toLowerCase().includes(k)
      );
      return key
        ? results[key]
        : `لا توجد نتائج محددة لـ "${query}". جرّب استعلامًا أكثر تحديدًا.`;
    },
  }),
  calculator: tool({
    description: "إجراء عمليات حسابية رياضية",
    inputSchema: z.object({
      expression: z.string().describe("تعبير رياضي، مثل: '2 + 2'"),
    }),
    execute: async ({ expression }) => {
      console.log(`  🧮 جارٍ الحساب: ${expression}`);
      try {
        // تقييم رياضي آمن باستخدام مُنشئ Function
        const sanitized = expression.replace(/[^0-9+\-*/().% ]/g, "");
        const result = new Function(`return ${sanitized}`)();
        return { expression, result: Number(result) };
      } catch {
        return { expression, error: "تعبير غير صالح" };
      }
    },
  }),
};
 
// حلقة ReAct اليدوية
async function runAgent(userPrompt: string, maxSteps = 10) {
  const messages: ModelMessage[] = [
    {
      role: "system",
      content:
        "You are a helpful research assistant. Use the available tools to find information and perform calculations. Think step by step.",
    },
    { role: "user", content: userPrompt },
  ];
 
  console.log(`\n🤖 بدأ الوكيل: "${userPrompt}"\n`);
 
  for (let step = 0; step < maxSteps; step++) {
    console.log(`--- الخطوة ${step + 1} ---`);
 
    const result = await generateText({
      model: openai("gpt-4o"),
      messages,
      tools,
    });
 
    // إضافة استجابة النموذج إلى سجل المحادثة
    messages.push(...result.response.messages);
 
    // إذا أنشأ النموذج نصًا (بدون استدعاءات أدوات)، فقد انتهينا
    if (result.text) {
      console.log(`\n✅ أنهى الوكيل في ${step + 1} خطوة/خطوات`);
      console.log(`\n📝 الإجابة النهائية:\n${result.text}`);
      return result.text;
    }
 
    // تسجيل استدعاءات الأدوات لهذه الخطوة
    for (const toolCall of result.toolCalls) {
      console.log(`  أداة: ${toolCall.toolName}(${JSON.stringify(toolCall.args)})`);
    }
  }
 
  console.log("⚠️ وصل الوكيل إلى الحد الأقصى للخطوات دون إكمال");
  return null;
}
 
// تشغيل الوكيل
await runAgent(
  "Search for information about the ReAct pattern and AI agents. Then calculate what percentage of the $50B projected agent market would be $7.6B."
);

شغّله:

npx tsx src/02-manual-agent-loop.ts

سترى الوكيل يستدل عبر خطوات متعددة:

🤖 بدأ الوكيل: "ابحث عن معلومات حول..."

--- الخطوة 1 ---
  🔍 جارٍ البحث: "react pattern"
  أداة: search({"query":"react pattern"})
--- الخطوة 2 ---
  🔍 جارٍ البحث: "ai agents"
  أداة: search({"query":"ai agents"})
--- الخطوة 3 ---
  🧮 جارٍ الحساب: (7.6 / 50) * 100
  أداة: calculator({"expression":"(7.6 / 50) * 100"})
--- الخطوة 4 ---

✅ أنهى الوكيل في 4 خطوات

📝 الإجابة النهائية:
نمط ReAct... سوق وكلاء الذكاء الاصطناعي... 7.6 مليار دولار تمثل 15.2% من السوق المتوقع بـ 50 مليار دولار.

هذا هو جوهر كل وكيل ذكاء اصطناعي: حلقة يقرر فيها النموذج ما يجب فعله بعد ذلك. استدعى النموذج search مرتين لجمع المعلومات، ثم calculator لمعالجة الأرقام، وأخيرًا جمع كل شيء في استجابة واحدة.

الخطوة 4: وكيل إنتاجي مع ToolLoopAgent

تعمل الحلقة اليدوية لكنها تتطلب كودًا نمطيًا كثيرًا. يتولى صنف ToolLoopAgent في AI SDK كل عمليات التنسيق نيابةً عنك. أنشئ src/03-tool-loop-agent.ts:

import "dotenv/config";
import { ToolLoopAgent, tool, stepCountIs } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
 
const researchAgent = new ToolLoopAgent({
  model: openai("gpt-4o"),
  system:
    "You are a research assistant. Use tools to find and analyze information. Always verify claims with searches before presenting them as facts.",
  tools: {
    searchWeb: tool({
      description:
        "البحث في الويب عن معلومات حالية حول أي موضوع",
      inputSchema: z.object({
        query: z.string().describe("استعلام البحث"),
        topic: z
          .enum(["technology", "science", "business", "general"])
          .describe("فئة الموضوع لتركيز النتائج"),
      }),
      execute: async ({ query, topic }) => {
        console.log(`  🔍 [${topic}] جارٍ البحث: "${query}"`);
        // محاكاة — استبدل باستدعاءات API حقيقية
        return {
          results: [
            {
              title: `أفضل نتيجة لـ: ${query}`,
              snippet: `معلومات شاملة حول ${query} في مجال ${topic}. تشمل النتائج الرئيسية التطورات الأخيرة والاتجاهات المتوقعة لـ 2026-2027.`,
              relevance: 0.95,
            },
          ],
          totalResults: 1,
        };
      },
    }),
    analyzeData: tool({
      description:
        "تحليل ومقارنة نقاط البيانات، وتحديد الاتجاهات والأنماط",
      inputSchema: z.object({
        data: z.string().describe("البيانات أو الحقائق المراد تحليلها"),
        analysisType: z
          .enum(["comparison", "trend", "summary", "sentiment"])
          .describe("نوع التحليل المطلوب"),
      }),
      execute: async ({ data, analysisType }) => {
        console.log(`  📊 جارٍ التحليل (${analysisType}): ${data.slice(0, 60)}...`);
        return {
          analysisType,
          findings: `كشف التحليل من نوع '${analysisType}' على البيانات المقدمة عن أنماط رئيسية ورؤى قابلة للتنفيذ.`,
          confidence: 0.87,
        };
      },
    }),
  },
  stopWhen: stepCountIs(10),
});
 
// تشغيل الوكيل
const result = await researchAgent.generate({
  prompt:
    "Research the current state of AI agent frameworks in 2026. Compare the top 3 frameworks and tell me which one is best for TypeScript developers.",
});
 
console.log("\n📝 الاستجابة النهائية:\n");
console.log(result.text);
console.log(`\n📊 إجمالي الخطوات: ${result.steps.length}`);
console.log(
  `📊 إجمالي الرموز: ${result.steps.reduce((sum, s) => sum + (s.usage?.totalTokens ?? 0), 0)}`
);

يمنحك صنف ToolLoopAgent:

  • إدارة تلقائية للمحادثة — لا حاجة لإضافة الرسائل يدويًا
  • شروط إيقاف مدمجةstepCountIs(10) يمنع الحلقات الهاربة
  • تتبع الخطوات — فحص كل خطوة للتصحيح والمراقبة
  • تتبع استخدام الرموز — مراقبة التكاليف عبر تشغيل الوكيل بالكامل

الخطوة 5: التحكم المتقدم في الحلقات

تحتاج وكلاء العالم الحقيقي إلى تحكم دقيق في تنفيذها. أنشئ src/04-forced-tool-pattern.ts:

import "dotenv/config";
import { ToolLoopAgent, tool, stepCountIs } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
import type { StopCondition } from "ai";
 
// تعريف الأدوات مع الأنواع لنوع StopCondition العام
const tools = {
  gatherEvidence: tool({
    description:
      "جمع الأدلة والحقائق حول ادعاء ما. استدعِ هذا دائمًا قبل تقديم أي تأكيدات.",
    inputSchema: z.object({
      claim: z.string().describe("الادعاء المراد التحقيق فيه"),
    }),
    execute: async ({ claim }) => {
      console.log(`  📋 جارٍ جمع الأدلة: "${claim}"`);
      return {
        claim,
        evidence: [
          { source: "ورقة بحثية", supports: true, confidence: 0.9 },
          { source: "تقرير صناعي", supports: true, confidence: 0.85 },
        ],
        consensusStrength: "strong",
      };
    },
  }),
  assessRisk: tool({
    description:
      "تقييم المخاطر المحتملة أو الحجج المضادة لاستنتاج ما",
    inputSchema: z.object({
      conclusion: z.string().describe("الاستنتاج المراد تقييمه"),
    }),
    execute: async ({ conclusion }) => {
      console.log(`  ⚠️ جارٍ تقييم المخاطر: "${conclusion.slice(0, 50)}..."`);
      return {
        risks: ["حجم عينة محدود", "مجال يتطور بسرعة"],
        overallRisk: "medium",
        recommendation: "عرض النتائج مع التحفظات المناسبة",
      };
    },
  }),
  // أداة "انتهاء" بدون دالة execute — تعمل كإشارة إنهاء
  submitReport: tool({
    description:
      "تقديم تقرير البحث النهائي. استدعِ هذا فقط عندما تُجمع الأدلة وتُقيَّم المخاطر.",
    inputSchema: z.object({
      title: z.string().describe("عنوان التقرير"),
      findings: z.string().describe("ملخص النتائج الرئيسية"),
      confidence: z
        .enum(["high", "medium", "low"])
        .describe("مستوى الثقة العام"),
      caveats: z.array(z.string()).describe("تحفظات مهمة"),
    }),
    // لا توجد دالة execute — استدعاء هذه الأداة يوقف الحلقة
  }),
};
 
// شرط إيقاف مخصص: مبني على الميزانية
const budgetExceeded: StopCondition<typeof tools> = ({ steps }) => {
  const totalTokens = steps.reduce(
    (sum, step) => sum + (step.usage?.totalTokens ?? 0),
    0
  );
  const estimatedCost = (totalTokens / 1000) * 0.005; // تقدير تقريبي
  if (estimatedCost > 0.10) {
    console.log(`  💰 تجاوز الميزانية: ~$${estimatedCost.toFixed(4)}`);
    return true;
  }
  return false;
};
 
const factCheckAgent = new ToolLoopAgent({
  model: openai("gpt-4o"),
  system: `You are a rigorous fact-checking agent. Follow this process:
1. Gather evidence for each major claim
2. Assess risks and counterarguments
3. Submit a final report with your findings
 
You MUST call tools at every step. When done, call submitReport.`,
  tools,
  toolChoice: "required", // إجبار النموذج على استدعاء أداة دائمًا
  stopWhen: [stepCountIs(15), budgetExceeded], // شروط إيقاف متعددة
  prepareStep: async ({ stepNumber }) => {
    // توفر أدوات مبني على المراحل
    if (stepNumber <= 3) {
      return { activeTools: ["gatherEvidence"] };
    }
    if (stepNumber <= 5) {
      return { activeTools: ["gatherEvidence", "assessRisk"] };
    }
    return { activeTools: ["assessRisk", "submitReport"] };
  },
});
 
const result = await factCheckAgent.generate({
  prompt:
    "Fact-check this claim: AI agents will handle 40% of enterprise applications by end of 2026.",
});
 
// مع toolChoice: 'required' وأداة انتهاء، تكون الإجابة في staticToolCalls
console.log("\n📄 تم تقديم التقرير:");
const report = result.staticToolCalls.find(
  (tc) => tc.toolName === "submitReport"
);
if (report) {
  console.log(JSON.stringify(report.args, null, 2));
}
console.log(`\n📊 اكتمل في ${result.steps.length} خطوات`);

يوضح هذا المثال ثلاثة أنماط متقدمة:

نمط الأداة الإجبارية

من خلال الجمع بين toolChoice: "required" وأداة submitReport بدون دالة execute، نُجبر الوكيل على استخدام الأدوات دائمًا. عندما يستدعي الوكيل submitReport، تتوقف الحلقة لعدم وجود دالة للتنفيذ. يتم التقاط المخرجات المُهيكلة في result.staticToolCalls.

شروط الإيقاف المخصصة

تتتبع دالة budgetExceeded الاستخدام التراكمي للرموز وتوقف الوكيل إذا تجاوزت التكاليف حدًا معينًا. يمكنك دمج شروط متعددة في مصفوفة — تتوقف الحلقة عندما يتحقق أي شرط.

توفر الأدوات المرحلي

يتحكم رد النداء prepareStep ديناميكيًا في الأدوات المتاحة في كل خطوة. تسمح الخطوات المبكرة فقط بجمع الأدلة، وتضيف الخطوات الوسطى تقييم المخاطر، وتركز الخطوات الأخيرة على تقديم التقرير. هذا يوجه الوكيل عبر سير عمل مُهيكل.

الخطوة 6: بناء وكيل بحث متكامل

دعنا نجمع كل شيء في وكيل بحث عملي بأنماط واقعية. أنشئ src/05-research-agent.ts:

import "dotenv/config";
import { ToolLoopAgent, tool, stepCountIs } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
 
// --- تعريفات الأدوات ---
 
const searchTool = tool({
  description:
    "البحث عن معلومات حالية. استخدم استعلامات محددة للحصول على أفضل النتائج.",
  inputSchema: z.object({
    query: z.string().describe("استعلام بحث محدد"),
  }),
  execute: async ({ query }) => {
    console.log(`  🔍 بحث: "${query}"`);
    // استبدل بواجهة بحث حقيقية (Tavily، Serper، Brave، إلخ.)
    return {
      results: [
        {
          title: `نتيجة لـ: ${query}`,
          content: `معلومات مفصلة حول ${query}. تُظهر أحدث البيانات من 2026 تطورات كبيرة في هذا المجال، مع نمو التبني 3 أضعاف سنويًا.`,
          url: `https://example.com/search?q=${encodeURIComponent(query)}`,
        },
      ],
    };
  },
});
 
const readUrlTool = tool({
  description: "قراءة المحتوى الكامل لعنوان URL لتحليل أعمق",
  inputSchema: z.object({
    url: z.string().url().describe("عنوان URL المراد قراءته"),
  }),
  execute: async ({ url }) => {
    console.log(`  📄 جارٍ القراءة: ${url}`);
    // استبدل بأداة كشط ويب حقيقية (Firecrawl، Jina Reader، إلخ.)
    return {
      url,
      content: `محتوى المقال الكامل من ${url}. يحتوي على تحليل مفصل وإحصائيات وآراء خبراء حول الموضوع. إحصائيات رئيسية: حجم السوق ومعدل النمو ومقاييس التبني.`,
      wordCount: 1500,
    };
  },
});
 
const noteTool = tool({
  description:
    "حفظ نتيجة مهمة في ملاحظاتك. استخدم هذا لتتبع الحقائق الرئيسية أثناء البحث.",
  inputSchema: z.object({
    category: z
      .enum(["fact", "statistic", "quote", "insight"])
      .describe("نوع الملاحظة"),
    content: z.string().describe("محتوى الملاحظة"),
    source: z.string().describe("مصدر هذه المعلومات"),
    reliability: z
      .enum(["high", "medium", "low"])
      .describe("مدى موثوقية هذه المعلومات"),
  }),
  execute: async ({ category, content, source, reliability }) => {
    console.log(`  📝 ملاحظة [${category}/${reliability}]: ${content.slice(0, 60)}...`);
    return { saved: true, category, reliability };
  },
});
 
const outlineTool = tool({
  description:
    "إنشاء أو تحديث مخطط التقرير قبل كتابة التقرير النهائي",
  inputSchema: z.object({
    sections: z
      .array(
        z.object({
          heading: z.string(),
          keyPoints: z.array(z.string()),
        })
      )
      .describe("أقسام التقرير مع النقاط الرئيسية"),
  }),
  execute: async ({ sections }) => {
    console.log(`  📋 تم إنشاء المخطط: ${sections.length} أقسام`);
    return { sections: sections.length, status: "outline_ready" };
  },
});
 
// --- تعريف الوكيل ---
 
const researchAgent = new ToolLoopAgent({
  model: openai("gpt-4o"),
  system: `You are an expert research agent. Your process:
 
1. SEARCH: Start by searching for information from multiple angles
2. READ: Deep-dive into the most relevant sources
3. NOTE: Save key findings with reliability ratings
4. OUTLINE: Organize your findings into a structured outline
5. WRITE: Synthesize everything into a comprehensive response
 
Be thorough. Cross-reference information. Note when sources disagree.
Always save important findings as notes before writing your final response.`,
  tools: {
    search: searchTool,
    readUrl: readUrlTool,
    saveNote: noteTool,
    createOutline: outlineTool,
  },
  stopWhen: stepCountIs(15),
  prepareStep: async ({ stepNumber, messages }) => {
    // تقليم الرسائل القديمة لإدارة نافذة السياق
    if (messages.length > 30) {
      return {
        messages: [messages[0], ...messages.slice(-20)],
      };
    }
    return {};
  },
});
 
// --- التنفيذ ---
 
async function main() {
  console.log("🚀 بدء وكيل البحث\n");
  console.log("=".repeat(60));
 
  const startTime = Date.now();
 
  const result = await researchAgent.generate({
    prompt:
      "Research the state of AI agent development in 2026. Cover the leading frameworks, design patterns, and enterprise adoption trends. Include specific data points.",
  });
 
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
 
  console.log("\n" + "=".repeat(60));
  console.log("\n📝 تقرير البحث:\n");
  console.log(result.text);
 
  // طباعة إحصائيات التنفيذ
  console.log("\n" + "=".repeat(60));
  console.log("📊 إحصائيات التنفيذ:");
  console.log(`   الخطوات: ${result.steps.length}`);
  console.log(`   الوقت: ${elapsed}ث`);
 
  const totalTokens = result.steps.reduce(
    (sum, s) => sum + (s.usage?.totalTokens ?? 0),
    0
  );
  console.log(`   الرموز: ${totalTokens.toLocaleString()}`);
 
  // تسجيل تفاصيل استخدام الأدوات
  const toolUsage: Record<string, number> = {};
  for (const step of result.steps) {
    for (const tc of step.toolCalls) {
      toolUsage[tc.toolName] = (toolUsage[tc.toolName] ?? 0) + 1;
    }
  }
  console.log(`   استخدام الأدوات:`, toolUsage);
}
 
main().catch(console.error);

يوضح وكيل البحث هذا أنماطًا واقعية:

  • أدوات متعددة متخصصة — كل واحدة تتعامل مع جانب مختلف من عملية البحث
  • تدوين ملاحظات مُهيكل — يحفظ الوكيل النتائج مع تقييمات الموثوقية أثناء بحثه
  • إدارة نافذة السياقprepareStep يقلم الرسائل القديمة لمنع تجاوز السياق
  • إحصائيات التنفيذ — تتبع الخطوات والوقت والرموز واستخدام الأدوات للمراقبة

اختبار التطبيق

شغّل كل ملف لرؤية الوكيل أثناء العمل:

# استدعاء أداة أساسي
npx tsx src/01-basic-tool-call.ts
 
# حلقة ReAct يدوية — شاهد النمط الخام
npx tsx src/02-manual-agent-loop.ts
 
# ToolLoopAgent — تنسيق جاهز للإنتاج
npx tsx src/03-tool-loop-agent.ts
 
# أنماط متقدمة — أدوات إجبارية، ميزانيات، مراحل
npx tsx src/04-forced-tool-pattern.ts
 
# وكيل بحث متكامل
npx tsx src/05-research-agent.ts

مرجع أنماط تصميم الوكلاء

إليك مرجعًا سريعًا للأنماط التي تم تغطيتها ومتى تستخدم كل منها:

النمط 1: حلقة أدوات بسيطة

const agent = new ToolLoopAgent({
  model: openai("gpt-4o"),
  tools: { /* ... */ },
  stopWhen: stepCountIs(10),
});

متى تستخدمه: لمعظم مهام الوكلاء. يقرر النموذج متى يستدعي الأدوات ومتى يستجيب.

النمط 2: أداة إجبارية مع إشارة انتهاء

const agent = new ToolLoopAgent({
  model: openai("gpt-4o"),
  tools: {
    /* أدوات العمل... */
    done: tool({
      description: "Signal completion",
      inputSchema: z.object({ answer: z.string() }),
      // لا توجد دالة execute
    }),
  },
  toolChoice: "required",
});

متى تستخدمه: عندما تحتاج مخرجات مُهيكلة أو تريد ضمان أن الوكيل يستخدم الأدوات دائمًا قبل الاستجابة.

النمط 3: التنفيذ المرحلي

const agent = new ToolLoopAgent({
  model: openai("gpt-4o"),
  tools: { search, analyze, summarize },
  prepareStep: async ({ stepNumber }) => {
    if (stepNumber <= 3) return { activeTools: ["search"] };
    if (stepNumber <= 6) return { activeTools: ["analyze"] };
    return { activeTools: ["summarize"] };
  },
});

متى تستخدمه: عندما يجب أن يتبع الوكيل سير عمل محدد — البحث أولًا، ثم التحليل، ثم الاستنتاج.

النمط 4: الحلقة اليدوية

const messages: ModelMessage[] = [{ role: "user", content: prompt }];
for (let i = 0; i < maxSteps; i++) {
  const result = await generateText({ model, messages, tools });
  messages.push(...result.response.messages);
  if (result.text) break;
}

متى تستخدمه: عندما تحتاج أقصى قدر من التحكم — تصفية رسائل مخصصة، أو حقن أدوات ديناميكي، أو منطق تفرع معقد.

قائمة مراجعة الإنتاج

قبل نشر الوكلاء في الإنتاج، ضع هذه العوامل في الاعتبار:

الأمان

  • عيّن maxSteps أو stepCountIs() — ضع دائمًا حدًا أقصى لعدد التكرارات لمنع الحلقات الهاربة
  • طبّق ميزانيات التكلفة — تتبع استخدام الرموز وأوقف عندما تتجاوز التكاليف حدًا معينًا
  • تحقق من مدخلات الأدوات — تتولى مخططات Zod هذا، لكن أضف التحقق من منطق الأعمال في execute
  • استخدم needsApproval — للأدوات ذات الآثار الجانبية (إرسال رسائل بريد، إجراء مشتريات، تعديل بيانات)

المراقبة

  • سجّل كل خطوة — سجّل استدعاءات الأدوات والمدخلات والمخرجات واستخدام الرموز
  • تتبع وقت التنفيذ — قد تستغرق الوكلاء ثوانٍ إلى دقائق؛ عيّن مهلات زمنية
  • راقب معدلات الأخطاء — ستفشل الأدوات؛ تعامل مع الأمر بلطف ودع الوكيل يعيد المحاولة أو يتكيف

الأداء

  • استخدم prepareStep لإدارة السياق — قلّم الرسائل القديمة للبقاء ضمن حدود السياق
  • اختر النموذج المناسب — استخدم نموذجًا أسرع/أرخص للخطوات البسيطة، ونموذجًا أكثر قدرة للاستدلال المعقد
  • خزّن نتائج الأدوات مؤقتًا — إذا ظهر نفس استعلام البحث مرتين، أعد النتيجة المخزنة

استكشاف الأخطاء وإصلاحها

الوكيل يدور في حلقة لا نهائية: من المحتمل أن لديك toolChoice: "required" بدون أداة انتهاء، أو أن أداة الانتهاء لديها دالة execute. احذف دالة execute حتى يؤدي استدعاؤها إلى إنهاء الحلقة.

الوكيل لا يستخدم الأدوات: تحقق من أوصاف أدواتك. يستخدم النموذج الأوصاف لتقرير متى يستدعي الأدوات. كن محددًا: "ابحث في الويب عن معلومات حالية" أفضل من "بحث".

أخطاء مخطط الأداة: تأكد أن مخططات Zod تطابق ما ينتجه النموذج. استخدم .describe() على كل حقل لتوجيه مخرجات النموذج.

تجاوز نافذة السياق: استخدم prepareStep لتقليم الرسائل القديمة. احتفظ بأمر النظام والرسائل الأخيرة؛ أزل نتائج الأدوات القديمة.

الخطوات التالية

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

الخلاصة

كل وكيل ذكاء اصطناعي — من روبوت دردشة بسيط إلى تنسيق معقد متعدد الوكلاء — مبني على نفس الأساس: نموذج لغة كبير في حلقة يمكنه الاستدلال والتصرف. يمنح نمط ReAct الوكلاء قوتهم، ويمنحك Vercel AI SDK الأدوات الأصلية لـ TypeScript لبنائهم بأمان.

لقد تقدمت من استدعاء أداة واحد، عبر حلقة ReAct يدوية، إلى وكلاء جاهزين للإنتاج بميزانيات ومراحل ومخرجات مُهيكلة. هذه الأنماط هي اللبنات الأساسية لأي نظام وكلاء ستبنيه في 2026 وما بعده.

الفكرة الرئيسية: الوكلاء ليسوا سحرًا. إنهم مجرد حلقات بأدوات جيدة وتعليمات واضحة. الآن اذهب وابنِ شيئًا.


هل تريد قراءة المزيد من الدروس التعليمية؟ تحقق من أحدث درس تعليمي لدينا على 6 أساسيات Laravel 11: الطلبات.

ناقش مشروعك معنا

نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.

دعنا نجد أفضل الحلول لاحتياجاتك.

مقالات ذات صلة