Bot de chamadas do Graph
Visão geral
Essa abordagem transforma o agente em uma identidade do Teams que pode receber chamadas. Um usuário o busca pelo nome e faz uma chamada 1:1, e o agente responde em tempo real — sem número de telefone, PSTN ou Créditos de Comunicação. É a única abordagem que permite chamadas pelo nome e também a mais complexa de executar.
Ela usa um bot de mídia em tempo real do Microsoft Graph (a plataforma de chamadas do Cloud Communications). O SDK de mídia (Microsoft.Skype.Bots.Media) funciona apenas com .NET no Windows Server — não há suporte para Linux ou alternativas fora do .NET para áudio bruto em chamadas do Teams.
Esta é a única abordagem que permite chamadas pelo nome no Teams. Para uma configuração mais simples, prefira a aba do widget ou use o ACS se você quiser especificamente um número de telefone.
Como funciona
O bot atende com mídia hospedada pelo aplicativo, recebe 50 frames de áudio por segundo (PCM de 16 kHz e 20 ms), conecta-os ao agente da ElevenLabs por WebSocket e transmite o áudio do agente de volta para a chamada.
Requisitos
- Um registro de Azure Bot + aplicativo (registro de aplicativo do Entra).
- Permissões de aplicativo do Graph com consentimento de administrador:
Calls.AccessMedia.All(mídia bruta) eCalls.Initiate.All. - Uma VM Windows Server (≥ 2 núcleos físicos — por exemplo,
Standard_D4s_v3) com IP público e portas de mídia abertas. - Um certificado TLS assinado por uma CA em um FQDN público para o endpoint de mídia/sinalização (a plataforma de mídia rejeita certificados autoassinados).
- Um agente da ElevenLabs configurado como PCM 16000 Hz nos dois lados: formato de saída de TTS na aba Voice e formato de áudio de entrada do usuário na aba Advanced.
Uma D2s_v3 (2 vCPU = 1 núcleo físico) falha com MediaPlatform needs a system with at least 2 cores. Use um tamanho com ≥ 2 núcleos físicos (por exemplo, D4s_v3).
Permissões e funções
Etapa 1 — Registrar o bot + permissões do Graph
Crie um registro de aplicativo e um Azure Bot vinculado a ele. Em seguida, conceda as permissões de chamada e dê consentimento a elas (você precisa ser Administrador Global / Administrador de Funções Privilegiadas para consentir):
Conceda as duas funções de aplicativo do Graph e o consentimento de administrador (requer Administrador Global / Administrador de Funções Privilegiadas) e confirme que as atribuições foram aplicadas:
Se admin-consent retornar Consent validation failed, conceda as funções do aplicativo diretamente na entidade de serviço:
No portal, verifique na central de administração do Entra, em App registrations → seu aplicativo → API permissions: ambas as permissões devem aparecer como Granted, com marcas de verificação verdes.

