Como adicionar isolamento de locutor a um worker do LiveKit Agents?
Execute o SDK da Anecho sobre o áudio de entrada dentro do stt_node do worker, em saltos de 240 amostras a 16 kHz. Não existe pacote de plugin para o LiveKit, então este artigo mostra o código que você mesmo escreve, com notas de reamostragem e os números.
Você adiciona isolamento de locutor a um worker do LiveKit Agents passando os frames de áudio de entrada pelo SDK da Anecho antes de chegarem à etapa de fala para texto, em saltos de 240 amostras a 16 kHz. Não existe um pacote livekit-plugins-anecho; não publicamos nenhum. O que segue é o contrato do SDK aplicado aos tipos de frame do LiveKit, como código que é seu.
O contrato
O SDK tem três objetos: Model (o arquivo .anecho do seu painel), Processor (float32 na entrada, o mesmo número de amostras na saída, 15 ms atrás) e UsageReporter (o heartbeat da licença; envia durações, nunca áudio). O modelo trabalha a 16 kHz em saltos de 240 amostras. As primeiras 240 amostras de um fluxo saem como silêncio, que é o atraso algorítmico.
O laço de frames
No Agents, stt_node recebe um iterador assíncrono de rtc.AudioFrame. Nós o envolvemos, reagrupamos em saltos, rodamos o processador e entregamos frames do mesmo formato.
import os
import numpy as np
from scipy.signal import resample_poly
from livekit import rtc
from livekit.agents import Agent
from anecho import Model, Processor, UsageReporter
RATE, HOP = 16_000, 240 # model rate; 240 samples = 15 ms
reporter = UsageReporter(os.environ["ANECHO_API_KEY"])
model = Model.from_file("anecho.ai_focus_model_16khz_v8_2.anecho") # from your dashboard
class IsolatedAgent(Agent):
async def stt_node(self, audio, model_settings):
async def isolated():
proc = Processor(model, reporter.ensure_license()) # one per call
reporter.attach(proc)
reporter.start()
pending = np.zeros(0, dtype=np.float32)
async for frame in audio: # rtc.AudioFrame, int16
x = np.frombuffer(frame.data, dtype=np.int16).astype(np.float32) / 32768.0
if frame.num_channels > 1: # mix down to mono
x = x.reshape(-1, frame.num_channels).mean(axis=1)
if frame.sample_rate != RATE: # e.g. 48000 -> 16000
x = resample_poly(x, RATE, frame.sample_rate).astype(np.float32)
pending = np.concatenate([pending, x])
while len(pending) >= HOP:
block, pending = pending[:HOP], pending[HOP:]
y = proc.process(block) # same length out, 15 ms behind
pcm = (np.clip(y, -1.0, 1.0) * 32767).astype(np.int16)
yield rtc.AudioFrame(
data=pcm.tobytes(), sample_rate=RATE,
num_channels=1, samples_per_channel=HOP,
)
return Agent.default.stt_node(self, isolated(), model_settings)
É um esboço contra o hook Agent.stt_node do Agents 1.x. Não medimos um worker LiveKit em produção, então confira a assinatura do hook na sua versão do Agents e teste com o seu próprio tráfego.
Notas de reamostragem
- Frames do LiveKit são int16 e costumam estar a 48 kHz ou 24 kHz. O modelo quer float32 a 16 kHz, então reamostre antes do processador com um filtro polifásico adequado (
resample_polyacima), não descartando amostras. - Reamostre uma vez só. Se seu STT também reamostra, o áudio isolado a 16 kHz já é o que a maioria dos reconhecedores quer.
- Um trecho de telefonia chega a 8 kHz. Subir para 16 kHz não recupera largura de banda; veja 8 kHz é onde a IA de voz quebra.
- Mantenha uma derivação bruta se você também grava ou tem um segundo consumidor; veja o pipeline dividido.
Custo e a alternativa de plataforma
| Item | Valor | Fonte e data |
|---|---|---|
| Atraso algorítmico | 15 ms | Null Test, 2026-08-14 |
| Fator de tempo real, uma thread de CPU | 0.067 | Null Test, 2026-08-14 (Apple M1 Max) |
| Pior tempo de bloco, p99 | 3.96 ms | Null Test, 2026-08-14 |
| Nossa tarifa de entrada após 10,000 minutos grátis por mês | $0.0010 por minuto | anecho.ai/pricing |
| Isolamento de voz do LiveKit Cloud, acima da cota do plano | $0.0012 por minuto | livekit.com/pricing, consultado em 2026-10-15 |
O LiveKit Cloud vende isolamento de voz como item medido, preenchido por modelos da Krisp e da ai-coustics (livekit.com/pricing e docs.livekit.io, consultados em 2026-10-15). Se você roda seu worker no LiveKit Cloud e um desses slots serve, é um caminho razoável. Rodar o SDK você mesmo mantém o áudio no seu processo e funciona onde o worker rodar. Os dois preços não são equivalentes: o nosso é por minuto processado numa escala publicada, o deles é por plano. Se o isolamento ajuda o seu tráfego é uma medição, não um padrão: como avaliar isolamento de locutor.
FAQ
Existe um plugin da Anecho para o LiveKit Agents?
Não. Não há pacote de plugin publicado. O SDK é uma biblioteca Python e Node, e este artigo mostra o código de integração.
Onde o processador entra no pipeline do LiveKit?
No áudio de entrada, antes da etapa de fala para texto, no hook stt_node.
Quanta latência ele adiciona?
15 ms de atraso algorítmico, medidos no Null Test em 2026-08-14 com fator de tempo real de 0.067 em uma thread de CPU.