Home Ai Tools Artikel 1
Teil 1 Generative AI

Beuys: Jeder Agent ist ein Künstler

Bild: KI-generiert


Beuys: Jeder Agent ist ein Künstler

Kleine, spezialisierte Werkzeuge als ideale Erweiterung für KI-Agenten.


1. Das Problem: Der Medienbruch im Agent-Workflow

KI-Agenten wie Claude Code arbeiten primär in einer textbasierten Umgebung (Terminal, Editor). Die Notwendigkeit einer visuellen Ausgabe führt in der Praxis oft zu einem signifikanten Medienbruch:

  1. Kontextwechsel: Der Entwickler muss den Editor verlassen und den Browser öffnen.
  2. Manueller Prozess: Einloggen bei Portalen wie Midjourney oder DALL-E.
  3. Integration: Das Herunterladen und Einordnen der generierten Bilder in das Projektverzeichnis erfolgt händisch.

Dieser Bruch verhindert die vollständige Automatisierung von Workflows, bei denen Bildmaterial (z. B. Icons für Dokumentationen oder UI-Elemente) direkt durch den Agenten erzeugt werden soll.

"A tool should be transparent. It should not be something you think about. It should be something you think with." — Bjarne Stroustrup: The C++ Programming Language

Für einen Agenten ist ein Tool dann "transparent", wenn es über eine standardisierte Schnittstelle (CLI) aufrufbar ist und deterministische Ergebnisse liefert.

2. Die Lösung: Bildgenerierung per CLI

beuys ist ein minimalistisches Werkzeug, das die Bildgenerierung in den Terminal-Workflow integriert. Es reduziert die Interaktion auf einen einzigen Befehl:

beuys "Ein minimalistisches Icon für ein Terminal-Tool" --size 1024x1024

Die Vorteile für den Agenten und den Entwickler: - Kontext-Erhalt: Der Aufruf erfolgt direkt aus dem Arbeitsverzeichnis. - Automatisierbarkeit: Der Agent kann das Tool selbstständig aufrufen, den Pfad des generierten Bildes erfassen und es weiterverarbeiten. - Minimalismus: Fokus auf eine einzige Aufgabe gemäß dem Unix-Prinzip.

→ GitHub: github.com/mhennemeyer/beuys

Installation

# Option A: Binary kopieren
cp scripts/dist/beuys /usr/local/bin/

# Option B: Direkt als Script ausführen
./scripts/beuys "Eine Blume im Sonnenlicht"

3. Implementierung: Zero-Dependency-Ansatz

Moderne Software-Stacks leiden häufig unter "Dependency Bloat". Ein CLI-Tool für Agenten sollte jedoch leichtgewichtig und auf jedem System ohne komplexe Installation (pip install ...) lauffähig sein.

❌ Impure/Heavy: OpenAI Client-Bibliothek

Die Nutzung des offiziellen Clients bringt transitive Abhängigkeiten mit sich und erfordert eine Pflege der Versionen.

from openai import OpenAI
client = OpenAI()

response = client.images.generate(
  model="dall-e-3",
  prompt="...",
  n=1,
)
image_url = response.data[0].url

✅ Pure/Light: Direkter API-Aufruf via urllib

beuys nutzt ausschließlich die Python-Standardbibliothek. Das macht das Tool immun gegen Änderungen in Drittanbieter-Bibliotheken und sorgt für sofortige Einsatzbereitschaft.

import json
import urllib.request

def call_openai(prompt, api_key):
    payload = json.dumps({
        "model": "dall-e-3",
        "prompt": prompt,
        "size": "1024x1024",
        "n": 1,
    }).encode("utf-8")

    req = urllib.request.Request(
        "https://api.openai.com/v1/images/generations",
        data=payload,
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}",
        },
        method="POST",
    )

    with urllib.request.urlopen(req) as resp:
        body = json.loads(resp.read().decode("utf-8"))
        return body["data"][0]["url"]

4. Architektur: Spezialisierung vs. Integration

Die Entscheidung gegen eine direkte Integration der Bildgenerierung als Plugin folgt architektonischen Überlegungen. Die Bereitstellung als eigenständiges, kleines Tool bietet mehrere Vorteile:

Merkmal Spezialisiertes Tool (Beuys) Integrierte Funktion
Testbarkeit Isoliert im Terminal testbar Erfordert komplettes Agenten-Setup
Wartbarkeit ~180 Zeilen Code, vollständig erfassbar Teil einer komplexen Codebase
Portabilität Als Binary überall einsetzbar Gebunden an den Agenten
Unix-Prinzip "Do one thing and do it well" "Swiss Army Knife" (Komplexität)

Diese Spezialisierung erlaubt es, die Bildgenerierung unabhängig vom Rest des Systems zu versionieren. Wenn sich die API von OpenAI ändert, muss nur dieses eine winzige Tool angepasst werden.

Selbst ausprobieren

Der zentrale Baustein des beuys-CLIs ist eine reine Funktion, die Eingabeparameter in ein API-konformes JSON-Payload überführt – ohne Netzwerk, ohne Seiteneffekt. Genau das macht das Tool testbar und API-Updates trivial: Was an OpenAI geschickt wird, lässt sich isoliert prüfen.

import json

def build_payload(prompt: str, size: str = "1024x1024", n: int = 1) -> dict:
    """Reiner Payload-Builder für die OpenAI Image-API."""
    if not prompt.strip():
        raise ValueError("prompt darf nicht leer sein")
    if size not in {"256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"}:
        raise ValueError(f"Ungültige size: {size}")
    return {
        "model": "dall-e-3",
        "prompt": prompt.strip(),
        "size": size,
        "n": n,
    }

def encode_payload(payload: dict) -> bytes:
    """Serialisierung getrennt vom Bauen – Single Responsibility."""
    return json.dumps(payload).encode("utf-8")

examples = [
    ("Ein minimalistisches Icon für ein Terminal-Tool", "1024x1024"),
    ("Eine Blume im Sonnenlicht",                       "512x512"),
]

for prompt, size in examples:
    payload = build_payload(prompt, size=size)
    body = encode_payload(payload)
    print(f"prompt={prompt!r:50}  size={size:9}  bytes={len(body)}")
    print(f"  payload = {payload}")

Erweiterungs-Idee: Ergänze einen reinen validate_prompt-Helper (z. B. Mindestlänge, verbotene Begriffe) und kombiniere ihn mit build_payload zu einer kleinen Pipeline – die Funktion bleibt rein und ohne Netzwerk testbar.

Genau diese Erweiterung machen wir jetzt: Ein reiner validate_prompt-Helper plus eine kleine prepare-Pipeline, die Validierung und Payload-Bau verkettet. Das Ergebnis ist ein Tupel ("ok", payload) oder ("err", reason) – ohne Exception, ohne Seiteneffekt, problemlos in Tests einsetzbar.

FORBIDDEN = {"nsfw", "violence", "blood"}

def validate_prompt(prompt: str, min_len: int = 8):
    """Reiner Validator: (ok, prompt) oder (err, reason)."""
    p = prompt.strip()
    if len(p) < min_len:
        return ("err", f"prompt zu kurz (<{min_len} Zeichen)")
    lowered = p.lower()
    hit = next((w for w in FORBIDDEN if w in lowered), None)
    if hit:
        return ("err", f"verbotener Begriff: {hit!r}")
    return ("ok", p)

def build_payload(prompt: str, size: str = "1024x1024", n: int = 1) -> dict:
    return {"model": "dall-e-3", "prompt": prompt, "size": size, "n": n}

def prepare(prompt: str, size: str = "1024x1024"):
    """Pipeline: validate → build_payload. Bleibt rein."""
    status, value = validate_prompt(prompt)
    if status == "err":
        return ("err", value)
    return ("ok", build_payload(value, size=size))

cases = [
    "Ein minimalistisches Icon für ein Terminal-Tool",
    "kurz",                              # zu kurz
    "Bild mit NSFW-Inhalt bitte",        # verbotener Begriff
    "Eine Blume im Sonnenlicht",
]
for c in cases:
    print(f"{c!r:48} → {prepare(c)}")

5. Fazit

beuys zeigt, dass funktionale Erweiterungen für KI-Agenten keine komplexen Frameworks benötigen. Ein tiefes Verständnis der Standard-Protokolle (HTTP/JSON) und der Verzicht auf unnötige Abhängigkeiten führen zu robusteren und wartbareren Systemen.


Quellen & Ressourcen

📄 Als PDF