Ein Kind tippt auf einen Wolf. In weniger als drei Sekunden heult es aus dem Lautsprecher. Kein Sample aus einer Bibliothek. Sondern ein Klang, den ein KI-Modell in genau diesem Moment erzeugt hat, auf einem Rechner im eigenen Büro oder Keller.

Das ist Sound Box. Und der Weg dorthin war interessanter als das Ergebnis.

In den letzten Tagen habe ich Stable Audio 3 Small SFX auf meinem Server installiert und als API-Endpunkt bereitgestellt. Beides habe ich hier auf meinem Blog ausführlich beschrieben. Jetzt ging es um die Frage, was man damit eigentlich anfängt.

Die Idee

Ein Kommandozeilenwerkzeug ist schön. Aber es ist kein User-Interface für Kinder…

Der Auslöser war banal. Wie kann ich ein Video vertonen mit verschiedenen Sound-Effekten wie wir es in Filmen kennen. Ein Textfeld, in das man einen englischen Prompt tippt, hilft einem Kind nicht wirklich weiter. Er müsste wissen, dass das Modell nur auf Englisch vernünftig arbeitet. Er müsste wissen, dass vage Beschreibungen auch keine guten Ergebnisse liefern.

Kinder brauchen keine Eingabefelder. Kinder brauchen Bilder zum Antippen.

Was die App macht

Sound Box bietet daher zwei Möglichkeiten an einen Sound-Effekt generieren zu lassen.

  • Der erste Weg sind große bunte Kacheln, sortiert nach fünf Kategorien. Tiere, Wetter, Draußen, Fahrzeuge und Zuhause. Hinter jeder Kachel liegt ein sorgfältig formulierter englischer Prompt. Ein Tipp auf den Hahn, und im Hintergrund geht „rooster crowing at dawn, close mic, clean recording“ an den Server.
  • Der zweite Weg ist das Feld Your idea. Dort kann man frei beschreiben, was man hören will. Diese Eingabe geht nicht direkt an das Audiomodell, sondern erst an ein Sprachmodell, das daraus einen brauchbaren Prompt formt.

Alle erzeugten Klänge landen unter My Sounds als Kacheln mit Abspielknopf, Speichern-Button und Löschen.

Sound-Box effect generator

Sound-Box effect generator

Die Oberfläche ist komplett auf Englisch. Das war eine bewusste Entscheidung. Die Prompts für das Audiomodell müssen ohnehin englisch sein, weil es auf englischen Beschreibungen trainiert wurde. Eine zweisprachige App hätte eine Übersetzungsschicht gebraucht, die niemand pflegen will.

Die drei Bausteine

Sound Box ist kein Monolith. Es sind drei Dienste, die alle bei mir im Netzwerk laufen.

Dienst Aufgabe Läuft auf
Stable Audio 3 Small SFX erzeugt die WAV-Dateien RTX 6000 Ada, FastAPI, Port 8770
Ollama mit qwen3.8:27b formt freie Eingaben zu Prompts zweiter Server im LAN
Node.js Frontend Oberfläche, Galerie, Dateiverwaltung Port 7870

Kein Cloud-Zugang. Kein API-Key eines Anbieters. Kein Abo. Wenn ich das Netzwerkkabel ziehe, funktioniert alles weiter.

Wie ich Stable Audio 3 installiert und als API-Endpunkt bereitgestellt habe, findest Du in diesen beiden Beiträgen:

Wie die App entstanden ist

Und jetzt kommt der Teil, der mich eigentlich beschäftigt hat. Ich habe keine Zeile Code für Sound Box selber geschrieben.

Die komplette Umsetzung hat OpenCode übernommen, angetrieben von Qwen3.8 27B, das bei mir über Ollama läuft. Also wieder: kein externer Dienst, kein Token-Verbrauch bei einem Anbieter, kein Code, der irgendwohin abfließt.

Was ich stattdessen geschrieben habe, war ein Auftrag. Ein sehr genauer.

Video

Hier gibt es das Video zum Blog-Post auf YouTube: https://youtu.be/oGoUHWoyagE

Der Auftrag war die eigentliche Arbeit

