Zum Hauptinhalt springen
OpenAI

Wie wir in sechs Monaten ein Echtzeitsystem für reaktionsschnelle Sprach-KI entwickelt haben

Von Justin Uberti und Zahan Malkani, Members of Technical Staff

Laden …

Bei Sprach-KI ist es schwieriger als gedacht, den richtigen Moment zum Sprechen zu erkennen. Menschen übergeben einander mühelos in Sekundenbruchteilen das Wort. Frühere Sprach-KI-Systeme konnten mit diesem Rhythmus jedoch nicht Schritt halten. Ihre rundenbasierte Architektur nutzte kleine Modelle, sogenannte Sprecherwechsel-Detektoren. Diese standen vor einer undankbaren Aufgabe: Entscheiden sie zu früh, wird die nutzende Person unterbrochen. Entscheiden sie zu spät, wirkt die Antwort träge. Erst nachdem der Detektor entschieden hatte, konnte das wesentlich größere LLM seine Arbeit aufnehmen.

GPT‑Live, unser Sprachsystem der dritten Generation, entfernt den Sprecherwechsel-Detektor aus dem Audiopfad. Sein Sprachmodell arbeitet im Vollduplexbetrieb und kann daher gleichzeitig zuhören und sprechen. Damit entfällt ein separater Detektor und Gespräche wirken unmittelbarer und natürlicher. Wenn tiefergehendes Reasoning oder die Nutzung von Tools erforderlich ist, kann GPT‑Live zudem unsere Frontier-Modelle wie GPT‑5.5 hinzuziehen, ohne den Gesprächsfluss zu unterbrechen. Zusammen verleihen diese Fähigkeiten GPT‑Live eine bisher unerreichte Kombination aus Reaktionsgeschwindigkeit im Gespräch und Intelligenz.

Um dieses Erlebnis in großem Maßstab bereitzustellen, war eine neue, auf geringe Latenz optimierte Systemarchitektur erforderlich. Anders als bei einer typischen Anfrage-Antwort-Inferenz streamt unser System eingehende Audiodaten in das Sprachmodell und die erzeugte Sprache zurück zu den Nutzenden. Die Delegation läuft dabei über einen separaten asynchronen Pfad. In den vergangenen sechs Monaten haben wir Modellinferenz, Kontextverwaltung und Medientransport überarbeitet, damit die Sprache im gesamten System gleichmäßig fließt.

Die Architektur schafft zudem eine klare Grenze zwischen dem zentralen Sprachpfad und der Anwendungslogik. So lässt sich das Verhalten der Anwendung einfach anpassen, ohne die Reaktionsgeschwindigkeit zu beeinträchtigen. Diese Grundlage unterstützt immer mehr Funktionen im ChatGPT Sprachchat. Dazu gehört auch die neu eingeführte Möglichkeit, deinen Computer zu steuern und deine Agenten in der ChatGPT‑Desktop‑App zu koordinieren.

In diesem Beitrag erklären wir, warum frühere rundenbasierte Systeme unsere Anforderungen nicht erfüllten und wie wir das neue System auf jeder Ebene für schnelle Reaktionen ausgelegt haben. Wir behandeln zustandsbehaftete Inferenz, dynamische Kontextverwaltung, asynchrone Delegation und Optimierungen auf Protokollebene. All dies wirkt zusammen, damit sich GPT‑Live wirklich live anfühlt.

Vom Sprecherwechsel zum Streaming

Frühere Spracharchitekturen übernahmen die rundenbasierte Funktionsweise textbasierter LLMs. Jeder Beitrag wurde jedoch nicht als Text, sondern als separater Audioblock dargestellt. In kaskadierten Systemen wurden Spracherkennung, LLM und Sprachsynthese nacheinander ausgeführt. Diese Abfolge erhöhte die Latenz und ignorierte Hinweise wie Tonfall und Sprechtempo.

Speech-to-Speech-Modelle verbesserten diesen Ansatz, indem sie Audiodaten direkt verarbeiteten. Da das Modell Sprache von Grund auf verstehen und erzeugen lernte, konnte es Details bewahren, die bei der Transkription verloren gehen, und schneller antworten. Das System war jedoch weiterhin auf den Sprecherwechsel-Detektor angewiesen, um den Beginn der Inferenz festzulegen. Das Modell übernahm einen größeren Teil der Interaktion, doch diese blieb rundenbasiert.

