So lässt sich der Arbeitsablauf wie folgt gestalten

Chat-Konversation

KI-Eingabeaufforderung

"Du bist ein professioneller Reiseassistent. Du arbeitest in drei unterschiedlichen Phasen und musst strenge Formatierungsregeln für jede Phase befolgen.

Bitte führe ein Gespräch mit dem Benutzer, begrüße ihn und zeige die Schaltfläche gemäß der Benutzeranfrage.

PHASE 1: Länder-Erkennung

Auslöser: Anfängliche Begrüßung.

Aktion: get_destinations aufrufen.

Format: Beginne mit [TYPE:DESTINATION], gefolgt von einer Begrüßung, dann das rohe JSON […].

PHASE 2: Stadt-Erkennung

Auslöser: Der Benutzer wählt ein Land aus.

Aktion: get_cities aufrufen.

Format: Beginne mit [TYPE:CITY], gefolgt von einer kurzen Auswahlbitte, dann das rohe JSON […].

PHASE 3: Paket-Erkennung

Auslöser: Der Benutzer wählt eine Stadt aus.

Aktion: tour_packages unter Verwendung des Payload-Wertes aufrufen.

Anleitung zum Abrufen der Stadt-ID: Wenn der Benutzer eine Stadt auswählt, erhältst du eine Nachricht mit einem Payload-Wert. Dieser Payload ist die term_id für diese Stadt. Du musst diesen spezifischen Wert beim Aufrufen des tour_packages-Tools verwenden. Wenn du keine term_id hast, bitte den Benutzer, seine Stadtauswahl zu klären.

Format: Beginne mit [TYPE:PACKAGES], gefolgt von einer kurzen Bestätigung, dann das rohe JSON […].

KRITISCHE PROTOKOLLE:

ROUTING-ÜBERSCHRIFTEN: Jede Nachricht MUSS mit [TYPE:DESTINATION], [TYPE:CITY] oder [TYPE:PACKAGES] beginnen.

KEINE ZUSAMMENFASSUNGEN: Schreibe niemals Gesprächslisten oder Zählungen. Gebe nur das Tag, eine kurze Begrüßung und das rohe JSON an.

MASCHINENLESBAR: Das JSON […] muss der letzte Teil jeder Nachricht sein.

TOOL-VERWENDUNG: Verwende immer die bereitgestellten Tools zum Abrufen von Daten. Erfinde nie Pakete oder Städte."

WICHTIG:

  • Gebe NUR gültiges JSON zurück
  • KEINE Erklärungen
  • KEINE escaped Anführungszeichen
  • KEINE [TYPE:…] innerhalb von JSON
  • Die Ausgabe muss direkt von JSON.parse analysierbar sein

Arbeitsablauf

Globaler Parser

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

// =========================
// Hilfsfunktion: Standardrückgabe
// =========================
function formatResponse(data) {
return [{ json: data }];
}

// =========================
// Erkenne 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;
}

// =========================
// Extrahiere SAUBERES JSON
// =========================
function extractJSONArray(text) {
if (!text) return null;

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

// Entferne Platzhalter
if (cleaned.includes("[...]")) return null;

// Finde JSON-Grenzen
const start = cleaned.indexOf('[');
const end = cleaned.lastIndexOf(']');

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

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

// 🔥 Behebe häufige KI-Probleme
jsonString = jsonString
    .replace(/\\\//g, "/")     // behebe escaped slashes
    .replace(/;\s*$/, "")      // entferne nachfolgende ;
    .trim();

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

    // Behandle doppelt kodiertes JSON
    if (typeof parsed === "string") {
        parsed = JSON.parse(parsed);
    }

    return parsed;
} catch (e) {
    throw new Error("JSON Parse Fehlgeschlagen:\n" + jsonString);
}

}

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

// =========================
// DESTINATION
// =========================
if (type === “DESTINATION” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “Wähle ein Land:”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.destination,
payload: i.id
}))
}
});
}

// =========================
// CITY
// =========================
if (type === “CITY” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “Wähle eine Stadt:”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.city || i.name,
payload: i.id
}))
}
});
}

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

const elements = packages.map(pkg => ({
    title: pkg.title,
    subtitle: pkg.subtitle || "Bestes verfügbares Reisepaket",
    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
            }
        }
    }
});

}

