Comment faire en sorte que le flux de travail fonctionne comme ci-dessous

Conversation de Chat

Message du Prompt IA

"Vous êtes un assistant de voyage professionnel. Vous opérez en trois phases distinctes et devez respecter des règles de formatage strictes pour chaque phase.

Veuillez engager une conversation avec l’utilisateur, le saluer et afficher le bouton selon sa demande.

PHASE 1 : Découverte des Pays

Déclencheur : Salutation initiale.

Action : Appeler get_destinations.

Format : Commencer par [TYPE:DESTINATION], suivi d’un salutation, puis le JSON brut […].

PHASE 2 : Découverte des Villes

Déclencheur : L’utilisateur sélectionne un pays.

Action : Appeler get_cities.

Format : Commencer par [TYPE:CITY], suivi d’une brève invite de sélection, puis le JSON brut […].

PHASE 3 : Découverte des Forfaits

Déclencheur : L’utilisateur sélectionne une ville.

Action : Appeler tour_packages en utilisant la valeur de payload.

Instruction pour Obtenir l’ID de Ville : Lorsque l’utilisateur sélectionne une ville, vous recevrez un message avec une valeur de payload. Ce payload est le term_id pour cette ville. Vous devez utiliser cette valeur spécifique lors de l’appel de l’outil tour_packages. Si vous n’avez pas de term_id, demandez à l’utilisateur de clarifier sa sélection de ville.

Format : Commencer par [TYPE:PACKAGES], suivi d’une brève confirmation, puis le JSON brut […].

PROTOCOLES CRITIQUES :

ENTÊTES DE ROUTAGE : Chaque message DOIT commencer par [TYPE:DESTINATION], [TYPE:CITY], ou [TYPE:PACKAGES].

PAS DE RÉSUMÉS : N’écrivez jamais de listes conversationnelles ou de comptages. Fournissez uniquement l’étiquette, une courte salutation, et le JSON brut.

LISIBLE PAR MACHINE : Le JSON […] doit être la dernière partie de chaque message.

UTILISATION D’OUTILS : Utilisez toujours les outils fournis pour récupérer les données. Ne fabriquez jamais de forfaits ou de villes."

IMPORTANT :

  • Retournez UNIQUEMENT du JSON valide
  • NE PAS inclure d’explications
  • NE PAS échapper les guillemets
  • NE PAS inclure [TYPE:…] à l’intérieur du JSON
  • Le résultat doit être directement analysable par JSON.parse

Flux de Travail

Analyseur Global

const rawOutput = $input.first().json.output || “”;

// =========================
// Aide : Retour standard
// =========================
function formatResponse(data) {
return [{ json: data }];
}

// =========================
// Détecter TYPE
// =========================
function detectType(text) {
if (text.includes(“[TYPE:DESTINATION]”)) return “DESTINATION”;
if (text.includes(“[TYPE:CITY]”)) return “CITY”;
if (text.includes(“[TYPE:PACKAGES]”)) return “PACKAGES”;
return null;
}

// =========================
// Extraire JSON PROPRE
// =========================
function extractJSONArray(text) {
if (!text) return null;

// Supprimer les balises TYPE
let cleaned = text.replace(/\[TYPE:[A-Z]+\]/g, "").trim();

// Supprimer l'espace réservé
if (cleaned.includes("[...]")) return null;

// Obtenir les limites du JSON
const start = cleaned.indexOf('[');
const end = cleaned.lastIndexOf(']');

if (start === -1 || end === -1) return null;

let jsonString = cleaned.substring(start, end + 1);

// 🔥 Corriger les problèmes IA courants
jsonString = jsonString
    .replace(/\\\//g, "/")     // corriger les barres obliques échappées
    .replace(/;\s*$/, "")      // supprimer le ; final
    .trim();

try {
    let parsed = JSON.parse(jsonString);

    // Gérer le JSON double-encodé
    if (typeof parsed === "string") {
        parsed = JSON.parse(parsed);
    }

    return parsed;
} catch (e) {
    throw new Error("Échec de l'analyse JSON :\n" + jsonString);
}

}

// =========================
// PRINCIPAL
// =========================
const type = detectType(rawOutput);
const parsed = extractJSONArray(rawOutput);

// =========================
// DESTINATION
// =========================
if (type === “DESTINATION” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “Sélectionnez un pays :”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.destination,
payload: i.id
}))
}
});
}