GPT‑Live überträgt dem Sprachmodell die Kontrolle über das Gespräch: Audiodaten fließen in das Modell hinein und wieder heraus, während tiefergehendes Reasoning und die Tool-Nutzung asynchron erfolgen. Die Hauptaufgabe des Systems besteht darin, eine unterbrechungsfreie Medienschleife aufrechtzuerhalten. Andere Aufgaben, etwa das Aufrufen führender Modelle und die dauerhafte Speicherung des Gesprächs, finden außerhalb des Live-Pfads statt.

Diagramm des Echtzeit-Sprachmodells im Frontend von GPT-Live mit asynchroner Delegation an ein Reasoning-Modell im Backend, Tool-Nutzung und bidirektionalem Audioaustausch mit Nutzenden.

Kontinuierliche Inferenz ermöglichen

Diese Medienschleife ohne Unterbrechung aufrechtzuerhalten, ist nicht immer einfach. Jede Verzögerung bei Transport, Verarbeitung oder Inferenz kann als Pause oder Störgeräusch hörbar werden. Ein früheres rundenbasiertes System konnte gewisse Schwankungen beim Eintreffen eines Audioblocks verkraften. Ein Live-Mediensystem muss dagegen jeden Audioframe pünktlich zustellen.

Frühere Arbeiten am ChatGPT Sprachchat und an der Realtime API schufen dafür eine wichtige Grundlage. Wir hatten bereits unsere Sprachinfrastruktur neu entwickelt, um Audio und Video mit geringerer und besser vorhersehbarer Latenz direkt in unsere Systeme und wieder heraus zu streamen. GPT‑Live führte dieses Konzept weiter und streamte Medien über ein neues zustandsbehaftetes Inferenzsystem für kontinuierliche Gespräche bis zum Modell.

Streaming-Inferenz war jedoch nur ein Teil der Lösung. Für einen zuverlässigen Produktionsbetrieb mussten wir außerdem die sichere Audioübertragung vom Client zum Inferenz-Stack gewährleisten und die Herausforderungen der Zustandsbehaftung bewältigen.

Medien schnell übertragen

Eine frühe Entscheidung bestand darin, den Medienfluss gezielt von der Anwendungs- und Geschäftslogik zu trennen. Audiodaten werden zwischen dem Client und dem Sprachmodell über einen dedizierten schnellen Pfad übertragen. Delegation, Tool-Nutzung und andere Anwendungsaufgaben laufen hinter einer asynchronen RPC-Grenze ab. Ein langsamer Tool-Aufruf oder Backend-Dienst kann sein eigenes Ergebnis verzögern, aber nicht den Medienfluss aufhalten.

Diese Trennung schafft zudem eine klare Grenze für Anpassungen am System. Anwendungen können ihre Tools, Richtlinien und das Verhalten ihres Backends ändern, ohne das Medien-Frontend zu beeinträchtigen, das den Audiofluss aufrechterhält. Der Live-Pfad bleibt schlank, vorhersehbar und auf die Aufgaben konzentriert, die in Echtzeit erledigt werden müssen.

Wir entwickelten das Medien-Frontend und die Inferenzlogik in Go und ersetzten damit eine frühere Python-Implementierung mit asyncio. Dadurch wurden die Frames wesentlich gleichmäßiger zugestellt. Der p95-Wert des neuen Systems entsprach dem p50-Wert des bisherigen Systems.

WebRTC bildet die Grundlage für den Transport. Es ist für Medienübertragung mit geringer Latenz konzipiert und funktioniert auch bei Paketverlusten, Taktabweichungen und Änderungen der Clientverbindung weiter. Treffen Pakete verspätet ein, kann WebRTC die Audiowiedergabe leicht strecken, um Lücken zu vermeiden, und sie anschließend kurz beschleunigen, bis sie wieder in Echtzeit läuft.

Indem wir Pufferung und Blockierungen im gesamten System minimieren, erreichen wir Reaktionszeiten von unter einer Sekunde, wie Menschen sie in Gesprächen erwarten.

Das (zustandsbehaftete) Gespräch am Laufen halten

Zustandsbehaftete Inferenz bringt eigene betriebliche Zielkonflikte mit sich. Eine Sprachsitzung kann lange aktiv bleiben, während ihr Kontext kontinuierlich wächst und Modellinstanzen je nach Nachfrage hoch- und heruntergefahren werden.

