Skip to main content
النموذج وحده لا يستطيع أن يخبرك بما يوجد على الصفحة الأولى لموقع Hacker News الآن. لفعل ذلك يحتاج إلى أدوات، وعلى أحدهم أن يبني تلك الأدوات ويصونها. Apify فعلت ذلك بالفعل: فهي تستضيف آلاف الـ Actors التي تكشط المواقع، وتزحف على الوثائق، وتسحب بيانات منظّمة، وتكشفها عبر Model Context Protocol. هذا المزيج مناسب تمامًا لـ Venice. تُوفّر Venice استدعاء دوال متوافقًا مع OpenAI دون الاحتفاظ بأي بيانات، وتُوفّر Apify الأدوات، وMCP هو صيغة الاتصال بينهما. لا تكتب كاشطًا لكل موقع — تتصل مرة واحدة وتدع النموذج يختار الـ Actor. في هذا الدرس، سنبني وكيل طرفية بلغة Python يفعل ذلك بالضبط. في النهاية، سيكون لديك CLI يكتشف نموذج استدعاء دوال من Venice وقت التشغيل، ويُحمّل كتالوج أدوات Apify عبر MCP، ويبثّ الإجابات إلى طرفيتك، ويستأذنك قبل أن ينفق مالًا على تشغيل Actor. مهتم بالتنفيذ الكامل للكود؟ اطّلع على مستودع GitHub. قبل أن نُكمل، ستحتاج إلى مفتاح Venice API:

ما الذي نبنيه

التنفيذ المرجعي هو حزمة Python صغيرة بمهمّة واحدة لكل وحدة: يمرّ السؤال الواحد عبرها هكذا:
  1. اسأل Venice عن نموذج استدعاء الدوال الحالي، ما لم تكن ثبّتّ واحدًا.
  2. اتصل بخادم Apify MCP واسرد أدواته.
  3. أعِد كتابة أدوات MCP تلك في هيئة تعريفات دوال متوافقة مع OpenAI.
  4. أرسل السؤال مع قائمة الأدوات مرفقة.
  5. إذا أعاد النموذج tool_calls، شغّلها على Apify وألحق النتائج كرسائل tool.
  6. كرّر حتى يجيب النموذج بنص بدلًا من استدعاء أداة.
الخطوات من 4 إلى 6 هي الوكيل بأكمله. كل ما عدا ذلك موجود لجعل تلك الخطوات الثلاث آمنة وممتعة الاستخدام.
يستطيع هذا الوكيل إنفاق حوسبة Apify على حسابك. ابدأ دون APIFY_TOKEN إن كنت تريد أدوات البحث والوثائق فقط، ولا تُفعّل --yes حتى تنوي فعلًا تشغيل Actors.

إعداد المشروع

يستخدم المشروع المرجعي Python 3.12+ وuv. أنشئ مشروعًا جديدًا:
ثبّت التبعيات:
هذه httpx2، أي سلسلة الإصدارات 2.x من httpx، التي يعتمد عليها كلٌّ من openai وmcp أصلًا. تثبيتها مباشرة يجنّبك أن ينتهي بك الأمر بعميلَي HTTP في البيئة نفسها. ثم أنشئ ملف .env:
يأتي VENICE_API_KEY من إعدادات Venice API. ويأتي APIFY_TOKEN من Apify Console وهو اختياري — سنشرح ما تحصل عليه بدونه بعد قليل.

تحميل التهيئة

