Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Un agent Teams peut fournir des mises à jour en temps réel sur son status lorsqu’il prépare une réponse à un utilisateur, puis diffuser le contenu de la réponse dans la conversation au fur et à mesure qu’elle est générée. Grâce à ces techniques, les agents peuvent clairement accuser réception des messages des utilisateurs, communiquer de la vivacité et optimiser la réactivité globale.
Remarque
L’implémentation de l’expérience de diffusion en continu illustrée ici avec le SDK Teams nécessite la version 2.1.0 ou ultérieure du package Microsoft.Teams.Apps . Les agents utilisant d’anciennes versions du SDK Teams peuvent uniquement utiliser l’API de diffusion en continu dans les conversations en tête-à-tête entre un agent et un utilisateur, et les mises à jour informatives et la génération de réponses seront générées dans une expérience héritée.
Remarque
L’implémentation de l’expérience de diffusion en continu illustrée ici avec le SDK Teams nécessite la version 2.0.15 ou ultérieure du package microsoft-teams-apps . Les agents utilisant d’anciennes versions du SDK Teams peuvent uniquement utiliser l’API de diffusion en continu dans les conversations en tête-à-tête entre un agent et un utilisateur, et les mises à jour informatives et la génération de réponses seront générées dans une expérience héritée.
Remarque
L’implémentation de l’expérience de diffusion en continu illustrée ici avec le SDK Teams nécessite la version 2.0.14 ou ultérieure du package @microsoft/teams.apps . Les agents utilisant d’anciennes versions du SDK Teams peuvent uniquement utiliser l’API de diffusion en continu dans les conversations en tête-à-tête entre un agent et un utilisateur, et les mises à jour informatives et la génération de réponses seront générées dans une expérience héritée.
Expérience utilisateur
La diffusion en continu de messages se compose de deux phases : mises à jour facultatives suivies de la diffusion en continu du contenu des messages.
Mises à jour informatives
Les mises à jour informatives sont de courts textes qu’un agent peut éventuellement afficher lors de la préparation de la diffusion d’une réponse à un message utilisateur. Ils apparaissent directement sous le message de conversation auquel l’agent répond, et non dans des bulles de message, et sont accompagnés d’une icône animée. Chaque nouvelle mise à jour envoyée par l’agent remplace la précédente.
Les mises à jour ne créent pas de notifications et ne déclenchent pas le badge de message non lu pour la conversation. Dans les conversations de groupe, les canaux et les conversations de réunion, des mises à jour informatives sont affichées à tous les participants à la conversation.
Diffusion en continu du contenu des messages
La diffusion en continu de contenu de message ajoute des segments de contenu de message dans une bulle de conversation à mesure qu’un agent les émet.
L’émission du premier bloc de contenu crée la bulle et arrête l’affichage des mises à jour informatives. La position de la bulle dans la conversation reste fixe à mesure que le contenu diffusé en continu est ajouté et la bulle s’anime lorsque l’agent signale que la diffusion en continu est terminée.
Les messages diffusés en continu envoyés à l’aide du mode Markdown étendu affichent leur mise en forme progressivement pour offrir une expérience de lecture fluide. Pour plus d’informations, consultez Mettre en forme les messages de l’agent .
Considérations générales des développeurs pour la diffusion en continu
Un agent ne peut maintenir qu’un seul flux ouvert par conversation, mais peut avoir des flux ouverts dans plusieurs conversations simultanément.
Chaque texte de mise à jour informative ne doit pas dépasser 1 ko ou 1 000 caractères.
Une fois qu’un agent commence à émettre du contenu diffusé en continu, les mises à jour informatives supplémentaires qu’il émet ne sont pas affichées.
Le mode Markdown étendu est compatible avec la diffusion en continu du contenu des messages et permet une mise en forme progressive.
Les flux expirent et sont automatiquement fermés 10 minutes après que l’agent a écrit la première mise à jour informative ou le premier bloc de contenu.
Les mises à jour informatives et la diffusion en continu de contenu de message sont destinées à répondre à des messages utilisateur spécifiques dans le contexte du gestionnaire d’activité du message reçu. Ils ne sont pas pris en charge dans les scénarios de messagerie proactive.
Certaines fonctionnalités de messagerie, telles que la pièce jointe, les étiquettes AI, les boutons de commentaires et les étiquettes de confidentialité, ne sont rendues qu’une fois la diffusion terminée par l’agent. Pour plus d’informations, consultez les pièces jointes, les étiquettes de contenu AI et les contrôles de commentaires utilisateur.
Implémenter la diffusion en continu avec le SDK Teams
Le flux est exposé dans le contexte d’activité du message entrant. Utilisez l’objet stream pour envoyer des mises à jour informatives, émettre des blocs de contenu et finaliser la réponse lorsque la génération est terminée. Le Kit de développement logiciel (SDK) gère la limitation pour vous, de sorte que vous pouvez émettre des tronçons au fur et à mesure que votre modèle les produit sans rythmer manuellement chaque requête. Dans TypeScript et Python, le Kit de développement logiciel (SDK) ferme automatiquement le flux à la fin du gestionnaire si vous ne l’avez pas fermé explicitement. En C#, vous devez fermer explicitement le flux avec writer.FinalizeResponseAsync(finalActivity).
Permet TeamsStreamingWriter d’écrire des mises à jour informatives et de diffuser du contenu en continu à partir du contexte du message. Après avoir ajouté tous les blocs de contenu, fermez explicitement le flux en appelant writer.FinalizeResponseAsync(finalActivity) avec l’activité de message final. Le SDK C# ne ferme pas automatiquement le flux lorsque le gestionnaire revient. Lorsque la réponse diffusée utilise une mise en forme plus riche, définissez la propriété de l’activité de TextFormat message final sur extendedmarkdown. Certaines fonctionnalités de message, telles que les étiquettes ou les cartes IA, ne sont rendues qu’après la fermeture du flux.
teams.OnMessage(async (context, cancellationToken) =>
{
TeamsStreamingWriter writer = TeamsStreamingWriter.CreateFromContext(context);
await writer.SendInformativeUpdateAsync("Reviewing the latest project status...", cancellationToken);
await Task.Delay(1000, cancellationToken);
var finalActivity = new Activity
{
Type = ActivityTypes.Message,
TextFormat = "extendedmarkdown",
Text = """
## Project status
- [x] API tests passed
- [x] Deployment checks completed
- [ ] Final sign-off pending
The release is on track for Friday.
"""
};
await writer.AppendResponseAsync(finalActivity.Text, cancellationToken);
await writer.FinalizeResponseAsync(finalActivity);
});
Le contenu émis peut inclure des titres Markdown, des listes de tâches et une emphase pour améliorer la lisibilité pendant la diffusion du message. Si vous incluez des fonctionnalités de message supplémentaires telles qu’une étiquette ou une carte IA, elles s’affichent uniquement après la fermeture du flux.
Utilisez l’objet stream dans le contexte d’activité des messages entrants pour envoyer des mises à jour informatives et émettre des tronçons de contenu.
stream.update Peut être appelé plusieurs fois avec un texte de mise à jour différent et stream.emit écrit un morceau de contenu de message dans la bulle de conversation active. Le Kit de développement logiciel (SDK) gère la limitation pour vous, de sorte que vous pouvez émettre des tronçons au fur et à mesure que votre modèle les produit, sans rythmer manuellement les requêtes. Si vous ne fermez pas le flux explicitement, le SDK le finalise automatiquement lorsque le gestionnaire de messages se ferme.
Permet stream.emit d’écrire un morceau de contenu dans le flux. Les blocs seront affichés dans le message dès qu’ils seront reçus par Teams. Après le premier appel à , les mises à stream.emitjour informatives ne seront plus affichées et stream.update n’auront aucun effet.
app.on('message', async ({ activity, stream }) => {
stream.update("Preparing a project status update...");
await new Promise(resolve => setTimeout(resolve, 1000));
const summary = [
'## Project status',
'',
'- [x] API tests passed',
'- [x] Build completed',
'- [ ] Final sign-off pending',
'',
'The rollout is still on track for Friday.'
].join('\n');
// AI labels and cards render only after the stream is closed.
stream.emit(new MessageActivityInput(summary).withTextFormat('extendedmarkdown'));
});
Le même modèle fonctionne pour les réponses en plusieurs parties qui sont diffusées progressivement, à l’aide de Markdown étendu pour afficher les titres, les listes et l’emphase en ligne à mesure que chaque morceau arrive.
Utilisez l’objet stream dans le contexte d’activité des messages entrants pour envoyer des mises à jour informatives et émettre des tronçons de contenu.
stream.update Peut être appelé plusieurs fois avec un texte de mise à jour différent et stream.emit écrit un morceau de contenu de message dans la bulle de conversation active. Le Kit de développement logiciel (SDK) gère la limitation pour vous, de sorte que vous pouvez émettre des tronçons au fur et à mesure que votre modèle les produit, sans rythmer manuellement les requêtes. Si vous ne fermez pas le flux explicitement, le SDK le finalise automatiquement lorsque le gestionnaire de messages se ferme.
Permet stream.emit d’écrire un morceau de contenu dans le flux. Les blocs seront affichés dans le message dès qu’ils seront reçus par Teams. Après le premier appel à , les mises à stream.emitjour informatives ne seront plus affichées et stream.update n’auront aucun effet.
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
ctx.stream.update("Preparing a status update...")
await asyncio.sleep(1)
status = """## Project status
- [x] API tests passed
- [x] Build completed
- [ ] Final sign-off pending
The rollout is still on track for Friday.
"""
# AI labels and cards render only after the stream is closed.
ctx.stream.emit(MessageActivityInput(text=status).with_text_format("extendedmarkdown"))
Pour une expérience de diffusion en continu plus naturelle, émettez une séquence de blocs de texte au format Markdown et laissez Teams les afficher progressivement au fur et à mesure qu’ils arrivent.
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
ctx.stream.update("Starting the *extended* markdown stream...", "markdown")
await asyncio.sleep(1)
for message in [
"### Release summary\n\n- [x] Build complete\n- [x] Tests passed\n",
"- [ ] Final sign-off pending\n\nThe app is ready to ship once approval is received.\n",
"**Important:** package validation is still running in the background.",
]:
await asyncio.sleep(0.5)
ctx.stream.emit(MessageActivityInput(text=message).with_text_format("extendedmarkdown"))
Implémenter la diffusion en continu via l’API REST
Malgré son nom, le streaming de contenu ne dépend pas du streaming HTTP ou de technologies similaires. Au niveau de l’API HTTP, il est implémenté en tant que séquence de requêtes. Chaque demande définit un nouveau texte de mise à jour informatif à afficher ou met à jour le contenu du message diffusé en continu.
Ouvrir un flux
Pour commencer la diffusion en continu, envoyez une charge utile d’activité au point de /conversations/<conversationId>/activities terminaison en incluant les valeurs de charge utile requises suivantes (en plus des autres valeurs requises) :
-
type:typing -
replyToId: ID du message utilisateur auquel vous avez répondu. Facultatif pour les conversations en tête-à-tête, mais la diffusion en continu et les mises à jour informatives seront rendues dans une expérience héritée. -
text: premier texte de mise à jour informatif. Si vous ignorez la phase de mise à jour informative, le premier morceau de contenu. -
entities[0].type:streamInfo -
entities[0].streamType:informative. Si vous ignorez la phase de mise à jour informative et envoyez le premier bloc de contenu, définissez surstreaming. -
entities[0].streamSequence: 1
POST /conversations/<conversationId>/activities HTTP/1.1
{
"type": "typing",
"serviceurl": "<https://smba.trafficmanager.net/amer/>",
"channelId": "msteams",
"from": {
"id": "<botId>",
"name": "<BotName>"
},
"conversation": {
"conversationType": "personal",
"id": "<conversationId>"
},
"recipient": {
"id": "<recipientId>",
"name": "<recipientName>",
"aadObjectId": "<recipient aad objecID>"
},
"locale": "en-US",
"replyToId": "<userMessageId>",
"text": "Searching through documents...",
"entities":[
{
"type": "streaminfo",
"streamType": "informative",
"streamSequence": 1
}
]
}
La 201 Created réponse inclura une charge utile JSON avec une id propriété dont la entities.streamId valeur doit être utilisée comme valeur dans toutes les requêtes ultérieures.
Envoyer des mises à jour informatives et des mises à jour du contenu des messages
Une fois le flux ouvert, envoyez des demandes supplémentaires à l’aide de l’ID du flux pour afficher des mises à jour informatives et diffuser le contenu des messages. Incluez la charge utile suivante :
-
type:typing -
replyToId: ID du message utilisateur auquel vous avez répondu. Facultatif pour les conversations en tête-à-tête, mais la diffusion en continu et les mises à jour informatives seront rendues dans une expérience héritée. -
text: nouveau texte de mise à jour informative à afficher, ou intégralité du contenu du message généré à ce stade -
entities[0].type:streamInfo -
entities[0].streamType:informativesi vous définissez un nouveau texte de mise à jour informatif,streamingsi vous mettez à jour le contenu du message -
entities[0].streamSequence: <Incrémenté à chaque demande envoyée>
Une fois que vous commencez à envoyer du contenu de message, n’envoyez plus de mises à jour, car elles ne seront pas affichées.
Lors de la diffusion en continu de contenu d’un message, chaque demande représente une mise à jour complète du message, et pas seulement un nouveau contenu à ajouter. Accumulez le contenu localement au fur et à mesure qu’il text est généré et envoyez la valeur totale accumulée comme charge utile avec chaque demande. Les demandes qui tentent de modifier le contenu fourni dans la demande précédente entraînent une 403 ContentStreamNotAllowed erreur avec le message Request streamed content should contain the previously streamed content.
Chaque demande de diffusion en continu peut inclure des valeurs supplémentaires entities représentant des fonctionnalités de message, mais la plupart des fonctionnalités ne seront pas affichées dans le client Teams avant la fermeture du flux.
Le service est limité à 1 par seconde, par flux. Mettre en mémoire tampon le contenu généré pour limiter les requêtes si nécessaire.
POST /conversations/<conversationId>/activities HTTP/1.1
{
"type": "typing",
"serviceurl": "https://smba.trafficmanager.net/amer/",
"channelId": "msteams",
"from": {
"id": "<botId>",
"name": "<BotName>"
},
"conversation": {
"conversationType": "personal",
"id" : "<conversationId>"
},
"recipient": {
"id": "<recipientId>",
"name": "<recipientName>",
"aadObjectId": "<recipient aad objecID>"
},
"locale": "en -US",
"replyToId": "<userMessageId>",
"text": "Searching through emails...",
"entities":[
{
"type": "streaminfo",
"streamId": "a-0000l",
"streamType": "informative",
"streamSequence": 2
}
],
}
Fermer le flux
Une fois la génération du message terminée, fermez le flux en envoyant une activité de message avec les propriétés de charge utile suivantes :
-
type:message -
replyToId: ID du message utilisateur auquel vous avez répondu. Facultatif pour les conversations en tête-à-tête, mais la diffusion en continu et les mises à jour informatives seront rendues dans une expérience héritée. -
text: contenu complet du message -
entities[0].type:streamInfo -
entities[0].streamIdid: valeur obtenue à partir de la réponse initiale -
entities[0.streamType:final
Ne pas inclure entities[0].streamSequence dans la charge utile de la requête finale.
POST /conversations/<conversationId>/activities HTTP/1.1
{
"type": "message",
"serviceurl" : "https://smba.trafficmanager.net/amer/ ",
"channelId": "msteams",
"from": {
"id": "<botId>",
"name": "<BotName>"
},
"conversation": {
"conversationType": "personal",
"id" : "<conversationId>"
},
"recipient": {
"id" : "recipientId>",
"name": "<recipientName>",
"aadObjectId": "<recipient aad objecID>"
},
"locale": "en-US",
"replyToId": "<userMessageId>", // ID of the user's message that the agent is responding to. Required in conversations other than one-on-one chats.
"text": "A brown fox jumped over the fence.", // (required) first streaming content.
"entities":[
{
"type": "streaminfo",
"streamId": "a-0000l", // // (required) must be present for any subsequent request after the first chunk.
"streamType": "final", // (required) final is only allowed for the last message of the streaming.
}
],
}
Codes de réponse
Voici les codes de réussite et d’erreur :
Code de réussite
| Code d’status http | Valeur renvoyée | Description |
|---|---|---|
201 |
streamId, il est identique à activityId{"id":"1728640934763"} |
L’agent renvoie cette valeur après avoir envoyé la demande initiale de diffusion en continu.
Pour toutes les demandes de diffusion en continu ultérieures, le streamId est requis. |
202 |
{} |
Code de réussite pour toutes les demandes de diffusion en continu ultérieures. |
Codes d’erreur
| Code d’status http | Code d’erreur | Message d’erreur | Description |
|---|---|---|---|
202 |
ContentStreamSequenceOrderPreConditionFailed |
PreCondition failed exception when processing streaming activity. |
Peu de demandes de diffusion en continu peuvent arriver dans le désordre et être abandonnées. La demande de diffusion en continu la plus récente, déterminée par streamSequence, est utilisée lorsque les demandes sont reçues de manière désordonnée. Veillez à envoyer chaque demande de manière séquentielle. |
400 |
BadRequest |
Selon le scénario, vous pouvez rencontrer différents messages d’erreur, tels que Start streaming activities should include text |
La charge utile entrante n’adhère pas aux valeurs nécessaires ou ne contient pas les valeurs nécessaires. |
403 |
ContentStreamNotAllowed |
Content stream is not allowed |
La fonctionnalité d’API de diffusion en continu n’est pas autorisée pour l’utilisateur ou l’agent. |
403 |
ContentStreamNotAllowed |
Content stream is not allowed on an already completed streamed message |
Un agent ne peut pas diffuser en continu un message déjà diffusé et terminé. |
403 |
ContentStreamNotAllowed |
Content stream finished due to exceeded streaming time. |
L’agent n’a pas terminé le processus de diffusion en continu dans le délai imparti de 10 minutes. |
403 |
ContentStreamNotAllowed |
Message size too large |
L’agent a envoyé un message qui dépasse la restriction de taille de message actuelle. |
403 |
ContentStreamNotAllowed |
Request streamed content should contain the previously streamed content |
Le contenu entrant du message de flux ne contient pas ce qui a déjà été diffusé. |
429 |
N/A | API calls quota exceeded |
Le nombre de messages transmis par l’agent a dépassé le quota. |
Exemple de code
| Exemple de nom | Description | Node.js | C# | Python |
|---|---|---|---|---|
| Exemple de streaming du SDK Teams | Cet exemple montre comment diffuser en continu les réponses des agents et utiliser le formatage Markdown étendu dans les derniers SDK. | View | View | View |
| Streaming + exemple Markdown étendu | Cet exemple illustre le rendu progressif d’une sortie au format Markdown pendant que le contenu est toujours en streaming. | View | N/A | View |