Um diese Herausforderungen zu bewältigen, entwickelten wir einen nahtlosen Übergabemechanismus zwischen Modellinstanzen. Wenn ein Wechsel erforderlich ist, können wir parallel zur bestehenden Instanz eine Ersatzinstanz aufwärmen, sie mit dem aktuellen Sitzungskontext vorbefüllen, die Inferenz auf beiden Instanzen parallel ausführen und umschalten, sobald die neue Instanz vollständig bereit ist.

Derselbe grundlegende Mechanismus unterstützt auch die dynamische Kontextverdichtung. Im Verlauf eines Gesprächs kann der angesammelte Kontext schließlich das Kontextlimit des Modells überschreiten. Die Kontextverdichtung kann den Kontext so verkleinern, dass er wieder innerhalb des Limits liegt. Dieser Vorgang braucht jedoch Zeit. Da sie außerdem den bisherigen Kontext verändert, macht sie den Key-Value-Cache (KV-Cache) des Modells ungültig. Darin werden Attention-Schlüssel und -Werte bereits verarbeiteter Tokens gespeichert. Um diesen Zustand wiederherzustellen, ist eine neue Vorbefüllung nötig, die zusätzliche Verzögerungen verursacht.

Stattdessen behandeln wir die Kontextverdichtung als weiteren gesteuerten Übergang. Während die ursprüngliche Modellinstanz das Gespräch fortsetzt, verdichtet das System den Kontext und bereitet mit dem neuen Kontext eine Ersatzinstanz vor. Sobald diese Instanz bereit ist, können wir ohne Unterbrechung des Medienflusses umschalten. So kann das System lange Gespräche unterstützen und den Kontext bei Bedarf verdichten.

Diagramm eines kompakten Snapshots, der von Inferenzserver A zu Inferenzserver B übertragen wird. Dort wird er vorab geladen und aktualisiert, bevor die Übergabe erfolgt.

Die aufwendigen Aufgaben bleiben außerhalb des Live-Pfads. Dadurch läuft das Gespräch selbst während einer Übergabe ohne Unterbrechung weiter.

Delegation, ohne das Gespräch zu blockieren

GPT‑Live kann bestehende Modelle auf dem neuesten Stand der Technik aufrufen und gewinnt dadurch erheblich an Leistungsfähigkeit. So werden „Sprechen“ und tiefergehendes „Denken“ effektiv voneinander entkoppelt. Damit sich diese Architektur aus zwei Modellen wie ein einziges System anfühlt, mussten wir jedoch zwei miteinander verbundene technische Probleme lösen.

Delegation für tiefere Arbeit

GPT-Live bietet schnelle, natürliche Antworten, während GPT-5.5 die Suche im Hintergrund übernimmt

Transkript
Beispielgespräch mit GPT-Live-1 unter Verwendung von GPT-5.5 Instant

Erstens müssen Ergebnisse schnell genug zurückkommen, um im laufenden Gespräch nützlich zu sein. Deshalb mussten wir die Latenz über den gesamten Delegationspfad hinweg minimieren, vom Routing und der Prompt-Verarbeitung bis zur Inferenz und zu Tool-Aufrufen. Gleichzeitig benötigen andere Systeme im Produkt weiterhin einzelne Nachrichten. Daher mussten wir das laufende Gespräch in eine für sie verständliche Form bringen.

Delegation schnell genug für natürliche Gespräche machen

Wenn eine Delegation ausgelöst wird, optimieren wir die Zeit, bis das Frontier-Modell etwas für das Gespräch Nützliches erzeugt. Das Sprachmodell kann das Gespräch kurz weiterführen, während ein Frontier-Modell schlussfolgert oder Tools nutzt. Eine beliebig langsame Antwort kann es jedoch nicht überbrücken. Deshalb bezogen wir die gesamte Delegationsschleife aus Routing, Prompt-Verarbeitung, Inferenz und Tool-Aufrufen in das Latenzbudget ein.

Die erste Optimierung besteht darin, das Frontier-Modell und alle benötigten Tools vorzubereiten, bevor eine Delegation angefordert wird. Beim Start einer Sprachsitzung erstellt der Anwendungsserver eine Inferenzsitzung für das Frontier-Modell und befüllt sie mit dem anfänglichen Gesprächskontext. So ist der Prompt bereits vor der ersten delegierten Anfrage vollständig verarbeitet.