// =========================
// FALLBACK
// =========================
return formatResponse({
message: {
text: rawOutput || “Keine Antwort verfügbar.”
}
});

Meine Fragen

  • Ich möchte auch die Konversation haben und der KI-Agent soll selbst suchen und liefern.
  • Derzeit funktioniert es nur gemäß Schaltflächenklick und Payload.
  • Nachdem der Benutzer auf die Programmdetails klickt, soll die KI die Daten nur für dieses Paket abrufen und das Gespräch fortsetzen.

Um all das zum Funktionieren zu bringen, bitte ich um Vorschläge, wie ich den Arbeitsablauf gestalte, wie das System-Design aussehen sollte, wie viele KI-Agenten ich benötige und wie ich dem Arbeitsablauf mitteile, welches Tool wann verwendet werden soll?

Bitte helfen Sie mir beim Brainstorming oder leiten Sie mich an. Danke!

Okay, nach dem Lesen deiner Beiträge hier ist mein Feedback nach Berücksichtigung der Anforderungen, ich hoffe, das hilft.

Ziel und Ansatz

  • Erstelle einen modularen, selbstlernenden Gesprächsfluss, der Daten über vordefinierte Button-Payloads hinaus abrufen kann.

  • Verwende einen kleinen Satz spezialisierter KI-Agenten (oder Tools), um Entdeckung, Auswahl, Verpackung und narrative Konversation abzudecken.

  • Orchestriere die Tool-Nutzung deklarativ im Workflow, damit das System das richtige Tool zur richtigen Zeit auswählt.


Systemdesign-Übersicht

  • Primäre Komponenten

    1. Chat Orchestrator (n8n oder ein Microservice): treibt den Gesprächszustand an und leitet zu Agenten/Tools weiter.

    2. AI Agent Layer: ein kleiner Satz spezialisierter Agenten (Discovery, City, Packages, Narrative) mit definierten Aufgabenbereichen.

    3. Daten & Tools: get_destinations, get_cities, tour_packages und alle externen Datenquellen. Alle über stabile APIs zugänglich.

    4. State & Context Store: speichert Benutzersitzungsdaten, gewähltes Land/Stadt und ausgewähltes Paket, sowie IDs für Nachverfolgbarkeit.

    5. Message Formatter: erzwingt die [TYPE:DESTINATION]/[TYPE:CITY]/[TYPE:PACKAGES] Routing-Header und finale JSON-Payload.

    6. Observability: strukturierte Logs, Tracing IDs und Error Dashboards.

  • Datenfluss-Muster

    1. Benutzer grüßt → Discovery Agent stellt Ziele bereit.

    2. Benutzer wählt ein Ziel → City Agent stellt Städte für dieses Land bereit.

    3. Benutzer wählt eine Stadt → Packages Agent ruft Pakete ab; Konversation setzt sich mit Paketdetails fort.

    4. Nach Paketauswahl ruft das System detaillierte Paketdaten ab und aktualisiert die Konversation mit reichhaltigen Inhalten.


KI-Agent-Design & Rollen

  • Agent A: Discovery

    • Zweck: Ziele abrufen und präsentieren; JSON-Payload als Single Source of Truth halten.

    • Output: [TYPE:DESTINATION] Header + Begrüßung + rohes JSON.

  • Agent B: City

    • Zweck: Städte für ein gewähltes Ziel abrufen; prägnante Aufforderungen zur Stadtauswahl bereitstellen.

    • Output: [TYPE:CITY] Header + kurze Aufforderung + rohes JSON.

  • Agent C: Packages

    • Zweck: Pakete für eine Stadt abrufen, wenn eine Stadt ausgewählt wird; kompakte, leicht zu überfliegende Details bereitstellen.

    • Output: [TYPE:PACKAGES] Header + kurze Bestätigung + rohes JSON.

  • Agent D: Narrative/Conversation

    • Zweck: menschenähnliche Dialoge generieren, die das gewählte Ziel/Stadt/Paket referenzieren und den Benutzer leiten.

    • Output: natürlichsprachliche Nachrichten, die vom aktuellen Kontext geleitet werden, während sie immer noch den erforderlichen TYPE Header bei Bedarf ausgeben.

  • Agent E: Verification & Safety

    • Zweck: Datengenauigkeit sicherstellen, Halluzinationen verhindern, Datenschutz durchsetzen und Payload-Integrität über alle Schritte hinweg validieren.
  • Optional: Data Enrichment Agent

    • Zweck: zusätzliche Metadaten abrufen (Saisonalität, Wetter, lokale Tipps), um Paketbeschreibungen zu erweitern.
  • Beginne mit 4 Kern-Agenten (Discovery, City, Packages, Narrative) plus einem leichten Verification Agent. Du kannst Enrichment später hinzufügen.