Meine erste Fassung war zwei Seiten lang. Die Endfassung hat rund achthundert Zeilen. Der Unterschied liegt nicht in der Menge, sondern in der Art der Anweisungen. Ein paar Beispiele aus dem Dokument.

  • Ein DOM-Vertrag. Eine Tabelle mit jedem Element, das die Tests ansprechen müssen, samt festem Selektor. Dazu die Regel: Weicht die Umsetzung davon ab, ist das ein Fehler in der App und nicht im Test.
  • Ein Copy-Inventar. Eine Tabelle mit jedem sichtbaren Text der Oberfläche. Ohne die erfindet ein Agent beim Schreiben Formulierungen, und man bekommt drei Varianten derselben Fehlermeldung.
  • Ein Testhook am window-Objekt. Bei Audio kannst Du am DOM nicht prüfen, ob wirklich Ton herauskam. Deshalb hängt dauerhaft ein AnalyserNode in der Wiedergabekette, dessen Pegel die Tests auslesen können. Über 0,05 bedeutet: Es hat wirklich geklungen.
  • Zwei Mock-Server. Einer ersetzt im Test das Audiomodell und liefert eine WAV-Datei, deren Länge sich aus einem Hash des Prompts ergibt. Damit lässt sich beweisen, dass zwei verschiedene Prompts auch zwei verschiedene Dateien erzeugen. Der andere ersetzt Ollama und liefert absichtlich auch kaputtes JSON.
  • Eine Sprachprüfung als Test. „Kein Deutsch in der App“ als Satz im Auftrag reicht nicht. Das rutscht durch. Also läuft bei jedem Testlauf ein Prüfer über das gerenderte DOM und schlägt bei jedem Zeichen außerhalb von ASCII an, Emoji ausgenommen.
  • Ein Arbeitsjournal. Der Agent legt nach jedem Lauf eine Datei an: Was gebaut wurde, was kaputtging, welche Erkenntnis in welchen Skill gewandert ist.

Dazu die härteste Regel im ganzen Dokument: Never weaken a test to make it pass. Ohne die verschwindet bei der ersten roten Ampel die Assertion statt des Fehlers.

Hier die Datei zum Download mit der ihr selber direkt loslegen könnt. Dabei müsst ihr nicht zwinged OpenCode als Agenten-Framework verwenden…

Download: instruction_opencode.zip

Was gut funktioniert hat

Die Kacheln funktionieren genau so, wie ich es mir vorgestellt hatte. Antippen, kurze Wartezeit mit animierter Wellenform, Klang. Der fertige Sound spielt automatisch einmal ab. Das ist die Belohnung für den Tap, und sie sitzt.

Die Sperre während einer Generierung war die richtige Entscheidung. Kinder trommeln auf Bildschirme. Ohne diese Sperre stünden nach zehn Sekunden zwölf Anfragen in der Warteschlange.

Und die Qualität der Klänge überrascht mich immer noch. Regen, Wind, knarrende Türen und Lagerfeuer sind erstaunlich brauchbar. Tierstimmen sind durchwachsen, aber für ein Spielzeug allemal gut genug.

Was noch nicht rund ist

Hier die Verbesserungen die ich noch vornehmen möchte.

Die Prompt-Verbesserung über Ollama muss deutlich besser werden.

Das ist die größte Baustelle. Qwen3.8 27B ist ein Reasoning-Modell und denkt ausgiebig, bevor es antwortet. Das kostet Zeit, und bei einem Kind ist Wartezeit die härteste Währung überhaupt. Dazu kommt, dass die Ergebnisse schwanken. Manchmal entsteht aus einer knappen Eingabe ein präziser Prompt. Manchmal etwas erstaunlich Generisches.

Ich habe drei Ideen, die ich der Reihe nach durchprobieren werde. Ein kleineres Modell für diese Aufgabe, denn 27B ist für das Umformulieren eines Halbsatzes vermutlich völlig überdimensioniert. Deutlich mehr Beispiele im Systemprompt, weil Few-Shot bei so einer Formataufgabe mehr bringt als weitere Regeln in Prosa. Und ein vorgelagerter Cache, der bei bekannten Eingaben gar nicht erst fragt.

Die Wartezeit ist noch zu lang.

Bei einem freien Wunsch summieren sich der Denkvorgang des Sprachmodells und die Generierung des Klangs. Der zweistufige Ablauf mit Bestätigungsschritt federt das ab, aber er löst es nicht.

Fazit

Am meisten hat mich nicht das Ergebnis begeistert, sondern der Weg über die lokalen Services.

Ein lokal laufendes Modell hat aus einer schriftlichen Spezifikation eine funktionierende Anwendung gebaut, inklusive Testsuite. Das hätte ich vor zwei Jahren nicht für realistisch gehalten. Was dabei den Ausschlag gibt, ist nicht die Größe des Modells. Es ist die Präzision des Auftrags.

Jede Stunde, die ich in den Auftrag gesteckt habe, hat mir mehrere Stunden Nachbesserung erspart. Die Stellen, an denen ich vage geblieben bin, sind exakt die Stellen, an denen ich jetzt nachbessere.

Für mich ist Sound Box damit vor allem eins: der Beweis, dass die ganze Kette lokal funktioniert. Modell, API, Sprachmodell, Coding-Agent. Alles im eigenen Rack, nichts in der Cloud.

Im nächsten Schritt nehme ich mir die Prompt-Verbesserung vor. Darüber schreibe ich dann wieder.