Diese Inferenzsitzung halten wir für die Dauer des Sprachgesprächs verfügbar und nutzen für aufeinanderfolgende Anfragen eine stabile Sitzungsaffinität. Zusammen mit Prompt-Caching verbessern diese Verfahren die Latenz, während sich der Ausfall eines Workers weiterhin problemlos auffangen lässt.

Auch der Reasoning-Aufwand, Ausgabelimits, Tool-Schemas und die Hin- und Rückwege zwischen Modell und Tool beeinflussen, wann ein nützliches Ergebnis im Gespräch ankommt. Diese Stellschrauben passten wir für schnellere Antworten an. Indem wir den Aufwand im Delegationspfad minimierten, konnte das Sprachmodell Ergebnisse unserer Frontier-Modelle schnell in das Gespräch einbeziehen.

Einzelne Gesprächsbeiträge aus kontinuierlicher Sprache ableiten

Das Sprachmodell verarbeitet kontinuierliche Sprachstreams. Viele der umgebenden Systeme arbeiten jedoch weiterhin mit einzelnen Beiträgen von Nutzenden und Assistent, darunter die Gesprächsoberfläche von ChatGPT sowie Teile unserer Analyse- und Sicherheitsinfrastruktur. Der Anwendungsserver zerlegt das überlappende und gelegentlich mehrdeutige Gespräch daher in einzelne Nachrichten.

Während Audiodaten eintreffen, ermittelt der Server anhand vorläufiger Transkripte und Zeitsignale, wer gerade spricht, und erstellt eine Nachrichtenwarteschlange. Die neueste Nachricht bleibt vorläufig. Ihr Text, ihr Timing und ihre Zuordnung zur sprechenden Person können sich ändern, wenn weitere Sprache eintrifft. Sobald eine Person lange genug gesprochen hat, um sie zuverlässig zuzuordnen, schließt der Server die entsprechende Nachricht ab.

Sprechen mehrere Personen gleichzeitig, wird dies komplizierter. Eine kurze Bestätigung des Assistenten, während die nutzende Person spricht, etwa „mhm“ oder „okay“, sollte nicht unbedingt zu einer eigenen Nachricht werden. Ein inhaltlich relevanter Einwurf des Assistenten sollte dagegen häufig als eigene Nachricht erfasst werden. Ebenso priorisieren wir zusammenhängende angezeigte Antworten des Assistenten, selbst wenn Nutzende zwischendurch sprechen.

Jede Segmentierungsrichtlinie muss Aktualität und Sicherheit gegeneinander abwägen. Eine zu frühe Festlegung führt zu einem fragmentierten Verlauf und einer instabilen Reihenfolge. Zu langes Warten verzögert dagegen Transkripte und die davon abhängigen Funktionen. Das System verwaltet daher zwei miteinander verbundene Ansichten des Gesprächs: eine vorläufige Ansicht des aktuellen Zustands und eine verbindliche Aufzeichnung des Gesagten. Die Gesprächsansicht in der Benutzeroberfläche der Anwendung kann Aktualisierungen verarbeiten und nutzt daher die vorläufige Ansicht. Für die Protokollierung in der Analysepipeline ist dagegen ein endgültiges Transkript erforderlich.

So erhält der übrige Teil von ChatGPT eine stabile Ansicht des Gesprächs, ohne dass dem Live-Sprachpfad ein starrer Sprecherwechsel aufgezwungen wird.

Sitzungen mit einem schnelleren Protokoll starten

Die Reaktionsgeschwindigkeit zählt bereits ab dem ersten Klick. Bei GPT‑Live muss das System zunächst den Medienpfad einrichten und Audiodaten durch das Modell leiten, bevor das Gespräch beginnen kann. Damit liegt jeder Teil der Startsequenz auf dem kritischen Pfad.

