Exemplos de chats construídos com o AIKit, no tema claro

Um chat para governar todos: criamos uma biblioteca para assistentes de IA baseada no Gravity UI
Um chat para governar todos: criamos uma biblioteca para assistentes de IA baseada no Gravity UI
Artigo sobre o lançamento da biblioteca AIKit: o que consideramos no desenvolvimento, por que ela é necessária e como aplicá-la em seus projetos.
No último ano, vimos um boom de assistentes de IA, e isso também afetou as interfaces no Yandex Cloud: ora aparece um chat-bot com modelo no suporte, ora um agente para operações do dia a dia no console. As equipes conectavam modelos, pensavam na lógica de diálogo, desenhavam o design e montavam chats — e faziam tudo isso separadamente.
Equipes diferentes montavam interfaces no framework comum Gravity UI, mas aos poucos surgiram tantas variações que ficou difícil manter uma experiência de usuário unificada. E os colegas passaram a enfrentar cada vez mais a situação de gastar tempo nas mesmas soluções, repetidamente.
Para parar de reinventar a roda toda vez, reunimos as práticas acumuladas em uma abordagem única e criamos uma ferramenta para chat-bots com IA — @gravity‑ui/aikit. Ela permite criar uma interface completa de assistente em poucos dias e, ao mesmo tempo, adaptá-la facilmente a diferentes cenários.

Meu nome é Ilya Lomtev, sou desenvolvedor sênior na equipe Foundation Services do Yandex Cloud, e neste artigo vou contar por que decidimos criar o AIKit, como ele é estruturado, um pouco sobre os planos para o futuro — e o que você pode experimentar por conta própria.
Como e por que criamos o AIKit
No último ano, cresceu o número de serviços no Yandex Cloud com assistentes de IA, por exemplo:
-
Code Assistant Chat no SourceCraft — o assistente ajuda desenvolvedores a escrever código e, no modo de agente de IA, cria e configura repositórios, executa processos de CI/CD, responde perguntas sobre a documentação e automatiza tarefas. Também sabe gerenciar issues, pull requests e trabalhar com código: explicar, criar e editar arquivos.
-
Assistente de IA no console da nuvem — um assistente desenvolvido para gerenciar recursos no Yandex Cloud. A principal tarefa é ajudar a configurar, alterar e administrar a infraestrutura de nuvem de forma rápida e segura, ocultando a complexidade da interação com APIs e ferramentas.
No ecossistema, surgiram cerca de uma dezena de chats, cada um com sua lógica, seu formato de mensagens e seu conjunto de casos de borda.
Descobrimos que as equipes chegam a um conjunto de tarefas mais ou menos igual. O que a maioria precisa:
-
exibir com cuidado as mensagens do usuário e do assistente;
-
organizar corretamente o streaming das respostas;
-
mostrar o indicador “o assistente está digitando”;
-
tratar erros como conexão interrompida ou retries.
As tarefas, na prática, são as mesmas, mas existem muitos caminhos de solução — e o UX varia. Por exemplo, a posição e a forma de exibir o histórico de chats: pode ser tanto uma tela separada que abre como um menu, quanto uma lista de chats em um popup.
O problema ficou evidente: a experiência nos diferentes chats variava muito. Em um lugar o assistente fazia streaming da resposta, e em outro mostrava imediatamente o texto pronto. Em uma interface as mensagens eram agrupadas, e em outra vinham em uma única linha do tempo contínua. Isso quebrava o UX geral — no fim, o usuário alternava entre produtos de um mesmo ecossistema, mas a sensação do assistente era completamente diferente.

