Construa sessões de voz em tempo real com a API MKA1 usando LiveKit. Configure opções de LLM, ferramentas, ajuste de STT e continuidade de conversas.
A API MKA1 oferece uma interface de voz em tempo real através do LiveKit. Este guia cobre como obter um token de sala, conectar-se a uma sessão de voz, enviar áudio e texto como entrada e capturar as respostas do agente.
A integração de voz consiste em três componentes principais:
Token de Sala: Um JWT que concede acesso a uma sala do LiveKit
Conexão LiveKit: Comunicação em tempo real baseada em WebRTC
Agente de Voz: Processa entrada de áudio/texto e gera respostas faladas
O pipeline do agente funciona da seguinte forma:
STT (Fala para Texto): O áudio é transmitido via WebSocket a 16kHz e transcrito
LLM: O texto transcrito é processado pela API de Respostas MKA1
TTS (Texto para Fala): A saída do LLM é sintetizada em áudio a 24kHz
Toda requisição que o agente de voz envia para a API de Respostas inclui automaticamente "voice_mode": "true" no metadata da requisição. Isso permite distinguir respostas originadas por voz das baseadas em texto ao revisar o uso ou o histórico de respostas.
Para iniciar uma sessão de voz, primeiro solicite um token de sala à API MKA1. O endpoint de token requer uma chave de API e aceita opcionalmente X-On-Behalf-Of para identificar usuários finais. Veja Autenticação para detalhes.
import { SDK } from '@meetkai/mka1';const mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}`,});const session = await mka1.llm.speech.livekitToken({ llm: { model: 'auto', reasoning: { effort: 'none' } }}, { headers: { 'X-On-Behalf-Of': 'user-123' } }); // Opcionalconsole.log(session.token); // Token JWTconsole.log(session.url); // URL WebSocketconsole.log(session.roomName); // Nome da sala
O objeto llm aceita os mesmos campos do corpo da requisição da API de Respostas, exceto campos gerenciados pelo agente de voz (input, stream, store, background).
Campo
Obrigatório
Descrição
model
Sim
Modelo LLM a ser usado (ex: auto)
instructions
Não
Instruções de sistema personalizadas para o agente
previous_response_id
Não
Encadeia esta sessão a uma resposta específica de uma sessão anterior
conversation
Não
Continua uma conversa existente — passe { "id": "conv_abc123..." } ou apenas o ID da conversa como string
tools
Não
Array de definições de ferramentas (function, web_search, file_search, etc.)
tool_choice
Não
Como o modelo seleciona ferramentas ("auto", "none", "required" ou uma ferramenta específica)
parallel_tool_calls
Não
Permite execução paralela de ferramentas
max_tool_calls
Não
Número máximo de chamadas de ferramenta por resposta (padrão: 30)
temperature
Não
Temperatura de amostragem (ex: 0.7)
max_output_tokens
Não
Máximo de tokens na resposta
reasoning
Não
Configuração de raciocínio (ex: { "effort": "high" }). Defina { "effort": "none" } para sessões de voz para minimizar latência — veja nota abaixo.
top_p
Não
Parâmetro de amostragem nucleus
presence_penalty
Não
Penalidade de presença para repetição de tokens
frequency_penalty
Não
Penalidade de frequência para repetição de tokens
truncation
Não
"auto" ou "disabled" — controla truncamento de contexto
context_management
Não
Estratégias de gerenciamento de contexto para truncamento de conversas
service_tier
Não
"auto", "default", "flex" ou "priority"
prompt
Não
Referência a um template de prompt e suas variáveis
text
Não
Configuração de saída de texto (formato, verbosidade)
metadata
Não
Metadados chave-valor passados para a API de Respostas
Você não pode especificar ambos previous_response_id e conversation.
Os metadados do token são incorporados em um JWT, que é passado como um header HTTP. Mantenha o payload total de llm abaixo de ~8 KB — arrays grandes de tools podem precisar ser reduzidos.
Para sessões de voz, desative o raciocínio definindo "reasoning": { "effort": "none" }. O raciocínio adiciona tempo de “pensamento” antes da resposta do modelo, o que aumenta a latência e cria pausas perceptíveis na conversa. Desativando-o, as respostas ficam rápidas e naturais.
const mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}`,});const session = await mka1.llm.speech.livekitToken({ llm: { model: 'auto', previousResponseId: 'resp_abc123...' }}, { headers: { 'X-On-Behalf-Of': 'user-123' } }); // Opcional, mas deve corresponder se a sessão original usou
Para continuar uma conversa existente:
const mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}`,});const session = await mka1.llm.speech.livekitToken({ llm: { model: 'auto', conversation: { id: 'conv_abc123...' } }}, { headers: { 'X-On-Behalf-Of': 'user-123' } }); // Opcional, mas deve corresponder se a sessão original usou
Ao continuar uma sessão, a chave de API e o header X-On-Behalf-Of (se usado) devem corresponder à sessão original. O agente de voz criptografa ambos no token da sala e os repassa para todos os serviços MKA1 subsequentes. Se não corresponderem, o agente não terá acesso ao contexto anterior.
Depois de obter um token, use o SDK do LiveKit para conectar-se à sala.
import { Room, RoomEvent, Track } from 'livekit-client';const room = new Room();// Conectar à salaawait room.connect(session.url, session.token);console.log('Conectado à sala:', room.name);
O agente aceita entrada de áudio através da trilha de áudio da sala do LiveKit. O áudio é processado a uma taxa de amostragem de 16kHz.
import { createLocalAudioTrack } from 'livekit-client';// Cria uma trilha de áudio local do microfoneconst audioTrack = await createLocalAudioTrack({ echoCancellation: true, noiseSuppression: true, autoGainControl: true});// Publica a trilha na salaawait room.localParticipant.publishTrack(audioTrack);
Detecção de Atividade de Voz (VAD): O VAD é tratado no servidor pelo agente MKA1, não localmente. O agente detecta automaticamente quando você para de falar e inicia o processamento.
Taxa de amostragem: O áudio é transmitido a 16kHz para o serviço de STT.
Finalização: O agente usa finalização no servidor para determinar quando a fala termina. Não há atraso de finalização local.
Você também pode enviar mensagens de texto diretamente para o agente sem falar.
// Envia uma mensagem de texto para o agenteconst message = JSON.stringify({ type: 'user_message', content: 'Qual é a capital da França?'});await room.localParticipant.publishData( new TextEncoder().encode(message), { reliable: true, topic: 'lk.chat' });
O agente publica o response_id e o conversation_id (se aplicável) quando começa a gerar uma resposta. Salve o response_id para encadear futuras sessões usando previous_response_id.
room.on(RoomEvent.DataReceived, (payload, participant) => { if (participant.identity !== room.localParticipant.identity) { const data = JSON.parse(new TextDecoder().decode(payload)); if (data.response_id) { console.log('ID da resposta:', data.response_id); console.log('ID da conversa:', data.conversation_id); // presente se estiver usando uma conversa // Salve o response_id para encadear futuras sessões com previous_response_id } }});
O agente suporta conversas de múltiplas interações com memória persistente. Cada resposta recebe automaticamente um response_id, enquanto conversas devem ser explicitamente criadas e gerenciadas pela API de Conversas.Existem duas formas de continuar uma conversa:llm.previous_response_id encadeia uma nova sessão a uma resposta específica. O agente recebe o contexto dessa resposta e de todas as anteriores na cadeia. Use quando:
Você quer continuar de um ponto específico em uma conversa
Está construindo um fluxo de conversa linear
Deseja ramificar a partir de uma resposta específica
llm.conversation referencia uma conversa criada via API de Conversas. Use quando:
Precisa gerenciar metadados da conversa (títulos, tags, etc.)
Deseja listar ou buscar conversas passadas
Está construindo uma interface de chat com histórico persistente
Múltiplos clientes precisam acessar a mesma conversa
Use previous_response_id para encadear uma nova sessão à última resposta, preservando o contexto da conversa:
// Use a mesma chave de API e X-On-Behalf-Of da sessão originalconst mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}`,});// 1. Obtenha um novo token encadeado à resposta anteriorconst session = await mka1.llm.speech.livekitToken({ llm: { model: 'auto', previousResponseId: lastResponseId }}, { headers: { 'X-On-Behalf-Of': 'user-123' } }); // Opcional, mas deve corresponder se a sessão original usou// 2. Conecte-se à nova salaconst room = new Room();await room.connect(session.url, session.token);// 3. O agente agora tem contexto da sessão anterior// Usuário: "O que eu te perguntei antes?"// Agente: "Você perguntou sobre a capital da França..."
Use conversation_id para continuar uma conversa existente criada pela API de Conversas:
// Use a mesma chave de API e X-On-Behalf-Of da sessão originalconst mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}`,});// 1. Obtenha um novo token com o ID da conversaconst session = await mka1.llm.speech.livekitToken({ llm: { model: 'auto', conversation: { id: conversationId } }}, { headers: { 'X-On-Behalf-Of': 'user-123' } }); // Opcional, mas deve corresponder se a sessão original usou// 2. Conecte-se à nova salaconst room = new Room();await room.connect(session.url, session.token);// 3. O agente agora tem contexto de todo o histórico da conversa
Ao continuar uma conversa, a chave de API e o header X-On-Behalf-Of (se usado) devem corresponder à sessão original. O contexto é restrito à identidade autenticada.