Files
2025-11-13 13:09:07 +01:00

11 KiB
Raw Permalink Blame History

Agenten-API Planung & Architektur

Zielsetzung

Die Agenten-API erweitert die Basis-API aus 00_Globale_Richtlinien um OpenAPI-kompatible Endpunkte, die als Vermittlungsschicht zwischen externen Anfragenden, internen Worker/Agenten und einem LLM mit OpenAI-kompatibler Schnittstelle fungieren. Sie übernimmt folgende Aufgaben:

  1. Entgegennahme von Nutzeranfragen (z.B. Anweisungen, Aufgabenbeschreibungen, Kontextdaten).
  2. Anreicherung, Validierung und Normalisierung der Anfragen.
  3. Koordination eines Worker/Agenten, der Vorverarbeitungsschritte ausführt (z.B. Kontextsuche, Prompt-Erweiterung, Werkzeugaufrufe).
  4. Weiterleitung der aufbereiteten Anfrage an ein LLM mit OpenAI-kompatibler REST-API.
  5. Postprocessing der LLM-Antwort (z.B. Extraktion strukturierter Resultate, Fehlerbehandlung, Logging) und Rückgabe an den ursprünglichen Anfragenden.

Die API bleibt streng modular: Planung unter /Planung/, Umsetzung unter /Entworfener_Code/.


Anwendungsfälle

Use-Case Beschreibung
submit_task Externe Systeme übermitteln komplexe Arbeitsaufträge an den Agenten.
status_query Abfrage, ob ein Auftrag bereits verarbeitet wurde (Polling).
cancel_task Steuerung laufender Aufträge (Cancel/Abort).
interactive_chat Ad-hoc-Konversationen mit dem LLM inkl. Kontextanreicherung.
tool_feedback Worker meldet Zwischenergebnisse zurück, die an das LLM angehängt werden.

API-Design (OpenAPI)

Basisdaten

  • Base Path: /api/agent
  • Version: v1
  • Schema: JSON (application/json)
  • Authentifizierung: zukünftige Erweiterung; initial optionales api_key-Header-Feld.
  • Fehlerformat: RFC7807-kompatibles JSON (type, title, detail, instance, optionale meta).

Endpunkte (first iteration)

Methode & Pfad Zweck Status
POST /v1/tasks Erstellt neuen Auftrag. Implementieren
GET /v1/tasks/{task_id} Status & Ergebnis abrufen. Implementieren
POST /v1/chat Direkter Chat (Streaming optional). Optional (Stretch)
POST /v1/tasks/{task_id}/cancel Laufenden Auftrag abbrechen. Optional
POST /v1/tasks/{task_id}/feedback Worker liefert Zwischenstände/Tool-Ausgaben. Optional

Komponentenarchitektur

FastAPI Router (agent_api/router.py)
└── AgentService (agent_api/service.py)
    ├── WorkerAdapter (agent_api/worker_adapter.py)
    ├── LLMClient (agent_api/llm_client.py)
    ├── Persistence (optional spätere Erweiterung)
    └── Config Provider (agent_api/config.py)

1. Router (router.py)

  • Definiert die FastAPI-Routen und Pydantic-Modelle.
  • Validiert Eingaben (z.B. Pflichtfelder, Limits).
  • Übersetzt Exceptions in HTTP-Fehler (Problem Details).

2. Service (service.py)

  • Zentrale Koordinationslogik.
  • Verantwortlich für:
    • Generierung Task-ID.
    • Übergabe an WorkerAdapter (Vorverarbeitung).
    • Aufruf des LLMClient.
    • Zusammenführung von Ergebnissen, Logging, Telemetrie.
  • Kapselt Retries, Timeout-Handling, Circuit-Breaker (später).

3. WorkerAdapter (worker_adapter.py)

  • Abstraktionslayer für Worker/Agenten (lokal, remote, Message-Bus).
  • Erste Version: synchroner Stub, der eingehende Daten durchreicht.
  • Später: Integration in Task-Queue (Celery, Arq, RQ) oder Event-System.

