مقالات معمّقة حول التكنولوجيا التي تشكّل المستقبل.

تشغيل وكلاء AI ذوي حالة على Serverless مع Talorys

كيف تشغّل وكيل ذكاء اصطناعي له حالة على بنية Serverless بلا حالة؟ يستخدم Talorys Cloudflare Workers وDurable Objects وSQLite ضمن الخطة المجانية.

رسم توضيحي لمنزل صغير مربوط بمكعب متوهج واحد داخل شبكة لا نهائية من كتل تشبه الخوادم.
وكيل واحد، كائن واحد، حساب واحد: التطبيق كله يعيش داخل Durable Object واحد على شبكة شخص آخر.

هذا رأيي المخالف للمألوف، وسأدافع عنه: وكيل الذكاء الاصطناعي الشخصي يناسب البنية التحتية بلا خوادم (serverless) أكثر بكثير مما يناسب Raspberry Pi الموضوع تحت مكتبك. مشروع Talorys، وهو مساعد شخصي مفتوح المصدر ينشر نفسه في حساب Cloudflare الخاص بك بأمر واحد npx create-talorys@latest، هو أفضل دليل حتى الآن على أن مشكلة وكيل ذكاء اصطناعي ذي حالة فوق بنية serverless عديمة الحالة ليست قابلة للحل فحسب، بل ملائمة لها بطبيعتها. أما جمهور Hacker News الذي يتجادل حول ما إذا كان يُعد «مستضافاً ذاتياً»، فهو يناقش السؤال الخطأ تماماً.

قضيت سنوات في تشغيل البنية التحتية وتنظيف ما تخلّفه. ما يقتل البرمجيات الشخصية المستضافة ذاتياً ليس عملية النشر، بل الشهر الثالث: حين تمتلئ الأقراص بالسجلات، وتنتهي صلاحية شهادة TLS، ولا تتذكر أي وحدة systemd مسؤولة عن الجدولة. يتجنب Talorys فئة الأعطال هذه كلها بعدم وجود خادم أصلاً. كل ما يحتاجه، من المحادثة والذاكرة والمهام إلى التذكيرات المجدولة، يعمل على الخطة المجانية لـ Cloudflare: Pages للواجهة، وWorker خاص للـ API، وDurable Object مدعوم بـ SQLite لكل الحالة، وWorkers AI للنموذج. التكلفة الشهرية الإجمالية لمستخدم واحد: صفر.

المشكلة الحقيقية: الوكلاء ذوو حالة، وServerless ليس كذلك

وكيل الذكاء الاصطناعي حزمة من حالة طويلة الأمد تتظاهر بأنها تطبيق طلب-استجابة. يحتاج إلى سجل المحادثات، وذكريات دائمة، وقائمة مهام، ومهام مجدولة تعمل الساعة 7 صباحاً سواء كان أحد مسجلاً للدخول أم لا، ومكان يحفظ فيه مخرجات الأدوات أثناء تنفيذ سلسلة من عدة خطوات. كل جزء من ذلك معادٍ لنموذج Serverless الكلاسيكي، حيث تكون دالتك كسمكة ذهبية: تستيقظ، وتعالج طلباً واحداً، ثم تنسى كل شيء.

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

يتخذ Talorys الرهان المعاكس: ضع كل الحالة في مكان واحد. Durable Object واحد، باسم personal-agent، يحتفظ بالعالم كله، أي المحادثات والذكريات والمهام والملاحظات والمشاريع والأتمتة والجلسات والإعدادات وتتبع الاستخدام، داخل قاعدة بيانات SQLite المضمنة فيه. لا KV ولا D1 ولا R2 ولا Vectorize، ويوضح README أن أياً منها غير مُهيّأ. هذا ليس صدفة، بل هو جوهر المعمارية.

Durable Objects هي الحل السحري

