En Perplexity nos importa mucho crear productos que dé gusto usar. En el caso de Perplexity Comet, nuestro navegador con capacidades de agente, y de Perplexity Computer, nuestro potente trabajador digital de propósito general, una parte importante era que pudieras usar todas sus funciones con la voz. Es especialmente satisfactorio poder decir lo que quieres, delegar la tarea y ver cómo se lleva a cabo. Apostamos por la voz como interfaz porque interactuar así tiene algo de mágico.
Usamos Realtime-1.5 en producción para llevar esa magia a los millones de sesiones de voz que Perplexity gestiona cada mes. Ver cómo crece el uso de la voz en la interfaz de Computer ha sido muy emocionante y nos ha enseñado mucho. Queremos compartir algunas cosas que nos han sorprendido hasta ahora. Te invitamos a probar Realtime-1.5 y a compartir con nosotros lo que aprendas.
1. Define cómo vas a gestionar el contexto
El contenido extenso, en especial los podcasts de varias horas con mucha información, fue una de las pruebas que mejor nos permitieron evaluar la gestión del contexto. Queríamos que se pudieran consultar las transcripciones de los podcasts por voz. Así, alguien podría preguntar directamente qué pasaba en un momento concreto, dos horas y media después del inicio, y obtener una respuesta coherente.
La transcripción completa no cabe en la ventana de contexto. Primero probamos a enviarla en bloques grandes. Pronto descubrimos que, cuando falla una actualización grande, se pierde todo el historial. Si intentas enviar una actualización de 10 000 tokens a una ventana en la que solo caben 5000 tokens más, el modelo pierde todo el historial anterior. Por eso los bloques grandes eran mucho más arriesgados. Una sola actualización demasiado grande podía borrar un bloque entero de contexto en vez de permitir que el sistema descartara información poco a poco.
Así que cambiamos de enfoque. Empezamos a dividir todo en bloques mucho más pequeños, de 2000 tokens, y a enviarlos uno a uno. Esto requiere más procesamiento, pero el comportamiento es mucho más estable. Cuando se trunca el contexto, solo se recorta una parte del historial en vez de borrarlo todo.
También aprendimos algo menos evidente. Conviene distinguir cómo se le presenta al modelo cada tipo de contexto. Cuando usas conversation.item.create para actualizar el contexto, un elemento con item.type: "message" puede tener uno de tres roles: system, user y assistant. Estos roles le indican al modelo qué clase de mensaje recibe. El rol system sirve para dar instrucciones y orientar el comportamiento, user corresponde a lo que aporta el usuario final y assistant a lo que genera el modelo.
Cuando asignábamos mal los roles, la interacción empezaba a sentirse extraña. Si llegaba demasiado contexto como user, el modelo actuaba como si el usuario estuviera leyendo en voz alta cada bloque de texto, incluidos los fragmentos de páginas web y los comentarios, cuando en realidad solo hacía una pregunta sobre ese material. Si llegaba demasiado contexto como system, ocurría lo contrario. El modelo dejaba de distinguir entre lo que ya “sabía”, lo que había recibido como contexto y lo que el usuario preguntaba en ese momento.
La navegación es un buen ejemplo. A medida que alguien se desplaza por una página, actualizamos continuamente el contexto del modelo con lo que aparece en pantalla. Si presentamos todo ese contenido como un mensaje del usuario, el modelo empieza a actuar como si la persona hubiera dicho cada párrafo en voz alta. Así no es como debe interpretar la interacción. Queremos que dé la impresión de que el sistema sigue el contenido de la página en segundo plano y responde con naturalidad cuando el usuario pregunta algo. Para lograrlo, resultó más importante representar correctamente el papel de cada mensaje en la conversación que ajustar la cantidad de contexto.
2. Estandariza el audio en todos los productos
Perplexity ofrece varias interfaces, como Ask, Comet y Computer. Cada una usa tecnologías distintas del lado del cliente. Swift, TypeScript, Rust y C++ pueden producir búferes de audio nativos diferentes. Cuando dejábamos que cada cliente enviara audio sin procesar o en su propio formato nativo a la Realtime API, el rendimiento variaba de un cliente a otro.
Terminamos creando un SDK en Rust para abstraer esas diferencias entre plataformas y garantizar que todos los clientes enviaran audio a la API conforme a la misma especificación. En la práctica, esto implicaba procesar la forma de onda antes de que llegara al servidor. Remuestreábamos el audio a 48 kHz en mono, una frecuencia que coincide con la preferida por el códec Opus y con la frecuencia interna de WebRTC. Luego lo pasábamos por el módulo APM de WebRTC para cancelar el eco, controlar la ganancia automáticamente, reducir el ruido y aplicar un filtro pasaaltos. Por último, lo codificábamos para transmitirlo. Con el SDK pudimos estandarizar las constantes de audio, remuestrear la señal y configurar toda la cadena de procesamiento en un solo lugar, sin tener que hacerlo en cada cliente.
3. Ajusta la detección de voz en condiciones reales
Es importante ajustar la detección de actividad de voz (VAD) en el entorno cotidiano de los usuarios. Eso implica calibrarla con micrófonos reales, teniendo en cuenta el volumen de los altavoces y el ruido de fondo. Una de nuestras pruebas internas tuvo lugar en un bar ruidoso de San Francisco porque nos parecía una situación en la que alguien realmente usaría el producto. Alguien pregunta: “¿Ya probaste la nueva aplicación de Perplexity?”. Su amigo saca el teléfono y, si la voz falla, acabamos de perder a dos usuarios. Cuando funciona, la reacción es más bien “¡a la m**rda!”. Esa prueba nos obligó a ajustar el sistema para situaciones así. Lo que funciona en condiciones ideales suele fallar en el mundo real. Es mejor empezar por los entornos difíciles.
Uno de los mayores retos al diseñar la interacción por voz fue interpretar bien las pausas. Es natural que alguien se detenga a pensar, a buscar algo en pantalla o a prepararse para leerlo en voz alta. El modelo puede interpretar esa pausa como el final del turno e intervenir demasiado pronto. Lo vimos, por ejemplo, cuando alguien pedía ayuda con una derivación matemática. Hacía una pausa para buscar la fórmula y el modelo intervenía antes de que terminara la pregunta. Así surgió el bloqueo del turno de voz. En el esquema tradicional de pulsar para hablar, la voz está desactivada de forma predeterminada y el usuario tiene que presionar un botón para hablar. Nosotros invertimos esa lógica. De forma predeterminada, la interacción por voz permanece activa en segundo plano y, cuando el usuario necesita conservar la palabra un momento, puede bloquear el turno para que el modelo espere. Creemos que esta idea va más allá de una función puntual. A medida que las interfaces de voz se incorporen a flujos de trabajo más complejos, creemos que alguna variante de este patrón de interacción se convertirá en la norma.
4. Usa solo las herramientas esenciales y mantén sus formatos dentro de la distribución de entrenamiento
Limita el conjunto de herramientas a las que más importan. En nuestro caso, eran menos de diez. Nos concentramos en un pequeño grupo que cubría las acciones de mayor valor. Esa decisión tenía sentido y probablemente dará aún mejores resultados a medida que mejoren las nuevas versiones de los modelos.
Incluimos en el prompt del sistema instrucciones explícitas sobre cuándo y cómo llamar a cada herramienta. Procuramos que tanto los esquemas de las herramientas como sus resultados se ajustaran a la distribución de datos con la que se entrenó el modelo. En la práctica, dábamos a los resultados el formato habitual de los datos estructurados de una herramienta, en vez de presentarlos como intervenciones del asistente. Devolvíamos JSON estructurado con campos claramente separados, como response_text para el texto que se diría al usuario e indicadores como require_repeat_verbatim para controlar el comportamiento. Así evitábamos mezclar el contenido que debía decirse en voz alta con instrucciones intercaladas. Esto hizo más estable el uso de herramientas y mantuvo el patrón de interacción más cerca de lo que el modelo probablemente había visto durante el entrenamiento.
// Good:
{
"response_text": "I kicked-off the task to create a market research dashboard",
"require_repeat_verbatim": true
}
// Avoid:
I kicked-off the task to create a market research dashboard
# Response Instructions
Read the above instructions EXACTLY as they are
Realtime ya está listo
Realtime-1.5 marca un punto de inflexión para la industria. Sin duda, hay margen para mejorar el manejo de contextos largos, el uso de un mayor número de herramientas y la ejecución de tareas que exigen más capacidad de razonamiento. Esperamos que los modelos sigan mejorando. En Perplexity ya pensamos en cómo desarrollar productos para ese futuro. Queremos que los sistemas actuales sean fáciles de usar mientras nos preparamos para la próxima generación de modelos Realtime y las nuevas experiencias de voz que harán posibles.