First Pipeline Tutorial

Build your first Open Ticket AI pipeline end-to-end with orchestration and classification.

Erstellen Ihres ersten Pipelines

Diese Anleitung führt Sie durch den Bau eines funktionierenden Ticket-Klassifizierungs-Pipeline auf Basis des aktuellen Open Ticket AI Konfigurations-Schemas. Sie lernen, wie Plugin-Module geladen werden, wie Services durch Identifikator registriert werden und wie der Orchestrator vollständig aus verschachtelten PipeConfig-Definitionen zusammengesetzt wird.

Konfigurations-Bausteine

Alle Konfiguration befindet sich unter dem Top-Level-Key open_ticket_ai. Jedes Objekt unterhalb wird durch Pydantic-Modelle validiert, bevor der Orchestrator startet, daher ist die Übereinstimmung mit dem Schema essentiell.

Plugin-Module (open_ticket_ai.plugins)

Plugins werden durch Modulnamen (Entry Point) aktiviert. Listen Sie jedes Plugin, das Sie laden möchten, als String auf. Mindestens benötigen Sie das Core-Plugin otai-base, um Zugriff auf die integrierten Runner, Orchestrators und Utility-Pipes zu erhalten.

Service-Registry (open_ticket_ai.services)

Services werden in einem Dictionary definiert, das durch ihren Identifikator keyed ist. Jeder Service beschreibt die zu instanzierende Implementierung via use, optionale Constructor-Dependencies via injects und Konfigurationsdaten via params. Services werden injizierbare Dependencies für Pipes und andere Services. Open Ticket AI erwartet genau einen TemplateRenderer Service; das Beispiel unten registriert den default Jinja Renderer.

Orchestrator (open_ticket_ai.orchestrator)

Der Orchestrator selbst ist eine PipeConfig. Sie wählen eine Orchestrator-Implementierung via use (zum Beispiel base:SimpleSequentialOrchestrator) und konfigurieren ihn via params. Im sequentiellen Orchestrator ist params.steps eine Liste verschachtelter PipeConfig Objekte. Jeder Schritt kann jede Pipe sein – einschließlich Runner wie SimpleSequentialRunner, andere Orchestrators oder konkrete Business-Logic-Pipes.

Die folgende minimale Konfiguration zeigt die Struktur und validiert gegen das aktuelle Schema:

open_ticket_ai:
  api_version: '1'
  plugins:
    - otai-base
  services:
    default_renderer:
      use: 'base:JinjaRenderer'
  orchestrator:
    id: orchestrator
    use: 'base:SimpleSequentialOrchestrator'
    params:
      steps: []

Bau eines minimalen Ticket-Routing-Pipeline

Wir werden das Skelett oben in eine ausführbare Pipeline erweitern, die Tickets von OTOBO/Znuny abruft, die Queue mit einem Hugging Face Model klassifiziert, das Ticket aktualisiert und eine Notiz speichert. Jeder Abschnitt erklärt, wie die Konfiguration auf konkrete Klassen im Codebase abgebildet wird.

Schritt 1: Plugin-Module und Template Renderer deklarieren

Fügen Sie die Plugins hinzu, die die benötigten injizierbaren Komponenten bereitstellen:

  • otai-base – Core Orchestrators (SimpleSequentialOrchestrator), Runner (SimpleSequentialRunner), Pipes (CompositePipe, FetchTicketsPipe, UpdateTicketPipe, AddNotePipe, ExpressionPipe), Triggers (IntervalTrigger) und der default JinjaRenderer.
  • otai-otobo-znuny – Ticket-System-Integration-Service (OTOBOZnunyTicketSystemService).
  • otai-hf-local – On-Device Hugging Face Klassifizierungs-Service (HFClassificationService).

Halten Sie den default_renderer Service registriert, damit Template Rendering verfügbar ist, bevor irgendein anderer Service instanziiert wird.

Schritt 2: Externe Services verbinden

Definieren Sie Services keyed durch ID:

  • default_renderer instanziiert base:JinjaRenderer, erfüllt die Anforderung, dass genau ein TemplateRenderer existiert.
  • otobo_znuny zeigt auf otobo-znuny:OTOBOZnunyTicketSystemService und übergibt Verbindungs-Credentials innerhalb params.
  • hf_classifier resolved zu hf-local:HFClassificationService mit einem optionalen API Token.

Diese IDs (zum Beispiel otobo_znuny und hf_classifier) werden später aus Pipe injects Abschnitten referenziert.

Schritt 3: Orchestrator und Runner konfigurieren

Benutzen Sie base:SimpleSequentialOrchestrator für einen kontinuierlich laufenden Event Loop. Seine params.orchestrator_sleep kontrolliert die Idle-Zeit zwischen Cycles. Innerhalb params.steps fügen Sie einen einzelnen SimpleSequentialRunner hinzu. Dieser Runner erwartet zwei verschachtelte PipeConfig Definitionen unter params:

  • on – ein Trigger Pipe; wir benutzen base:IntervalTrigger mit einem timedelta Interval (PT60S läuft einmal pro Minute).
  • run – die Pipeline, die ausgeführt wird, wenn der Trigger erfolgreich ist. Hier referenzieren wir base:CompositePipe, welche ihre eigenen params.steps sequentiell prozessiert.

Schritt 4: Composite Pipeline Steps definieren

