← Todo el material
Curso Avanzado 24 de agosto de 2026

Voz e IA — Módulo 11: evaluar un sistema de voz

Undécimo módulo del Curso de Voz e IA en tiempo real: cómo se mide si un agente de voz funciona. WER para el ASR, MOS y naturalidad para el TTS, las métricas de latencia que importan, y lo más difícil — evaluar la conversación completa: interrupciones, turn-taking, tareas resueltas y errores en cascada.

☰ Índice del contenido

En el módulo 10 sacamos el agente de voz del laboratorio y lo pusimos en el teléfono: el audio comprimido, la red que se corta, el eco, el ruido de fondo. Todo ese mundo real degrada al sistema de maneras que no se ven en una demo con un buen micrófono. La pregunta que queda abierta es incómoda: ¿cómo sabes si tu agente funciona? No “funciona” en el sentido de que arranca, sino en el sentido de que resuelve lo que el usuario necesita, en la voz de la calle, a través de una línea telefónica mala. Este módulo trata de medir eso. Y la mala noticia es que un agente de voz no es un modelo: son varios modelos apilados, así que hay que medir cada capa y el todo. La buena noticia es que la disciplina para hacerlo ya existe —es la del Curso de Evals— y acá la aplicamos a la voz.

La tesis del módulo

Un agente de voz falla en cadena: un error de ASR envenena al LLM, y el usuario escucha una respuesta perfecta a la pregunta equivocada. Por eso no basta medir cada componente por separado. Un ASR con 5% de error y un LLM impecable pueden producir una llamada pésima si ese 5% cae justo en el número de cuenta. La métrica que manda no es la de ninguna capa: es la de la conversación completa, evaluada de punta a punta, contra la única vara que le importa al usuario —“¿resolvió lo que vine a resolver?”.

Por qué medir capa por capa no alcanza

El pipeline de voz tiene tres modelos en serie: ASR (Automatic Speech Recognition, audio a texto), el LLM que decide qué responder, y TTS (Text-to-Speech, texto a audio). Cada uno tiene su métrica clásica, y las vamos a ver todas. Pero antes conviene entender por qué esas métricas, sumadas, no describen el sistema.

El problema es el error en cascada: el fallo de una capa no se queda en esa capa, se propaga y a veces se amplifica. Si el ASR transcribe “quiero cancelar” cuando el usuario dijo “no quiero cancelar”, el LLM recibe un texto gramaticalmente perfecto, sin ninguna señal de que está corrupto, y actúa sobre él con total confianza. El TTS después sintetiza esa respuesta equivocada con una prosodia impecable. Cada capa hizo “bien” su trabajo sobre la entrada que recibió; la llamada fue un desastre. Ninguna métrica de componente lo capta, porque cada una mide su tramo contra la entrada que le llegó, no contra la verdad original.

De ahí la regla del módulo: se mide cada capa para diagnosticar, y se mide la conversación completa para decidir. Las métricas de capa te dicen dónde está el problema; solo la evaluación end-to-end te dice si tienes un problema.

Evaluar el ASR: WER y CER

La métrica canónica del reconocimiento de voz es el WER (Word Error Rate, tasa de error por palabra). Se define comparando la transcripción del sistema (la hipótesis) contra la transcripción correcta hecha por un humano (la referencia), y contando cuántas palabras hay que cambiar para pasar de una a la otra:

        S + I + D
 WER = ───────────
            N

donde S son sustituciones (una palabra por otra), I inserciones (palabras que el sistema agregó y no estaban), D borrados (deletions, palabras que se comió) y N el total de palabras de la referencia. Ese numerador es exactamente la distancia de edición (edit distance o distancia de Levenshtein: el mínimo de operaciones para transformar una secuencia en otra), calculada a nivel de palabra. Un WER de 0.10 significa una palabra mal de cada diez; según la industria, 5–10% es buena calidad y bajo 5% es excelente.

