إنشاء واجهات متقدمة للذكاء الاصطناعي باستخدام Chainlit كبديل متخصص لـ Streamlit

دقائق القراءة: 5

لماذا يُعد Chainlit خياراً متخصصاً لبناء واجهات الذكاء الاصطناعي؟

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

من منظور هندسي، فإن Chainlit لا ينافس Streamlit في كل شيء، بل يتموضع كأداة متخصصة عندما يكون التطبيق عبارة عن وكيل ذكي، نظام RAG، أو واجهة محادثة تحتاج إلى إبراز دورة التفكير، استدعاء الأدوات، أو إظهار المصادر المسترجعة من Vector DB. هذا التخصص يقلل كثيراً من الجهد الذي يبذله المطور في كتابة طبقة الواجهة يدوياً.

البنية المعمارية لتطبيق Chainlit في مشاريع LLM

لفهم قيمة Chainlit، يجب النظر إلى تدفق البيانات داخله. تبدأ الرحلة من رسالة المستخدم في الواجهة، ثم تنتقل إلى معالج حدث مثل @cl.on_message. بعد ذلك يمكن تمرير النص إلى سلسلة LangChain، أو إلى نموذج مباشر عبر API، أو إلى خط معالجة مركب يشمل الاسترجاع والذاكرة والتحقق من المخرجات.

المكونات الرئيسية في هذا التدفق

  • واجهة المحادثة لاستقبال السؤال وعرض الردود.
  • طبقة الأحداث لمعالجة كل رسالة أو بداية جلسة.
  • منطق التطبيق، وقد يحتوي على Chains أو Agents.
  • طبقة الذاكرة لتخزين السياق القصير أو الطويل.
  • طبقة الاسترجاع من المستندات أو قواعد البيانات.
  • طبقة الإخراج لعرض النص، المصادر، الملفات، أو الخطوات الوسيطة.

هذا الفصل الواضح بين الواجهة والمنطق يسهّل لاحقاً اختبار النظام، مراقبة الأداء، وربطه بمزودات مختلفة مثل OpenAI أو Ollama أو نماذج سحابية أخرى.

متى يكون Chainlit أفضل من Streamlit؟

إذا كان هدفك بناء لوحة بيانات، رفع ملفات مع رسوم بيانية وجداول متعددة، فإن Streamlit ممتاز. أما إذا كان التطبيق يدور حول محادثة تفاعلية متقدمة تشبه ChatGPT أو وكيل يستخدم أدوات ويعرض خطواته، فإن Chainlit غالباً أكثر كفاءة.

  • يوفر دعماً طبيعياً للمحادثات متعددة الرسائل.
  • يدعم Streaming Tokens بشكل سهل.
  • يُظهر خطوات التنفيذ والعمليات الوسيطة للمطور والمستخدم.
  • أسهل في دمج الذاكرة، الوكلاء، ونتائج RAG Pipeline.

البدء العملي: تثبيت البيئة وبناء تطبيق محادثة أولي

قبل كتابة الكود، تأكد من تجهيز البيئة كما شرحنا في إعداد بيئة العمل الذكية: تثبيت مكتبات Python الأساسية للتعامل مع الذكاء الاصطناعي، ثم ثبّت الحزم المطلوبة. الفكرة هنا أن Chainlit يعمل كخادم واجهة، بينما ينفذ Python منطق الذكاء الاصطناعي خلف الكواليس.

pip install chainlit openai langchain langchain-openai

ثم أنشئ ملفاً مثل app.py واكتب داخله تطبيقاً أولياً:

import os
import chainlit as cl
from openai import AsyncOpenAI

client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))

@cl.on_chat_start
async def start():
    await cl.Message(content="مرحباً، أنا مساعدك الذكي المبني باستخدام Chainlit.").send()

@cl.on_message
async def main(message: cl.Message):
    response = await client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "أنت مساعد تقني دقيق ومختصر."},
            {"role": "user", "content": message.content}
        ],
        temperature=0.3
    )

    answer = response.choices[0].message.content
    await cl.Message(content=answer).send()

تشغيل التطبيق يكون عبر الأمر التالي:

chainlit run app.py

إضافة Streaming لتحسين تجربة المستخدم

من أهم أسباب تميز Chainlit أنه ينسجم مع مفهوم البث المباشر للردود، وهو ما شرحناه تقنياً في البث المباشر للردود (Streaming Responses): كيف تجعل الكلمات تظهر تباعاً مثل ChatGPT؟. هذا الأسلوب لا يحسن الانطباع البصري فقط، بل يقلل الإحساس بزمن الانتظار، خصوصاً في الردود الطويلة أو عند استخدام سلاسل مركبة.