// =========================
// VILLE
// =========================
if (type === “CITY” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “Sélectionnez une ville :”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.city || i.name,
payload: i.id
}))
}
});
}

// =========================
// FORFAITS
// =========================
if (type === “PACKAGES” && parsed) {
const packages = parsed[0].data;

const elements = packages.map(pkg => ({
    title: pkg.title,
    subtitle: pkg.subtitle || "Meilleur forfait touristique disponible",
    image_url: pkg.image_url,
    buttons: (pkg.buttons || []).map(btn => ({
        type: btn.type === "web_url" ? "web_url" : "postback",
        title: btn.title,
        url: btn.url,
        payload: btn.payload
    }))
}));

return formatResponse({
    recipient: { id: "123456" },
    message: {
        attachment: {
            type: "template",
            payload: {
                template_type: "generic",
                elements: elements
            }
        }
    }
});

}

// =========================
// SECOURS
// =========================
return formatResponse({
message: {
text: rawOutput || “Aucune réponse disponible.”
}
});

Mes Questions

  • Je voudrais avoir la conversation aussi et l’Agent IA cherchera lui-même et donnera des résultats.
  • Actuellement, cela ne fonctionne que selon le clic sur le bouton et le payload.
  • Après que l’utilisateur clique sur les détails du programme, l’IA récupérera les données uniquement pour ce forfait et engagera la conversation.

Pour que tout fonctionne, veuillez me suggérer comment créer le flux de travail et la conception du système, combien d’Agents IA j’ai besoin d’utiliser, et comment indiquer au flux de travail quel outil utiliser quand c’est nécessaire ?

Veuillez m’aider à faire un remue-méninges ou me guider, merci.

Bon, après avoir lu vos posts, voici mon retour après avoir pris en compte les exigences, j’espère que cela vous aidera.

Objectif et approche

  • Construire un flux conversationnel modulaire et auto-apprenant capable de récupérer des données au-delà des payloads de boutons prédéfinis.

  • Utiliser un petit ensemble d’agents IA spécialisés (ou outils) pour couvrir la découverte, la sélection, l’empaquetage et la conversation narrative.

  • Orchestrer l’utilisation des outils de manière déclarative dans le flux de travail, afin que le système choisisse le bon outil au bon moment.


Aperçu de la conception du système

  • Composants principaux

    1. Chat Orchestrator (n8n ou un microservice) : pilote l’état de la conversation, routant vers les agents/outils.

    2. Couche Agent IA : un petit ensemble d’agents spécialisés (Discovery, City, Packages, Narrative) avec des périmètres délimités.

    3. Données & Outils : get_destinations, get_cities, tour_packages, et toute source de données externe. Tous accessibles via des API stables.

    4. Magasin d’état & contexte : stocke les données de session utilisateur, le pays/la ville choisis et le package sélectionné, plus les ID pour la traçabilité.

    5. Formateur de message : applique les en-têtes de routage [TYPE:DESTINATION]/[TYPE:CITY]/[TYPE:PACKAGES] et le payload JSON final.

    6. Observabilité : logs structurés, ID de traçage et tableaux de bord d’erreurs.

  • Schéma de flux de données

    1. L’utilisateur salue → l’agent Discovery fournit les destinations.

    2. L’utilisateur sélectionne une destination → l’agent City fournit les villes pour ce pays.

    3. L’utilisateur sélectionne une ville → l’agent Packages récupère les packages ; la conversation continue avec le détail du package.

    4. À la sélection du package, le système récupère les données détaillées du package et met à jour la conversation avec du contenu enrichi.


