Ingénierie

Dictée vocale omni-modale : compréhension multimodale, MoE et sortie texte en streaming

Une visite guidée technique de la façon dont Loqua combine l'écoute, la compréhension multimodale de la tâche et le rendu texte, sans rendre la voix lente.

TL;DR

La dictée vocale omni-modale n'est pas un seul gigantesque modèle audio. Loqua est un outil de dictée vocale natif Mac qui découpe la reconnaissance vocale, la planification d'instructions multimodale et le rendu texte en un pipeline de sortie texte en streaming. Cette séparation nous laisse de la place pour un MoE sur l'encodeur audio, du contexte d'écran local et une interaction de classe 200 ms, sans laisser entendre que le produit serait un wrapper autour d'un modèle tiers.

Voici la note d'ingénierie plus profonde derrière notre stack de dictée vocale omni-modal : pourquoi on sépare la reconnaissance acoustique de la compréhension multimodale de la tâche et du rendu texte, où les experts conditionnels ont aidé, où ils n'ont pas aidé, et pourquoi le streaming a dicté presque chaque choix d'architecture.

Pourquoi les LM audio monolithiques heurtent un mur Mac

Un modèle de langage audio monolithique est séduisant sur le papier : on donne audio, frames d'écran et texte à un gros modèle et on lui demande d'émettre la dictée finale. Dans l'usage quotidien sur Mac, ce design heurte trois murs à la fois. D'abord, le budget de latence est brutal. Si le premier token utile arrive après que le locuteur a marqué une pause, la dictée vocale ressemble à de la transcription batch plutôt qu'à de la frappe.

Voici le budget qu'on s'impose. Du microphone au premier caractère visible, on a environ 200 millisecondes. Là-dedans, environ 40 ms vont à l'overhead plateforme (buffering Core Audio, livraison inter-processus et rendu final), 60 ms à l'extraction de features acoustiques et à l'inférence du front end, 70 ms au décodage du planificateur d'instructions pour le premier partial, et il reste 30 ms au text renderer pour émettre un early commit sûr. Un seul LM audio de 1B+ paramètres exécutant chaque étape dans cette fenêtre est plausible sur une machine de benchmark mais peu fiable sur un vrai laptop avec un navigateur, un IDE et Zoom déjà ouverts.

Deuxièmement, le job visible par l'utilisateur, ce n'est pas seulement de l'automatic speech recognition. La même énonciation doit devenir un paragraphe Slack, un sujet de commit Git, un prompt Cursor ou un commentaire Python. Un modèle monolithique peut être entraîné à tout ça, mais il doit réapprendre les conventions de format pour chaque app et les redériver à chaque déplacement du curseur. Troisièmement, le modèle doit tenir dans l'enveloppe thermique et mémoire d'un laptop. Un modèle audio-vision-texte de 7B chargé en VRAM à côté d'un index d'IDE, c'est la recette pour le thermal throttling et le ventilateur bruyant. Les travaux publics comme Whisper et les rapports récents sur les modèles omni-modaux ont aidé le champ à comprendre la modélisation audio robuste et multimodale, mais expédier un produit local force des choix plus restreints et plus assumés.

Notre conclusion était simple : la dictée vocale omni-modale doit être un pipeline, pas un seul bloc universel. Le pipeline permet à chaque couche de garder un objectif petit, un mode de défaillance mesurable et un coût runtime borné.

Le pipeline d'instruction multimodal

Loqua n'a pas de couche de réponse vocale ou TTS dans ce chemin produit. Le planificateur d'instructions consomme les features audio en streaming, le contexte d'écran sélectionné, les métadonnées de l'app active, le texte récent autour du curseur et le prompt d'instruction actif. Il produit un plan de sortie texte compact : intention, entités, mode d'édition, format cible et incertitude.

Le text renderer convertit ce plan en texte. Il ne génère ni audio, ni réponses parlées, ni TTS. Il décide si le plan devient une checklist Markdown, une phrase, un commentaire de code ou une instruction structurée. Cette séparation garde le raisonnement cross-modal coûteux hors du chemin chaud quand l'utilisateur dicte simplement de la prose.