El CER (Character Error Rate, tasa de error por carácter) es lo mismo pero contando caracteres en vez de palabras. Sirve cuando la unidad “palabra” es ambigua —idiomas sin espacios, o cuando quieres crédito parcial: transcribir “Briceño” como “Bricena” es un WER de 1.0 (la palabra entera mala) pero un CER bajo (un carácter de siete). El CER es más indulgente y más informativo para errores de ortografía y nombres propios.

La normalización lo es todo

Antes de calcular WER hay que normalizar ambos textos, o la métrica miente. Si la referencia dice “veinte dólares” y el sistema transcribe “$20”, sin normalizar eso cuenta como dos errores, cuando semánticamente es idéntico. La normalización típica: pasar todo a minúsculas, quitar puntuación, colapsar espacios múltiples, y —la más delicada— unificar números y fechas a una forma canónica. El WER que reportas depende tanto de tu normalización como de tu modelo. Dos equipos con el mismo ASR pueden reportar WER distintos solo por normalizar diferente; por eso, al comparar, la normalización tiene que ser la misma o los números no significan nada.

Con jiwer (la librería estándar de Python para esto) el cálculo con normalización se ve así:

"""WER y CER con jiwer, con normalización explícita.

jiwer.wer() y jiwer.cer() llaman por debajo a process_words /
process_characters; para una sola métrica basta la función corta.
La normalización se pasa como una cadena de transformaciones que se
aplica IGUAL a referencia e hipótesis.
"""
import jiwer

referencia = "Quiero transferir veinte dólares a la cuenta de Ana."
hipotesis  = "quiero transferir $20 a la cuenta de ana"

# La transformación se aplica a ambos textos por igual. El orden
# importa: primero se limpia, al final se parte en palabras.
normaliza = jiwer.Compose([
    jiwer.ToLowerCase(),
    jiwer.RemovePunctuation(),
    jiwer.RemoveMultipleSpaces(),
    jiwer.Strip(),
    jiwer.ReduceToListOfListOfWords(),
])

# OJO: '$20' vs 'veinte dólares' sigue contando como error aquí.
# La normalización de números/monedas es aparte y es tu decisión.
wer = jiwer.wer(referencia, hipotesis,
                reference_transform=normaliza,
                hypothesis_transform=normaliza)
cer = jiwer.cer(referencia, hipotesis)
print(f"WER={wer:.3f}  CER={cer:.3f}")

# Para el desglose S/I/D (útil para diagnosticar), usa process_words:
salida = jiwer.process_words(referencia, hipotesis,
                             reference_transform=normaliza,
                             hypothesis_transform=normaliza)
print(salida.substitutions, salida.insertions, salida.deletions)

El WER de benchmark no es tu WER

Un proveedor te dice “nuestro ASR tiene 4% de WER”. Ese número salió de un dataset de laboratorio: audio limpio, hablantes de acento estándar, micrófono de estudio, temas generales. Tu WER va a ser otro, y casi siempre peor, porque:

  • Tu dominio tiene vocabulario que el benchmark no vio: nombres de productos, términos técnicos, códigos alfanuméricos. Ahí el WER se dispara.
  • Tu acento puede no ser el que el modelo vio más. El español chileno rural rinde distinto que el español neutro de locutor.
  • Tu canal es el teléfono del módulo 10: 8 kHz, comprimido, con ruido. El benchmark era wideband limpio.

La conclusión operativa: el único WER que te sirve es el que mides sobre TU audio, con TUS transcripciones de referencia. Grabar 100–300 llamadas reales, transcribirlas a mano una vez, y correr tu ASR contra ese set vale más que cualquier número de la ficha técnica del proveedor.

Evaluar el TTS: MOS y naturalidad

Con el TTS el problema cambia de forma: no hay una “respuesta correcta” contra la cual contar errores. La voz sintética o suena natural o no, y eso es subjetivo. La métrica histórica es el MOS (Mean Opinion Score, puntaje medio de opinión): se le pide a un grupo de oyentes humanos que califiquen muestras de audio del 1 (malo) al 5 (excelente), y el MOS es el promedio. Es el estándar desde la telefonía clásica, y sigue siendo la vara de oro para naturalidad.

