ボット メッセージをStreamする
注:
- ストリーミング ボット メッセージは、1 対 1 のチャットと パブリック開発者プレビューでのみ使用できます。
- ストリーミング ボット メッセージは、関数呼び出しと OpenAI
o1
モデルでは使用できません。 - ストリーミング ボット メッセージは、Web、デスクトップ、モバイル (Android) でサポートされています。 iOS ではサポートされていません。
ボット メッセージをストリーミングして、ユーザー エクスペリエンスを向上させるために完全な応答が生成されている間に、ボットの応答を小さな更新としてユーザーに配信できます。 多くの場合、ボットは、ユーザー インターフェイスを更新せずに応答を生成するのに長い時間がかかるため、関与の少ないエクスペリエンスが得られます。
ユーザーが要求を処理しているボットをリアルタイムで観察すると、満足度と信頼が高まる可能性があります。 この認識された応答性と透明性により、ユーザーエンゲージメントが向上し、ボットとの会話の破棄が減少します。
ストリーミング ボット メッセージには、次の 2 種類の更新プログラムがあります。
情報更新: 有益な更新は、チャットの下部に青い進行状況バーとして表示されます。 応答の生成中にボットの進行中のアクションについてユーザーに通知します。
応答ストリーミング: 応答ストリーミングは、入力インジケーターとして表示されます。 完全な応答が生成されている間に、ボットの応答が小さな更新プログラムとしてユーザーに表示されます。
ストリーミング ボット メッセージは、次のいずれかの方法でアプリに実装できます。
Teams AI ライブラリを使用してメッセージをStreamする
Teams AI ライブラリには、AI を利用したボットのメッセージをストリーミングする機能が用意されています。 ストリーミング ボット メッセージは応答時間の遅れを緩和するのに役立ち、L 言語モデル (LLM) では完全な応答が生成されます。 応答時間が遅くなる主な要因には、Retrieval-Augmented 生成 (RAG) や関数呼び出しなどの複数の前処理手順と、LLM が完全な応答を生成するために必要な時間が含まれます。
注:
ストリーミング ボット メッセージは、関数呼び出しでは使用できません。
ストリーミングを通じて、AI を利用したボットは、ユーザーにとって魅力的で応答性の高いエクスペリエンスを提供できます。 AI 搭載アプリのストリーミング メッセージに対して次の機能を構成します。
AI を利用したボットのストリーミングを有効にする:
ボット メッセージは AI SDK を介してストリーミングできます。 AI を利用したボットは、モデルが応答を生成すると、チャンクをユーザーに送信します。 ストリーミング メッセージはテキストをサポートします。 ただし、添付ファイル、AI ラベル、フィードバック ループ、秘密度ラベルは、最終的なストリーミング メッセージでのみ使用できます。
情報メッセージを設定します。
AI を利用するボットの有益なメッセージを定義できます。 このメッセージは、ボットが更新プログラムを送信するたびにユーザーに表示されます。 アプリで設定できる情報メッセージの例を次に示します。
- ドキュメントをスキャンする
- コンテンツの概要
- 関連する作業項目の検索
次の例は、AI 搭載ボットの情報の更新を示しています。
最終的なストリーミング メッセージの形式を設定します。
AI SDK を使用すると、ストリーミング中にテキスト メッセージと単純なマークダウンを書式設定できます。 ただし、アダプティブ カード、画像、またはリッチ HTML の場合、最終的なメッセージが完了したら書式設定を適用できます。 ボットは、最終的なストリーミング チャンク内でのみ添付ファイルを送信できます。
次の例は、AI 搭載ボットのストリーミング応答を示しています。
次の例は、AI を利用したボットでの最終的なストリーミング応答を示しています。
最後のメッセージに対して AI を利用した機能を有効にします。
ボットから送信された最終的なメッセージに対して、次の AI を利用した機能を有効にすることができます。
- 引用: Teams AI ライブラリには、ボットの応答に引用が自動的に含まれます。 これは、ボットが応答の生成に使用したソースの参照を提供します。 これにより、ユーザーはテキスト内引用と参照を通じてソースを参照できます。
- 秘密度ラベル: ユーザーがメッセージの機密性を理解するのに役立つ秘密度ラベルを使用します。
- フィードバック ループ: これにより、ユーザーはボット メッセージに対して肯定的または否定的なフィードバックを提供できます。
- AI によって生成される: Teams AI ライブラリには、ボットの応答に [生成済み AI] ラベルが自動的に含まれます。 このラベルは、ユーザーが AI を使用してメッセージが生成されたことを識別するのに役立ちます。
AI を利用したボット メッセージの書式設定の詳細については、「 AI によって生成されたコンテンツを含むボット メッセージ」を参照してください。
ストリーミング ボット メッセージを構成する
ストリーミング ボット メッセージを構成するには、次の手順に従います。
AI を利用したボットのストリーミングを有効にする:
a.
config.json
ファイルおよびボット アプリの次のメイン アプリケーション クラスのいずれかで、DefaultAugmentation
クラスを使用します。- C# ボット アプリの場合:
Program.cs
を更新します。 - JavaScript アプリの場合:
index.ts
を更新します。 - Python アプリの場合:
bot.py
を更新します。
b.
OpenAIModel
宣言でstream
を true に設定します。- C# ボット アプリの場合:
情報メッセージの設定:
StartStreamingMessage
構成を使用して、ActionPlanner
宣言で情報メッセージを指定します。最終的なストリーミング メッセージの形式を設定します。
- アプリ宣言内の
AIOptions
オブジェクトでフィードバック ループトグルを設定し、ハンドラーを指定します。- Python を使用して構築されたボット アプリの場合は、
AIOptions
オブジェクトに加えて、ActionPlannerOptions
オブジェクトのフィードバック ループトグルを設定します。
- Python を使用して構築されたボット アプリの場合は、
-
ActionPlanner
宣言内のEndStreamHandler
を使用して、最終的なチャンクに添付ファイルを設定します。
- アプリ宣言内の
次のコード スニペットは、ストリーミング ボット メッセージの例を示しています。
// Create OpenAI Model
builder.Services.AddSingleton<OpenAIModel > (sp => new(
new OpenAIModelOptions(config.OpenAI.ApiKey, "gpt-4o")
{
LogRequests = true,
Stream = true, // Set stream toggle
},
sp.GetService<ILoggerFactory>()
));
ResponseReceivedHandler endStreamHandler = new((object sender, ResponseReceivedEventArgs args) =>
{
StreamingResponse? streamer = args.Streamer;
if (streamer == null)
{
return;
}
AdaptiveCard adaptiveCard = new("1.6")
{
Body = [new AdaptiveTextBlock(streamer.Message) { Wrap = true }]
};
var adaptiveCardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = adaptiveCard,
};
streamer.Attachments = [adaptiveCardAttachment]; // Set attachments
});
// Create ActionPlanner
ActionPlanner<TurnState> planner = new(
options: new(
model: sp.GetService<OpenAIModel>()!,
prompts: prompts,
defaultPrompt: async (context, state, planner) =>
{
PromptTemplate template = prompts.GetPrompt("Chat");
return await Task.FromResult(template);
}
)
{
LogRepairs = true,
StartStreamingMessage = "Loading stream results...", // Set informative message
EndStreamHandler = endStreamHandler // Set final chunk handler
},
loggerFactory: loggerFactory
);
カスタム Plannerとモデル開発
StreamingResponse
クラスは、クライアントへの応答をストリーミングするためのヘルパー クラスです。 これにより、1 回の応答で一連の更新プログラムを送信できるため、対話がよりスムーズになります。 独自のカスタム モデルを使用している場合は、このクラスを簡単に使用して応答をシームレスにストリーミングできます。 ユーザーのエンゲージメントを維持するための優れた方法です。
ストリーミング ボット メッセージでは、次のシーケンスを使用する必要があります。
queueInformativeUpdate()
queueTextChunk()
endStream()
モデルが endStream()
を呼び出した後、ストリームは終了し、ボットはそれ以上の更新プログラムを送信できません。
アプリ エクスペリエンスをカスタマイズするために使用できるその他の方法の一覧を次に示します。
setAttachments
setSensitivityLabel
setFeedbackLoop
setGeneratedByAILabel
Azure OpenAI または OpenAI の制限事項
- ボットがストリーミング API を呼び出す速度が速すぎると、問題が発生し、ストリーミング エクスペリエンスが中断される可能性があります。 これを回避するには、一度に 1 つのメッセージを一貫したペースでストリーミングします。 そうしないと、要求が調整される可能性があります。 スムーズなストリーミングを確保するために、モデルからトークンを 1.5 ~ 2 秒間バッファーします。
- 引用、秘密度ラベル、フィードバック ループ、 生成された AI ラベルなどの AI を利用した機能は、最終的なチャンクでのみサポートされます。 引用は、キューに入っている各テキスト チャンクごとに設定されます。
- リッチ テキストのみをストリーミングできます。
- 設定できる情報メッセージは 1 つだけです。 ボットは、更新ごとにこのメッセージを再利用します。 たとえば、次のような情報が含まれます。
- ドキュメントをスキャンする
- コンテンツの概要
- 関連する作業項目の検索
- このモデルでは、LLM から返される各メッセージの先頭にのみ情報メッセージがレンダリングされます。
- 添付ファイルは、最終的なチャンク内でのみ送信できます。
- ストリーミングは、AI SDK の関数呼び出しと AOAI または OAI の
o1
モデルでは使用できません。 - AI SDK に
streamSequence
を使用する要件を次に示します。- シーケンスは番号 '1' で始まる必要があります。
- 後続の数値 (final を除く) は、単調な増加整数である必要があります (たとえば、1->2->3)。
- 最後のメッセージでは、
streamSequence
を設定しないでください。
REST API を使用してメッセージをStreamする
ボット メッセージは REST API を介してストリーミングできます。 ストリーミング メッセージは、リッチ テキストと引用をサポートします。 添付ファイル、AI ラベル、フィードバック ボタン、秘密度ラベルは、最終的なストリーミング メッセージでのみ使用できます。 詳細については、「AI によって生成されたコンテンツを含む添付ファイルとボット メッセージ」を参照してください。
ボットが REST API を介してストリーミングを呼び出すときは、最初の API 呼び出しから正常な応答を受け取った後にのみ、次のストリーミング API を呼び出すようにします。 ボットが SDK を使用している場合は、送信アクティビティ メソッドから null 応答オブジェクトを受け取って、前の呼び出しが正常に送信されたことを確認します。
ボットがストリーミング API を呼び出す速度が速すぎると、問題が発生し、ストリーミング エクスペリエンスが中断される可能性があります。 ボットは、ストリーミング API を一貫したペースで呼び出すために、一度に 1 つのメッセージをストリーミングすることをお勧めします。 そうでない場合は、要求が調整される可能性があります。 スムーズなストリーミング プロセスを確保するために、モデルからトークンを 1.5 ~ 2 秒間バッファーします。 ボットは、ストリーミング API を一貫したペースで呼び出すために、一度に 1 つのメッセージをストリーミングすることをお勧めします。 そうでない場合は、要求が調整される可能性があります。 スムーズなストリーミング プロセスを確保するために、モデルからトークンを 1.5 ~ 2 秒間バッファーします。
ストリーミング ボット メッセージのプロパティを次に示します。
プロパティ | 必須 | 説明 |
---|---|---|
type |
✔️ | サポートされる値は、 typing または message です。
• typing : メッセージをストリーミングするときに使用します。
• message : 最終的なストリーミング メッセージに使用します。 |
text |
✔️ | ストリーミングされるメッセージの内容。 |
entities.type |
✔️ | にする必要があります。 |
entities.streamId |
✔️ |
streamId は、最初のストリーミング要求から ストリーミングを開始します。 |
entities.streamType |
ストリーミング更新プログラムの種類。 サポートされる値は、 informative 、 streaming 、または final のいずれかです。 既定値は streaming です。
final は、最終的なメッセージでのみ使用されます。 |
|
entities.streamSequence |
✔️ | 各要求の増分整数。 |
注:
REST API に streamSequence
を使用するための要件を次に示します。
- 最初の 1 つは数値 '1' である必要があります。
- 後続の数値 (final を除く) は、単調な増加整数である必要があります (たとえば、1->2->3)。
- 最後のメッセージでは、
streamSequence
を設定しないでください。
ボットでストリーミングを有効にするには、次の手順に従います。
ストリーミングを開始する
ボットは、最初の通信として有益なメッセージまたはストリーミング メッセージを送信できます。 応答には、後続の呼び出しを実行するために重要な streamId
が含まれています。
ボットは、ドキュメントのスキャン、コンテンツの要約、関連する作業項目の検出など、ユーザーの要求の処理中に複数の情報更新を送信できます。 ボットがユーザーに最終的な応答を生成する前に、これらの更新プログラムを送信できます。
//Ex: A bot sends the first request with content & the content is informative loading message.
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",
"text": "Searching through documents...", //(required) first informative loading message.
"entities":[
{
"type": "streaminfo",
"streamType": "informative", // informative or streaming; default= streaming.
"streamSequence": 1 // (required) incremental integer; must be present for start and continue streaming request, but must not be set for final streaming request.
}
],
}
201 created { "id": "a-0000l" } // return stream id
次の図は、ストリーミング開始の例です。
ストリーミングを続行する
最初の要求から受信した streamId
を使用して、有益なメッセージまたはストリーミング メッセージを送信します。
情報更新から始めて、最終的な応答の準備ができたら、後で応答ストリーミングに切り替えることができます。
有益な更新プログラムから始める
ボットが応答を生成すると、 ドキュメントのスキャン、 コンテンツの概要、 関連する作業項目が見つかったなどの情報更新がユーザーに送信されます。 ボットが前の呼び出しから正常な応答を受け取った後にのみ、後続の呼び出しを行う必要があります。
// Ex: A bot sends the second request with content & the content is informative loading message.
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",
"text ": "Searching through emails...", // (required) second informative loading message.
"entities":[
{
"type": "streaminfo",
"streamId": "a-0000l", // // (required) must be present for any subsequent request after the first chunk.
"streamType": "informative", // informative or streaming; default= streaming.
"streamSequence": 2 // (required) incremental integer; must be present for start and continue streaming request, but must not be set for final streaming request.
}
],
}
202 0K { }
次の図は、有益な更新プログラムを提供するボットの例です。
応答ストリーミングに切り替える
ボットがユーザーの最終的なメッセージを生成する準備ができたら、情報更新の提供から応答ストリーミングへの切り替えを行います。 応答ストリーミング更新ごとに、メッセージの内容は最終メッセージの最新バージョンである必要があります。 つまり、ボットには、大きな言語モデル (LLM) によって生成された新しいトークンを組み込む必要があります。 これらのトークンを以前のメッセージ バージョンに追加し、ユーザーに送信します。
ボットがストリーミング要求をディスパッチする場合は、ボットが 1 秒あたり 1 回の要求の最小レートで要求を送信することを確認します。
// Ex: A bot sends the third request with content & the content is actual streaming content.
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" ,
"text ": "A brown fox", // (required) first streaming content.
"entities":[
{
"type": "streaminfo",
"streamId": "a-0000l", // // (required) must be present for any subsequent request after the first chunk.
"streamType": "streaming", // informative or streaming; default= streaming.
"streamSequence": 3 // (required) incremental integer; must be present for start and continue streaming request, but must not be set for final streaming request.
}
],
}
202 0K{ }
// Ex: A bot sends the fourth request with content & the content is actual streaming content.
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" ,
"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": "streaming", // informative or streaming; default= streaming.
"streamSequence": 4 // (required) incremental integer; must be present for start and continue streaming request, but must not be set for final streaming request.
}
],
}
202 0K{ }
次の図は、チャンクで更新を提供するボットの例です。
最終的なストリーミング
ボットがメッセージの生成を完了したら、最後のメッセージと共にエンド ストリーミングシグナルを送信します。 最後のメッセージでは、アクティビティの type
が message
されます。 ここでは、ボットは、通常のメッセージ アクティビティで許可されるすべてのフィールドを設定しますが、 final
は streamType
に許可される唯一の値です。
// Ex: A bot sends the second request with content && the content is informative loading message.
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",
"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.
}
],
}
202 0K{ }
次の図は、ボットの最終的な応答の例です。
応答コード
成功コードとエラー コードを次に示します。
成功コード
Http 状態コード | 戻り値 | 説明 |
---|---|---|
201 |
streamId は、次のような activityId と同じです。 {"id":"1728640934763"} |
ボットは、最初のストリーミング要求を送信した後、この値を返します。
後続のストリーミング要求の場合は、 streamId が必要です。 |
202 |
{} |
後続のストリーミング要求の成功コード。 |
エラー コード
Http 状態コード | エラー コード | エラー メッセージ | 説明 |
---|---|---|---|
202 |
ContentStreamSequenceOrderPreConditionFailed |
PreCondition failed exception when processing streaming activity. |
一部のストリーミング要求が順番に到着し、ドロップされる可能性があります。
streamSequence によって決定される最新のストリーミング要求は、要求が無秩序な方法で受信されるときに使用されます。 各要求をシーケンシャルな方法で送信することを確認します。 |
400 |
BadRequest |
シナリオによっては、次のようなさまざまなエラー メッセージが表示される場合があります。 Start streaming activities should include text |
受信ペイロードは、必要な値に準拠しないか、含まれません。 |
403 |
ContentStreamNotAllowed |
Content stream is not allowed |
ストリーミング API 機能は、ユーザーまたはボットに対して許可されていません。 |
403 |
ContentStreamNotAllowed |
Content stream is not allowed on an already completed streamed message |
ボットは、既にストリーミングおよび完了したメッセージで継続的にストリーミングすることはできません。 |
403 |
ContentStreamNotAllowed |
Content stream finished due to exceeded streaming time. |
ボットは、2 分間の厳密な制限時間内にストリーミング プロセスを完了できませんでした。 |
403 |
ContentStreamNotAllowed |
Message size too large |
ボットは、現在のメッセージ サイズ制限を超える メッセージ を送信しました。 |
429 |
該当なし | API calls quota exceeded |
ボットによってストリーミングされたメッセージの数がクォータを超えています。 |
コード サンプル
サンプルの名前 | 説明 | Node.js | C# | Python |
---|---|---|---|---|
Teams ストリーミング ボットのサンプル | このコード サンプルでは、LLM に接続されたボットを構築し、Teams を介してメッセージを送信する方法を示します。 | 該当なし | 表示 | 該当なし |
会話型ストリーミング ボット | これは、Teams AI ライブラリを使用した会話型ストリーミング ボットです。 | 表示 | 表示 | 表示 |
関連項目
Platform Docs