نظرة عامة
تعامل التطبيقات المحادثية مع كل سطر من المستخدم كـ تشغيل flow جديد بنفس معرّف الجلسة. توفر CrewAI مساعدات لسجل الرسائل، وتوجيه النية الاختياري، وتأجيل التتبع، والبث المنظّم للجولات، إضافة إلى REPL محلي عبرflow.chat().
واجهات الجولات
استخدمflow.handle_turn(message, session_id=...) لكل رسالة مستخدم من REST أو WebSocket أو الاختبارات أو الواجهات المخصصة. استخدم flow.chat() عندما تريد حلقة دردشة محلية في الطرفية لـ Flow محادثي.
لا يقبل Flow.kickoff() الوسيطين user_message= أو session_id=. في التدفقات المحادثية، يخزن handle_turn() الرسالة المعلقة ويستدعي داخلياً kickoff(inputs={"id": session_id}) بعد إعادة ضبط حالة التنفيذ الخاصة بالجولة.
ترفع
handle_turn() وstream_turn() وchat() الخطأ ValueError ما لم يكن الوضع المحادثاتي مفعّلاً. يؤدي تطبيق @ConversationConfig(...) إلى تفعيله تلقائياً؛ وإلا فعيّن conversational = True.
بداية سريعة
بث جولة
استخدمstream_turn() عندما تحتاج واجهة مستخدم أو بيئة تشغيل إلى أحداث منظّمة لجولة دردشة واحدة. يعيد جلسة بث تحتوي على إطارات مرتبة لتوجيه Flow، وأجزاء LLM، ونشاط الأدوات، ورسائل المحادثة.
دورة حياة الجولة
يشغّل كلhandle_turn المسار التالي:
- إعداد الجولة — يخزن رسالة المستخدم المعلقة، ويحل معرّف الجلسة، ويعيد ضبط تعقّب التنفيذ الخاص بالجولة، ثم يستدعي
kickoff(inputs={"id": session_id}). - استعادة الحالة — إذا وُجد
inputs["id"]وكان@persistمهيّأً، تُحمّل أحدث لقطة. FlowStarted— في أول جولة للجلسة المؤجلة فقط.- ترطيب الجولة المعلقة — تُضاف رسالة المستخدم إلى
state.messages، وتُضبطcurrent_user_message/last_user_message، ويُجرى التصنيف اختيارياً عند ضبطintents/default_intentsمعintent_llm. - تنفيذ الرسم — طرق
@startالتي يعرّفها المستخدم (إن وجدت) →route_conversation(نقطة البدء/الموجّه المدمجة) → معالج@listenالمختار. تستدعيroute_conversationأيضاً المساعد القابل للتجاوزconversation_start(). - نهاية التشغيل — يُتخطى
flow_finishedلكل جولة وإنهاء التتبع عند تفعيل التأجيل؛ كما لا تغلق استدعاءاتAgent.kickoff()المتداخلة أو crews دفعة الأب.
append_assistant_message(reply) عندما لا تطابق الرد الظاهر قيمة الإرجاع، أو عند قصّ التاريخ. تُسجَّل أيضاً سلسلة الإرجاع العامة كمساعد وتُضمَّن في لقطة @persist، فتستعيدها نسخة Flow جديدة. سطر المستخدم محفوظ عبر handle_turn — لا تُضفه مرة أخرى.
نظرة عامة على الإعداد
يؤدي تزيين صنف فرعي منFlow بـ ConversationConfig إلى إرفاق افتراضيات الدردشة وتفعيل الوضع المحادثاتي معاً. راجع مرجع الحقول الكامل أدناه. ويمكنك تجاوز التصنيف المسبق لكل جولة عبر handle_turn(..., intents=..., intent_llm=...).
مساعدات ChatState منخفضة المستوى
تظل ChatState وConversationalConfig القديمة ومساعدات crewai.flow.conversation قابلة للاستيراد للتنسيق المتقدم أو الاختبارات أو الأغلفة المخصصة. وهي منفصلة عن واجهتي ConversationState / ConversationConfig، ولا تضيف وسيطي user_message= أو session_id= إلى Flow.kickoff().
ConversationalInputs هو TypedDict لمفاتيح kickoff(inputs={...}) الاصطلاحية: id وuser_message وlast_intent.
تخزن ConversationState رسائل messages ككائنات ConversationMessage، وتوفر أيضاً current_user_message وended وevents وagent_threads. استخدم conversation_messages عند تمرير سجلها القانوني إلى LLM.
API المحادثة على Flow
معاملات handle_turn
معاملات kickoff
يقبل Flow.kickoff() كلاً من inputs وinput_files وfrom_checkpoint وrestore_from_state_id. مرر inputs={"id": session_id} عندما تحتاج إلى تنفيذ flow خام، لكن استخدم handle_turn() عندما يمثل الاستدعاء رسالة دردشة.
سمات المثيل
طرق وخصائص
مساعدات الوحدة (crewai.flow.conversation)
يمكن استيرادها من crewai.flow.conversation للاختبارات أو التنسيق المخصص. تستخدم هذه المساعدات بنية ConversationalConfig القديمة؛ كما تمسح prepare_conversational_turn() قيمة last_intent، بخلاف handle_turn() التي تحتفظ بها كسياق للموجّه.
أنماط توجيه النية
أ. تصنيف مسبق عبر ConversationConfig (الأبسط)
عيّن default_intents وintent_llm. يصنّف كل handle_turn() الرسالة الحالية مسبقاً. تكون الأولوية لنتيجة غير فارغة يعيدها route_turn() مخصص؛ وإلا تستخدم route_conversation النية المصنّفة للجولة الحالية.
ب. تصنيف داخل route_turn (مطالبات أغنى)
عيّن default_intents=None كي يضيف handle_turn() رسالة المستخدم فقط. داخل route_turn()، استدعِ classify_intent بمطالبة أو أوصاف مخصصة:
@listen("RESEARCH") مع Agent.kickoff() وأدوات — وليس LLM.call() فقط.
عندما ينتهي الـ flow ويستمر المستخدم
يُكمل كلhandle_turn() تشغيل رسم واحد، وتستمر المحادثة عبر handle_turn() آخر يستخدم session_id نفسه. مع دورة حياة التتبع المؤجلة افتراضياً، يصدر ذلك التشغيل conversation_turn_completed، بينما يصدر FlowFinished مرة واحدة عندما تغلق finalize_session_traces() الجلسة. ويستعيد @persist الرسائل والأعلام والسياق.
نمط الحفظ: يُفضّل @persist على خطوة نهائية واحدة (مثل finalize) وليس على صنف Flow بالكامل. يحفظ الاستمرار على مستوى الصنف بعد كل طريقة؛ وتستخدم load_state أحدث صف، وقد يكون لقطة في منتصف التشغيل (مثلاً بعد bootstrap مباشرة) لا تتضمن تحديثات المعالج من الجولة نفسها.
لا تستخدم @human_feedback لأسطر المتابعة في الدردشة إلا عند الحاجة لموافقة بشرية على مخرجات خطوة محددة.
Flow المحادثاتي
اشترك في رسم الدردشة المحادثاتي بتعيين conversational = True على صنف فرعي من Flow أو بتطبيق @ConversationConfig(...). يوفر Flow الأساسي عندئذٍ route_conversation كنقطة البدء/الموجّه المدمجة، إضافة إلى مستمعي converse_turn وend_conversation. يظل المستمع المهمل answer_from_history_turn متاحاً للتوافق. يدير الإطار state.messages، ويمكنه تشغيل LLM للموجّه، ويبقي دفعة trace مفتوحة عبر الجولات. أنت تكتب المسارات المخصصة؛ والإطار يتولى الباقي.
استخدمه عندما تريد دردشة متعددة الجولات مع موجّه قائم على LLM ومعالجات لكل مسار دون توصيل دورة الحياة يدوياً. استخدم Flow[ChatState] (النمط الأدنى مستوى في الأعلى) عندما تحتاج تحكماً كاملاً.
مثال سريع
chat():
chat() استدعاءات handle_turn() داخل REPL، ويخرج عند exit / quit، ويتجاهل الأسطر الفارغة افتراضياً، ويستدعي finalize_session_traces() عند انتهاء الجلسة.
ConversationConfig
مزخرف صنف يُلحق افتراضيات الدردشة على مستوى الصنف.
عند عدم وجود مسارات مخصصة، تسقط الجولات إلى
converse. ومع وجود مسارات مخصصة وLLM للمحادثة/الموجّه، ينشئ الإطار RouterConfig افتراضية؛ لا توفر واحدة صراحةً إلا لتخصيص المطالبة أو قائمة المسارات أو الأوصاف أو سلوك fallback. أما ضبط default_intents فيستخدم مسار التصنيف المسبق القديم.
إذا لم يُهيأ LLM للمحادثة، يعيد converse_turn المدمج عنصراً نائباً للإعداد بدلاً من توليد إجابة.
RouterConfig وفهرس المسارات المُولَّد تلقائياً
RouterConfig.route_descriptions[label]— تجاوز صريح.Flow.builtin_route_descriptions[label]— نص جاهز من الإطار لـconverseوendولمسار التوافق المهملanswer_from_history(مصاغ لـ LLM التوجيه).- قيمة
descriptionالمعلنة للطريقة (تستخدمها التدفقات التعريفية وإسقاطات DSL). - أول سطر غير فارغ من docstring معالج
@listen(label). - فارغ (المسار يظهر في الفهرس بلا وصف).
@listen("X") + docstring من سطر واحد:
RouterConfig.prompt مخصص لـ تأطير النطاق (شخصية المساعد، قواعد العمل، النبرة). فهرس المسارات يُبنى تلقائياً — لا تُدرج المسارات في prompt؛ سيختل التزامن لحظة إضافة معالج جديد.
تسمية المعالجات
السلسلة النصية في@listen("…") هي تسمية مسار للموجّه (اسم حدث)، وليست اسم طريقة Python. تتشارك تسميات المسارات وأحداث اكتمال الطرق مساحة مشغلات واحدة، ولذلك تؤدي تسمية المعالج باسم مساره نفسه إلى إعادة تشغيل المعالج في حلقة.
استخدم اسماً مختلفاً للطريقة — تستخدم أمثلة التوثيق بادئة handle_*:
المسارات المدمجة
يمكنك تجاوز أي من هذه بتعريف معالج بنفس الاسم في الصنف الفرعي.
دلالات handle_turn()
flow.handle_turn(message) يُشغّل جولة واحدة:
- يعيد ضبط تعقّب التنفيذ لكل جولة (
_completed_methods,_method_outputs) ليُعاد تشغيل الرسم — بدون ذلك، استدعاءاتkickoffالمتكررة على نفس النسخة ستُحدث دائرة قصر من الجولة الثانية لأنFlow.kickoff_asyncيعتبرinputs={"id": ...}استعادة من نقطة تفتيش. - يُلحق رسالة المستخدم بـ
state.messagesويضبطcurrent_user_message/last_user_message. يُحافَظ علىlast_intentمن الجولة السابقة كي يستخدمها LLM التوجيه كإشارة. - يُشغّل طرق
@startالتي يعرّفها المستخدم (إن وجدت)، ثمroute_conversationكنقطة البدء/الموجّه المدمجة، ثم معالج@listenالمختار. وتستدعيroute_conversationالمساعد القابل للتجاوزconversation_start(). - يخزّن الموجّه قراره في
state.last_intent(يكون مرئياً لسياق التوجيه في الجولة التالية). - إذا أعاد معالجك سلسلة نصية ولم يستدعِ
append_assistant_message، فإنhandle_turnيُلحقها نيابةً عنك ويحفظstate.messagesالمحدَّث حتى تشمل استعادة@persistجولة المساعد.
handle_turn() لرسائل الدردشة. استدعاء kickoff(inputs={"id": ...}) مباشرةً يشغل الرسم بدون غلاف الجولة المحادثية.
chat() للـ REPL المحلي
flow.chat() هو غلاف الطرفية الجاهز فوق handle_turn():
- يطلب رسالة من المستخدم.
- يتوقف عند
exit/quitأوEOFErrorأوKeyboardInterrupt. - يستدعي
handle_turn(message, session_id=...). - يطبع نتيجة المساعد.
- ينهي traces الجلسة المؤجلة داخل كتلة
finally.
chat(defer_trace_finalization=True) مؤقتاً علم التأجيل على مستوى المثيل للـ REPL، ثم يعيد قيمته السابقة عند الخروج.
خصص سلوك الطرفية عبر I/O قابل للحقن:
handle_turn() مباشرةً.
سلوك موجّه مخصص
لتشغيل آثار جانبية (إعداد ناقل أحداث، قياس عن بُعد) في كل قرار توجيه، تجاوزroute_turn:
route_turn. لا يؤدي إرجاع قيمة falsy من التجاوز إلى استدعاء _route_with_config()؛ بل يسقط التوجيه إلى النية المصنّفة مسبقاً لهذه الجولة، ثم إلى مسار التوافق المهمل answer_from_history عند إعداده، وأخيراً إلى converse. تكون last_intent من الجولة السابقة متاحة في سياق الموجّه، لكنها لا تُعاد أبداً كـ fallback.
append_assistant_message وappend_agent_result
داخل معالج @listen(label)، اختر:
self.append_assistant_message(text)— يضيف جولة مساعد مرئية للمستخدم إلىstate.messages. سيراهاconverse_turnفي الجولة التالية.self.append_agent_result(agent_name, result, visibility="private")— يسجّل حدثاً منظماً فيstate.eventsوموضوعاً فيstate.agent_threads[agent_name]. الرؤية العامة تستدعيappend_assistant_messageأيضاً. استخدم النتائج الخاصة للعمل الجانبي الذي يجب ألا يلوث التاريخ القانوني.
ConversationConfig.visible_agent_outputs رفع النتائج الخاصة لـ agents محددين إلى عامة عالمياً ("all" أو قائمة بالأسماء).
تعريف تدفق محادثاتي بصيغة JSON/YAML
يمكن لـ التدفق التعريفي أن يكون محادثاتيًا أيضًا. أضف كتلةconversational في المستوى الأعلى وعرّف مساراتك الخاصة كطرق تستمع (listen) إلى تسمية مسار:
enabled هي true. اضبطها على enabled: false للاحتفاظ بالإعدادات مع إيقاف المحادثة. يؤدي ذلك أيضاً إلى تعطيل إنشاء الطرق المدمجة، ولذلك يجب أن توفر التعريفة رسماً عادياً غير محادثاتي.
تُوفَّر لك ثلاثة أشياء:
تقبل حقول
llm وrouter.llm وintent_llm التعريفية إما معرّف نموذج أو خريطة إعدادات مثل {model: openai/gpt-4o-mini, max_tokens: 512}. وتدعم كتلة conversational أيضاً default_intents وvisible_agent_outputs وdefer_trace_finalization وحقول RouterConfig الموضحة أعلاه. تظل تعريفات answer_from_history_prompt / answer_from_history_llm المهملة مقبولة للتوافق.
شغّله من Python بنفس واجهات الجولة المستخدمة مع تدفق محادثاتي معرّف بصنف:
تسمية المسارات
تتشارك تسميات المسارات وأسماء الطرق مساحة اسم واحدة للمشغّلات، لذا يجب ألا يحمل المعالج اسم المسار الذي يستمع إليه — يُرفضcreate_video الذي يستمع إلى create_video عند بناء التدفق. استخدم بادئة handle_*.
ما لا يمكن للتعريفة التعبير عنه
يفتح
crewai run واجهة المحادثة النصية للتدفق المحادثاتي التعريفي — نفس الواجهة التي يحصل عليها Flow محادثاتي مكتوب بلغة Python. تحتاج حلقة المحادثة إلى طرفية، ولذلك يخرج التشغيل بدون طرفية برمز غير صفري مع إرشادات بدلاً من تنفيذ جولة واحدة؛ شغّله من Python هناك عبر handle_turn() أو stream_turn(). وتعمل الطريقة التعريفية ذات كتلة human_feedback: (وفي Python: @human_feedback) على REPL طرفي، لأن runtime يجمع الملاحظات بمطالبة حاجزة لا تستطيع TUI خدمتها. لا يُقبل --inputs مع Flow محادثاتي — فمدخل كل جولة هو الرسالة التي تكتبها — واستئناف جلسة حسب المعرّف غير موصول بواجهة CLI بعد؛ استخدم flow.handle_turn(message, session_id=...) من Python لذلك.
التتبع عبر الجولات
معdefer_trace_finalization=True (افتراضي في ConversationConfig):
- دفعة trace واحدة لجلسة الدردشة.
flow_startedفي الجولة الأولى فقط؛flow_finishedمرة فيfinalize_session_traces().kickoffلكل جولة لا يطبع “Trace batch finalized”.- العمل المتداخل (
Agent.kickoff(), crews, Exa) يُلحق بدفعة الأب؛ flow داخلي منAgentExecutorلا يغلق دفعة الجلسة مبكراً.
flow.chat() يستدعي finalize_session_traces() نيابةً عنك. عندما تملك الحلقة عبر handle_turn()، استدعِ finalize_session_traces() عند انتهاء الجلسة.
يخفي suppress_flow_events=True لوحات Rich ويمنع أحداث تنفيذ الطرق. وتظل أحداث بدء/انتهاء Flow تصدر، فيبقى بالإمكان تتبع دورة حياة Flow الخارجية، بينما تُحذف spans الطرق الفردية.
دورة حياة trace لـ Flow المحادثاتي
يستخدم Flow المحادثاتي دورة حياة التتبع نفسها: القيمة الافتراضية لـ defer_trace_finalization هي True، ولذلك يبقي كل handle_turn() trace الجلسة مفتوحاً. تمنع الجولات المؤجلة أيضاً إصدار flow_failed لكل جولة؛ وعند حدوث خطأ في جولة أو إلغاء الجلسة، أنهِ الجلسة صراحةً. يغلق ذلك الدفعة بحدث FlowFinished على مستوى الجلسة بدلاً من حدث FlowFailed لكل جولة. لُف REPL/الحلقة دائماً بـ try/finally واستدعِ flow.finalize_session_traces() عند الخروج. بدون ذلك، تبقى دفعة trace مفتوحة وقد لا تُصدَّر المحادثة النهائية أبداً.
البث
استخدمstream_turn() للواجهات المحادثية، وكرّر عبر كائنات StreamFrame المرتبة التي يعيدها:
stream = True إلى جعل kickoff() يعيد StreamSession. لا تضبط flow.stream = True عند استخدام handle_turn()؛ إذ تملك stream_turn() دورة حياة البث المحادثاتي.