4. LLMClient (llm_client.py)

  • Kapselt HTTP-Aufrufe gegen OpenAI-kompatible APIs.
  • Unterstützt:
    • Text Completion / Chat Completion.
    • Streaming (später).
    • Fehlerbehandlung (Rate-Limit, Timeout, Invalid Request).
  • Konfiguration aus agenten-spezifischem Config-File (API-Key, Endpoint, Model).

5. Config (config.py)

  • Lädt agent_api.yaml (siehe unten) und ermöglicht Zugriffe auf Parameter.
  • Option auf Umgebungsvariablen (Override sensibler Felder, z.B. API-Key).
  • Links zur globalen Config (00_Globale_Richtlinien/Entworfener_Code/app/src/config_loader.py).

Konfigurationsschema (agent_api.yaml)

agent_api:
  metadata:
    version: "0.1.0"
    description: "Agent Gateway für Worker + OpenAI-kompatible LLMs"

  http:
    base_path: "/api/agent/v1"
    timeout_seconds: 60
    rate_limit_per_minute: 120
    enable_cors: true

  auth:
    api_key_header: "x-agent-api-key"
    allowed_keys: []        # Optional: Liste statischer Schlüssel
    allow_unauthenticated: true

  worker:
    adapter: "inline"       # inline | queue | external
    endpoint: null          # URL falls adapter=external
    timeout_seconds: 30

  llm:
    provider: "openai"      # openai | azure_openai | anthropic (kompatibel)
    base_url: "https://api.openai.com/v1"
    model: "gpt-4o-mini"
    temperature: 0.2
    max_tokens: 1200
    api_key: null           # via ENV: AGENT_API_LLM_KEY
    request_timeout_seconds: 45
    retry:
      max_attempts: 3
      backoff_seconds: 2

  execution:
    mode: "async"              # async | sync
    response_timeout_seconds: 30
    queue_ttl_seconds: 300
    heartbeat_interval_seconds: 10
    allow_long_polling: true

  logging:
    enabled: true
    log_payloads: false
    redact_fields:
      - "user_input"
      - "llm_response"
  • Sensible Werte (API-Key) werden über Umgebungsvariablen überschrieben.
  • adapter kann später für Worker-Typen erweitert werden.

Timeout- und TTL-Strategie

Verhalten von OpenAI-kompatiblen APIs

  • Der Standard-Endpunkt von OpenAI (und kompatiblen Anbietern) ist request/response-basiert. Wenn ein LLM länger braucht, bestimmt der Client, wie lange er wartet, bevor er mit einem Timeout abbricht.
  • HTTP-Clients sowie Proxys besitzen meist ein Standard-Timeout (z.B. 3060Sekunden). Bleibt die Antwort länger aus, wird die Verbindung beendet unabhängig davon, ob der LLM-Aufruf intern noch läuft.
  • Streaming-Endpunkte (Server-Sent Events) halten die Verbindung offen. Sobald keine Daten übertragen werden, trennen viele Proxys nach ihrer Idle-Timeout-Regel.

Anforderungen für die Agenten-API

  • Verhindern, dass externe Clients wegen langer LLM-Laufzeiten abbrechen.
  • Aufträge weiterbearbeiten können, auch wenn der initiale HTTP-Request beendet wurde.
  • Ergebnisse bereitstellen, sobald sie fertig sind (Polling, später Webhook/Streaming).

Konzept und API-Verhalten

  1. Async-Standardmodus (execution.mode = "async")
    • POST /v1/tasks antwortet unmittelbar mit 202 Accepted + task_id.
    • Verarbeitung geschieht im Hintergrund (WorkerAdapter).
  • Client ruft periodisch GET /v1/tasks/{task_id} auf. Optional ermöglicht allow_long_polling längeres Offenhalten der Verbindung mit Retry-After-Headern.
  1. Synchroner Modus (execution.mode = "sync")
    • Die API wartet maximal response_timeout_seconds.
    • Benötigt das LLM länger, wird eine Antwort mit 408 Request Timeout oder erneut 202 Accepted plus Hinweis zurückgegeben.
    • Die Aufgabe bleibt aktiv; Clients können später den Status abrufen.
  2. TTL und Heartbeat
    • queue_ttl_seconds begrenzt die Gesamtlebensdauer eines Tasks (z.B. 5Minuten).
    • heartbeat_interval_seconds definiert, wie oft Worker/Adapter Aktivität melden. Bleibt der Heartbeat aus, wird der Task als expired markiert.

