Files
KI-Cluster-Roadmap/00_Globale_Richtlinien/Planung/Komponenten_Standardstruktur.md
2025-11-12 11:49:38 +01:00

17 KiB
Raw Blame History

🧩 Komponenten-Standardstruktur

1. Ziel

Dieses Dokument beschreibt die einheitliche interne Struktur, den Lebenszyklus und die Schnittstellen aller Programme, Module und Komponenten im KI-Cluster.
Ziel ist, dass jede Komponente ob Router, API-Server, Agent, Speicher oder Tool nach demselben Aufbau funktioniert und sich konsistent starten, erweitern und warten lässt.


2. Grundprinzip

Jede Komponente ist ein eigenständiges, klar abgegrenztes Modul.
Eine Komponente kann:

  • Aufgaben empfangen (z.B. vom Router oder über eine API),
  • eigene Logik ausführen (lokal oder verteilt),
  • Ergebnisse speichern oder weiterleiten,
  • und Statusinformationen melden.

Diese Struktur erlaubt, dass alle Module untereinander austauschbar bleiben und dennoch einheitlich funktionieren.


3. Standardverzeichnisstruktur

/<Komponentenname>/
│
├── Planung/
│   ├── Architektur.md
│   ├── Funktionsbeschreibung.md
│   └── Kommunikationsschnittstellen.md
│
├── Entworfener_Code/
│   ├── start.py
│   ├── config.yaml
│   ├── src/
│   │   ├── core.py
│   │   ├── logic.py
│   │   ├── api_connector.py
│   │   └── storage.py
│   ├── tests/
│   │   └── test_core.py
│   └── README.md
│
└── README.md

4. Klassenaufbau

Jede Komponente kann, falls objektorientiert entwickelt, auf einer einheitlichen Basisklasse aufbauen, um Grundfunktionen wie Logging, Config-Handling und Kommunikation gemeinsam zu nutzen.

# Datei: src/core.py

from utils.api_client import APIClient
from utils.memory_connector import Memory
from utils.logging_setup import get_logger

class BaseComponent:
    """Abstrakte Basisklasse für alle Komponenten des KI-Clusters."""

    def __init__(self, name: str):
        self.name = name
        self.api = APIClient()
        self.memory = Memory()
        self.logger = get_logger(name)

    def register(self):
        """Registriert die Komponente beim Router oder Systembus."""
        self.logger.info(f"{self.name} registriert sich beim System.")
        self.api.register_component(self.name)

    def start(self):
        raise NotImplementedError("Jede Komponente muss eine start()-Methode implementieren.")

Beispiel für eine spezialisierte Komponente:

# Beispiel: Router-Modul

from src.core import BaseComponent

class RouterModule(BaseComponent):
    """Koordiniert Aufgaben zwischen Komponenten und verteilt Anfragen."""

    def start(self):
        self.logger.info("Router gestartet.")
        self.listen_for_tasks()

    def listen_for_tasks(self):
        # Beispielhafte Implementierung
        self.logger.info("Warte auf eingehende Aufgaben...")

5. Lebenszyklus einer Komponente

Phase Beschreibung
Initialisierung start.py lädt Konfiguration, Logging und die src/core.py-Klasse.
Registrierung Komponente meldet sich beim Router oder globalen System an.
Ausführung Logik läuft (z.B. Verarbeitung, API-Handling, Kommunikation).
Feedback Ergebnisse oder Status werden an zentrale Systeme übermittelt.
Beendigung Logs und Speicherzustände werden gesichert, Prozesse sauber beendet.

6. Konfigurationsdatei (config.yaml)

Beispiel:

component:
  name: "RouterModule"
  type: "Systemkomponente"
  version: "1.0"

communication:
  router_endpoint: "http://localhost:5000"
  memory_endpoint: "http://localhost:6000"

logging:
  level: "INFO"
  file: "logs/router_module.log"

7. Gemeinsame Schnittstellen

Schnittstelle Zweck Implementierung
APIClient Kommunikation zwischen Komponenten utils/api_client.py
Memory Zugriff auf Wissensspeicher utils/memory_connector.py
Logger Zentrales Logging-System utils/logging_setup.py
Config Loader Einheitliche YAML-Konfiguration utils/config_loader.py

8. Kommunikation zwischen Komponenten

Jede Komponente unterstützt mindestens folgende Methoden:

Methode Beschreibung
register() Meldet sich beim zentralen System an
start() Startet die Logik der Komponente
receive_message(data: dict) Empfängt Nachrichten oder Aufgaben
send_message(data: dict) Sendet Ergebnisse oder Events
shutdown() Fährt die Komponente kontrolliert herunter

9. Anforderungen an neue Komponenten