الإعدادات تأتي أولًا لأن كل وحدة أخرى تأخذها كوسيط. سنستخدم pydantic-settings حتى تصبّ متغيرات البيئة و.env ورايات CLI جميعها في كائن واحد مُتحقَّق منه. في src/venice_terminal_agent/config.py، تحمل فئة Settings(BaseSettings) الحقول المهمة:
اثنان من هذه الحقول يحملان قرارات لا مجرّد قيم افتراضية. venice_model هو None بدلًا من مُعرّف نموذج، وسنعود إلى ذلك في القسم التالي. أما max_rounds مع max_tool_result_chars فهما الحدّان اللذان يوقفان وكيلًا انفلت عقاله: الأول يُقيّد عدد جولات الأدوات التي قد يستهلكها سؤال واحد، والثاني يُقيّد مقدار ما يُعاد إدخاله في السياق من صفحة مكشوطة. الدالة المثيرة للاهتمام في هذه الوحدة هي بانية الروابط:
يقبل خادم Apify MCP المستضاف مُعامل استعلام tools يُحدّد الأدوات التي يُعلن عنها. دون APIFY_TOKEN نطلب الأدوات المجهولة الأربع التي تعمل دون مصادقة — البحث عن Actors، وتفاصيل Actor، والبحث في الوثائق، وجلب الوثائق. هذا يعني أن أي شخص يستطيع استنساخ المشروع وإضافة مفتاح Venice فقط، ومع ذلك يحصل على وكيل عامل يستطيع البحث عن Apify Actors. لكنه لا يستطيع تشغيل أي منها.

التحدث إلى Venice

Venice متوافقة مع OpenAI، لذا يمكننا استخدام OpenAI SDK لإكمالات المحادثة وhttpx الخام لاستدعاء اكتشاف النماذج. أنشئ src/venice_terminal_agent/venice.py:
عميلان لواجهة API واحدة يبدو أمرًا زائدًا، لكنهما يؤديان مهمّتين مختلفتين. يمنحنا AsyncOpenAI مُساعد البثّ وtool_calls مُنمّطة مجانًا. أما عميل httpx الخام فموجود لنقاط نهاية Venice التي لا يعرفها OpenAI SDK، وهي في هذا المشروع /models/traits. مهلة المحادثة أطول بكثير من مهلة الاكتشاف عن قصد. السؤال الذي يُطلق زحفًا على الويب قد يستغرق دقيقتين بشكل مشروع تمامًا.

اكتشاف نموذج وقت التشغيل

تتبدّل مُعرّفات نماذج Venice، وتثبيت أحدها في الكود هو أسرع طريق لشحن وكيل يتعطّل بعد شهر. تُطابق GET /models/traits أسماء سمات ثابتة مع أيّ نموذج يشغل ذلك الدور حاليًا، لذا نطلب function_calling_default بدلًا من تسمية نموذج:
ترتيب الأسبقية هنا مهم: راية --model الصريحة تفوز، ثم VENICE_MODEL من البيئة، ثم استعلام السمة. وهكذا لا يحتاج المسار الافتراضي إلى أي تهيئة إطلاقًا، لكنك ما زلت تستطيع تثبيت نموذج حين تقارن السلوك بين نموذجين.
ليست كل نماذج النصوص تدعم استدعاء الدوال. طلب سمة function_calling_default يعني أنك تحصل على نموذج يدعمها، دون أن تصون قائمة بنفسك. راجع الإيقافات لمعرفة وتيرة تغيّر المُعرّفات الأساسية.

بثّ الإكمالات

أضِف الآن استدعاء الإكمال:
نبثّ حتى يرى المستخدم النص وهو يُولَّد، لكننا ما زلنا نريد الرسالة المُجمَّعة بعد ذلك — تصل استدعاءات الأدوات في شظايا عبر أجزاء كثيرة، وإعادة تجميعها يدويًا عمل مضنٍ. مدير السياق stream() في SDK يتولّى الأمرين: أحداث content.delta تُحرّك مخرجات الطرفية، وget_final_completion() تُعيد رسالة كاملة مع tool_calls مخيّطة بالفعل. الطلب نفسه تبنيه دالة منفصلة لتبقى سهلة الاختبار:
extra_body هي طريقة OpenAI SDK لتمرير الحقول التي لا يُنمذجها، وهنا يذهب venice_parameters. ضبط include_venice_system_prompt على false يُبقي موجّه المساعد الافتراضي في Venice خارج المحادثة، فيصبح موجّه النظام الخاص بنا هو التعليمات الوحيدة التي يتلقّاها النموذج. ولوكيل ذي قواعد أدوات صارمة، هذا ما تريده بالضبط. أرفق tools وtool_choice فقط حين توجد أداة واحدة على الأقل. إرسال مصفوفة tools فارغة طريقة لا داعي لها لإرباك النموذج. تحتوي الوحدة أيضًا على مُساعد format_http_error() يُحوّل APIStatusError أو httpx2.HTTPStatusError إلى سطر واحد يحمل رمز الحالة وجسم الاستجابة. يفشل الوكلاء عند حدود واجهة API أكثر من أي مكان آخر، ورسالة مقروءة هناك توفّر الكثير من التخمين.