import os
import chainlit as cl
from openai import AsyncOpenAI

client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))

@cl.on_message
async def main(message: cl.Message):
    msg = cl.Message(content="")
    await msg.send()

    stream = await client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "أنت مساعد برمجي يشرح خطوة بخطوة."},
            {"role": "user", "content": message.content}
        ],
        stream=True
    )

    async for part in stream:
        token = part.choices[0].delta.content or ""
        if token:
            await msg.stream_token(token)

    await msg.update()

دمج LangChain وذاكرة المحادثة داخل الواجهة

القوة الحقيقية تظهر عندما تربط الواجهة بسلاسل ذكية وذاكرة سياقية. يمكنك الاستفادة من مفاهيم الذاكرة في الذكاء الاصطناعي وBuffer Memory حتى لا يتعامل النموذج مع كل رسالة بمعزل عن السابق.

import os
import chainlit as cl
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain

@cl.on_chat_start
async def start():
    llm = ChatOpenAI(
        model="gpt-4o-mini",
        temperature=0.2,
        api_key=os.getenv("OPENAI_API_KEY")
    )
    memory = ConversationBufferMemory()
    chain = ConversationChain(llm=llm, memory=memory)
    cl.user_session.set("chain", chain)

@cl.on_message
async def main(message: cl.Message):
    chain = cl.user_session.get("chain")
    result = await chain.apredict(input=message.content)
    await cl.Message(content=result).send()

هنا تحتفظ الجلسة بكائن chain لكل مستخدم، وبذلك يصبح لكل جلسة محادثة مستقلة. هذا مهم جداً في التطبيقات الإنتاجية التي تخدم عدة مستخدمين بالتوازي.

كيف نربط Chainlit مع نظام RAG؟

في أنظمة RAG، تكون الواجهة مجرد بوابة أمامية لسير عمل أكثر تعقيداً: سؤال المستخدم يذهب إلى Retriever، ثم تُستخرج المقاطع الأكثر صلة من قاعدة متجهة مبنية على Embeddings، وبعدها تُحقن داخل البرومبت المرسل إلى النموذج. هذه البنية تقلل الهلوسة وتزيد موثوقية الرد.

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

هذه الصياغة ترتبط أيضاً بممارسات الأمان وجودة الإجابات، وهي مكملة لما تناولناه في حماية تطبيقات الذكاء الاصطناعي: منع المستخدمين من التلاعب بالأوامر (Prompt Injection). وعند إظهار المقاطع المسترجعة داخل الواجهة، يصبح التطبيق أكثر شفافية للمستخدم، وهو عامل مهم في المنتجات الاحترافية.

خطوات الدمج باختصار

  • استقبال سؤال المستخدم من واجهة Chainlit.
  • تمرير السؤال إلى Retriever.
  • استرجاع المقاطع الأقرب دلالياً من قاعدة المتجهات.
  • بناء برومبت نهائي يدمج السؤال مع السياق.
  • إرسال الطلب إلى LLM.
  • عرض الجواب مع المصادر أو المستندات المرتبطة.

اعتبارات هندسية للإنتاج والجودة

عند الانتقال من نموذج تجريبي إلى تطبيق فعلي، لا يكفي أن تعمل الواجهة؛ بل يجب إدارة التكلفة والموثوقية. لذلك من المفيد الربط مع أدوات تتبع مثل LangSmith، والاهتمام بقياس Tokens، مع وضع حدود للطلبات وتخزين السجل حيث يلزم.

  • افصل مفاتيح API في متغيرات بيئة.
  • لا تُرسل كامل سجل المحادثة إذا كانت الذاكرة قابلة للتلخيص.
  • اعرض رسائل الخطأ للمطور بشكل آمن دون كشف تفاصيل حساسة للمستخدم.
  • أضف طبقة تحقق على المدخلات في التطبيقات المعتمدة على الملفات أو الأدوات.
  • جهّز التطبيق للنشر لاحقاً عبر النشر السحابي أو Docker.

الخلاصة الهندسية

Chainlit ليس مجرد بديل شكلي لـ Streamlit، بل إطار موجه بوضوح لبناء واجهات تطبيقات الذكاء الاصطناعي الحوارية. قيمته الحقيقية تظهر عندما تحتاج إلى محادثة حيّة، بث مباشر، ذاكرة، أدوات، أو تكامل عميق مع LangChain وRAG Apps. باختصار: إذا كانت واجهتك مركزها المحادثة الذكية نفسها، فغالباً سيكون هذا الإطار أكثر تخصصاً وأقل احتياجاً للحلول الالتفافية من الأدوات العامة.

1 comment

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *