Beispiele für mit AIKit erstellte Chats im hellen Theme

Ein Chat für alle: Wir haben eine KI-Assistenten-Bibliothek auf Basis von Gravity UI entwickelt
Ein Chat für alle: Wir haben eine KI-Assistenten-Bibliothek auf Basis von Gravity UI entwickelt
Ein Artikel über den Start der AIKit-Bibliothek: worauf wir uns während der Entwicklung konzentriert haben, warum sie benötigt wird und wie man sie in eigenen Projekten verwendet.
Im letzten Jahr beobachten wir einen Boom von KI-Assistenten — und das ging auch an den Interfaces in Yandex Cloud nicht vorbei: mal tauchte im Support ein Chatbot mit einem Modell auf, mal in der Konsole ein Agent für operative Aufgaben. Teams haben Modelle angebunden, Dialoglogik durchdacht, Design entworfen und Chats gebaut — und das alles jeweils für sich.
Verschiedene Teams haben Interfaces auf dem gemeinsamen Framework Gravity UI aufgebaut, aber nach und nach entstanden so viele Varianten, dass es schwierig wurde, ein einheitliches Nutzererlebnis zu unterstützen. Außerdem stießen Kolleginnen und Kollegen immer häufiger darauf, dass sie Zeit in immer dieselben Lösungen investierten.
Damit wir nicht jedes Mal das Rad neu erfinden, haben wir die gesammelten Praktiken in einem einheitlichen Ansatz gebündelt und ein Tool für KI-Chatbots entwickelt — @gravity‑ui/aikit. Damit lässt sich in wenigen Tagen ein vollwertiges Assistenten-Interface erstellen, das sich zugleich leicht an unterschiedliche Szenarien anpassen lässt.

Mein Name ist Ilja Lomtev, ich bin Senior Developer im Team Foundation Services von Yandex Cloud. In diesem Artikel erzähle ich, warum wir uns entschieden haben, AIKit zu bauen, wie es aufgebaut ist, ein wenig über unsere Zukunftspläne — und darüber, was ihr selbst ausprobieren könnt.
Wie und warum wir AIKit entwickelt haben
Im letzten Jahr ist in Yandex Cloud die Zahl der Services mit KI-Assistenten gewachsen, zum Beispiel:
-
Code Assistant Chat in SourceCraft — der Assistent hilft Entwicklern beim Schreiben von Code und erstellt bzw. konfiguriert im KI-Agentenmodus Repositories, startet CI/CD-Prozesse, beantwortet Fragen zur Dokumentation und automatisiert Aufgaben. Er kann außerdem Issues und Pull Requests verwalten und mit Code arbeiten: erklären, Dateien erstellen und bearbeiten.
-
KI-Assistent in der Cloud-Konsole — ein Assistent, der für die Verwaltung von Ressourcen in Yandex Cloud entwickelt wurde. Hauptaufgabe ist es, die Cloud-Infrastruktur schnell und sicher zu konfigurieren, zu ändern und zu verwalten, indem die Komplexität der Interaktion mit API und Tools verborgen wird.
Im Ökosystem entstanden etwa ein Dutzend Chats, jeder mit eigener Logik, eigenem Nachrichtenformat und einem eigenen Satz an Corner Cases.
Wir haben festgestellt, dass Teams auf ungefähr denselben Satz an Aufgaben stoßen. Was die meisten brauchen:
-
Nachrichten von Nutzer und Assistent sauber darstellen,
-
das Streaming von Antworten korrekt organisieren,
-
den Indikator “Assistent tippt” anzeigen,
-
Fehler wie eine abgebrochene Verbindung oder Retries behandeln.
Die Aufgaben sind im Kern gleich, aber es gibt viele Lösungswege — und der UX unterscheidet sich. Zum Beispiel die Position und Art der Anzeige der Chat-Historie: das kann ein separater Screen sein, der sich wie ein Menü öffnet, oder eine Chat-Liste in einem Popup.
Ein Problem trat zutage: Die Erfahrung in den verschiedenen Chats unterschied sich deutlich. An manchen Stellen streamte der Assistent die Antwort, an anderen wurde sofort der fertige Text angezeigt. In einem Interface wurden Nachrichten gruppiert, in einem anderen liefen sie als durchgehender Feed. Das brach den gemeinsamen UX — der Nutzer wechselt zwischen Produkten desselben Ökosystems, aber das Gefühl beim Assistenten ist völlig unterschiedlich.

