Passer au contenu
megapromotingDiscutons

Solutions · Transport & logistique

Quand le client demande où est le colis, l’agent ne devine pas : il appelle le courier, lui demande, puis revient avec la réponse.

La répartition par voix, construite comme un mécanisme, et non comme une promesse : un tableau avec des états explicites, trois tentatives à deux minutes d’intervalle, le résultat de l’appel écrit de manière structurée et un filtre qui retire le numéro du chauffeur de tout ce qui arrive au modèle, afin qu’il ne puisse pas être dicté au client.

Déjà construitMecanismul de dispecerizare e scris și migrat în platforma noastră vocală: tabela `courier_calls` cu șapte stări posibile, trei încercări implicite, pauză de 120.000 ms între ele și rezultatul apelului păstrat structurat, plus cinci funcții de server care o folosesc — inițierea apelului către curier, verificarea rezultatului, mătura pentru apelurile rămase agățate, identificarea celui care sună înapoi și webhookul de după apel. A doua implementare e filtrul de ieșire scris pentru un client din transport, care elimină recursiv câmpurile de contact ale șoferului din rezultatul uneltei, păstrând numerele dispeceratului. Rezerva, spusă înainte să întrebi: partea de telefon trece printr-o gazdă SIP, iar gazda prin care merg liniile noastre de test nu răspunde la data scrierii — nu-ți dăm un număr de demonstrație pe care nu l-am putea ridica în fața ta.

Dans une entreprise de transport ou de livraison, la plupart des appels reçus sont la même question posée par des personnes différentes : où est la marchandise, à quelle heure arrive-t-elle, pourquoi n’est-elle pas arrivée. La réponse n’est ni dans un document ni dans un système — elle est dans la tête du chauffeur, qui conduit. Le dispatch fait le lien : il prend l’appel du client, appelle le chauffeur, revient vers le client. Ce travail occupe une personne entière et se fait cent fois par jour, avec les mêmes trois phrases.

Nous avons construit exactement cette chaîne, comme mécanisme à états, et non comme fonction marketing. Un agent parle avec le client. Lorsqu’il a besoin d’une réponse qu’il n’a pas, il appelle une fonction qui lance un deuxième appel — vers le coursier — lié à la conversation dont il est parti. Cet appel a sa propre ligne dans une table, avec un statut qui passe par `calling`, `in_progress`, `retrying`, `completed`, `failed`, `no_answer`, `timeout`, avec le numéro de la tentative, avec un maximum de trois tentatives et une pause de deux minutes entre elles. Le résultat est écrit de manière structurée : le résumé de ce qu’a dit le coursier, le temps estimé, la position.

La partie facile à oublier et que nous traitons comme une exigence, et non comme une précaution : le numéro de téléphone du chauffeur ne doit pas parvenir au client. Ce n’est pas une instruction écrite dans le prompt de l’agent, car une instruction dans un prompt peut être contournée. C’est un filtre qui parcourt récursivement le résultat de l’outil et supprime les champs de contact du chauffeur avant que ce résultat n’atteigne le modèle — tout en conservant les numéros du dispatch. Ce qui a été supprimé ne peut pas être dicté, quelle que soit la manière dont l’agent est interrogé.

Et la limite la plus importante est une limite d’infrastructure, non d’intelligence : un agent vocal au téléphone dépend d’un hôte SIP entre votre opérateur et la plateforme. Quand cet hôte tombe, les appels ne partent pas, et la signature du défaut est reconnaissable — requête expirée, identifiant d’appel vide, durée zéro. L’hôte par lequel passent nos lignes de test ne répond pas à la date d’écriture de cette page. Sur le web, le parcours vocal est vérifiable aujourd’hui ; au téléphone, la première étape de tout travail est d’établir sur quel hôte entrent vos numéros.

Ce que cela comprend

Ce qui change concrètement dans le transport et la logistique

L’agent qui parle avec le client peut lancer un deuxième appel

Lorsque la réponse n’est pas dans l’information dont il dispose, l’agent appelle une fonction serveur qui téléphone au coursier. L’appel vers le coursier conserve son lien avec la conversation dont il est parti, au moyen d’un identifiant de la conversation parente — on sait donc toujours pour qui l’appel a été passé et pourquoi. Le contexte de la commande est transmis sous forme de structure, depuis votre système de commandes, il n’est pas redicté.

L’appel vers le coursier a des états, pas seulement « l’appel a été passé »

