Skip to main content
LLMProvider هو ما يولّد به الوكيل ردوده. تأتي الـ SDK بمزوّدين لـ OpenAI وAnthropic وOpenRouter وOllama (كل منهم يستند إلى حزمة نظيرة اختيارية، انظر التثبيت) وبمزوّد وهمي حتمي للاختبارات. حدِّد المزوّد بسلسلة نصية بصيغة provider/model، أو مرِّر كائن مزوّد (instance).

اختيار المزوّد في createAgent()

يقبل createAgent() واحدًا فقط مما يلي:
  1. model: 'provider/model' - يُحلّ بواسطة resolveProvider()؛ ويأتي المفتاح من متغير البيئة المتعارف عليه للمزوّد (انظر بيانات اعتماد المزوّدين).
  2. provider: <LLMProvider> - مزوّدك الخاص، أو مزوّد مدمج مضبوط، أو مزوّد وهمي. يمكنك أيضًا تمرير model (معرّف مجرد مثل 'gpt-4o'): فيصبح نموذج هذا الوكيل، ويتقدّم على النموذج الافتراضي للمزوّد.
  3. لا هذا ولا ذاك - يُحلّ من البيئة: LOUSHO_MODEL (سلسلة provider/model) إن كان مضبوطًا، وإلا فأول الموجود من OPENAI_API_KEY وANTHROPIC_API_KEY وOPENROUTER_API_KEY وOLLAMA_BASE_URL. وإذا لم يكن أي منها مضبوطًا رمى خطأً يسرد الحلول.
أخطاء سوء الإعداد تبيّن طريقة إصلاحها: المفتاح الناقص يُذكر معه اسم المتغير، والبادئة غير المعروفة تُسرد معها البادئات المدعومة ويُقترح أقربها، والحزمة النظيرة الناقصة يُطبع معها أمر npm install الدقيق.

إعادة المحاولة والنماذج الاحتياطية

يعيد createAgent() محاولة استدعاء النموذج الفاشل (تجاوز حدّ المعدّل، انتهاء المهلة، خطأ شبكة، خطأ 5xx) مرتين افتراضيًا، ومع fallbackModels ينتقل إلى النموذج التالي حين يستمر فشل الاستدعاء:
تُحلّ سلسلة model وكل نموذج احتياطي مع تعطيل إعادة المحاولة الخاصة بحزمة ai، فتكون retry طبقة إعادة المحاولة الوحيدة. أما كائن provider فلا يُغلَّف إلا حين تضبط retry. يبلّغ agent.stream() عن الحدثين provider.retry وprovider.fallback. التفاصيل في إعادة المحاولة والبديل الاحتياطي للمزوّد.

أي نموذج يعمل؟

بالترتيب: settings.model الخاص بالوكيل (يُضبط بـ AgentBuilder.setSettings({ model })، أو بـ model إلى جانب provider في createAgent())، ثم النموذج الذي بُني به المزوّد (resolveProvider('openai/gpt-4o-mini')، أو provider.model في ملف مواصفات، أو defaultModel)، ثم النموذج الافتراضي المدمج في المزوّد. لا يوجد نموذج احتياطي مثبَّت في الشيفرة.

الإدخال متعدد الوسائط

Message.content سلسلة نصية أو قائمة أجزاء: { type: 'text', text }، و{ type: 'image', image, mimeType? } (عنوان http(s)، أو عنوان data:، أو البايتات على هيئة Uint8Array) و{ type: 'file', data, mimeType, filename? }. تقبل agent.send() وagent.stream() وsession.send() / stream() وt.send() في التقييمات وsend() في خطّاف React كلها قيمة من نوع AgentInput: سلسلة نصية، أو قائمة أجزاء (تُرسَل كرسالة مستخدم واحدة)، أو Message[] (تُمرَّر كما هي). ويقبل AgentExecutor.execute() الرسائل نفسها في input:
  • الصور تصل إلى النموذج ضمن رسائل user مع كل المزوّدين المدمجين (مع Anthropic وOllama تنزّل حزمة ai الصورة من عنوانها أولًا). اختر نموذجًا يدعم الرؤية: Ollama يتجاهل الصور مع نموذج نصي فقط، وOpenRouter يرفضها معه.
  • الملفات لا يرسلها المزوّدون المدمجون، على أي إصدار رئيسي من ai: يُرسَل جزء الملف كملاحظة نصية ([file report.pdf (application/pdf) not sent]) ويحذّر المزوّد مرة واحدة. الصنف الفرعي من مزوّد يقبل نموذجه الملفات يضبط protected readonly acceptsFileParts = true ليرسلها كأجزاء ملفات بصيغة ai v4.
  • رسائل system وassistant وtool تُرسَل بأجزائها النصية.
  • كل ما يقرأ نص الرسائل يستخدم textOf(): estimateTokens() (يُحتسب كل جزء صورة أو ملف 1,000 رمز ثابتة)، وضغط السياق، وأشرطة تسجيل recordReplay() (التي تخزّن النص وبصمة كل صورة أو ملف، أو عنوانه) وmockModel(). يحفظ FileSessionStore البايتات بترميز base64 ({ "$bytes": "..." }) ويعيد تحميلها على هيئة Uint8Array؛ ويفعل SqliteStore (للجلسات ونقاط الحفظ) الشيء نفسه.

أصناف المزوّدين

لاستخدام خدمة خلفية أخرى، نفّذ الواجهة LLMProvider (name وgenerate() وstream() وsupportsTools() وsupportsStreaming() وgetModels()، واختياريًا defaultModel) ومرِّر الكائن بوصفه provider، أو سجّل مصنعًا بـ LLMProviderRegistry.register(name, factory).