Ce que chaque couche ne doit pas faire

La discipline est dans ce qu'on a retiré. Le front end acoustique n'essaie pas d'être malin sur le format de destination ; il fait remonter des tokens audio avec timing et confiance. Le planificateur d'instructions n'écrit pas la prose finale ; il fait un plan structuré assez petit pour être révisé à bas coût. Le text renderer ne relit pas l'audio et ne synthétise pas de parole ; il fait confiance au plan, au contexte de destination et au prompt d'instruction. Laisser n'importe quelle couche franchir ces frontières était la cause la plus fréquente de régressions de latence dans nos premiers prototypes, parce que les boucles de feedback inter-couches transforment le streaming en traitement batch sans que personne ne s'en aperçoive avant de lire la trace.

CoucheEntrée principaleSortieDéfaillance qu'on surveille
Front end acoustiqueFrames microphone en streamingTokens audio avec timingRatés en voix basse et pièce bruyante
Planificateur d'instructionsTokens audio + contexte d'écran + prompt d'instructionIntention et plan de sortie texteMauvaise hypothèse de destination
Text rendererPlan + contraintes d'appTexte final uniquementSur-formatage ou correction tardive

Le bénéfice, c'est la déboguabilité. Quand la sortie est fausse, on peut dire si c'est le recognizer qui a entendu le mauvais mot, le planificateur d'instructions qui a choisi la mauvaise intention, ou le text renderer qui a écrit dans le mauvais registre. C'est bien plus facile que d'interpréter une longue trajectoire cachée. Dans notre triage interne, environ deux tiers des correctifs qualité post-lancement s'isolent proprement à une seule couche ; le reste demande des changements inter-couches, mais seulement après que le diagnostic est clair.

MoE sur l'encodeur audio

L'encodeur audio est l'endroit où le calcul conditionnel a payé. Toutes les énonciations n'ont pas besoin du même traitement acoustique. La parole douce, l'anglais accentué, le mélange anglais-chinois, les identifiants de code et le bruit de fond d'une salle de réunion stressent des parties différentes du modèle. Un petit routeur mixture-of-experts permet à l'encodeur de dépenser plus de capacité sur les régions difficiles sans rendre chaque frame coûteuse.

On a gardé le routage conservateur. Le routeur est conditionné sur des statistiques acoustiques et des indices lexicaux superficiels, pas sur des profils utilisateur personnels. Les experts se spécialisent dans des patterns comme la parole à faible amplitude, la dictée technique rapide et le code-switching. On a rejeté un pool d'experts plus grand parce que l'instabilité de routage rendait le comportement en streaming pire : un modèle précis mais qui change de style en milieu d'énonciation n'est pas utilisable pour taper.

Ce qu'on a essayé et abandonné

Deux idées paraissaient séduisantes en recherche et ont échoué en produit. D'abord, l'adaptation d'experts par utilisateur : entraîner un petit adaptateur par utilisateur intensif. Ça améliorait la précision en cold-start de quelques points sur notre jeu de test interne mais doublait l'empreinte mémoire au cold-launch et brouillait les frontières de confidentialité. Ensuite, un routeur qui prenait l'identifiant de l'app active comme signal fort. Il surapprenait sur une poignée d'apps courantes et se dégradait silencieusement sur les nouvelles. On l'a remplacé par le routeur acoustique-et-lexical actuel et on a remonté le comportement conscient de l'app jusqu'au planificateur d'instructions et au text renderer, où ça a sa place.

En pratique, le MoE sur l'encodeur audio aide Loqua à garder le chemin courant rapide tout en rendant la longue traîne moins fragile. Voilà la valeur produit : pas un truc de benchmark, mais moins de moments où un nom de bibliothèque, une phrase chuchotée ou un fragment bilingue casse le flow.

Streaming : token par token vs phrase par phrase

Le streaming était le compromis le plus difficile. La sortie token par token paraît réactive mais peut exposer des suppositions prématurées. La sortie phrase par phrase est plus propre mais paraît en retard. On utilise un hybride : partials précoces pour les passages à faible risque, commits retardés pour les entités et les éditions qui ont besoin de contexte d'écran.

Par exemple, quand tu dis "change the fetch profile function to return early if the auth client is missing", le système peut streamer rapidement les mots ordinaires. Mais les tokens autour de fetchProfile et authClient attendent que la couche de contexte confirme les identifiants visibles. C'est pour ça que le rendu de texte est séparé de la reconnaissance : il peut réviser un petit passage avant de committer le texte, sans redémarrer toute l'énonciation.

L'entrée bilingue en milieu de phrase est un cas connexe. Quand tu dis "把这个 retry 函数改成指数退避", le planificateur d'instructions produit un plan de sortie texte qui entrelace des passages chinois avec un token de code anglais. Le text renderer émet les caractères chinois dès qu'ils passent un seuil de confiance interne et attend quelques millisecondes de plus sur l'identifiant anglais pour le confirmer face au buffer d'IDE visible. L'utilisateur voit d'abord le flux chinois, puis l'identifiant, puis le reste. Réordonner la sortie aurait été plus rapide mais aurait paru faux ; l'œil s'attend à une frappe de gauche à droite.

Les commit boundaries sont l'autre levier. Une commit boundary est le moment où le text renderer s'engage à ne plus réviser. On les fixe aux pauses naturelles, aux terminaisons de phrase et aux transitions structurelles comme paragraphe, item de liste ou bloc de code. À l'intérieur d'une commit boundary, le text renderer est libre de réviser ; une fois committé, le texte est final du point de vue de l'utilisateur. Ce contrat est ce qui rend le streaming honnête plutôt que tremblotant.

Le résultat, c'est un streaming voice stack qui paraît immédiat mais ne traite pas chaque supposition acoustique précoce comme finale. Pour la dictée vocale, ce compromis compte plus que la vitesse brute de transcription.

Contexte de recherche ouverte

On suit la recherche ouverte de près parce qu'elle affûte notre vocabulaire pour les problèmes qu'on voit en produit. Les papiers et rapports sur la modélisation audio-langue, les encodeurs multimodaux et l'optimisation par préférences montrent le champ qui converge vers des responsabilités séparées, des contraintes de streaming et de l'alignement cross-modal. Pour le contexte, commence par Whisper, le rapport technique Qwen2 et l'aperçu public Qwen2.5-Omni.

La frontière produit importante : ces références sont du contexte littéraire. Le stack de production de Loqua est une recherche originale entraînée et optimisée en interne pour la dictée Mac. On cite les travaux ouverts pour expliquer le champ, pas pour suggérer une provenance.

Ce qu'on a construit et la suite

Ce qui a été expédié dans cette direction, c'est un système restreint : une dictée vocale Mac qui écoute, lit le contexte d'écran local et écrit du texte conscient de l'app. Le prochain chantier, c'est une évaluation plus rigoureuse. Il nous faut une méthodologie publique pour la latence, le NER technique, le WER multilingue et la désambiguïsation par le contexte d'écran, pour que les affirmations soient révisables hors de notre boucle de dogfooding.

La deuxième direction, c'est une meilleure calibration. Quand le modèle est incertain sur un identifiant visible, il devrait demander moins à l'utilisateur en choisissant une forme de sortie sûre ou en préservant la phrase brute. On explore aussi des marqueurs d'incertitude légers dans le text renderer pour que l'UI en aval puisse surligner les passages à faible confiance pour une correction clavier rapide, sans casser le rythme de la dictée.

La troisième direction, c'est l'audio non verbal. Ce travail est encore à l'état de prototype, et on le couvre séparément dans Des sons porteurs de sens. Avec nos travaux sur l'apprentissage par renforcement et le listener multimodal, ça forme l'agenda de l'année à venir pour notre stack de dictée vocale omni-modal.

Questions fréquentes