Sept états écrits comme contrainte dans la base de données : `calling`, `in_progress`, `retrying`, `completed`, `failed`, `no_answer`, `timeout`. Plus le numéro de tentative en cours. La différence entre « n’a pas répondu » et « le système est tombé » est visible dans les données, pas devinée à partir des journaux — et cela compte quand quelqu’un demande demain pourquoi le client n’a pas reçu de réponse.

Les relances sont configurées, pas improvisées

Par défaut : trois tentatives, avec 120.000 millisecondes — deux minutes — entre elles, toutes deux écrites comme valeurs par défaut dans le tableau et dans la configuration du processus. Un chauffeur qui roule sur une route sans signal ne répond pas au premier appel. Un système qui appelle une seule fois et déclare un échec est inutile précisément dans le cas pour lequel il a été construit.

Le résultat de l’appel revient structuré, pas sous forme de récit

Ce qu’a dit le courier est enregistré sous forme de résumé, de temps estimé et de position, dans un champ structuré lié à la ligne de l’appel. De là, cela peut aller plus loin : vers l’agent qui parle avec le client, vers le dispatch, vers votre système. Un webhook après l’appel et une fonction de nettoyage pour les appels restés accrochés complètent la chaîne, afin qu’un appel manqué ne reste pas à l’état `calling` indéfiniment.

Le numéro du chauffeur ne peut pas être dicté, parce qu’il n’atteint pas le modèle

Le filtre de sortie parcourt récursivement le résultat de l’outil et supprime les champs de contact du chauffeur, tout en conservant les numéros du dispatch. C’est écrit dans le code, appliqué précisément à l’intégration où le problème apparaît. La raison est simple : l’interface du fournisseur renvoyait les numéros des chauffeurs dans la réponse, et la politique de l’entreprise interdisait que l’agent les donne aux clients. Une instruction dans le prompt aurait pu être contournée par une question bien formulée ; un champ supprimé ne peut pas être contourné.

Qui rappelle est reconnu par son numéro

Le courier qui revient avec un appel est identifié par une fonction dédiée, donc il n’entre pas dans le flux général des clients et son menu n’est pas lu depuis le début. Cela semble un détail ; c’est la différence entre un système que les chauffeurs utilisent et un système qu’ils contournent en appelant directement le dispatch, ce qui annule tout le travail.

La prise en charge vers le dispatch, à portée de main de celui qui parle

Transfert aveugle via `##` et transfert assisté via `*2`, avec un contexte d’atterrissage dans le plan d’appel qui distingue les extensions internes de quatre chiffres des numéros externes. Quand le client demande avec insistance un humain — et dans le transport il le demande, parce que sa marchandise est en retard — le transfert ne doit pas passer par un menu.

L’agent peut être interrompu, et cela se règle avec des chiffres

Sur le parcours OpenAI Realtime : détection sémantique de la parole avec seuil 0,5, marge de 300 ms, 500 ms de silence, interruption autorisée par défaut. Sur le parcours ElevenLabs, l’événement d’interruption est transmis à la centrale afin de couper la lecture. `turn_timeout` est défini par agent. Dans un appel de transport, où l’interlocuteur se trouve souvent dans une cabine bruyante, ces seuils représentent la moitié de la qualité perçue.

Ce qu’un agent vocal ne fait pas dans le transport

Il ne décide pas de l’itinéraire et ne réoptimise pas les livraisons. Il ne donne pas un tarif s’il n’est pas connecté à la source qui le calcule. Il ne sait pas où se trouve la marchandise si personne ne le lui a dit — ni le courier, ni votre système. Et il ne remplace pas le dispatch : il prend les appels répétitifs et lui laisse les exceptions, qui sont précisément la partie pour laquelle il est payé.

Traseul

Comment une demande passe par le système.

01

Nous établissons d’abord sur quel hôte SIP vos numéros entrent

La première étape n’est pas le scénario de l’agent, mais la téléphonie : par quel trunk le numéro entre, qui le contrôle, que se passe-t-il lorsque l’hôte ne répond pas. Nous livrons une vérification écrite du parcours et, si le parcours n’est pas sûr, nous le disons avant de construire quoi que ce soit par-dessus. Un excellent agent sur un hôte qui tombe est un agent qui ne répond pas.

02

Nous écrivons le scénario de la répartition, avec ses exceptions

Ce que l’agent demande au courier, dans quel ordre, ce qu’il fait lorsque le courier ne répond pas à la troisième tentative, ce qui se passe lorsque la réponse est floue, quand il transfère au dispatcheur humain. Nous livrons le scénario écrit et la liste des états dans lesquels un appel peut se retrouver — y compris les moches.

03

Nous connectons la source des commandes et mettons les filtres à la sortie