Etapa 2 — Provisionar a VM Windows, o certificado e as portas
Na VM (o código nativo da plataforma de mídia precisa deles — o Windows Server não os inclui por padrão):
Abra as mesmas portas no firewall do Windows e anote a impressão digital do certificado — o bot vincula o Kestrel (443 + uma porta de notificações) e a plataforma de mídia (8445) a ele.
O próprio FQDN *.cloudapp.azure.com da VM funciona com um certificado Let’s Encrypt — não é
necessário ter um domínio separado.
Etapa 3 — Compilar e executar o bot
Comece pelo PublicSamples/EchoBot do microsoft-graph-comms-samples da Microsoft — ele usa net6.0 e é compilado com o SDK do .NET (não precisa das Visual Studio Build Tools):
Configure a seção AppSettings do appsettings.json com seu AadAppId, AadAppSecret, ServiceDnsName/MediaDnsName (o FQDN da VM), CertificateThumbprint e as portas (chamadas 443, notificações 9441, mídia 8445). Adicione duas configurações para a ponte da ElevenLabs abaixo: ElevenLabsAgentId e ElevenLabsOrigin (wss://api.elevenlabs.io ou seu host de residência). Execute-o como uma tarefa agendada / serviço do Windows para que sobreviva a reinicializações.
O limite de tempo de execução padrão do Agendador de Tarefas (72 horas) encerra silenciosamente tarefas de longa duração — um bot iniciado na inicialização para de funcionar três dias depois e as chamadas falham com “we couldn’t connect you”. Desative o limite e adicione reinicialização em caso de falha:
O EchoBot padrão falha em uma chamada feita para a porta padrão 443: HttpHelpers.SetAbsoluteUri
chama req.Host.Port.Value, que é nulo quando o cabeçalho Host não tem uma porta explícita. Corrija-o para
req.Host.Port ?? (req.IsHttps ? 443 : 80).
Substitua o eco pela ElevenLabs
A integração de áudio do EchoBot é simples: SpeechService.AppendAudioBuffer(in) e um evento OnSendMediaBufferEventArgs(out). Substitua o corpo do Azure Speech por uma ponte WebSocket do agente da ElevenLabs que mantenha a mesma interface:
Os dois lados usam PCM mono de 16 kHz, portanto é uma passagem direta em base64 — configure o agente como pcm_16000. Em uma interruption (interrupção de fala) da ElevenLabs, a ponte gera FlushMedia; conecte isso ao seu fluxo de mídia para descartar quaisquer AudioMediaBuffers em fila. Caso contrário, o agente continuará falando sobre o interlocutor. A referência completa de mensagens está na documentação de WebSocket. O desligamento no fim da chamada e a transferência assistida são abordados nas seções abaixo.
A URL em Connect() acessa um agente público. Para um agente privado, solicite uma URL assinada
de curta duração no servidor — GET /v1/convai/conversation/get-signed-url?agent_id=... com sua
chave de API — e conecte-se à URL retornada. Em residência de
dados, defina ElevenLabsOrigin como seu host de residência
(wss://api.eu.residency.elevenlabs.io, .in. ou .sg.) — as solicitações de URL assinada usam o
host https:// correspondente.
Etapa 4 — Permitir chamadas no Teams
-
Habilite Calling no canal Teams do Azure Bot e defina o webhook de chamadas como
https://YOUR_FQDN/api/calling:No portal, isso fica em seu recurso do Azure Bot → Channels → Microsoft Teams → aba Calling:

Azure Bot → Channels — o canal Microsoft Teams conectado 
Canal Microsoft Teams → Calling — chamadas habilitadas com o webhook do bot -
Crie um manifesto de aplicativo do Teams com
bots[0].supportsCalling: truee o ID do aplicativo do bot. Em seguida, carregue-o localmente (Apps → Manage your apps → Upload a custom app) ou publique-o para toda a organização sem usar a interface:New-TeamsApp -DistributionMethod organization -Path ./bot-app.zip(módulo PowerShell MicrosoftTeams).
Busque o aplicativo pelo nome no Teams e ligue para ele — o bot atende e o agente da ElevenLabs fala.

Não é necessário ter número de telefone ou conta de recurso para chamadas 1:1 pelo nome — eles são
necessários apenas para chamadas PSTN. Calls.AccessMedia.All é o que habilita a ponte de áudio bruto.
Chat de texto (mesmo bot)
O mesmo bot do Azure também pode responder por texto no Teams — assim, os usuários podem ligar para o agente ou conversar com ele por chat. Chamadas e mensagens são canais independentes no bot: o webhook de chamadas processa a voz, e um endpoint de mensagens (/api/messages) do Bot Framework processa o chat.

Aponte o endpoint de mensagens do bot para o host que o atende (o bot de mídia ou qualquer outro serviço — não precisa ser a VM do Windows):
Implemente o endpoint com o SDK do Bot Framework e encaminhe cada mensagem para o agente no modo de texto pelo mesmo WebSocket de conversa usado para voz — envie um evento user_message e leia o evento agent_response. Primeiro, ative o campo de primeira mensagem nas configurações de substituições do agente — o código abaixo o substitui por um valor vazio para que a resposta seja a resposta à mensagem do usuário, em vez da saudação do agente:
Registre-o da forma padrão (um CloudAdapter, o bot via AddTransient<IBot, ChatBot>() e um controlador /api/messages) e adicione escopos de chat à entrada do bot no manifesto:
O exemplo abre uma nova conversa por mensagem, então cada turno é independente. Para ter
memória no chat, mantenha um WebSocket aberto por conversation.id do Teams (reutilize-o entre os turnos) e encerre
sessões inativas — assim, o agente se lembra das mensagens anteriores nesse chat. A substituição de
first_message precisa estar ativada nas configurações de
substituições do agente — o servidor
fecha a conversa se uma substituição não permitida for enviada. Se não puder ativá-la, omita a
substituição e, em vez disso, descarte o primeiro agent_response de cada sessão (a saudação) e retorne
o seguinte.
Se as respostas do chat nunca chegarem, ative o evento do cliente
agent_response nas configurações
Avançadas do agente — as respostas de texto são enviadas por esse evento.
Fim da chamada
Quando a ElevenLabs encerra a conversa (a ferramenta Encerrar chamada fecha o WebSocket), desligue a conexão do Teams:
Transferência assistida para uma pessoa
O agente dispara uma ferramenta de cliente personalizada transfer_to_human; o bot convida um usuário do Teams para a chamada em andamento (adição consultiva) e então sai da chamada:
A transferência consultiva (replacesCallId) exige que ambas as partes sejam usuários do Teams no **mesmo
locatário **; destinos de transferência PSTN exigem uma instância de aplicativo. Para contextualizar a pessoa primeiro, envie um
parâmetro reason do agente e reproduza-o para a pessoa antes de conectar as chamadas.
Solução de problemas
MediaPlatform precisa de um sistema com pelo menos 2 núcleos
MediaPlatform precisa de um sistema com pelo menos 2 núcleos
A VM tem apenas um núcleo físico. Redimensione para ≥ 2 núcleos físicos (por exemplo, D4s_v3) e reinicie.
Não foi possível carregar a DLL 'NativeMedia'
Não foi possível carregar a DLL 'NativeMedia'
Instale o VC++ Redistributable (vcredist140) e o recurso do Windows Server-Media-Foundation e,
em seguida, reinicie o bot.
A chamada recebida retorna 500 / a chamada não conecta
O bug de porta nula do EchoBot na 443 — corrija HttpHelpers.SetAbsoluteUri (consulte a Etapa 3). Confirme também
que o certificado é assinado por uma CA e está acessível na 443.
Ao ligar para o bot, é exibida a mensagem 'não foi possível conectar você'
Confirme que Calling está ativado no canal do Teams com o webhook /api/calling correto, que a permissão do
Graph Calls.AccessMedia.All foi concedida e que as portas 443/8445/9441 estão abertas tanto no
NSG quanto no firewall do Windows. Se as chamadas funcionavam antes e pararam, verifique se o processo do bot
ainda está em execução na VM — o limite padrão de execução de 72 horas do Agendador de Tarefas o encerra alguns
dias após a inicialização (consulte o aviso na Etapa 3).