Qu'est-ce que la dictée vocale omni-modale ?
La dictée vocale omni-modale veut dire que le système de dictée tient compte d'autre chose que l'audio. Il peut combiner la parole avec un contexte d'écran local, les métadonnées de l'app active, le texte sélectionné et l'entourage du curseur. Dans Loqua, ce contexte aide le système à décider si la même phrase parlée doit devenir de la prose, un commentaire de code, une liste ou une édition.
Pourquoi Loqua sépare-t-il la compréhension du rendu de texte ?
Cette séparation rend le pipeline plus rapide et plus facile à déboguer. Le planificateur d'instructions résout l'intention, les entités, le contexte de destination et le prompt d'instruction actif. Le text renderer écrit le texte final dans la bonne forme. Il ne génère ni voix ni TTS. Si la sortie échoue, on peut inspecter si c'est l'écoute, la compréhension de la tâche ou le rendu de texte qui est responsable, plutôt que de deviner à l'intérieur d'un seul modèle monolithique.
Le MoE ne rend-il pas la dictée vocale locale trop lourde ?
Il peut, si le pool d'experts est grand ou si le routage est instable. Loqua garde le MoE de l'encodeur audio conservateur : petits experts, signaux de routage simples, et un chemin par défaut rapide. L'objectif n'est pas la capacité maximale. L'objectif est de dépenser du calcul supplémentaire uniquement sur les régions acoustiques difficiles.
Pourquoi ne pas streamer chaque token immédiatement ?
Le streaming immédiat peut exposer des suppositions coûteuses à corriger, surtout autour des identifiants et du formatage spécifique à l'app. Loqua streame rapidement les passages à faible risque et retarde les passages risqués jusqu'à confirmation par le contexte. Ça reste réactif tout en évitant les corrections en milieu d'énonciation les plus frustrantes.
Cette architecture n'est-elle utile que pour Mac ?
La séparation générale peut marcher ailleurs, mais Mac est l'endroit où on peut faire des hypothèses produit fortes : Apple Silicon, contexte d'app desktop, APIs d'Accessibilité et workflows pilotés au clavier. Restreindre la plateforme permet au modèle et au runtime d'optimiser pour un environnement quotidien plutôt qu'un compromis multi-plateforme générique.
Comment des ingénieurs devraient-ils évaluer un voice stack comme celui-ci ?
Ne te contente pas du word error rate. Mesure aussi le temps jusqu'au premier texte utilisable, la préservation des entités, la précision du formatage conscient de l'app, le taux de correction et le comportement à la frontière de confidentialité. Un voice stack peut avoir un bon ASR et pourtant être mauvais pour écrire du texte utile dans l'app de destination.
Que signifie une commit boundary dans un voice stack en streaming ?
Une commit boundary est le point auquel le text renderer s'engage à ne plus réviser le texte déjà émis. Loqua place les boundaries aux pauses naturelles, terminaisons de phrase et transitions structurelles. À l'intérieur d'une boundary, le text renderer peut réviser librement ; une fois committé, le texte est final du point de vue de l'utilisateur, et c'est ça qui rend le streaming honnête.
Pourquoi ne pas personnaliser l'encodeur audio par utilisateur ?
On a essayé et on a abandonné. Les adaptateurs par utilisateur amélioraient la précision en cold-start de quelques points sur nos jeux internes mais doublaient l'empreinte mémoire au lancement et affaiblissaient notre récit de confidentialité. Loqua garde l'encodeur générique et pousse le comportement spécifique à l'utilisateur plus haut dans le stack : planificateur d'instructions, text renderer et dictionnaires locaux qui ne quittent jamais l'appareil.

Try Loqua today

Free to start. Mac native. Built by algorithm researchers who use it every day.

Download for Mac

More from the Loqua Blog

how-to
How to dictate code on Mac: a complete guide for Cursor, VS Code, and Claude Code
compare
Loqua vs Wispr Flow: a Mac-first Wispr Flow alternative for context, coding, and privacy
engineering
Private voice dictation Mac edition: how Loqua's hybrid voice typing stack keeps your data on your side