El MOS tiene un costo obvio: necesita humanos, lo que lo hace lento y caro. No puedes correr un MOS en cada commit. Por eso existe el MOS predicho (predicted MOS): modelos que estiman qué nota le pondría un humano, sin humano. El más conocido es UTMOS, un modelo entrenado sobre juicios reales que da una predicción por frase muy correlacionada con el MOS humano. Sirve como métrica automática de regresión —para detectar que una versión nueva del TTS empeoró— aunque nunca reemplaza del todo al panel humano para la decisión final.

Además de la naturalidad, hay dos cosas más que medir en el TTS:

  • Inteligibilidad. ¿Se entiende lo que dice, más allá de si suena lindo? Se mide de forma elegante con un truco: pasar el audio sintético por un ASR y calcular el WER de vuelta. Si un buen ASR no logra transcribir tu TTS, un humano tampoco lo entiende. Un TTS puede tener MOS alto (voz agradable) y aun así fallar en inteligibilidad con nombres o números.
  • Pronunciación y prosodia. Que diga bien los nombres propios, los números, las siglas; y que la prosodia (prosody: entonación, ritmo, acentos y pausas) sea la correcta —una pregunta que suena a afirmación, o un número de teléfono leído sin las pausas, arruinan la llamada aunque cada fonema esté bien.

Ojo: MOS alto no es lo mismo que TTS útil. Una voz preciosa que pronuncia “RUT 12.345.678-9” como una parrafada indescifrable falla en lo único que importaba de ese turno. En un agente transaccional, la inteligibilidad de datos (números, códigos, nombres) pesa más que la belleza de la voz.

Métricas de latencia

La latencia ya la tratamos en el módulo 5 como concepto de diseño; acá la retomamos como métrica que se mide en producción. Las tres que importan:

  • Latencia de turno end-to-end. Desde que el usuario termina de hablar hasta que empieza a oír la respuesta. Es la que el usuario siente, y la meta sigue siendo bajar de ~800 ms.
  • TTFB de audio (time-to-first-byte, tiempo hasta el primer fragmento de audio reproducible). En un sistema con streaming, esto es lo que corta el silencio; puede ser mucho menor que el turno completo y es lo que decide si “se siente” rápido.
  • Percentiles p50 y p95. El promedio de latencia miente igual que el promedio de seguridad del módulo de evals: esconde la cola. El p95 (el valor bajo el cual cae el 95% de los turnos) es el que refleja la experiencia real, porque el 5% de turnos lentos es justo donde el usuario se frustra y habla encima. Reportar p50 y p95 juntos; un p50 de 600 ms con p95 de 3000 ms es un sistema que se siente roto uno de cada veinte turnos.

Estas se miden en la conversación real, con marcas de tiempo en cada frontera del pipeline (fin de habla, texto del ASR listo, primer token del LLM, primer audio del TTS). Sin esas marcas no puedes atribuir la lentitud a una capa.

Evaluar la conversación (lo difícil)