Außerdem wurde deutlich, dass es immer schwieriger wurde, neue Features in den Modellen auszurollen. Um Nutzern z. B. Tool-Fähigkeiten, Multimodalität oder strukturierte Tool-Antworten zugänglich zu machen, musste man den Vertrag abstimmen, Backends nachrüsten und danach den UI in jedem Team separat aktualisieren. Unter solchen Bedingungen dauerten Änderungen lange und ließen sich schlecht skalieren.
Wir wollten dieses Wachstum an Variabilität stoppen und wieder Vorhersehbarkeit herstellen. Dafür mussten wir das Datenmodell und die Arbeitsmuster vereinheitlichen, fertige Komponenten und Hooks liefern, damit Teams nicht bei null anfangen müssen, und Raum für Customization lassen — denn die Szenarien sind bei allen unterschiedlich.
So kamen wir zur Idee einer eigenen Bibliothek @gravity‑ui/aikit — eine Erweiterung von Gravity UI, die denselben Prinzipien folgt, aber auf moderne KI-Szenarien ausgerichtet ist: Dialoge, Assistenten, Multimodalität.
AIKit-Architektur: worauf wir aufgebaut haben
Beim Entwurf von AIKkit haben wir uns am Erfahrungswissen von AI SDK und an einigen grundlegenden Prinzipien orientiert.
Atomic Design als Grundlage: Die gesamte Bibliothek wird von Atomen bis hin zu Seiten aufgebaut. Diese Struktur gibt eine klare Hierarchie, ermöglicht die Wiederverwendung von Komponenten und erlaubt bei Bedarf, Verhalten auf jeder Ebene zu ändern.