Neue Komponenten müssen:

  1. von BaseComponent erben (falls OOP),
  2. in start.py eingetragen werden,
  3. ihre Konfiguration in config.yaml speichern,
  4. Unit-Tests unter /tests/ bereitstellen,
  5. und saubere Logging- sowie Feedback-Mechanismen besitzen.

10. Beispielkommunikation

# Beispiel: Router sendet Aufgabe an API-Modul

task = {
    "type": "fetch_data",
    "parameters": {"url": "https://example.com/api"}
}

api_module.receive_message(task)

Die Komponente führt die Aufgabe aus und antwortet:

result = {
    "status": "success",
    "data": {"records": 24}
}
api_module.send_message(result)

11. Zusammenfassung

Alle Komponenten im System folgen diesem Grundschema.
Dadurch wird erreicht, dass:

  • der Router alle Programme gleich ansprechen kann,
  • der Builder-Agent neue Komponenten automatisch integrieren kann,
  • und das gesamte System modular, testbar und erweiterbar bleibt.

© 2025 KI-Cluster Homelab Architektur
Autor: [Dein Name oder Alias]

3.1 Variante: FastAPI-Web-API-Komponente (empfohlen)

Diese Variante verankert die lauffähige Grundstruktur für API-basierte Komponenten mit FastAPI, Logging und Tests.

/<Komponentenname>/
│
├── Planung/
│   ├── Architektur.md
│   ├── Funktionsbeschreibung.md
│   └── Kommunikationsschnittstellen.md
│
├── Entworfener_Code/
│   ├── start.py
│   ├── requirements.txt
│   ├── README.md
│   ├── Dockerfile
│   ├── docker-compose.yml
│   ├── app/
│   │   └── main.py
│   ├── api/
│   │   ├── __init__.py
│   │   ├── router.py
│   │   └── routes/
│   │       ├── __init__.py
│   │       └── execute.py
│   ├── core/
│   │   └── base_component.py
│   ├── config/
│   │   ├── config.yaml
│   │   └── logging.yaml
│   └── tests/
│       └── test_smoke.py
│
└── README.md

Pflichten dieser Struktur:

  • start.py: lädt Konfiguration (config/config.yaml), initialisiert Logging (config/logging.yaml) und startet den FastAPI-Server (uvicorn, optional Factory/Reload).
  • app/main.py: erzeugt die FastAPI-App (create_app), bindet CORS und registriert Router.
  • api/router.py und api/routes/execute.py: Beispiel-Routenstruktur inkl. POST /api/execute sowie GET /health.
  • core/base_component.py: Basisklasse mit Schnittstelle register() und start() für spätere Komponenten.
  • config/logging.yaml: Rotierende Logs (TimedRotatingFileHandler) und zentrale Logger (uvicorn, root).
  • tests/test_smoke.py: pytest-Smoketests für Health-Endpoint und /api/execute.
  • requirements.txt: Abhängigkeiten (u. a. fastapi, uvicorn, pyyaml, pytest, httpx).
  • Dockerfile, docker-compose.yml: Containerisierter Betrieb, Port 8000, Mounts für config/logs.
  • Namens-/Code-Style: snake_case, vollständige Typannotationen, Docstrings gemäß Richtlinien.

Hinweis: Diese Variante ergänzt die allgemeine Standardstruktur aus Abschnitt 3 für API-orientierte Komponenten und dient als verbindlicher Grundstock, auf dem spätere Erweiterungen aufbauen.

12. Laufzeit-Zielsetzung und Start-Events

  • Das Laufzeitprogramm start.py bleibt dauerhaft aktiv, da es einen Webserver offen hält und Anfragen entgegennimmt.
  • Der Code ist so vorzubereiten, dass bei eingehenden Start-Events (z.B. POST /start) ein Start-Prozess ausgelöst werden kann.
  • Mehrere Start-Events dürfen möglich sein. Die Entscheidung, ob diese ignoriert, parallel oder in einer Queue verarbeitet werden, wird in dieser Phase bewusst offengelassen und nur als Planungs-Hinweis dokumentiert. Die konkrete Ausführungsstrategie wird später festgelegt.

13. API-Struktur (Minimal-API unter src/api.py)

  • Eine Minimal-API wird in src/api.py bereitgestellt.
  • Der Webserver lauscht auf dem in der Konfiguration definierten Port (Standard 8000).
  • start.py startet den API-Server und bleibt aktiv, um Anfragen verarbeiten zu können.
  • Die Minimal-API umfasst mindestens:
    • POST /start: löst den Start-Prozess aus (nicht-blockierend).
    • Optional GET /health: einfacher Health-Check.
  • Die API darf den Event-Handling-Pfad nicht blockieren; Start-Prozesse werden asynchron oder in eigenen Threads/Tasks ausgeführt.

14. Globales Konfigurationssystem