Le contexte de la commande vient de votre système, et avant que le résultat d’un outil n’atteigne le modèle, nous passons par la liste des champs qui n’ont pas le droit de sortir. Nous livrons l’intégration, la liste écrite des champs filtrés et la preuve que le filtre s’applique au résultat, pas aux instructions.

04

Nous lançons sur un petit volume, avec les transcripts lus par un humain

Nous démarrons sur une partie des appels, avec le transfert au dispatcheur configuré largement, et nous lisons les transcripts. À partir de là, on règle les seuils d’interruption, `turn_timeout`, la formulation des questions et le seuil à partir duquel l’agent abandonne. Nous livrons le rapport de ces appels, avec les décisions de réglage, pas seulement l’agent lancé.

1Clientul întreabă2agentul cheamăfuncția de apel3apel către curier, custare proprie4până la treiîncercări, la douăminute5rezultat structurat(rezumat, timpestimat, poziție)6răspuns la client, cunumărul șoferuluifiltrat din drum
Traseul, în 6 pași

Les données

Ce que nous touchons, où elles sont et combien de temps elles restent

Les règles diffèrent d’un secteur à l’autre. Voici celles qui s’appliquent au transport & à la logistique.

Le numéro du chauffeur est une donnée personnelle d’une personne, pas un champ technique
Un courier ou un chauffeur sous-traitant est une personne physique. Son numéro, sa position et son enregistrement vocal sont ses données. C’est pourquoi le filtre de sortie n’est pas un caprice de sécurité, mais une minimisation appliquée à la source : le champ n’atteint pas le modèle, donc il ne peut pas se retrouver dans la conversation ni dans le transcript.
Ce qui est conservé d’un appel
Le numéro de l’appelant et le numéro appelé, le moment, la durée, le résultat, l’enregistrement audio, le transcript et l’analyse après l’appel. Pour les appels non pris, il existe le numéro, le moment et le motif de l’absence de réponse — il n’y a pas d’audio, parce qu’il n’a pas été produit. Tout est lié à l’espace de travail de votre entreprise ; il n’existe pas de dépôt commun entre clients.
L’annonce au début de l’appel est votre décision, pas un réglage
Le fait que l’interlocuteur parle à un système automatisé, que l’appel soit enregistré et sur quelle base — cela se décide avec vous et entre dans le scénario, dans les deux sens : vers le client et vers le courier. Le courier appelé par un agent doit savoir avec quoi il parle autant que le client.
La suppression sur demande existe ; la suppression automatique à terme, pas encore
Nous le disons tel quel, parce que c’est la différence entre une promesse et une fonction. La suppression à la demande est implémentée : une fonction dédiée supprime les objets du dépôt de fichiers, appelle la procédure de suppression dans la base et invalide les sessions. La rétention configurable par espace de travail n’est pas implémentée — elle apparaît dans un document de conception, dans aucune migration. Jusqu’à ce qu’elle le soit, la suppression à terme se fait par procédure.
Où les données se trouvent
PostgreSQL via Supabase sur infrastructure propre, avec des migrations versionnées, dont une partie active l’isolation par ligne. Les fichiers — enregistrements, documents de connaissances, échantillons vocaux — sont stockés dans des dépôts séparés, avec le chemin commençant par l’identifiant de l’espace de travail.

Un cas

Un appel qui a un état, pas seulement un résultat

La situation

Dans un flux de livraison, la question « où est ma commande » n’a de réponse dans aucun système : la réponse est chez le courier. La variante simple — l’agent écrit un message au courier et espère — échoue au premier courier qui conduit et ne regarde pas son téléphone.

Ce que nous avons construit

Nous avons construit la répartition comme un tableau, et non comme une fonction. Chaque appel au courier a une ligne avec sept états possibles, le numéro de tentative, au maximum trois tentatives, une pause de deux minutes entre elles et le résultat conservé de façon structurée — résumé, heure estimée, position. La ligne garde le lien avec la conversation du client d’où elle est partie. Autour du tableau : la fonction qui lance l’appel, celle qui vérifie le résultat, le balai pour les appels restés en suspens, l’identification du courier qui rappelle et le webhook d’après appel.

Ce qui en est sorti

On peut répondre, à tout moment et à partir des données, aux questions qu’une répartition reçoit chaque jour : a-t-on appelé, combien de fois, qu’a-t-on répondu, pourquoi n’a-t-on pas appelé. Un appel manqué ne reste plus bloqué dans un état intermédiaire, parce qu’il y a quelqu’un pour le balayer.

Ce que le cas ne dit pas