Durable Objects هي أكثر الأدوات الهادئة ثورية في الحوسبة السحابية حالياً، ولا أظن أن في هذا مبالغة. الـ Durable Object قطعة كود بنسخة واحدة، لها تخزين متسق بقوة وتعاملات (transactions) موجود فعلياً بجانبها. حين يصل طلب موجّه إلى الكائن personal-agent، يوقظ Cloudflare ذلك الكائن، في أجزاء من الثانية ومن حالة السكون، ويشغّل كودك على SQLite المحلية الخاصة به، ثم يجمّده من جديد حين يخمل. تحصل على راحة عملية الخادم طويلة الأمد مع نموذج فوترة يشبه Lambda.

بالنسبة لوكيل شخصي لمستخدم واحد، تتحول القيود الشهيرة لهذا النموذج إلى مزايا:

  • الكاتب الواحد ميزة. مستخدم واحد يعني كاتباً واحداً. يختفي كل رعب التزامن في الحالة متعددة المستأجرين، وتحصل مجاناً على وصول متسلسل ومتعامَل معه لكل شيء.
  • التموضع المشترك يقضي على زمن الاستجابة. استعلامات ذاكرة الوكيل وبحث المهام وسجل المحادثات كلها قراءات SQLite من القرص المحلي، لا رحلات شبكية ذهاباً وإياباً إلى قاعدة بيانات في منطقة توفر أخرى.
  • المنبّهات تحل محل cron. تتيح منبّهات Durable Object للكائن جدولة إيقاظه بنفسه. تعمل التذكيرات والروتينات المتكررة والملخصات اليومية دون بقاء أي جهاز متصلاً: ينام الكائن، فيوقظه المنبه، ينجز مهمته، ثم يعود إلى النوم.
  • السكون مجاني. وقت الخمول لا يكلّف شيئاً. المساعد الشخصي الذي يخمل 23 ساعة يومياً هو بالضبط نوع الحمل الذي وُلدت له تسعيرة serverless.

هذه هي الفكرة التي أتمنى أن يأخذها المزيد من الناس من هذا المشروع. إذا كان تطبيقك بطبيعته لمستخدم واحد، مثل أداة شخصية أو مساحة عمل لكل عميل أو منسّق لكل جهاز، فنمط «Durable Object واحد لكل مستأجر» يمنحك ما كان يتطلب خادماً خاصاً افتراضياً (VPS): حاسوب صغير يعمل مفاهيمياً دائماً، ولا يكلّف شيئاً في وضع الخمول، ولا يحتاج إلى مدير نظام. قصة الجدولة وحدها تستحق ثمن الدخول. كل من شغّل صندوق cron شخصياً يعرف نمط الفشل: يعيد الصندوق التشغيل، فلا يعود الـ cron daemon، ولا تكتشف إلا بعد أسبوعين أن تذكيراتك توقفت بصمت. المنبهات جدولة تملكها البنية التحتية نفسها، وهذا شيء أقل تحتاج إلى مراقبته.

بنية الشبكات أفضل من معظم إعدادات الإنتاج