Conception et rôles des agents IA

  • Agent A : Discovery

    • Objectif : récupérer et présenter les destinations ; maintenir le payload JSON comme source unique de vérité.

    • Sortie : en-tête [TYPE:DESTINATION] + greeting + JSON brut.

  • Agent B : City

    • Objectif : récupérer les villes pour une destination choisie ; fournir des invites concises pour sélectionner une ville.

    • Sortie : en-tête [TYPE:CITY] + prompt court + JSON brut.

  • Agent C : Packages

    • Objectif : récupérer les packages pour une ville lorsqu’une ville est sélectionnée ; fournir des détails compacts et faciles à parcourir.

    • Sortie : en-tête [TYPE:PACKAGES] + confirmation courte + JSON brut.

  • Agent D : Narrative/Conversation

    • Objectif : générer un dialogue semblable à celui d’un humain qui référence la destination/ville/package choisie et guide l’utilisateur.

    • Sortie : messages en langage naturel guidés par le contexte actuel, tout en émettant l’en-tête TYPE requis si nécessaire.

  • Agent E : Verification & Safety

    • Objectif : assurer l’exactitude des données, prévenir les hallucinations, appliquer la confidentialité des données et valider l’intégrité des payloads à chaque étape.
  • Optionnel : Agent d’enrichissement des données

    • Objectif : récupérer des métadonnées supplémentaires (saisonnalité, météo, conseils locaux) pour enrichir les descriptions des packages.
  • Commencez par 4 agents principaux (Discovery, City, Packages, Narrative) plus un agent Verification léger. Vous pourrez ajouter l’enrichissement plus tard.

Comment le flux de travail décide quel outil/agent utiliser

  • Implémenter une couche de routage dans l’Orchestrator :

    • Si aucun TYPE présent ou greeting initial → Discovery.

    • Si l’utilisateur a sélectionné un pays → City.

    • Si l’utilisateur a sélectionné une ville → Packages.

    • Si l’utilisateur demande un narrative ou plus de détails → Narrative.

    • Si l’intégrité des données ou les données sensibles sont impliquées → Verification.

  • Utiliser des transitions d’état explicites :

    • state: { phase: “discovery” | “city” | “packages” | “narrative”, country_id, city_id, package_id, user_id }
  • Définir un registre d’outils centralisé avec :

    • name, type (API call, local function, LLM), input schema, output schema, error policy.

Schéma de conversation & formatage

  • Maintenir l’en-tête de routage requis dans chaque message :

    • [TYPE:DESTINATION]

    • [TYPE:CITY]

    • [TYPE:PACKAGES]

  • Assurer que le payload JSON lisible par machine se trouve dans le dernier bloc du message.

  • Exemple de flux de conversation (niveau élevé)

    1. Discovery :

      • Sortie : [TYPE:DESTINATION] + greeting + JSON brut des destinations
    2. City :

      • Sortie : [TYPE:CITY] + prompt + JSON brut des villes
    3. Packages :

      • Sortie : [TYPE:PACKAGES] + confirmation + JSON brut des packages
    4. Narrative :

      • Sortie : messages en langage naturel avec contexte, ou un narrative détaillé du package, toujours taggé si requis.
  • Persistance et traçabilité

    • Attacher un session_id et un request_id à chaque message pour corréler les étapes.

Plan d’orchestration du flux de travail (orienté n8n)

  • Disposition des nœuds (blocs modulaires)

    1. Trigger : webhook HTTP ou Chat pour démarrer une session.

    2. State Loader : charger le contexte de session à partir d’un datastore.

    3. AI Gateway : sélectionner l’agent approprié en fonction de la phase.

    4. Agent Call : invoquer get_destinations / get_cities / tour_packages ou contenu narrative.

    5. Response Formatter : envelopper dans l’en-tête [TYPE:*] correct et le JSON final.

    6. State Saver : persister le contexte mis à jour et les sélections.

    7. Output : envoyer à l’utilisateur, logger l’interaction.

  • Contrats de données

    • L’API Destinations retourne : [{ id, country, name, description, image }, …]

    • L’API Cities retourne : [{ id, city, country_id, region }, …]

    • L’API Packages retourne : [{ id, title, summary, image_url, price, details }, …]

  • Gestion des erreurs

    • Politique de retry avec backoff exponentiel pour les erreurs API transitoires.

    • Messages de secours en cas d’échec des API, avec un ID de traçage clair.

    • Validation à chaque étape pour s’assurer que les champs requis existent avant de procéder.

  • Sécurité & isolation

    • Chaque conteneur utilise un réseau dédié et une clé API limitée à l’agent.

    • Secrets gérés par un coffre-fort ; rotation périodique.

    • Privilèges minimums dans les manifests Docker Compose ou Kubernetes.