Também ficou claro que lançar novas funcionalidades nas models estava ficando cada vez mais difícil. Para levar aos usuários, por exemplo, o uso de ferramentas, multimodalidade ou respostas estruturadas de tools, era preciso alinhar um contrato, evoluir os backends e depois atualizar o UI em cada equipe separadamente. Nessas condições, qualquer mudança levava muito tempo e não escalava bem.
Queríamos parar esse crescimento de variabilidade e recuperar previsibilidade. Para isso, era necessário unificar o modelo de dados e os padrões de trabalho, entregar componentes e hooks prontos para que as equipes não precisassem começar do zero, e deixar espaço para customização — afinal, os cenários são diferentes para cada um.
Assim chegamos à ideia de uma biblioteca separada @gravity‑ui/aikit — uma extensão do Gravity UI que segue os mesmos princípios, mas é orientada a cenários modernos de IA: diálogos, assistentes, multimodalidade.
Arquitetura do AIKit: no que nos baseamos
Ao projetar o AIKkit, nos orientamos pela experiência do AI SDK e por alguns princípios fundamentais.
Atomic Design como base: toda a biblioteca é construída de átomos até páginas. Essa estrutura dá uma hierarquia clara, permite reutilizar componentes e, se necessário, mudar o comportamento em qualquer nível.

Totalmente agnóstico de SDK: o AIKit não depende de um provedor de IA específico. Você pode usar OpenAI, Alice AI LLM ou seu próprio backend — o UI recebe os dados via props, e o estado e as requisições ficam do lado do produto.
Dois níveis de uso para cenários complexos: há um componente pronto que funciona “out of the box”, e há um hook com a lógica que permite controlar totalmente o UI. Por exemplo, você pode usar PromptInput ou montar seu próprio campo de entrada com base em usePromptInput. Isso dá flexibilidade sem precisar reescrever os fundamentos.
Sistema de tipos extensível. Para garantir consistência e type safety, montamos um modelo de dados extensível. As mensagens são representadas por uma estrutura única e tipada: há mensagens do usuário, mensagens do assistente e vários tipos base de conteúdo — texto (text), raciocínio do modelo (thinking), ferramentas (tool). Ao mesmo tempo, é possível adicionar seus próprios tipos via MessageRendererRegistry.
Tudo isso é tipado em TypeScript, o que ajuda a montar cenários complexos mais rapidamente e evitar erros na fase de desenvolvimento.
// 1. Definimos o tipo de dados
type ChartMessageContent = TMessageContent<
'chart',
{
chartData: number[];
chartType: 'bar' | 'line';
}
>;
// 2. Criamos o componente de renderização
const ChartRenderer = ({part}: MessageContentComponentProps<ChartMessageContent>) => {
return <div>Visualização do gráfico: {part.data.chartType}</div>;
};
// 3. Registramos o renderer
const customRegistry = registerMessageRenderer(createMessageRendererRegistry(), 'chart', {
component: ChartRenderer,
});
// 4. Usamos em AssistantMessage
<AssistantMessage message={message} messageRendererRegistry={customRegistry} />;
Por fim, previmos tematização via variáveis CSS, adicionamos i18n (RU/EN), garantimos acessibilidade (ARIA, navegação por teclado) e configuramos testes de regressão visual via Playwright Component Testing em Docker — e a biblioteca ficou pronta para uso em produção.
O que tem por baixo do capô
No coração do AIKit está um modelo de diálogo unificado. Para criá-lo, primeiro foi preciso entender a hierarquia das mensagens.
As mensagens, por si só, são entidades bastante multifacetadas. Há a primeira mensagem do LLM — isso é um stream. Mas dentro dela pode haver muitas mensagens aninhadas diferentes: na prática, são raciocínios, sugestões, chamadas de tools para resolver uma questão. Todas essas submensagens diferentes são, de fato, uma única mensagem do backend. Mas ao mesmo tempo cada uma delas pode perfeitamente ser uma mensagem separada em um uso mais simples do LLM.
Por isso, mantivemos a possibilidade de usar o chat dos dois jeitos: as mensagens podem ser aninhadas umas nas outras ou podem ser planas — aqui tudo depende da necessidade.
O gerenciamento de estado permanece com o serviço. O AIKit não armazena dados por conta própria — ele os recebe de fora. As equipes podem usar React State, Redux, Zustand, Reatom — o que for mais conveniente. Nós apenas fornecemos hooks que encapsulam a lógica típica de UI, por exemplo:
-
rolagem inteligente com
useSmartScroll; -
trabalho com datas, por exemplo, formatação de datas com base na localidade via
useDateFormatter; -
tratamento de mensagens de tool com
useToolMessage; -
e todo o resto necessário para construir um diálogo.
Além disso, o AIKit permanece extensível. Dá para conectar quaisquer modelos, criar tipos de conteúdo próprios e construir o UI completamente para suas necessidades — usando a lógica dos hooks ou usando componentes prontos como base. A arquitetura permite experimentar sem violar os princípios gerais.
Como montar seu próprio chat
Para criar seu primeiro chat, vamos usar o componente preparado 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) => {
// Sua lógica de envio de mensagens
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message: content })
});
const data = await response.json();
// Atualizamos o estado
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”, tudo fica assim:

Vamos adicionar um pouco de clima festivo:
-
Ajustamos o estado inicial.
Para uma configuração mais fina, vamos montar o chat a partir de componentes separados:
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="Pergunte qualquer coisa..." /> </div> ); } -
Aplicamos diferentes tipos de mensagens встроенные, importadas via
MessageType.-
thinking— mostra o processo de raciocínio da IA (assim o usuário pode entender a lógica com que o assistente prepara a resposta). -
tool— serve para exibir blocos interativos da resposta; no nosso caso, é um bloco de código em que a sintaxe funciona corretamente, e são suportadas operações de edição e cópia para a área de transferência.
Também é possível adicionar tipos próprios, por exemplo, mensagens com imagens:
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} /> -
-
Adicionamos estilização via CSS…
…e obtemos um chat com o Papai Noel:)

Para customização completa de elementos individuais, é possível usar hooks — vamos gostar de ver suas variações de estilização nos comentários do artigo!
Como o AIKit impactou os serviços
O resultado do uso do AIKit no Yandex Cloud ficou evidente rapidamente. Em todos os serviços, os assistentes passaram a se comportar da mesma forma: fazer streaming das respostas do mesmo jeito, exibir erros do mesmo jeito, agrupar mensagens do mesmo jeito. O UX ficou uniforme; agora é mais fácil interagir com ele em todo o ecossistema, o comportamento é mais esperado e previsível.
-
A linguagem de UX ficou unificada — os chats de assistentes em diferentes produtos agora são percebidos como parte de um único ecossistema. Os usuários veem um comportamento previsível: o mesmo streaming, tratamento de erros e padrões de interação.
-
A velocidade de desenvolvimento do UI do chat é muito maior.
-
Evolução centralizada — novas funcionalidades, como o tipo de conteúdo thinking ou melhorias no trabalho com tools, são adicionadas uma vez e ficam automaticamente disponíveis para todos.
-
A biblioteca virou a base para formar padrões de interfaces de IA no ecossistema.
O que vem depois
Agora, sobre os planos. Destacamos algumas frentes:
-
Melhorar a performance via virtualização para trabalhar com históricos de chat muito grandes.
-
Ampliar cenários base para novas capacidades de agentes de IA, que estão evoluindo ativamente.
-
Adicionar utilitários para simplificar o mapeamento de dados de modelos de IA populares para o nosso modelo de dados de chat.
Além disso, vamos evoluir a documentação e os exemplos. E, claro, o desenvolvimento da comunidade — queremos que a biblioteca seja útil não só dentro da empresa, mas também para desenvolvedores externos.
Como experimentar o AIKit
Vá para a seção da biblioteca no nosso site. Se você está criando seu próprio assistente de IA, quer um chat com interface rápida e previsível e já usa o Gravity UI (ou está disposto a experimentar), confira o README e os exemplos. E também vamos agradecer pelo feedback — abra issues, envie PRs, conte o que ainda falta para os seus cenários!
Se você gosta do nosso projeto, vamos agradecer por uma ⭐️ no AIKit e no UIKit!

Илья Ломтев
Desenvolvedor frontend