تحويل أدوات MCP إلى أدوات Venice

تصف أدوات MCP وأدوات الدوال بأسلوب OpenAI الشيءَ نفسه بشكلين مختلفين. لكلٍّ منهما اسم ووصف ومخطط JSON للوسائط. الترجمة ميكانيكية في معظمها، مع مطبّ واحد: أسماء أدوات Apify تتضمّن محارف لا تسمح بها أسماء الدوال. قد تُسمّى أداة Actor باسم apify/rag-web-browser، وتلك الشرطة المائلة غير صالحة. لذا نُعقّم الأسماء في طريق الخروج ونحتفظ بخريطة كي نستطيع استعادتها في طريق العودة. في src/venice_terminal_agent/tools.py، تتولّى ToolCatalog الترجمة وتحمل الخريطة:
ثلاثة مُساعدات صغيرة تؤدي العمل غير البرّاق. sanitize_tool_name() تستبدل بالمحارف غير المشروعة شرطاتٍ، وتُسبق الأسماء التي تبدأ برقم ببادئة، وتقتطع إلى 64 محرفًا. ثم تُلحق unique_name() لاحقة رقمية إن تسبّب ذلك الاقتطاع في تصادم Actor مع آخر — وهو ما يجنّبك علّة مربكة حقًا يستدعي فيها النموذج Actor فيعمل Actor مختلف. أما tool_input_schema() فتتعامل مع خوادم MCP التي تُعيد dict أو نموذج Pydantic أو لا شيء إطلاقًا.

تنسيق النتائج وإعادتها إلى السياق

تذهب نتائج الأدوات مباشرة إلى المحادثة، لذا يجب أن تكون سلسلة نصية، ويجب أن يكون لها حدّ حجم. كشط موقع وثائق قد يُعيد بسهولة نصًا أكبر مما تتّسع له نافذة السياق. تُفضّل format_tool_result() حقل structured_content حين يوفّره الخادم، وإلّا تُسطّح كتل المحتوى إلى نص، متعاملةً مع الكتل التي ليست TextContent. وتنتهي بالسطرين المهمّين:
إشعار الاقتطاع مكتوب للنموذج، لا لك. إخباره بأن المحتوى قُصّ واقتراح مرشّحات أو حدود أو إزاحات يكفي عادةً ليُجري استدعاءً ثانيًا أضيق بدلًا من افتراض أنه رأى كل شيء. الأخطاء تُغلَّف كـ {"error": "..."} بدلًا من رفعها. استدعاء الأداة الفاشل معلومة يستطيع النموذج التصرّف بناءً عليها — يمكنه اختيار Actor مختلف أو إصلاح وسائطه — ولا يستطيع فعل ذلك إلا إذا وصله الفشل كنتيجة أداة اعتيادية.

وسم الأدوات التي تُكلّف مالًا

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

الاتصال بـ Apify عبر MCP

تقدّم Apify طريقين للدخول. الخادم المستضاف على https://mcp.apify.com يتحدث Streamable HTTP، و@apify/actors-mcp-server يعمل محليًا عبر stdio بواسطة npx. سندعم كليهما، لأنهما يناسبان حالتين مختلفتين: المستضاف لا يحتاج إلى Node.js، وstdio يُبقي الاتصال على جهازك. في src/venice_terminal_agent/apify_mcp.py، تُغلّف فئة ApifyMcp الجلسة المتصلة. ودالتها call_tool() هي حيث يُترجم الاسم المُعقَّم عائدًا — تُرسل Venice الاسم apify-rag-web-browser، وتستقبل Apify الاسم apify/rag-web-browser:
بناء الكتالوج يحتاج إلى حلقة مؤشّر (cursor) فوق client.list_tools()، لأن رمزًا مميزًا يملك وصولًا إلى Actors كثيرة يُنتج قائمة مُقسَّمة على صفحات.