Vollständig SDK-agnostisch: AIKit hängt nicht von einem konkreten KI-Provider ab. Man kann OpenAI, Alice AI LLM oder das eigene Backend verwenden — der UI nimmt Daten über Props entgegen, während State und Requests auf der Produktseite bleiben.
Zwei Nutzungsebenen für komplexe Szenarien: Es gibt eine fertige Komponente, die “out of the box” funktioniert, und es gibt einen Hook mit Logik, der eine vollständige Kontrolle über den UI erlaubt. Zum Beispiel kann man PromptInput verwenden oder ein eigenes Eingabefeld auf Basis von usePromptInput bauen. Das gibt Flexibilität, ohne das Fundament neu schreiben zu müssen.
Erweiterbares Typ-System. Um Einheitlichkeit und Typsicherheit zu gewährleisten, haben wir ein erweiterbares Datenmodell zusammengestellt. Nachrichten werden durch eine einheitliche typisierte Struktur abgebildet: Es gibt Nutzernachrichten, Assistentennachrichten und mehrere Basistypen von Content — Text (text), Modell-Überlegungen (thinking), Tools (tool). Gleichzeitig kann man eigene Typen über MessageRendererRegistry hinzufügen.
Alles ist in TypeScript typisiert, was hilft, komplexe Szenarien schneller zu bauen und Fehler schon in der Entwicklungsphase zu vermeiden.
// 1. Datentyp definieren
type ChartMessageContent = TMessageContent<
'chart',
{
chartData: number[];
chartType: 'bar' | 'line';
}
>;
// 2. Darstellungskomponente erstellen
const ChartRenderer = ({part}: MessageContentComponentProps<ChartMessageContent>) => {
return <div>Diagramm-Visualisierung: {part.data.chartType}</div>;
};
// 3. Renderer registrieren
const customRegistry = registerMessageRenderer(createMessageRendererRegistry(), 'chart', {
component: ChartRenderer,
});
// 4. In AssistantMessage verwenden
<AssistantMessage message={message} messageRendererRegistry={customRegistry} />;
Schließlich haben wir Theming über CSS-Variablen vorgesehen, i18n (RU/EN) hinzugefügt, Barrierefreiheit sichergestellt (ARIA, Tastaturnavigation) und visuelle Regressionstests über Playwright Component Testing in Docker eingerichtet — und die Bibliothek war bereit für den Produktionseinsatz.
Was unter der Haube steckt
Die Basis von AIKit ist ein einheitliches Dialogmodell. Um es zu erstellen, mussten wir zunächst die Hierarchie der Nachrichten verstehen.
Nachrichten sind an sich recht vielschichtige Entitäten. Es gibt die erste Nachricht vom LLM — das ist ein Stream. Innerhalb davon kann es jedoch viele verschiedene verschachtelte Nachrichten geben: im Grunde sind das Überlegungen, Vorschläge, Tool-Calls zur Lösung einer Frage. All diese unterschiedlichen Teilnachrichten sind faktisch eine Nachricht vom Backend. Gleichzeitig kann jede davon bei einer einfachen Nutzung eines LLM durchaus eine separate Nachricht sein.
Deshalb haben wir die Möglichkeit gelassen, den Chat auf beide Arten zu verwenden: Nachrichten können ineinander verschachtelt sein oder flach — das hängt vom Bedarf ab.
Das State-Management bleibt dabei beim Service. AIKit speichert Daten nicht selbst — es nimmt sie von außen entgegen. Teams können React State, Redux, Zustand, Reatom verwenden — alles, was passt. Wir liefern lediglich Hooks, die typische UI-Logik kapseln, zum Beispiel:
-
intelligentes Scrollen mit
useSmartScroll; -
Arbeit mit Datumswerten, z. B. datumsformatierung unter Berücksichtigung der Locale mit
useDateFormatter; -
Verarbeitung von Tool-Nachrichten mit
useToolMessage; -
und alles Weitere, was man zum Aufbau eines Dialogs braucht.
Zusätzlich bleibt AIKit erweiterbar. Man kann beliebige Modelle anbinden, eigene Content-Typen erstellen und den UI vollständig nach den eigenen Aufgaben bauen — entweder mit der Logik aus den Hooks oder indem man fertige Komponenten als Basis nutzt. Die Architektur erlaubt Experimente, ohne die gemeinsamen Prinzipien zu verletzen.
Wie man seinen eigenen Chat baut
Für die Erstellung unseres ersten Chats nutzen wir die vorbereitete Komponente ChatContainer:
import React, { useState } from 'react';
import { ChatContainer } from 'aikit';
import type { ChatType, MessageType } from 'aikit';
function App() {
const [messages, setMessages] = useState<MessageType[]>([]);
const [chats, setChats] = useState<ChatType[]>([]);
const [activeChat, setActiveChat] = useState<ChatType | null>(null);
const handleSendMessage = async (content: string) => {
// Your message sending logic
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message: content })
});
const data = await response.json();
// Update state
setMessages(prev => [...prev, data]);
};
return (
<ChatContainer
messages={[]}
onSendMessage={() => {}}
welcomeConfig={{
description: 'Start a conversation by typing a message or selecting a suggestion.',
image: <Icon data={() => {}} size={48}/>,
suggestionTitle: 'Try asking:',
suggestions: [
{
id: '1',
title: 'Explain quantum computing in simple terms'
},
{
id: '2',
title: 'Write a poem about nature'
},
{
id: '3',
title: 'Help me debug my JavaScript code'
},
{
id: '4',
title: 'Summarize recent AI developments'
}
],
title: 'Welcome to AI Chat'
}}
/>
);
}
“Out of the box” sieht das so aus:

Fügen wir etwas Feststimmung hinzu:
-
Passen wir den initialen State an.
Für eine feinere Konfiguration bauen wir den Chat aus einzelnen Komponenten:
Header,MessageList,PromptBox.import { Header, MessageList, PromptBox } from 'aikit'; function CustomChat() { return ( <div className="custom-chat"> <Header title="AI Assistant" onNewChat={() => {}} /> <MessageList messages={messages} showTimestamp /> <PromptBox onSend={handleSend} placeholder="Fragen Sie irgendetwas..." /> </div> ); } -
Verwenden wir verschiedene eingebaute Nachrichtentypen, importiert über
MessageType.-
thinking— zeigt den Denkprozess der KI (so kann der Nutzer die Logik nachvollziehen, nach der der Assistent die Antwort vorbereitet). -
tool— eignet sich zur Darstellung interaktiver Antwortblöcke; in unserem Fall ist das ein Code-Block, in dem Syntax-Highlighting korrekt funktioniert und Bearbeiten sowie Kopieren in die Zwischenablage unterstützt werden.
Außerdem kann man eigene Typen hinzufügen, zum Beispiel Nachrichten mit Bildern:
type ImageMessage = BaseMessage<ImageMessageData> & { type: 'image' }; const ImageMessageView = ({ message }: { message: ImageMessage }) => ( <div> <img src={message.data.imageUrl} /> {message.data.caption && <p>{message.data.caption}</p>} </div> ); const customTypes: MessageTypeRegistry = { image: { component: ImageMessageView, validator: (msg) => msg.type === 'image' } }; <ChatContainer messages={messages} messageTypeRegistry={customTypes} /> -
-
Fügen wir Styling via CSS hinzu…
…und erhalten einen Chat mit Väterchen Frost:)

Für die vollständige Anpassung einzelner Elemente kann man Hooks verwenden — wir freuen uns, eure Styling-Varianten in den Kommentaren unter dem Artikel zu sehen!
Wie AIKit die Services beeinflusst hat
Das Ergebnis der Nutzung von AIKit in Yandex Cloud wurde schnell sichtbar. In allen Services begannen sich die Assistenten gleich zu verhalten: Antworten gleich zu streamen, Fehler gleich anzuzeigen, Nachrichten gleich zu gruppieren. Der UX wurde einheitlich; jetzt lässt er sich im gesamten Ökosystem leichter nutzen, das Verhalten ist erwartbarer und vorhersehbarer.
-
Die UX-Sprache ist einheitlich geworden — Assistenten-Chats in verschiedenen Produkten fühlen sich jetzt wie Teil eines einzigen Ökosystems an. Nutzer sehen vorhersehbares Verhalten: identisches Streaming, Fehlerbehandlung, Interaktionsmuster.
-
Die Entwicklungsgeschwindigkeit des Chat-UIs ist deutlich höher.
-
Zentrale Weiterentwicklung — neue Features wie der Content-Typ thinking oder verbesserte Tool-Unterstützung werden einmal hinzugefügt und sind automatisch für alle verfügbar.
-
Die Bibliothek wurde zur Grundlage für die Herausbildung von Standards für KI-Interfaces im Ökosystem.
Was als Nächstes kommt
Nun zu den Plänen. Wir haben mehrere Richtungen identifiziert:
-
Performance-Verbesserungen durch Virtualisierung für sehr große Chat-Historien.
-
Erweiterung der Basisszenarien für neue Fähigkeiten von KI-Agenten, die sich aktiv weiterentwickeln.
-
Hinzufügen von Utilities, um das Mapping der Daten populärer KI-Modelle auf unser Chat-Datenmodell zu vereinfachen.
Zusätzlich werden wir die Dokumentation und Beispiele ausbauen. Und natürlich die Community weiterentwickeln — wir möchten, dass die Bibliothek nicht nur intern, sondern auch für externe Entwickler nützlich ist.
Wie man AIKit ausprobieren kann
Schaut im Bibliotheksbereich auf unserer Website vorbei. Wenn ihr euren eigenen KI-Assistenten baut, ein schnelles und vorhersehbares Chat-Interface wollt und bereits Gravity UI verwendet (oder es ausprobieren möchtet), werft einen Blick ins README und in die Beispiele. Und wir sind auch dankbar für Feedback — erstellt Issues, schickt PRs und sagt uns, was ihr für eure Szenarien noch braucht!
Wenn Ihnen unser Projekt gefällt, freuen wir uns über ⭐️ in AIKit und UIKit!

Ilja Lomtev
Frontend-Entwickler