LogoKalli
Chatbot

Mode Orchestrateur

Mode Orchestrateur

Le mode orchestrateur est une fonctionnalité optionnelle qui permet au chatbot de détecter l'intention de l'utilisateur et de déléguer certaines requêtes à un agent externe (ex: système de réservation, API métier tierce) tout en conservant le RAG pour les questions standard.

Activation

ENABLE_ORCHESTRATOR=true
EXTERNAL_AGENT_URL=http://external-agent-service:8080

Sans ENABLE_ORCHESTRATOR=true, le chatbot fonctionne en mode RAG pur, sans classification d'intention.

Concept : sessions NORMAL vs ALTER

NORMAL → le chatbot répond via le RAG standard
ALTER  → le chatbot transfère la question à l'agent externe (SSE)

La session est unidirectionnelle: une fois en mode ALTER, toutes les questions suivantes sont envoyées à l'agent externe pour ce thread. Le mode est persisté dans les métadonnées du thread Chainlit.

Flux de traitement

process_question(question, session_mode, ...)

  ├─ si session_mode == "ALTER"
  │     → forward_to_external_agent(question, user_id, history)  # immédiat

  └─ sinon (NORMAL ou None)
        → prepare_rag_context(...)  # récupère contexte RAG
        → classify_intent_and_answer(client, question, context, few_shots, history)

              ├─ LLM retourne "ALTER ..."
              │     → yield "__MODE__:ALTER"
              │     → forward_to_external_agent(...)  # SSE

              └─ LLM retourne réponse normale
                    → yield "__MODE__:NORMAL"
                    → stream réponse (tokens)

classify_intent_and_answer

apps/chatbot/src/chatbot/core/intent_classifier.py

async def classify_intent_and_answer(
    client: Mistral,
    question: str,
    context: str,
    few_shots_examples: str,
    conversation_history: Optional[List[Dict[str, str]]] = None
) -> Tuple[IntentType, Optional[AsyncGenerator[str, None]]]:

Args:

  • client — client Mistral initialisé
  • question — question de l'utilisateur
  • context — chunks RAG récupérés (texte concaténé)
  • few_shots_examples — exemples Q&A formatés
  • conversation_history — historique de conversation (messages précédents)

Returns: (intent, answer_generator)

  • intentIntentType.NORMAL ou IntentType.ALTER
  • answer_generatorAsyncGenerator si NORMAL, None si ALTER

Comportement: effectue un seul appel LLM avec le prompt système d'intent detection (get_intent_detection_prompt()). Si la réponse commence par "ALTER", l'intention est ALTER et answer_generator est None. Sinon, l'intention est NORMAL et answer_generator streame la réponse déjà générée.

IntentType enum

class IntentType(str, Enum):
    NORMAL = "NORMAL"   # Répondre via RAG
    ALTER  = "ALTER"    # Déléguer à l'agent externe

forward_to_external_agent

apps/chatbot/src/chatbot/core/external_agent.py

async def forward_to_external_agent(
    question: str,
    user_id: str = "chainlit_user",
    conversation_history: Optional[List[Dict[str, str]]] = None
) -> AsyncGenerator[str, None]:

Args:

  • question — question à transmettre
  • user_id — identifiant utilisateur (transmis à l'agent externe)
  • conversation_history — historique de conversation

Yields: tokens streamés depuis l'agent externe.

Protocole:

  1. Envoie POST {EXTERNAL_AGENT_URL}/assistant avec:
    {
      "message": "question",
      "user_id": "user_id",
      "conversation_history": [...]
    }
  2. Lit la réponse en SSE (Server-Sent Events):
    • Événement message → yield le contenu
    • Événement tool_call → yield "__STEP__:tool:{message}"
    • Événement done → fin du stream
  3. Fallback: si SSE non supporté, tente une réponse JSON {"response": "..."}.
  4. En cas d'erreur réseau: yield un message d'erreur localisé.

Prompt de classification d'intention

Configurable via INTENT_DETECTION_PROMPT. Prompt par défaut (résumé):

You are an intent classifier. Given the user's question, context, and conversation history, determine:
- NORMAL: the question can be answered using the provided context (RAG)
- ALTER: the question requires an external action (booking, reservation, etc.)

If NORMAL: respond naturally using the context.
If ALTER: respond with exactly "ALTER" followed by a brief explanation.

get_enhanced_system_prompt

apps/chatbot/src/config/orchestrator_config.py

def get_enhanced_system_prompt(base_prompt: str) -> str:

Quand ENABLE_ORCHESTRATOR=true, ajoute au prompt système de base des instructions expliquant au modèle qu'il peut escalader vers un agent externe. Injecté dans le message système Chainlit au démarrage de chaque session.

Cas d'usage type

  1. Un utilisateur pose une question sur la politique de congés → intent NORMAL → réponse RAG.
  2. L'utilisateur demande de "réserver un voyage à Paris" → intent ALTER → session bascule en mode ALTER.
  3. Toutes les questions suivantes dans ce thread sont directement envoyées à l'agent de réservation via SSE.

Extension

  • Nouvel agent externe: implémentez POST /assistant avec SSE sur votre service, configurez EXTERNAL_AGENT_URL.
  • Prompt personnalisé: overridez INTENT_DETECTION_PROMPT pour adapter les critères NORMAL/ALTER à votre domaine.
  • Multi-agents: modifiez classify_intent_and_answer pour retourner des types d'intention supplémentaires et router vers différents agents.