Files
KI-Cluster-Roadmap/01_Modulerweiterungen/Planung/Agenten_API.md
2025-11-13 13:09:07 +01:00

247 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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**: 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
```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. 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.
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. 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:
```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.