هنا الجزء الذي أيقظني، وأنا قادم من خلفية أمنية. وكيل Worker في Talorys منشور بخاصيتي workers_dev: false وpreview_urls: false. ليس له أي عنوان URL عام على الإطلاق. المتصفح لا يتحدث إلا مع موقع *.pages.dev، ودالة Pages عند المسار /api/* تمرر الطلبات إلى الـ Worker عبر service binding، وهو الربط الداخلي الخاص من Cloudflare بين الحوسبة داخل الحساب نفسه. المصادقة والتفويض يحدثان في الـ Worker، لا في الواجهة الأمامية.

فكّر فيما يلغيه هذا: لا نقطة API عامة لتُفحص، ولا قواعد جدار ناري لتُضبط بشكل خاطئ، ولا reverse proxy لتنسى تحديثه. سطح الهجوم لخلفية الوكيل هو عملياً: «يجب أن تمر عبر تدفق المصادقة في الواجهة الأمامية». لقد راجعت نشرات إنتاج في شركات حقيقية، لديها ميزانيات وفرق أمنية، كانت وضعيتها الشبكية أضعف من هذا المشروع الجانبي. أكثر نمط حادث شائع رأيته في بيئات السحابة هو خدمة داخلية كانت «متاحة داخلياً فقط» حتى يوم لم تعد كذلك، لأن أحدهم أخطأ في إعداد موازن التحميل. لا يمكنك أن تجعل service binding عاماً بالخطأ، فعنوان الـ URL ببساطة غير موجود.

يستحق المثبّت الإشارة أيضاً. يُجزّئ كلمة مرور المالك محلياً باستخدام PBKDF2-SHA256 ويخزن الهاش فقط كسرّ في Cloudflare، ويولّد سرّ جلسة بطول 256 بت، ويسمّي الموارد بأسماء فريدة، ثم يتحقق من النشر الحي، بما في ذلك التأكد من أن الطلبات غير المصادَقة تُرفض فعلاً، دون استهلاك أي حصة استدلال للذكاء الاصطناعي. فحص ما بعد النشر الذي يؤكد أن المصادقة تمنع غير المصادَقين هو نوع الشيء الذي كتبته في تقارير ما بعد الحوادث. ورؤيته في مثبّت بأمر واحد مفاجأة سارّة.

حصن بباب واحد محروس وغرفة داخلية مغلقة لا يصل إليها إلا جسر داخلي.
بوابة عامة واحدة، وخلفية عامة صفر: تعني service bindings أن Worker الوكيل ليس له عنوان URL يُهاجم.

العيش داخل الخطة المجانية دون خداع النفس

الخطة المجانية حقيقية، لكنها ميزانية وليست بوفيه مفتوحاً. تمنح Cloudflare الحسابات المجانية حصة يومية لـ Workers AI تُقاس بوحدات تسمى «Neurons»، أي 10,000 يومياً، إضافة إلى حصص الطلبات واستخدام Durable Objects. هذه الأرقام تحددها Cloudflare وقد تتغير. يتعامل Talorys مع هذا بصدق أكبر من معظم مشاريع «الخطة المجانية» التي رأيتها: حين تنفد حصة الذكاء الاصطناعي، تقول المحادثة ذلك بوضوح وتستأنف بعد إعادة التعيين اليومية، بينما تستمر المهام والملاحظات والذكريات والتذكيرات في العمل لأن أياً منها لا يحتاج إلى النموذج.

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

تحذير من تجارب المجتمع: يبلّغ عدة أشخاص عن مفاجآت فوترة غامضة عند الجمع بين Workers AI وخطط Workers المدفوعة، مع محاسبة Neurons لا تتطابق مع الحدود الموثقة وتذاكر دعم بلا رد. لا أستطيع التحقق من التفاصيل، لكنه يطابق نمطاً أعرفه جيداً، فوترة الذكاء الاصطناعي المقاسة مربكة في كل مكان، و«صديقة للخطة المجانية» ليست مرادفة لـ«مستحيل أن تُفوتَر». إذا نشرت هذا على خطة مدفوعة، فاضبط تنبيه إنفاق في لوحة Cloudflare من اليوم الأول. اعتبر واجهة الاستخدام لدى المزوّد المصدر الموثوق، لا تقديرات التطبيق المحلية.

جدل «الاستضافة الذاتية» يفوت الهدف

الآن، التنازل الذي تتطلبه مقدمتي. أعلى التعليقات على هذا المشروع حرب كلامية حول كلمة «مستضاف ذاتياً»، ولدى المدققين نقطة حقيقية: هذا الشيء يعتمد كلياً على Cloudflare. بياناتك تعيش في مراكز بياناتهم، واستدلالك يعمل على وحدات GPU الخاصة بهم، ولو غيّروا الخطة المجانية غداً، سيتغير مساعدك معها. تسمية ذلك استضافة ذاتية تمدّ الكلمة إلى ما بعد حدها. القراءة المتسامحة، أي لا طرف ثالث سوى حساب Cloudflare تملكه أصلاً، ولا تتبع للمطورين، ولا مشغّل في المنتصف، أدق وصفها بأنها «مملوكة ذاتياً» أو «محفوظة ذاتياً». الكلمات مهمة، ولو اختار المشروع كلمات أدق لتلقى نقداً أقل.

لكن هنا يخسرني المدققون. التهديد الفعلي للبرمجيات الشخصية ليس «قد تتغير شروط خدمة شركة»، بل تسريب البيانات، والتتبع عن بُعد، ومطوّر يُفلس ويغلق النسخة المستضافة. في الثلاثة، يتمتع Talorys بقوة حقيقية: لا يوجد كود تحليلات أو تتبع، ولا شيء يتصل بالمؤلفين، ولا توجد نسخة مستضافة لإغلاقها. وفي الوقت نفسه، الكود مرخّص بموجب MIT، وكما لاحظ أحد المعلّقين، فإن توجيه استدعاءات الذكاء الاصطناعي إلى خادم نموذج محلي تعديل صغير، بل إن المكدّس كله يعمل محلياً تحت wrangler dev مع مزوّد ذكاء اصطناعي وهمي. إذا أصبحت Cloudflare غير مقبولة يوماً، فطريق الخروج قصير. قارن ذلك بتطبيق «مستضاف ذاتياً» متوسط، وهو في الحقيقة ملف Docker Compose يسحب من سجل شخص ما، ويتصل بالمنزل للتحقق من التراخيص.

هناك أيضاً نقد أنصف مدفون في النقاش: لا يوجد دليل على أن المساعد جيد فعلاً. واجهة المحادثة، وعمليات CRUD للذاكرة، والتضمينات (embeddings)، والـ cron، كلها سهلة البناء. أما الحزام البرمجي (harness)، والتوجيه (prompting)، وسياسة استرجاع الذاكرة، ومخططات الأدوات، فهي ما يحيا به المساعد الشخصي أو يموت، ولا يوثّق أيٌّ من ذلك مخطط معمارية أنيق. هذا ينطبق على كل مشروع تقريباً في هذا النوع، وهو محلّ الشك الصحيح. قيّم Talorys كبنية تحتية، أي هيكل مصمم جيداً، لا كمساعد برمجي مثبت. وإذا كنت تفاضل نماذج لشيء كهذا، فمقالنا عن تشغيل نماذج LLM على عتادك الخاص يغطي الطرف الآخر من طيف السيادة.

ميزان نحاسي يزن قفلاً معلقاً مقابل سحابة صغيرة.
التحكم والراحة على كفتي ميزان متقابلتين، والمقايضة الصادقة هي بين الارتهان للمزوّد وعبء التشغيل.

ما الذي يجب أن تسرقه من هذا التصميم

حتى لو لم تنشر Talorys أبداً، فالمعمارية مرجع يستحق أن تستوعبه. الأفكار القابلة للنقل:

  1. كائن واحد لكل مستأجر. إذا كان تطبيقك لمستخدم واحد أو قابلاً للتقسيم بنظافة، فضع الكود والحالة معاً في Durable Object واحد، واحذف طبقة الذاكرة المؤقتة وقائمة الرسائل ومجمّع الاتصالات.
  2. لا عنوان URL عاماً للخلفية. service bindings مع workers_dev: false هي أرخص مكسب أمني في serverless. الخدمة التي لا يمكن الوصول إليها لا يمكن مهاجمتها.
  3. المنبهات أفضل من صناديق cron. الجدولة التي تعيش مع البنية التحتية تنجو من إعادات التشغيل وإعادات النشر وإهمالك لنفسك.
  4. تدهور واعٍ بالحصص. صمّم التطبيق بحيث تستطيع التبعية المكلفة (النموذج) أن تفشل أو تنفد بينما يستمر المنتج الأساسي في العمل. يجب أن يكون التدهور ميزة، لا انقطاعاً.
  5. ترحيلات بالإلحاق فقط (Append-only). لا يُعاد إنشاء فضاء أسماء Durable Object عند التحديث، وتعمل ترحيلات المخطط بشكل تعاملي عند أول طلب. هكذا تحدّث serverless ذا الحالة دون مقامرة بفقدان البيانات.

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