Capstone: assistente de voz end-to-end
- ⬜📄 OCR moderno: Azure Doc Intelligence, Textract, LandingAI(Voice, Vision & Multimodal)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Objetivo do capstone
Construir um voice assistant completo, deployado e avaliado. Não é demo — é sistema que alguém pode usar. O entregável combina os 6 módulos anteriores em produto único e serve de peça de portfolio para vagas de IA aplicada / engenharia multimodal sênior.
Spec mínima
| Requisito | Como se comprova | O que ele revela |
|---|---|---|
| Duas arquiteturas alternáveis | Chave de configuração | Você não depende de um único fornecedor no caminho crítico |
| Interrupção durante a fala | Vídeo demonstrando | Você trunca a resposta no histórico, não só silencia o alto-falante |
| Três ferramentas com efeito real | Demonstração | Você valida argumento vindo do modelo antes de agir |
| Conjunto de áudios gravados | Script de avaliação | Você testa desde o microfone, não a partir da transcrição |
| Teto de gasto ativo | Código | Você entendeu que cobrança por minuto muda a natureza do risco |
| Latência até o primeiro áudio medida | Número no relatório | Você mede o que o usuário sente, não o tempo total |
# Voice Assistant Capstone — Spec
## Funcional
- Web app (Next.js) OU CLI (Python/Node) rodando em desktop
- Acionado por botão (push-to-talk) ou VAD contínuo (configurável)
- Responde em PT-BR com voz natural
- Executa 3+ tools: ex. get_weather, set_timer, search_web (ou domínio próprio)
- Histórico da conversa persistido (SQLite) por sessão
## Não-funcional
- TTFA p95 < 1.2s na arquitetura Realtime
- TTFA p95 < 2.5s na arquitetura pipeline (fallback)
- Feature flag para trocar arquiteturas
- Budget guard: derruba sessão se custo > $X
- Logs estruturados (request id, etapa, latência, custo)
- Barge-in funcional (interrupção durante fala do agent)
## Avaliação
- Golden set com 40+ interações categorizadas
- Script que roda o golden set e reporta métricas
- Writeup (README ou blog) com resultados, trade-offs, limitaçõesArquitetura recomendada
# Arquitetura dupla, escolhível por feature flag
modo_realtime:
transporte: webrtc
modelo: gpt-4o-realtime-preview
vantagem: TTFA ~400ms, cross-modal reasoning
uso: conversa natural, primeira escolha
modo_pipeline:
vad: silero-vad (local)
stt: deepgram-nova-2 streaming
llm: claude-3-5-sonnet-20241022
tts: cartesia-sonic streaming
vantagem: custo previsível, resiliência
uso: fallback e volumes altos
observabilidade:
tracing: opentelemetry spans (vad, stt, llm, tts, play)
metrics: ttfa, total_latency, cost_usd_per_session
storage: sqlite local + export jsonl
guardrails:
budget_session_usd: 0.50
max_turns: 30
pii_scrub: regex basico antes de logImplementação: esqueleto (modo pipeline)
// orchestrator.ts - pipeline fallback
import { vadDetect } from './vad';
import { streamSTT } from './stt';
import { streamLLM } from './llm';
import { streamTTS } from './tts';
import { tools } from './tools';
export async function runTurn(ctx: SessionContext, audioIn: AsyncIterable<Buffer>) {
const started = performance.now();
// 1. VAD segmenta a fala do usuário
const userAudio = await vadDetect(audioIn);
ctx.trace('vad_done', performance.now() - started);
// 2. STT streaming -> texto
const userText = await streamSTT(userAudio, { language: 'pt-BR' });
ctx.trace('stt_done', performance.now() - started);
ctx.history.push({ role: 'user', content: userText });
// 3. LLM com tools
const llmStream = streamLLM({ history: ctx.history, tools });
let firstToken = 0;
let llmText = '';
// 4. TTS recebe tokens à medida que saem
const ttsStream = streamTTS({ voice: ctx.voiceId });
for await (const event of llmStream) {
if (event.type === 'text' && event.delta) {
if (!firstToken) firstToken = performance.now() - started;
llmText += event.delta;
ttsStream.send(event.delta);
} else if (event.type === 'tool_call') {
const result = await tools[event.name].run(event.args, ctx);
llmStream.submitToolResult(event.id, result);
}
}
ttsStream.end();
ctx.history.push({ role: 'assistant', content: llmText });
ctx.trace('llm_done', performance.now() - started);
// 5. Playback com barge-in
for await (const chunk of ttsStream.audio()) {
if (ctx.bargeIn) { ttsStream.cancel(); break; }
ctx.speaker.write(chunk);
}
ctx.trace('done', performance.now() - started);
}O capstone pede duas arquiteturas alternáveis por chave de configuração. Qual é a justificativa de engenharia?
Golden set de avaliação
[
{ "id": "cmd_clear_1", "category": "comando_claro", "audio": "fixtures/timer_5min.wav",
"expected_tool": "set_timer", "expected_args": { "minutes": 5 } },
{ "id": "cmd_clear_2", "category": "comando_claro", "audio": "fixtures/clima_sp.wav",
"expected_tool": "get_weather", "expected_args": { "city": "São Paulo" } },
{ "id": "ambig_1", "category": "ambiguo", "audio": "fixtures/alarme_amanha.wav",
"expected_behavior": "asks_follow_up" },
{ "id": "offtopic_1", "category": "off_topic", "audio": "fixtures/piada.wav",
"expected_behavior": "redirects_politely" },
{ "id": "noise_1", "category": "com_ruido", "audio": "fixtures/cafe_noise.wav",
"expected_tool": "set_timer", "tolerance": 0.7 },
{ "id": "barge_1", "category": "barge_in", "script": "user_interrupts_at_1.5s",
"expected": "agent_stops_within_300ms" }
]Writeup: o que recrutador quer ler
# Voice Assistant — Writeup
## TL;DR
Sistema conversacional em PT-BR com duas arquiteturas (Realtime API e pipeline clássico),
fallback automático, 3 tools funcionais, TTFA p95 de 820ms (Realtime) e 2.1s (pipeline).
Avaliado em golden set de 42 interações — task success 88% (Realtime), 81% (pipeline).
## Decisões de arquitetura
- Por que WebRTC e não WebSocket: resiliência a perda de pacote em mobile
- Por que pipeline como fallback: outage Realtime em 2025-11 custou 4h
- Por que Cartesia no pipeline: TTFA 90ms vs ElevenLabs 300ms
## Trade-offs honestos
- Realtime API custa 3x mais por minuto → feature flag por tier de usuário
- VAD Silero dá false positive em ambiente barulhento → expus threshold na UI
- Barge-in ainda perde 15% dos casos em gravações de café (ruído acima de 65dB)
## Métricas (tabela)
| arquitetura | ttfa_p50 | ttfa_p95 | custo/sessão | task_success |
| Realtime | 410ms | 820ms | $0.18 | 88% |
| Pipeline | 1400ms | 2100ms | $0.06 | 81% |
## Limitações conhecidas
- ...
## Próximas iterações
- ...
## Links
- Código: github.com/user/voice-capstone
- Demo vídeo (3min): ...
- Dashboard ao vivo: ...Checklist final
Entregáveis: (1) repo público com README forte, (2) golden set + script de eval executável, (3) feature flag entre Realtime e pipeline, (4) budget guard ativo, (5) logs estruturados + export, (6) vídeo demo de 2-3min mostrando barge-in e tool calls, (7) writeup com trade-offs honestos e limitações. Esse nível de capstone vira peça de conversa em entrevista sênior — não é trophy, é evidência.
Perguntas frequentes
❓ Quais são as partes de um assistente de voz?
❓ Qual latência é aceitável em conversa por voz?
❓ Como registrar conversa de voz sem violar privacidade?
Fixando
- → áudio em fluxo
- → texto parcial → final
- → quando precisa
- → trechos
- → primeira frase primeiro
- → áudio em fluxo
- → fala sobre a resposta
- → aborta
- IA e machine learning
- Conceito de arquitetura
Abaixo de um segundo até o primeiro som soa natural; acima de dois, a conversa quebra. Todo o desenho existe para encurtar esse primeiro som, não o tempo total.
- O que define a percepção é o tempo até o primeiro som. Não o tempo total. Latência total maior com primeira frase rápida soa melhor que o inverso — e é por isso que tudo aqui é em fluxo.
- Transcrição parcial adianta o raciocínio. O modelo pode começar a processar antes de a frase terminar. O cuidado é não agir sobre transcrição parcial que ainda vai mudar.
- Recuperação só quando a pergunta pede. Buscar em toda fala acrescenta centenas de milissegundos em conversa que não precisava. A decisão de recuperar é do modelo, com ferramenta.
- Síntese por frase, não por resposta. Esperar o texto inteiro para sintetizar joga fora o ganho do fluxo. A primeira frase curta é o que faz a conversa parecer natural.
- Interrupção é caminho de primeira classe. Sem cortar a síntese quando o usuário fala, o assistente atropela e a conversa quebra. É tratamento de estado, não de modelo.
O conjunto de avaliação do capstone traz áudios classificados por categoria, com ferramenta e argumentos esperados. Por que gravar o áudio em vez de testar a partir da transcrição?
A especificação exige um limite de gasto ativo. O que ele protege, exatamente?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…