Wie der Workflow entscheidet, welches Tool/Agent zu verwenden ist

  • Implementiere eine Routing-Schicht im Orchestrator:

    • Wenn kein TYPE vorhanden oder initiale Begrüßung → Discovery.

    • Wenn Benutzer ein Land gewählt hat → City.

    • Wenn Benutzer eine Stadt gewählt hat → Packages.

    • Wenn Benutzer nach Narration oder tieferen Details fragt → Narrative.

    • Wenn Datenintegrität oder sensible Daten involviert sind → Verification.

  • Verwende explizite Zustandsübergänge:

    • state: { phase: “discovery” | “city” | “packages” | “narrative”, country_id, city_id, package_id, user_id }
  • Definiere ein zentrales Tool-Verzeichnis mit:

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

Konversationsschema & Formatierung

  • Erhalte den erforderlichen Routing-Header in jeder Nachricht:

    • [TYPE:DESTINATION]

    • [TYPE:CITY]

    • [TYPE:PACKAGES]

  • Stelle sicher, dass die finale maschinenlesbare JSON-Payload der letzte Block der Nachricht ist.

  • Beispiel Gesprächsfluss (hohe Ebene)

    1. Discovery:

      • Output: [TYPE:DESTINATION] + Begrüßung + rohes JSON Ziele
    2. City:

      • Output: [TYPE:CITY] + Aufforderung + rohes JSON Städte
    3. Packages:

      • Output: [TYPE:PACKAGES] + Bestätigung + rohes JSON Pakete
    4. Narrative:

      • Output: natürlichsprachliche Nachrichten mit Kontext, oder eine detaillierte Paketnarration, immer noch mit Tags, wenn erforderlich.
  • Persistenz und Nachverfolgbarkeit

    • Hänge eine session_id und eine request_id an jede Nachricht an, um Schritte zu korrelieren.

Workflow-Orchestrierungs-Blueprint (n8n-orientiert)

  • Nodes-Layout (modulare Blöcke)

    1. Trigger: HTTP oder Chat Webhook zum Starten einer Sitzung.

    2. State Loader: lade Sitzungskontext aus einem Datenspeicher.

    3. AI Gateway: wähle den geeigneten Agent basierend auf Phase.

    4. Agent Call: rufe get_destinations / get_cities / tour_packages oder Narrations-Inhalte auf.

    5. Response Formatter: wickle in den korrekten [TYPE:*] Header und finale JSON ein.

    6. State Saver: persistiere aktualisierte Kontext und Auswahlen.

    7. Output: sende an Benutzer, protokolliere die Interaktion.

  • Datenverträge

    • Destinations API gibt zurück: [{ id, country, name, description, image }, …]

    • Cities API gibt zurück: [{ id, city, country_id, region }, …]

    • Packages API gibt zurück: [{ id, title, summary, image_url, price, details }, …]

  • Fehlerbehandlung

    • Wiederholungsrichtlinie mit exponentiellem Backoff für transiente API-Fehler.

    • Fallback-Nachrichten, wenn APIs fehlschlagen, mit einer klaren Trace ID.

    • Validierung bei jedem Schritt, um sicherzustellen, dass erforderliche Felder vorhanden sind, bevor fortgefahren wird.

  • Sicherheit & Isolation

    • Jeder Container verwendet ein dediziertes Netzwerk und einen API-Schlüssel mit Scope für den Agent.

    • Geheimnisse verwaltet von einem Vault; regelmäßig rotieren.

    • Least-Privilege in Docker Compose oder Kubernetes Manifesten