Aquí está el corazón del módulo, y lo que separa un agente de voz que “pasa los tests” de uno que funciona. Las métricas de capa son necesarias pero ciegas al error en cascada. La evaluación de la conversación mira la llamada como un todo:

  • Tasa de tareas completadas (task success rate). La métrica reina. De un set de llamadas con un objetivo claro (“agendar una cita”, “pagar la cuenta”), ¿en qué fracción el usuario logró su objetivo? Es la que correlaciona con negocio y la que absorbe todos los errores en cascada: si el ASR envenenó al LLM, la tarea falla, y esta métrica lo cuenta aunque el WER se veía bien.
  • Corrección del turn-taking. ¿El agente respetó los turnos? Se cuentan las interrupciones indebidas (el agente habló encima del usuario) y los cortes prematuros (creyó que el usuario terminó cuando aún hablaba). Esto conecta directo con el módulo 7: un endpointing mal calibrado se ve acá como métrica.
  • Robustez a barge-in. El barge-in (que el usuario interrumpa al agente y el agente se calle y escuche) es una capacidad que hay que testear a propósito: casos donde el usuario habla mientras el agente responde, y se mide si el agente cede el turno o sigue hablando como una grabación.
  • Manejo de errores de ASR. ¿El agente pide confirmación cuando el dato es crítico y la confianza baja? Un buen agente que oyó mal un número de cuenta lo repite para confirmar en vez de actuar; esto se puede y se debe medir con casos donde inyectas audio difícil a propósito.
  • Atribución del error en cascada. Cuando una llamada falla, ¿cuánto del fallo vino del ASR, cuánto del LLM y cuánto del TTS? Se hace corriendo el pipeline con la capa sospechosa reemplazada por su versión perfecta: das al LLM la transcripción humana en vez de la del ASR; si con eso la tarea se resuelve, el culpable era el ASR. Aislar así cada capa convierte “la llamada falló” en “falló por el ASR en el 60% de los casos malos”.

El LLM juez sobre la transcripción de la llamada

Muchas de estas preguntas —¿resolvió la tarea?, ¿fue cortés?, ¿confirmó el dato crítico?— no se contestan con una regex. La técnica que las escala es la misma del Curso de Evals: un LLM juez (LLM-as-judge: un modelo que evalúa la salida de otro contra una rúbrica). Se le pasa la transcripción completa de la llamada —los turnos de usuario y de agente, con marcas de tiempo— y una rúbrica, y devuelve un veredicto estructurado.

"""LLM juez sobre la transcripción de una llamada de voz.

La transcripción es la conversación completa turno a turno. El juez
NO oye el audio: evalúa la lógica de la conversación. Las métricas
acústicas (WER, MOS, latencia) se miden aparte y se le pasan como
contexto para que juzgue con esos datos a la vista.
"""
import json
from openai import OpenAI

client = OpenAI()

RUBRICA = """Eres evaluador de llamadas de un agente de voz. Recibes la
TRANSCRIPCIÓN de una llamada y sus métricas acústicas. Evalúa:

- tarea_resuelta: ¿el usuario logró su objetivo? (true/false)
- turn_taking: ¿el agente respetó los turnos, sin cortar ni pisar? (1-5)
- manejo_errores: si hubo un dato dudoso, ¿pidió confirmación? (1-5)
- causa_probable_fallo: si falló, ¿"asr" | "llm" | "tts" | "ninguno"?

Responde SOLO JSON con esas claves más un campo "justificacion" breve."""


def juzgar_llamada(transcripcion: str, metricas: dict) -> dict:
    contexto = (f"MÉTRICAS: WER={metricas['wer']:.2f}, "
                f"latencia_p95={metricas['lat_p95']}ms\n\n"
                f"TRANSCRIPCIÓN:\n{transcripcion}")
    r = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "system", "content": RUBRICA},
                  {"role": "user", "content": contexto}],
        response_format={"type": "json_object"},
        temperature=0,  # el juez debe ser reproducible
    )
    return json.loads(r.choices[0].message.content)

El dataset de llamadas como suite de regresión

La pieza que hace todo esto operativo es un dataset de conversaciones grabadas: un conjunto de llamadas reales (o guiones actuados) con su transcripción de referencia, su objetivo y su resultado esperado. Ese set se convierte en tu suite de regresión: cada vez que cambias el prompt del LLM, subes el ASR de versión o cambias la voz del TTS, corres el sistema entero contra el set y comparas. Sin ese dataset, cada cambio es una apuesta a ciegas —exactamente el error que el Curso de Evals enseña a no cometer, ahora sobre audio.