امتلاك الناقل

اتصال MCP مورد غير متزامن طويل العمر، وكذلك عميل HTTP الذي تحته. يحمل مدير السياق غير المتزامن ApifyMcpSession كليهما في AsyncExitStack، ويختار ناقلًا بناءً على الإعدادات، ويُحمّل الكتالوج. التفصيلة الجديرة بالنسخ هي التنظيف:
هذا الـ except BaseException أهمّ مما يبدو. إن فشل سرد الأدوات بعد أن أصبح الناقل قائمًا، فبدونه تُسرّب عملية فرعية أو مقبسًا مفتوحًا في كل مرة يفشل فيها الوكيل في البدء. إليك الناقلين:
لاحظ مهلة القراءة البالغة 300 ثانية على ناقل HTTP. تشغيلات الـ Actors بطيئة، ومهلة الثلاثين ثانية الافتراضية ستقطع زحفًا سليمًا تمامًا. ولاحظ أيضًا أن عملية stdio الفرعية لا تحصل في بيئتها إلا على APIFY_TOKEN، لا على بيئة الصدفة كاملة — بما فيها مفتاح Venice الخاص بك.

تنفيذ استدعاء أداة

القطعة الأخيرة في هذه الوحدة، execute_venice_tool_call()، تُحوّل استدعاء أداة من Venice إلى نتيجة نصية. تُغلّف صنفَي الفشل كليهما — الوسائط غير القابلة للتحليل واستدعاء Apify الفاشل — كـ {"error": "..."} بدلًا من الرفع:
وسائط JSON المشوّهة تحدث. وحين تحدث، فإن تسليم النموذج {"error": "invalid arguments: ..."} يمنحك استدعاءً مُصحّحًا في الجولة التالية، في حين أن رفع الاستثناء يقتل الجلسة ويُضيّع المحادثة.

تشغيل حلقة الأدوات

والآن إلى الوكيل نفسه، في src/venice_terminal_agent/agent.py. ابدأ بموجّه النظام:
كل قاعدة هناك تقابل فشلًا محددًا نريد تجنّبه. قاعدة “فضّل search-actors وfetch-actor-details قبل استدعاء Actor غير مألوف” موجودة لأن النموذج الذي يُخمّن مخطط إدخال Actor يُهدر تشغيلًا مدفوعًا. وسطر الأدوات المرفوضة موجود لأن النموذج بدونه يعامل الرفض كخطأ عابر ويحاول مجددًا على الفور. تأخذ فئة Agent العميلين، ونموذجًا، وحدًّا للجولات، وثلاث دوال استدعاء راجع:
دوال الاستدعاء الراجع تلك هي ما يُبقي الوكيل مستقلًّا عن الطرفية. on_tool تُبلّغ عن استدعاء أداة، وon_text تستقبل الرموز المبثوثة، وapprove_tool تجيب عن سؤال التأكيد. استبدلها ويعمل الوكيل نفسه خلف تطبيق ويب أو روبوت محادثة. إليك الحلقة:
هذا هو الوكيل بأكمله: استدعِ النموذج، وإن طلب أدوات، شغّلها واستدعِه مجددًا. فهرس start وعبارة del في مُعالج الاستثناء يستحقّان نظرة أقرب. إن فشل سؤال في منتصف الطريق — خطأ شبكة، أو Ctrl+C، أو بلوغ حدّ الجولات — تبقى المحادثة حاملةً دورَ مساعدٍ يطلب أدوات لم تُنتج نتائج قط. وسترفض Venice الطلب التالي، لأن دور tool_calls يجب أن تتبعه رسائل tool مطابقة. التراجع إلى نقطة بداية السؤال يعني أن السؤال الفاشل لا يترك أثرًا وأن REPL يبقى قابلًا للاستخدام.

إرجاع دور المساعد كما هو