Le mécanisme est écrit et migré dans la plateforme ; la partie téléphonie dépend d’un hôte SIP, et celle par laquelle passent nos lignes de test ne répond pas à la date de rédaction. Nous ne présentons pas la répartition comme quelque chose que vous pouvez essayer en appelant aujourd’hui un de nos numéros.

Questions

Ce que demande quelqu’un du transport & logistique

L’agent appelle-t-il lui-même le courier ou lui envoie-t-il seulement un message ?

Il appelle. Il existe une fonction serveur qui lance l’appel au courier, lié à la conversation dont il est parti, avec le contexte de la commande transmis comme structure. L’appel a sa propre ligne dans un tableau, avec état, numéro de tentative et résultat — donc on peut répondre à tout moment à la question « a-t-on appelé, et qu’a-t-il dit ».

Que se passe-t-il si le chauffeur ne répond pas ?

On réessaie. Par défaut trois fois, à deux minutes d’intervalle, valeurs écrites dans le tableau et dans la configuration du processus. Si, à la troisième fois, il ne répond toujours pas, l’appel reste dans l’état `no_answer` — un état distinct de `failed`, qui signifie que quelque chose est tombé chez nous. Cette distinction est la raison pour laquelle un tableau vaut la peine, et non un journal.

L’agent peut-il donner au client le numéro du chauffeur ?

Non, et pas parce qu’on lui a dit de ne pas le faire. Les champs de contact du chauffeur sont supprimés récursivement du résultat de l’outil avant que ce résultat n’arrive au modèle. Les numéros de la répartition restent. Ce qui n’arrive pas au modèle ne peut pas être dicté, quelle que soit l’habileté avec laquelle la question est formulée.

Peut-il dire où se trouve le colis en ce moment ?

Il peut dire ce que le courier lui a dit lors du dernier appel, avec l’heure de cet appel, ou ce qu’il lit dans votre système s’il y est connecté. Ce qu’il ne fait pas — et c’est une décision, pas une limite — c’est estimer lui-même. Une estimation inventée par un agent devient une promesse que le chauffeur supporte à la porte.

Puis-je appeler maintenant un numéro de démonstration ?

Pas aujourd’hui. La partie téléphonie passe par un hôte SIP, et l’hôte par lequel passent nos lignes de test ne répond pas à la date de rédaction de cette page. Nous ne mettons pas sur le site un numéro que nous ne pourrions pas prendre devant vous. Le parcours vocal sur le web est une autre histoire : là, on peut le vérifier immédiatement.

Parle-t-il russe avec le client et roumain avec la répartition ?

La configuration de l’agent prend en charge 32 langues, et le roumain est la langue par défaut d’un nouvel agent. La langue se définit par agent, donc l’agent qui parle avec le client et celui qui appelle le courier peuvent être configurés différemment. Ce qu’il faut savoir : pour la synthèse vocale dans des langues autres que l’anglais, le modèle par défaut est le plus rapide, et la variante de meilleure qualité est visiblement plus lente — le compromis se choisit en connaissance de cause.

Que se passe-t-il lorsque le client l’interrompt ?

Il s’arrête. La détection sémantique de la parole a un seuil de 0,5, un tampon de 300 ms et 500 ms de silence, et l’interruption est permise par défaut ; sur l’autre parcours, l’événement d’interruption est transmis à la centrale pour couper la lecture. Si un agent ne peut pas être interrompu, ce n’est pas un problème de ton, mais de configuration — et de réponses trop longues.

Combien de temps les enregistrements des appels avec les chauffeurs sont-ils conservés ?

C’est à vous de le définir, car vous êtes le responsable du traitement. Ce que vous devez savoir sur l’état actuel de la plateforme : la suppression à la demande est implémentée comme fonction, tandis que la suppression automatique à échéance, configurable par espace de travail, ne l’est pas — elle se fait par procédure. Nous préférons que vous l’appreniez de notre part, pas à la suite d’un audit.

Remplace-t-il le dispatcheur ?

Non. Il prend en charge la partie répétitive — la même question, le même appel, la même réponse — et lui laisse les exceptions. Le transfert vers lui reste lié à un code au clavier, et dans le transport les exceptions sont fréquentes : marchandise refusée, adresse erronée, client qui ne répond pas. Là, il faut une personne, et il vaut mieux que ce soit une personne qui n’a pas déjà répondu cent fois à « où est le colis ? ».

Qu'est-ce que vous voudriez voir mieux fonctionner ?

Racontez-nous votre processus. Ensemble, nous décidons ce qui vaut la peine d'être construit, ce que nous pouvons connecter et comment nous vérifions le résultat.

Discutons