إصدارات Vercel AI SDK

المزوّدون المدمجون مهايئات فوق Vercel AI SDK (ai). ما يعمل اليوم على كل إصدار رئيسي: نطاقات الاعتماديات النظيرة تقبل الإصدارات الرئيسية الثلاثة. قرِن كلًّا منها بحزم المزوّدين المناسبة له: تلميح التثبيت لحزمة مزوّد ناقصة وlousho doctor يذكران الإصدار المناسب لنسخة ai المثبَّتة لديك، وينبّه lousho doctor إلى الزوج غير المتوافق (مثلًا ai 7 مع @ai-sdk/openai 1.x). يحمّل OllamaProvider الحزمة ollama-ai-provider على ai 4 والحزمة ollama-ai-provider-v2 على ai 6/7؛ وحزمة v2 تعتمد اعتمادًا نظيرًا على zod 4، وهو ما تقبله الـ SDK، فثبّت zod 4 معها (مشاريع zod 3 تستخدم Ollama مع ai 4). ينشئ lousho init هيكل المشروع بـ ai@^7.0.0 مع @ai-sdk/*@^4.0.0 لـ OpenAI وAnthropic وOpenRouter، وبـ ai@^4.3.19 لـ Ollama. يستخدم OpenRouter الحزمة @ai-sdk/openai موجَّهة إلى عنوان OpenRouter الأساسي. ابتداءً من @ai-sdk/openai 2، يستهدف الاستدعاء الافتراضي openai(modelId) واجهة Responses API، التي لا ينفّذها OpenRouter، ولذلك يطلب OpenRouterProvider نموذج Chat Completions (provider.chat(modelId)) على كل إصدار رئيسي؛ وهو يعمل على ai 4 و6 و7 مع الاقتران المذكور أعلاه. يأخذ OllamaProvider عنوان الخادم الأساسي (baseURL، أو OLLAMA_BASE_URL في حالة resolveProvider()) ويُلحق /api بالمضيف المجرد، كما تتوقعه حزمتا Ollama كلتاهما: http://host:11434 وhttp://host:11434/ يصبحان http://host:11434/api. العنوان الذي ينتهي أصلًا بـ /api (أو /api/)، أو فيه أي مسار آخر مثل بادئة وكيل عكسي، يُستخدم كما هو. يختار generate() وstream() شكل الاستدعاء بحسب وحدة ai المثبَّتة: حين تصدّر stepCountIs (الإصدار v5 وما بعده)، يُرسَل الطلب بشكل v6/v7 وتُقرأ النتيجة وتُحوَّل إلى GenerateResult أو StreamResult نفسيهما:
  • تتحوّل الرسائل إلى كائنات ModelMessage: وسائط استدعاء الأداة تصبح input الخاص به، ونتيجة الأداة تصبح output (json أو text، وerror-json أو error-text حين تفشل الأداة)، وmimeType في جزء الصورة أو الملف يصبح mediaType. تبقى رسائل النظام في مواضعها (allowSystemInMessages).
  • يُرسَل maxTokens باسم maxOutputTokens، والخطوة الواحدة بالشكل stopWhen: stepCountIs(1)، والأدوات باسم inputSchema (مخطط zod كما هو، ومخطط JSON Schema عبر jsonSchema()) دون execute، وresponseFormat على هيئة output بوضع JSON لا يمسّ نص الرد.
  • يأتي الاستهلاك من inputTokens / outputTokens / totalTokens، مع cachedInputTokens من inputTokenDetails.cacheReadTokens وreasoningTokens من outputTokenDetails.reasoningTokens.
  • يقرأ stream() المجرى fullStream الخاص بـ AI SDK على أي من الإصدارين الرئيسيين ويحوّله إلى القطع (chunks) نفسها: text-delta (في v6/v7 الحقل text، وفي v4 الحقل textDelta)، وtool-call (الاستدعاء الكامل الذي يرسله v6/v7 بعد tool-input-start/-delta/-end، أو استدعاء يُجمَّع من ذلك الإدخال حين لا يرسل النموذج استدعاءً كاملًا)، وfinish مع سبب الانتهاء الذي تعطيه AI SDK والاستهلاك المذكور أعلاه (في v6/v7 الحقل totalUsage). جزء error يجعل المجرى يُرفض بخطئه، على v4 أيضًا (كان v4 ينهي مجرى كهذا بسبب الانتهاء error)، وجزء abort يرفضه بسبب الإشارة. تغيّرات الاستدلال الجزئية (deltas) يُبلَّغ عنها قطعًا من النوع reasoning-delta وتظهر أحداثًا reasoning.* (انظر الاستدلال).
على v6/v7 يجب أن يأتي النموذج من حزمة مزوّد خاصة بذلك الإصدار الرئيسي (الجدول أعلاه)؛ فحزم 0.0.x/1.x تنتج نماذج يرفضها ai v7. تُرسَل أجزاء الصور كأجزاء image، وهي ما يقبله ai v7 مع تحذير إهمال لكل جزء (globalThis.AI_SDK_LOG_WARNINGS = false يوقف تحذيرات ai). الإصدار ai v5 غير مدعوم.

أين يعمل كل مزوّد

كل المزوّدين يعملون على Node. هدف النشر cloudflare-worker يدعم mock وopenai وanthropic؛ أما ollama وopenrouter فيحتاجان إلى الهدف node-server أو docker (انظر النشر).