Innerhalb der Composite Pipe ist jedes Element in params.steps eine weitere PipeConfig, die 1:1 auf eine Pipe Klasse abbildet:

  1. fetch_open_tickets (base:FetchTicketsPipe) injiziert den Ticket-System-Service und lädt eingehende Tickets via ticket_search_criteria.
  2. ensure_tickets_found (base:ExpressionPipe) ruft fail() auf, wenn keine Tickets gefunden wurden, stoppt den Runner graceful.
  3. queue_classifier (base:ClassificationPipe) injiziert den Hugging Face Service und klassifiziert den Ticket-Text.
  4. update_queue (base:UpdateTicketPipe) schreibt die neue Queue-Auswahl zurück zu OTOBO/Znuny.
  5. add_classification_note (base:AddNotePipe) erfasst einen Audit Trail der automatisierten Klassifizierung.

Alle Parameter referenzieren frühere Ergebnisse mit Helper-Functions, die durch den Jinja Renderer exponiert werden (get_pipe_result, fail, get_env, etc.).

Vollständige Konfiguration

Speichern Sie die folgende validierte Konfiguration als config.yml in Ihrem Arbeits-Directory. Sie kombiniert alle oben beschriebenen Steps und passt exakt zum aktuellen Schema.

open_ticket_ai:
  api_version: '1'
  plugins:
    - otai-base
    - otai-otobo-znuny
    - otai-hf-local
  services:
    default_renderer:
      use: 'base:JinjaRenderer'
    otobo_znuny:
      use: 'otobo-znuny:OTOBOZnunyTicketSystemService'
      params:
        base_url: 'https://helpdesk.example.com/otobo/nph-genericinterface.pl'
        username: 'open_ticket_ai'
        password: "{{ get_env('OTOBO_API_TOKEN') }}"
    hf_classifier:
      use: 'hf-local:HFClassificationService'
      params:
        api_token: "{{ get_env('HF_TOKEN') }}"
  orchestrator:
    id: ticket-automation
    use: 'base:SimpleSequentialOrchestrator'
    params:
      orchestrator_sleep: 'PT60S'
      steps:
        - id: ticket-routing-runner
          use: 'base:SimpleSequentialRunner'
          params:
            on:
              id: every-minute
              use: 'base:IntervalTrigger'
              params:
                interval: 'PT60S'
            run:
              id: ticket-routing
              use: 'base:CompositePipe'
              params:
                steps:
                  - id: fetch_open_tickets
                    use: 'base:FetchTicketsPipe'
                    injects:
                      ticket_system: 'otobo_znuny'
                    params:
                      ticket_search_criteria:
                        queue:
                          name: 'OpenTicketAI::Incoming'
                        limit: 25
                  - id: ensure_tickets_found
                    use: 'base:ExpressionPipe'
                    params:
                      expression: "{{ fail('No isOpen tickets found') if (get_pipe_result('fetch_open_tickets','fetched_tickets') | length) == 0 else 'tickets ready' }}"
                  - id: queue_classifier
                    use: 'base:ClassificationPipe'
                    injects:
                      classification_service: 'hf_classifier'
                    params:
                      text: "{{ get_pipe_result('fetch_open_tickets','fetched_tickets')[0]['subject'] }} {{ get_pipe_result('fetch_open_tickets','fetched_tickets')[0]['body'] }}"
                      model_name: 'softoft/otai-queue-de-bert-v1'
                  - id: update_queue
                    use: 'base:UpdateTicketPipe'
                    injects:
                      ticket_system: 'otobo_znuny'
                    params:
                      ticket_id: "{{ get_pipe_result('fetch_open_tickets','fetched_tickets')[0]['id'] }}"
                      updated_ticket:
                        queue:
                          name: "{{ get_pipe_result('queue_classifier','label') }}"
                  - id: add_classification_note
                    use: 'base:AddNotePipe'
                    injects:
                      ticket_system: 'otobo_znuny'
                    params:
                      ticket_id: "{{ get_pipe_result('fetch_open_tickets','fetched_tickets')[0]['id'] }}"
                      note:
                        subject: 'Queue classification'
                        body: |
                          Auto-classified queue: {{ get_pipe_result('queue_classifier','label') }}
                          Confidence: {{ (get_pipe_result('queue_classifier','confidence') * 100) | round(1) }}%

Ausführung und Verifizierung des Pipelines

  1. Installieren Sie die benötigten Packages (Core plus die oben gelisteten Plugins).

  2. Stellen Sie Credentials durch Environment-Variables bereit, die in der Konfiguration referenziert sind (zum Beispiel OTOBO_API_TOKEN, HF_TOKEN).

  3. Platzieren Sie die Konfigurationsdatei als config.yml in Ihrem Arbeits-Directory, damit AppConfig sie automatisch aufnimmt.

  4. Starten Sie den Orchestrator:

    uv run python -m open_ticket_ai.main

AppConfig validiert das YAML gegen das Schema beim Startup. Wenn ein Abschnitt fehlt oder ein Parametername falsch ist, beendet die Application mit einem beschreibenden Validation Error, bevor irgendwelche Tickets prozessiert werden. Wenn er läuft, führt der Orchestrator den SimpleSequentialRunner jede Minute aus, appliziert die verschachtelten CompositePipe Steps und loggt den Progress durch die konfigurierten Services.