Es gibt eine einzige globale Konfiguration. Die Struktur ist folgendermaßen vorgegeben:

+-- globale_configuration
|   |-- variablename
|   |   |-- beschreibung erklärung
|   |   |-- wert
|
+-- logging
|   |-- variablename
|   |   |-- beschreibung erklärung
|   |   |-- wert
|
+-- worker
    |-- variablename
    |   |-- beschreibung erklärung
    |   |-- wert
  • Diese Konfiguration wird als Python-Struktur in src/config.py gepflegt und systemweit verwendet.
  • Zugriff erfolgt zentral über from src.config import CONFIG.
  • Der HTTP-Port wird ebenfalls in der globalen Konfiguration gepflegt (z.B. CONFIG["globale_configuration"]["port"]["wert"]).
  • Logging-Parameter (Level, Aktivierung, Ausgabeziele) werden ausschließlich über CONFIG gesteuert.

15. Technische Anforderungen (Laufzeit und Architektur)

  • Der Webserver darf beim Event-Handling nicht blockieren. HTTP-Handler delegieren die Start-Logik in asynchrone Tasks oder Threads.
  • Start-Routinen laufen asynchron (z.B. asyncio/BackgroundTasks) oder in eigenen Threads, sodass die API schnell antwortet.
  • Logging ist vollständig über die globale Konfiguration steuerbar (z.B. Level, Aktivierung).
  • Modulstruktur:
    • start.py: Einstiegspunkt (startet Webserver, bleibt aktiv)
    • src/config.py: zentrale Konfiguration (CONFIG)
    • src/api.py: API-Definition (u.a. POST /start)
    • src/worker.py: Start-/Arbeitslogik (ausgelöst durch Events)
    • src/logger.py: Logging-Setup/-Zugriff

16. Beispiel-/Gerüstcode in Entworfener_Code

Hinweis: Es handelt sich um Struktur- und Ablaufgerüste (kein finaler Code, keine vollständige Implementierung). Ziel ist, Verantwortlichkeiten und Aufrufreihenfolge klar zu dokumentieren.

Beispiel src/config.py:

# Globale Konfiguration als Python-Struktur (zentrale Quelle der Wahrheit)
CONFIG: dict = {
    "globale_configuration": {
        "port": {
            "beschreibung": "HTTP-Port des API-Servers",
            "wert": 8000,
        },
        "environment": {
            "beschreibung": "Laufzeitumgebung",
            "wert": "dev",
        },
    },
    "logging": {
        "enabled": {"beschreibung": "Aktiviert das Logging", "wert": True},
        "level": {"beschreibung": "Log-Level (z. B. INFO, DEBUG)", "wert": "INFO"},
    },
    "worker": {
        "concurrency": {
            "beschreibung": "Parallelisierungsgrad (Threads/Tasks), strategische Nutzung offen",
            "wert": 1,
        },
    },
}

Beispiel src/logger.py:

import logging
from src.config import CONFIG

def get_logger(name: str) -> logging.Logger:
    logger = logging.getLogger(name)
    logger.setLevel(getattr(logging, str(CONFIG["logging"]["level"]["wert"]).upper(), logging.INFO))
    return logger

Beispiel src/worker.py:

from typing import Any, Dict
from src.logger import get_logger

async def trigger_start(payload: Dict[str, Any]) -> None:
    logger = get_logger("worker")
    logger.info("Start-Event angenommen (Gerüst).")

Beispiel src/api.py:

from typing import Any, Dict, Optional
from fastapi import FastAPI, BackgroundTasks
from pydantic import BaseModel
from src.config import CONFIG
from src.logger import get_logger
from src.worker import trigger_start

app = FastAPI(title="Minimal-API (Gerüst)")

class StartRequest(BaseModel):
    job_id: Optional[str] = None
    params: Optional[Dict[str, Any]] = None

@app.post("/start")
async def start_endpoint(req: StartRequest, background: BackgroundTasks) -> Dict[str, str]:
    logger = get_logger("api")
    logger.info("Start-Event empfangen (Gerüst).")
    background.add_task(trigger_start, (req.dict()))
    return {"status": "accepted"}

Ablauf-Skizze start.py (Beschreibung):

  • Liest die globale Konfiguration aus src/config.py (oder eine projektspezifische Quelle).
  • Initialisiert das Logging über src/logger.py.
  • Startet den Webserver (z.B. uvicorn src.api:app) auf dem in CONFIG definierten Port und bleibt aktiv.
  • Nicht-blockierender Betrieb: API antwortet unmittelbar; Arbeitslogik läuft asynchron/parallel.

17. Restart-/Reload-Funktion (über API)

Ziel

  • Während der Laufzeit soll eine über die API verfügbare Funktion einen Neustart des Python-Prozesses anstoßen, um Konfigurationsänderungen zu übernehmen oder nach Laufzeiterweiterungen sauber durchzustarten.
  • Endpunkte: POST /restart sowie Alias POST /reload.