Status-Codes und Rückmeldungen

  • 202 Accepted: Aufgabe angenommen, Verarbeitung läuft. Response enthält task_id, status = processing, optional retry_after.
  • 200 OK: Aufgabe abgeschlossen. Antwort enthält fertige result-Payload sowie Metadaten (duration_ms, completed_at).
  • 408 Request Timeout: Synchroner Modus, Ergebnis liegt noch nicht vor. Response enthält task_id, status = processing, detail = "still_running".
  • 410 Gone: Aufgabe abgelaufen (expired) oder bewusst entfernt.
  • 500 Internal Server Error: Verarbeitung fehlgeschlagen. Response enthält Fehlerdetails und Hinweise zum Retrying.

Integration in die Implementierung

  • AgentService verwaltet Task-Status (processing, succeeded, failed, expired) und entscheidet anhand der Konfiguration über Sync/Async-Verhalten.
  • WorkerAdapter sendet Heartbeats; bleibt dieser aus, sorgt die TTL für automatisches Aufräumen.
  • LLMClient respektiert request_timeout_seconds und retry-Parameter; nach ausgeschöpften Retries wird der Task auf failed gesetzt.
  • Persistenzschicht (später Redis/DB) speichert expires_at und last_heartbeat, sodass Expiration sauber umgesetzt werden kann.

Damit ist festgelegt, wie der Agent weiterarbeitet, obwohl ein Client den ursprünglichen HTTP-Request beendet oder ein Timeout erreicht. Die Agenten-API übernimmt das Handling von Time-to-Live und Task-Lebenszyklen und stellt sicher, dass LLM-Laufzeiten den Client nicht blockieren.


Sequenzfluss (High-Level)

  1. Client sendet POST /v1/tasks mit Payload (user_input, optional context, metadata).
  2. Router validiert Payload → ruft AgentService.submit_task.
  3. AgentService:
    1. erzeugt Task-ID, speichert Minimalzustand (in-memory, später DB).
    2. ruft WorkerAdapter.pre_process für Kontextanreicherung.
    3. erstellt Request an LLMClient.generate.
  4. LLMClient:
    • baut ChatCompletion- oder Completion-Request.
    • sendet HTTP-Request (mit API-Key, Timeout, Retries).
  5. AgentService sammelt Antwort, führt optional Postprocessing aus (z.B. extrahierte Schritte).
  6. Router liefert HTTP-Response mit Task-ID, Status, generiertem Output.

Für GET /v1/tasks/{task_id} werden Ergebnisse aus internem Store (in-memory, Pydantic-Dict[str, TaskStatus]) gelesen; langfristig Persistenz (Redis/DB).


Integration mit Haupt-App

  • 00_Globale_Richtlinien/Entworfener_Code/app/code/app/main.py erweitert Try-Import:
    try:
        from agent_api.router import agent_router
        app.include_router(agent_router, prefix="/api")
    except Exception:
        ...
    
  • agent_api.router sorgt selbst für Prefix /agent.
  • Konfiguration: agent_api.yaml wird in start.py oder neuem Initialisierungsschritt geladen (via config_loader.Settings oder separatem Loader).

Tests & Qualität

  • Unit-Tests für Service + LLMClient (Mock HTTPX).
  • FastAPI TestClient für Endpunkte (Beispiel-Request + Response).
  • Konfig-Validierung (Fehlende API-Keys → Fehler).
  • Logging-Integration (ggf. in SQLite/External Logging einspeisen).

Offene Punkte / Nächste Schritte

  1. Planung finalisieren (dieses Dokument).
  2. Konfigurationsdatei app/config/agent_api.yaml erstellen.
  3. Codegerüst unter app/src/agent_api/ implementieren:
    • config.py, models.py, service.py, worker_adapter.py, llm_client.py, router.py.
  4. Tests: app/tests/test_agent_api.py.
  5. Integration in create_app + start.py.
  6. Security: API-Key-Check und Rate-Limiting (Basis).
  7. Dokumentation: README + Beispiel-Requests.

Dieses Dokument dient als Referenz und Abstimmungspunkt, bevor mit der Implementierung fortgefahren wird.