Dónde se mide cada métrica en el pipeline

          PIPELINE DE VOZ Y SUS MÉTRICAS

           ┌───────┐    ┌───────┐    ┌───────┐
  audio ─► │  ASR  │ ─► │  LLM  │ ─► │  TTS  │ ─► audio
           └───┬───┘    └───┬───┘    └───┬───┘    resp.
               │            │            │
             [WER]       [tarea]       [MOS]
             [CER]       [juez]        [inteligib.]
                                       [prosodia]

  latencia end-to-end / p50 / p95 abarca todo el turno

  ERROR EN CASCADA
  ────────────────
  ASR oye mal  ─►  LLM responde perfecto  ─►  TTS lo
  "no cancelar"    a "cancelar" (basura       sintetiza
  como "cancelar"  con confianza total)       impecable
                                                  │
                                                  ▼
                                     llamada mala, WER "ok"

El diagrama contiene la lección: las métricas de capa (fila del medio) viven cada una en su tramo, pero la única que abarca la fila de abajo —la llamada completa— es la de tarea/juez y la de latencia end-to-end. El error en cascada se cuela entre las cajas, donde ninguna métrica de componente mira.

Tabla: qué mide cada métrica y qué la engaña

MétricaQué capa mideAutomática / humanaQué la engaña
WER / CERASRAutomática (con referencia)Normalización distinta; benchmark ≠ tu dominio
MOSTTSHumanaPanel pequeño o sesgado; frases fáciles
MOS predicho (UTMOS)TTSAutomáticaVoces fuera de su distribución de entrenamiento
Inteligibilidad (WER de vuelta)TTSAutomáticaUn ASR muy bueno “adivina” lo que un humano no
Latencia p50 / p95PipelineAutomáticaReportar solo el promedio esconde la cola
Tasa de tareasConversaciónAuto (juez) o humanaTareas triviales; “éxito” mal definido
Turn-taking / barge-inConversaciónAuto o humanaNo testear interrupciones a propósito

La columna de la derecha es la que hay que tener presente al leer cualquier número: toda métrica tiene una forma de verse bien sin que el sistema sea bueno.

Errores comunes

  • Medir solo las capas y sumar. Un WER bajo, un MOS alto y una latencia buena no garantizan una buena llamada. El error en cascada vive entre las capas; solo la evaluación end-to-end lo ve.
  • Creerle al WER del proveedor. Ese número salió de audio limpio y dominio general. El único WER que te sirve es el que mides sobre tus llamadas reales, con tu normalización.
  • Comparar WER con normalizaciones distintas. Media diferencia de WER entre dos sistemas puede ser puro artefacto de cómo cada quien trató números y puntuación. Misma normalización o no hay comparación.
  • Reportar el promedio de latencia. El promedio esconde la cola. El p95 es el que refleja la frustración real; sin él, un sistema que se traba uno de cada veinte turnos parece sano.
  • Confundir MOS alto con TTS útil. Una voz bonita que no pronuncia bien los números falla en el turno que importaba. Mide inteligibilidad de datos, no solo naturalidad.
  • No testear el barge-in. Si nunca inyectas una interrupción en tus casos, no sabes si el agente cede el turno o atropella al usuario. Es una capacidad, y las capacidades se prueban a propósito.
  • No tener dataset de regresión. Sin un set de llamadas grabadas con resultado esperado, cada cambio de prompt o de modelo es una apuesta sin red.

La frase para llevarse

“Un agente de voz no falla en una capa: falla en la costura entre capas. El WER, el MOS y la latencia te dicen dónde mirar; solo la pregunta ‘¿resolvió lo que el usuario vino a resolver?’ te dice si tienes un producto.”

Qué viene

Módulo 12: voz en producción. Ya sabes construir el pipeline, sacarlo al teléfono y medir si funciona. El último módulo junta todo en un sistema que vive: monitoreo en vivo de WER y latencia, alertas cuando una capa se degrada, el ciclo de mejora con el dataset de regresión, control de costos por minuto de llamada, y las decisiones de arquitectura que solo aparecen cuando el agente atiende llamadas reales a escala. De la demo que impresiona al servicio que aguanta.

Material relacionado

VozEvaluaciónWERMOSEvals

Preguntas sobre este curso

Regístrate gratis para hacer preguntas y guardar tu progreso.

✉ Entérate de lo nuevo

Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.