Wie bereits erwähnt, bietet WebRTC eine solide Grundlage für Echtzeitanwendungen. Zum Start einer standardmäßigen WebRTC-Sitzung sind jedoch überraschend viele Protokoll-Handshakes und Netzwerk-Roundtrips erforderlich. WebRTC entstand vor dem Fokus auf möglichst wenige Roundtrips, der spätere Protokolle wie QUIC prägte. Daher führen die zugrunde liegenden Protokolle bei gemeinsamer Nutzung mitunter dieselben Schritte mehrfach aus. So enthielt etwa jedes Protokoll einen eigenen Mechanismus zum Schutz vor DoS-Angriffen, selbst wenn dieser im vollständigen WebRTC-Stack nicht erforderlich war.

Wir analysierten den Stack und entwickelten das WebRTC Abridged Roundtrip Protocol (WARP(wird in einem neuen Fenster geöffnet)). Es reduziert den Start von Medien- und Datenübertragungen von sechs Netzwerk-Roundtrips auf nur einen. WARP erreicht dies mit mehreren abwärtskompatiblen Protokollverbesserungen: dem Mitführen des DTLS-Handshakes über ICE (SPED(wird in einem neuen Fenster geöffnet)), dem schnelleren DTLS-1.3(wird in einem neuen Fenster geöffnet)-Handshake, der Vorab-Aushandlung des SCTP-Handshakes (SNAP(wird in einem neuen Fenster geöffnet)) und der Vorab-Aushandlung von Datenkanälen anstelle von DCEP(wird in einem neuen Fenster geöffnet).

Wir konzipierten WARP gemeinsam mit Mitwirkenden aus der WebRTC-Community als Reihe offener Spezifikationen, damit das gesamte Ökosystem von dieser Arbeit profitieren kann. Wir treiben die Vorschläge in der TSVWG-Arbeitsgruppe der IETF voran. Unterstützung für WARP wurde bereits in libwebrtc und Pion ergänzt, weitere WebRTC-Implementierungen arbeiten daran.

Vergleich des standardmäßigen WebRTC-Handshakes mit WebRTC und WARP. WARP stellt Medien und Daten mit weniger Netzwerk-Roundtrips bereit.

Nach der Optimierung des Medien-Handshakes fiel eine verbleibende Verzögerung besonders auf: der Signalisierungsaustausch, über den SDP-Parameter übermittelt werden, bevor WebRTC eine Verbindung herstellen kann. Um diesen Austausch aus dem kritischen Pfad zu entfernen, entwickelten wir Instant Connect. Instant Connect handelt diese Parameter im Voraus aus, ohne Serverkapazität zu reservieren oder bestehende WebRTC-Implementierungen zu ändern.

Instant Connect läuft parallel zum standardmäßigen Signalisierungsablauf. Sind die vorab ausgehandelten Parameter gültig, kann der Server die Sitzung beim Eintreffen des ersten Medienpakets bereitstellen. Sind sie veraltet oder ungültig, läuft der Signalisierungsablauf bereits. Der Client kann daher ohne zusätzliche Latenz darauf zurückgreifen.

Zusammen verkürzen Instant Connect und WARP die Zeit von der Nutzeraktion bis zum Live-Medienfluss erheblich. Da der SDP-Austausch nicht mehr auf dem kritischen Pfad liegt und WARP den Transport-Handshake verkürzt, kann der Client eine Sitzung jetzt mit einem einzigen UDP-Paket starten. Der Server kann sofort antworten. So kann der Rest des Systems mit dem beginnen, was für die Nutzenden wirklich zählt: zuhören und antworten.

GPT‑Live sicher im Produktivbetrieb mit echten Daten testen

Ein System kann auf dem Papier schnell wirken und unter realem Sprachdatenverkehr trotzdem ins Stocken geraten. Bevor GPT‑Live mit Nutzenden sprechen durfte, führten wir einen stillen Test durch. Dabei leiteten wir einen kleinen, schrittweise steigenden Anteil der produktiven Sitzungen im ChatGPT Sprachchat sowohl an den bestehenden erweiterten Sprachmodus als auch an unser neues System weiter. Der erweiterte Sprachmodus bediente die Nutzenden wie gewohnt, während der Schattenpfad die Inferenz schreibgeschützt ausführte. So wurde das System mit echten Clients, Netzwerken, Sitzungslängen und geografischen Verteilungen konfrontiert, ohne dass sich für die Nutzenden hörbar etwas änderte.