هذه الدالة التالية صغيرة ويسهل الوقوع في خطئها:
التنفيذ البديهي هو message.model_dump(exclude_none=True)، وهو يُعطّل استدعاء الأدوات. دورُ استدعاء الأدوات يحمل content: null، وإسقاط ذلك المفتاح يُغيّر شكل الرسالة التي تُعيد إرسالها. exclude_unset=True هو الخيار الذي تريده: فهو يُبقي قيم null التي ضبطها النموذج فعلًا، ويحذف الحقول التي لم يُرسلها قط. كما أنه يحافظ على حقول لا يعرفها مخطط OpenAI. تُعيد نماذج الاستدلال الحقلين reasoning_content وreasoning_details، ويجب أن يصمدا في رحلة الذهاب والعودة كي يحتفظ النموذج بسلسلة تفكيره عبر جولات الأدوات.

تنفيذ الاستدعاءات وحراستها

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

إضافة واجهة CLI

واجهة CLI في src/venice_terminal_agent/cli.py هي Typer زائد REPL، وهي أقل ملفات المشروع إثارة — لكن ثلاث تفاصيل فيها تستحق النسخ. الأولى أن خيارات Typer مُنمّطة كاختيارية وتأخذ افتراضيًا None، حتى يستطيع مُحمّل الإعدادات التمييز بين “لم يُمرَّر” و”مُرِّرت قيمة زائفة”:
قيم None الافتراضية تلك هي ما يجعل التسليم إلى load_settings() آمنًا، إذ إن راية لم تستخدمها لا تتجاوز البيئة أبدًا:
عبارة yes or None هي الفكرة نفسها مطبّقة على راية منطقية: --yes تضبطها، وإغفالها يُمرّر None بدلًا من False، فتنجو AUTO_APPROVE_TOOLS القادمة من البيئة. الثانية هي ترتيب البدء. استبِن النموذج، ثم افتح جلسة MCP، ثم ابنِ الوكيل — وأغلق عميل Venice في finally، لأن جلسة MCP وعملاء HTTP كليهما يحتاجان إلى التفكيك سواء نجح السؤال أم لا:
الثالثة هي المُوافِق، وهو الجزء الوحيد من الوكيل الموجود حصرًا لحماية فاتورة Apify الخاصة بك:
فحص isatty() هو الجزء الذي ينساه الناس. شغّل الوكيل من cron أو CI ولن يكون هناك من يجيب عن المطالبة، فينتهي التنفيذ الساذج إما بتعليق أبدي وإما بموافقة صامتة. هنا يرفض، ويقول لماذا، ويدع النموذج يُكمل بأدوات القراءة فقط. وdefault=False تعني أن ضغطة Enter شاردة لا تبدأ تشغيلًا مدفوعًا، وأن مقاطعة المطالبة تُحسب رفضًا. بقية الوحدة عمل طرفية اعتيادي، لذا يكفي أن تعرف ما فيها بدلًا من قراءتها: حلقة REPL بواسطة prompt_toolkit، وجدول _handle_command() لأوامر الشرطة المائلة، وملف render.py من مُساعدات Rich، ودالة _settings_error() تُحوّل غياب VENICE_API_KEY إلى رسالة مقروءة بدلًا من تتبّع مكدّس Pydantic. ثلاثة من تلك الأجزاء تحمل قرارًا: أوامر الشرطة المائلة هي /help و/clear و/quit واثنان يستحقّان وجودهما: /tools يطبع الكتالوج المُحمَّل، وهو ما يفسّر عادةً سبب اختيار الوكيل أداةً غريبة، و/reload يلتقط الـ Actors التي أضفتها إلى حساب Apify في منتصف الجلسة. أخيرًا، اربط نقطة الدخول في pyproject.toml حتى يعمل uv run venice-agent:

تشغيل الوكيل

