Edición de documentos por voz con Gemini Live: arquitectura y compensaciones
La mayoría de las demos de "editor controlado por voz" que has visto hacen algo que es silenciosamente costoso: el audio pasa por un modelo de transcripción, la transcripción pasa por un modelo de instrucciones, y el modelo de instrucciones emite llamadas a herramientas hacia el editor. Tres viajes de ida y vuelta, dos LLM, y la superficie que ve el modelo de voz no es la superficie que expone el editor.
AgentDoc toma un camino diferente. Conectamos Gemini 3.1 Flash Live (la variante de audio nativo) directamente al mismo servidor MCP que usa el agente de texto. No hay proxy de transcripción, ni un segundo LLM, ni una superficie de herramientas separada para la voz. Esta publicación recorre por qué elegimos este diseño, cuánto cuesta y dónde siguen estando las asperezas.
El diseño ingenuo (y por qué pierde)
El patrón de proxy de transcripción se ve así:
mic → STT → transcript → text-LLM → tool-call → MCP → editor
↑
(instructions, tool list, history)
Tiene tres problemas reales. Primero, la latencia es la suma de tres llamadas secuenciales a modelos; sientes la pausa cada vez que terminas de hablar. Segundo, el paso de STT descarta la prosodia, que es exactamente la señal que distingue "italic 'really'" de "really, italic". Tercero, mantienes dos superficies de prompt divergentes: la documentación de herramientas del agente de texto y la del agente de voz, que con el tiempo se separan.
El diseño de audio nativo
El camino de audio nativo de Gemini Live toma audio en bruto, ejecuta llamadas a herramientas contra un esquema tipado y devuelve audio en streaming. El diagrama se reduce a:
mic → Gemini Live → tool-call → MCP → editor
↑
(same tool list as text agent)
Se derivan dos consecuencias:
- Una única fuente de verdad para la superficie de herramientas. El
agente de voz llama a
insert_textcon el mismo esquema que usa el agente de texto. No mantenemos una "lista de herramientas de voz" paralela. - La prosodia sobrevive. El modelo recibe el audio directamente, así que el énfasis y las pausas informan la selección de la llamada a herramientas sin que tengamos que escribir reglas.
Lo que tuvimos que construir
Tres puntos de integración requirieron trabajo:
- Puente de WebSocket. Gemini Live habla un protocolo WS; el editor usa otro para la sincronización de documentos en tiempo real. El servicio del agente ejecuta ambos y traduce los resultados de las llamadas a herramientas en eventos de renderizado del editor. Consulta [agent/](agent/).
- Observabilidad de las llamadas a herramientas. El modelo de voz necesita retroalimentación estructurada para evitar el desfase de índices tras las mutaciones. Le devolvemos los mismos descriptores de rango sucio que recibe el agente de texto (tratado en la publicación sobre granularidad de herramientas).
- Control mediante FSM, variante de voz. El FSM ReAct restringido por estados no se preocupa por la modalidad: el bloqueo de las herramientas de escritura tras una mutación funciona de forma idéntica para la voz. Solo tuvimos que asegurarnos de que el canal de salida de audio no se quede bloqueado cuando el FSM fuerza una relectura.
Latencia: la victoria que esperábamos y la que no
La latencia de extremo a extremo "dejé de hablar → el documento muta" baja de unos 2,4 s en el diseño de proxy a unos 700 ms con audio nativo. La victoria esperada.
La victoria inesperada es lo que ocurre durante los flujos de varios turnos. Como no pagamos el viaje de ida y vuelta del STT por turno, el modelo puede mantener de forma económica un contexto más largo de conversación hablada. Las instrucciones compuestas ("pon el título en negrita, luego pon el siguiente párrafo en cursiva, y luego expórtalo") que antes nos obligaban a fragmentar la transcripción en llamadas LLM separadas ahora se ejecutan como una única secuencia de llamadas a herramientas en una sola sesión de Live.
Cómo se ven las asperezas
Tres cosas siguen molestando:
- Cuota de la Live API. Las sesiones de audio nativo cuentan contra una
cuota diferente a la de las completaciones de texto, y una sesión de voz larga puede
consumirla más rápido de lo que esperaría una persona escribiendo. Nuestra píldora de
estado de cuota (el nuevo módulo
quota_status.js) es la respuesta visible para el usuario. - Desambiguación entre homófonos. "Insert here" e "insert hear" no suenan distinto para un micrófono en una sala ruidosa. Añadimos un pequeño conjunto de confirmaciones en las operaciones irreversibles (decir en voz alta "¿eliminando el párrafo 3, confirmas?") que controlan la mutación real.
- Reconexiones. El WebSocket de Live puede caerse en redes inestables, y el estado del búfer de audio en el momento de la caída no siempre es recuperable. Actualmente reproducimos los últimos ~3 segundos de texto confirmado en una sesión nueva, lo cual es suficiente para la mayoría de los usuarios, pero es lo siguiente en la lista de pulido.
Por qué esto importa para la accesibilidad
La motivación original de la construcción centrada en la voz está en la página de accesibilidad: AgentDoc está pensado para que lo puedan usar personas que no pueden o no quieren usar un ratón y un teclado. El diseño de proxy de transcripción siempre se sintió mal para ese público porque imponía una penalización de 2 segundos en cada enunciado, algo que se acumula mal a lo largo de una sesión larga de escritura.
El audio nativo no es solo una preferencia de ingeniería. Es la diferencia entre la voz como una entrada novedosa y la voz como una entrada principal.
Qué sigue
Trabajo en curso: mejor manejo de las reconexiones, una alternativa al modo de texto consciente de la cuota cuando el presupuesto de Live es bajo, y un estudio que compara los tiempos de finalización solo con voz frente a solo con texto en los 13 escenarios de referencia. Ese último tendrá su propio artículo aquí cuando lleguen los datos.