Eine der ersten Erkenntnisse war, dass sich Kapazität nicht allein auf den GPU-Durchsatz reduzieren lässt. Sprachsitzungen bleiben geöffnet und senden kontinuierlich Frames. Daher müssen CPU-seitige Stream-Handler, Warteschlangen und Netzwerkpfade parallel zur Inferenz skalieren. Unter realer Last erreichte eine unterstützende Komponente früher als in unseren Lasttestprognosen ihre Kapazitätsgrenze. Dadurch stauten sich Inferenzanfragen und die Latenz nahm immer weiter zu. Wir änderten die Kapazitätsfrage von „Wie viele Anfragen kann eine GPU verarbeiten?“ zu „Wie viele gleichzeitige Sitzungen kann das System aufrechterhalten und dabei jeden Frame termingerecht verarbeiten?

Der Test zeigte außerdem, dass die geografische Verteilung von Anfang an berücksichtigt werden muss. Wird eine Sitzung an weit entfernte Kapazitäten weitergeleitet, kann das beim Start und während des Streamings an mehreren Stellen Verzögerungen verursachen. Wir begannen, Modell-Rollouts gemeinsam mit regionalen Kapazitäten und der Konfiguration der Verkehrssteuerung zu validieren. Anschließend schlüsselten wir die Latenz nach Herkunftsregion auf. Die Inferenz näher an die Nutzenden zu verlagern half. Zugleich bestätigte sich eine übergeordnete Erkenntnis: Die Reaktionsgeschwindigkeit des Gesamtsystems hängt von jedem Dienst im Pfad ab, nicht nur vom Modellserver.

Andere Fehler traten erst bei realistischen Sitzungsverläufen auf. Lang laufende Sitzungen offenbarten Belastungen für Arbeitsspeicher und Persistenz. Wiederverbindungen beanspruchten die Kontextverdichtung (Compaction) und die Wiederherstellung des Zustands. Normale Verbindungsabbrüche auf Clientseite deckten Race Conditions beim Handshake zum Beenden der Sitzung auf. In kurzen Lasttests traten diese Probleme selten auf, da sie von der Laufzeit, dem angesammelten Zustand und dem Verhalten über Dienstgrenzen hinweg abhingen.

Schließlich zwang uns der Produktionstest, die Beobachtbarkeit und die Rollout-Kontrollen zu verbessern. Wir fanden Metriken, die unterschiedliche Latenzquellen vermischten, Dashboards, deren aggregierte Werte einzelne fehlerhafte Engines verbargen, sowie Konfigurationsabweichungen zwischen getesteten und bereitgestellten Systemen. Daraufhin ergänzten wir detailliertere Telemetriedaten, eine Validierung anhand bekanntermaßen funktionierender Konfigurationen, stufenweise Erhöhungen und die Möglichkeit, einzelne Pfade schnell zu isolieren oder zu deaktivieren. Der stille Test wurde zu einer frühen Generalprobe für den Start. Dabei ging es nicht nur darum, wie viel Datenverkehr das System bewältigen konnte, sondern auch darum, wie schnell wir Fehler erkennen, eindämmen und beheben konnten.

Reaktionsschnell vom Client bis zum Modell

GPT‑Live auf die Größenordnung von ChatGPT zu skalieren, erforderte ein völlig neues System mit einem grundlegenden Prinzip: Der Sprachfluss darf nicht abreißen. Streaming-Inferenz versorgt das Vollduplex-Modell kontinuierlich mit Audiodaten. Ein dedizierter Medienpfad sorgt für die zuverlässige Zustellung von Frames. Durch asynchrone Delegation kann tiefergehendes Denken parallel erfolgen. Ein optimierter Transport sorgt bis zu den Nutzenden für schnelle Reaktionen.

Die Architektur hinter GPT‑Live entwickelt sich bereits zu einer umfassenderen Plattform für Echtzeitinteraktionen. Sie bildet die Grundlage für den ChatGPT Sprachchat, der sich von Gesprächen zur agentischen Koordination weiterentwickelt, und wird auch die kommende GPT‑Live API unterstützen. Mit der Zeit wird sie Spracherlebnisse über mehr Geräte, Apps und Modalitäten hinweg ermöglichen, ohne die Unmittelbarkeit zu beeinträchtigen, durch die sich Sprachunterhaltungen live anfühlen.

Wenn du solche technischen Herausforderungen lösen möchtest, komm zu uns ins Team.

Autor

Justin Uberti und Zahan Malkani