# Agenten-API – Planung & Architektur ## Zielsetzung Die Agenten-API erweitert die Basis-API aus [`00_Globale_Richtlinien`](../00_Globale_Richtlinien/README.md) 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**: RFC 7807-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 ```plaintext 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`) ```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. 30–60 Sekunden). 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. 2. **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. 3. **TTL und Heartbeat** - `queue_ttl_seconds` begrenzt die Gesamtlebensdauer eines Tasks (z. B. 5 Minuten). - `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: ```python 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.