ابدأ جلسة تفاعلية:
أو اسأل سؤالًا واحدًا واخرج:
سترى الشعار، ثم استدعاءات الأدوات لحظة حدوثها:
اقرأ سطر Apify في ذلك الشعار قبل أي شيء آخر. إن كان يقول “anonymous Apify tools only”، فإن APIFY_TOKEN لم يُحمَّل، وملاحظة ذلك الآن أفضل بكثير من ملاحظته بعد عشر دقائق من التساؤل عن سبب رفض الوكيل تشغيل Actor. قيّد كتالوج الأدوات حين تعرف ما تحتاج إليه:
الكتالوج الأصغر ليس مسألة كلفة فحسب. تختار النماذج عمومًا اختيارًا أفضل حين تكون الأدوات المتاحة أقلّ وأوثق صلة، و--tools هي أرخص طريقة لتضييق الخيار. شغّل خادم MCP محليًا بدلًا من استخدام المستضاف:
هذا الخيار يحتاج إلى Node.js على PATH لديك، لأنه يُطلق @apify/actors-mcp-server عبر npx، ويحتاج إلى APIFY_TOKEN — لا يوجد وضع مجهول للخادم المحلي. وحين تريد فعلًا تشغيلات Actor دون إشراف:

اختبار الأجزاء

لا شيء من المنطق المثير هنا يحتاج إلى شبكة. FakeVenice تسحب من قائمة ردود مُعدّة سلفًا، مع FakeApify تبني ToolCatalog حقيقيًا من أدوات SimpleNamespace، يكفيان لتشغيل جولة أدوات كاملة:
التأكيد على تسلسل الأدوار عادة جيدة في كود الوكلاء. فهو يلتقط عِلل المحادثة المشوّهة التي تبقى خفية إلى أن تُعيد Venice خطأ 400. ثلاثة اختبارات أخرى تستحقّ الكتابة، وجميعها تؤكّد على agent.messages بالطريقة نفسها. أنّ التشغيل الفاشل يُرجع السجلّ إلى ["system"] فقط، سواء فشل بخطأ من Venice أو باستنفاد max_rounds. وأنّ أداة القراءة فقط تعمل مع ذلك حين يُعيد المُوافِق False. وأنّ الأداة المدفوعة المرفوضة تترك رسالة tool تحتوي على declined بينما تبقى apify.calls فارغة. شغّل مجموعة الاختبارات بـ:

ملاحظات الخصوصية والكلفة

وكيل يصل إلى واجهتَي API يستحقّ الدقة في وصفه: تُغطّي سياسة Venice في عدم الاحتفاظ بأي بيانات جانبَ النموذج. وهي لا تُغطّي Apify، وتشغيل Actor يكتب النتائج في حساب Apify الخاص بك. إن كان ذلك مهمًّا لمهمّة معيّنة، فاعمل دون APIFY_TOKEN والتزم بأدوات الاكتشاف المجهولة. أما في الكلفة، فثلاث عادات تُحقّق الكثير:
  • أبقِ --yes مُعطَّلة أثناء التطوير. مراقبة الـ Actors التي يريد النموذج تشغيلها مفيدة في حدّ ذاتها.
  • استخدم --tools لتضييق الكتالوج إلى Actors راجعتها فعلًا.
  • أبقِ max_rounds متواضعًا. اثنتا عشرة جولة أكثر من كافية لمهام البحث، وسقف أدنى يحدّ من الضرر حين يعلق نموذج في حلقة.

توسيع هذا المثال

الحلقة هي الأساس. وحين تعمل، تشمل الاتجاهات المفيدة:
  • أضِف خادم MCP ثانيًا. لا شيء في Agent خاص بـ Apify، لذا فإن دمج الكتالوجات من عدة خوادم يعني في معظمه وضع مساحات أسماء لأسماء الأدوات.
  • خزّن المحادثات في SQLite لتستطيع استئناف جلسة أو مراجعة ما أعاده Actor.
  • أضِف ميزانيات لكل أداة تتعقّب تشغيلات الـ Actors وتتوقّف عند سقف، بدلًا من تأكيد كل تشغيل على حدة.
  • خزّن نتائج الأدوات مؤقتًا حسب الاسم والوسائط، حتى لا تُعيد عمليات البحث المتكرّرة في الوثائق الزحف من جديد.
  • ثبّت نموذجًا بـ --model وقارن جودة اختيار الأدوات مع function_calling_default.
  • استبدل بالمُوافِق دالةَ سياسة تعتمد Actors محدّدة بوسائط محدّدة تلقائيًا وتسأل عن كل ما عداها.
لنقطة بداية أصغر دون MCP، يشرح بناء وكيل يستخدم الأدوات الحلقة نفسها بثلاث دوال Python محلية.

الختام

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