Vorgaben

  • Nicht-blockierend: Der HTTP-Handler bestätigt den Auftrag zeitnah und plant den Neustart im Hintergrund mit kurzer Verzögerung (z.B. 3001000ms), damit die Antwort noch übertragen werden kann.
  • Prozess-Neustart: Entweder durch einen Vollneustart des Python-Prozesses (z.B. via os.execv) oder durch einen Supervisor (Docker/Compose/Systemd/K8s). In der Scaffold-Phase wird der direkte Prozess-Neustart skizziert.
  • Konfiguration: Optionaler Request-Parameter delay_ms zur Steuerung der Verzögerung vor dem Neustart. Weitere Steuerung (z.B. Freigabe-Flag, Backoff) kann über die zentrale CONFIG erfolgen.
  • Sicherheit/Robustheit (Hinweise):
    • Schutz vor Restart-Loops (Backoff/Minimum-Delay).
    • Optional Authentisierung/Autorisierung für administrative Endpunkte.
    • Log-Einträge vor Neustart (Grund, Zeitstempel, Kontext).
  • Start-/Mehrfach-Events: Die Strategie für konkurrierende Ereignisse bleibt offen (ignorieren, parallel, Queue). Der Restart-Event ist administrativ und sollte priorisiert behandelt werden, Details werden in der späteren Implementierung festgelegt.

Schnittstellenbeschreibung (Minimal)

  • POST /restart → Antwort: {"status": "scheduled", "delay_ms": <int>}
  • POST /reload → Alias zu /restart

Modulzuordnung

  • src/api.py: definiert die Endpunkte und plant den Neustart im Hintergrund.
  • src/worker.py: enthält die Restart-Hilfsroutine (z.B. restart_process(reason, delay_seconds)), die nach einer kurzen Verzögerung den Prozess ersetzt/neustartet.
  • start.py: bleibt dauerhaft aktiv; Neustart führt zur Neuinitialisierung inkl. erneuter Auswertung der Konfiguration.

3.2 Alternative Struktur: app/code-Aufteilung (empfohlen für klare Trennung)

Diese Variante verschiebt den ausführbaren Code, Tests und die API-Struktur unterhalb von app/code, während Konfigurationsdateien unter app/config leben. Einstiegspunkt und komponentenbezogene README liegen unter app/. Artefakte wie Dockerfile, docker-compose und requirements verbleiben auf oberster Ebene von Entworfener_Code/.

Entworfener_Code
├── app
│   ├── code
│   │   ├── api
│   │   │   ├── __init__.py
│   │   │   ├── router.py
│   │   │   └── routes
│   │   │       ├── execute.py
│   │   │       └── __init__.py
│   │   ├── app
│   │   │   └── main.py
│   │   ├── core
│   │   │   └── base_component.py
│   │   ├── src
│   │   │   ├── api.py
│   │   │   ├── config.py
│   │   │   ├── logger.py
│   │   │   └── worker.py
│   │   └── tests
│   │       └── test_smoke.py
│   ├── config
│   │   ├── config.yaml
│   │   └── logging.yaml
│   ├── README.md
│   └── start.py
├── docker-compose.yml
├── Dockerfile
└── requirements.txt

Leitlinien für diese Struktur:

  • app/start.py bleibt dauerhaft aktiv (Webserver offen) und liest Konfiguration aus app/config.
  • API für Start-Events und Admin-Endpunkte (POST /start, /restart, /reload) liegt in app/code/src/api.py. Diese Endpunkte dürfen nicht blockieren; Ausführung wird an app/code/src/worker.py delegiert (async/Threads).
  • Zentrale, einzige globale Konfiguration als Python-Struktur in app/code/src/config.py (from src.config import CONFIG); YAML-Konfigurationsdateien ergänzen diese bei Bedarf (z.B. für externe Operatoren) und werden in app/config gepflegt.
  • Logging wird über CONFIG gesteuert. Ein Gerüst für Logging-Zugriff liegt in app/code/src/logger.py; systemweite Handler/Formatter werden später konsolidiert.
  • Die beispielhafte Router-Struktur für REST-Endpunkte liegt in app/code/api und wird in app/code/app/main.py eingebunden.
  • Tests unter app/code/tests (pytest-Namenskonventionen test_*.py).

Hinweis zu Restart/Reload:

  • Die Endpunkte POST /restart und POST /reload planen (nicht-blockierend) einen Prozessneustart ein, um Konfigurationsänderungen oder Erweiterungen aufzunehmen. Die konkrete Neustartstrategie (Supervisor/execv, Backoff, Auth) ist bewusst noch offen und wird in einer späteren Implementierungsphase festgelegt.