注:
- ストリーミング エージェント メッセージは、1 対 1 のチャットでのみサポートされます。
- Teams では、チャットごとに一度に 1 つの同時ストリーミング応答のみがサポートされます。
- ストリーミングは、Web、デスクトップ、モバイルで一般に利用できます。
エージェント メッセージをストリーミングして、完全な応答を生成しながら、エージェントの応答を小さな更新としてユーザーに配信し、ユーザー エクスペリエンスを向上させることができます。 多くの場合、エージェントはユーザー インターフェイスを更新せずに応答を生成するのに長い時間がかかり、エクスペリエンスの魅力が低下します。
ユーザーがエージェントがリクエストをリアルタイムで処理しているのを観察すると、満足度と信頼が高まります。 この応答性と透明性により、ユーザーエンゲージメントが向上し、エージェントとの会話の放棄が減少します。
Stream メッセージのユーザー エクスペリエンス
ストリーミング エージェント メッセージには、次の 2 種類の更新プログラムがあります。
有益な更新: 有益な更新は、チャットの下部に青い進行状況バーとして表示されます。 応答の生成中にエージェントの進行中のアクションについてユーザーに通知します。
有益なメッセージは、1 KB または 1,000 文字を超えてはなりません。
応答ストリーミング: 応答ストリーミングは入力インジケーターとして表示されます。 完全な応答が生成されている間、ユーザーに対するエージェントの応答が小さな更新として表示されます。
停止ボタン:
ボタンを使用すると、ユーザーは応答を早期に停止することでストリーミング応答を制御できます。 ストリーミング中は既定で使用可能で、ユーザーはプロンプトを調整したり、新しいプロンプトを送信したりすることができます。 [ストリーミング停止] ボタンのしくみを理解すると、より効果的でユーザーフレンドリーな会話インターフェイスを設計するのに役立ちます。ストリーミングコンテンツ: ストリーミング中、エージェントメッセージには以前にストリーミングされたコンテンツが含まれている必要があります。
例: これは、許容可能なストリーミング応答の例です。
A 茶色
茶色いキツネ
茶色のキツネがフェンスを飛び越える例以外: これは、エラーを返すストリーミング応答の例です。
A 茶色
こんにちはエラーの詳細については、 エラー コードを参照してください。
Teams SDK を使用してストリーミングを実装する
メッセージ ストリームを開始する前に、 Stream.Update を使用して有益な更新を記述します。
Stream.Update は、異なる更新テキストを使用して複数回呼び出すことができます。
コンテンツ チャンクをストリームに書き込むには、 Stream.Emit を使用します。 チャンクは、Teams が受信するとすぐにメッセージにレンダリングされます。
Stream.Emit への最初の呼び出しの後、有益な更新プログラムは表示されなくなり、Stream.Updateは効果がなくなります。
app.OnMessage(async (context, cancellationToken) =>
{
context.Stream.Update("Testing");
await Task.Delay(1000);
context.Stream.Emit("hello");
context.Stream.Emit(", ");
context.Stream.Emit("world!");
});
メッセージ ストリームを開始する前に、 stream.update を使用して有益な更新を記述します。
stream.update は、異なる更新テキストを使用して複数回呼び出すことができます。
コンテンツ チャンクをストリームに書き込むには、 stream.emit を使用します。 チャンクは、Teams が受信するとすぐにメッセージにレンダリングされます。
stream.emit への最初の呼び出しの後、有益な更新プログラムは表示されなくなり、stream.updateは効果がなくなります。
app.on('message', async ({ activity, stream }) => {
stream.update("Thinking...");
await new Promise(resolve => setTimeout(resolve, 1000))
stream.emit('hello');
stream.emit(', ');
stream.emit('world!');
// result message: "hello, world!"
});
メッセージ ストリームを開始する前に、 stream.update を使用して有益な更新を記述します。
stream.update は、異なる更新テキストを使用して複数回呼び出すことができます。
コンテンツ チャンクをストリームに書き込むには、 stream.emit を使用します。 チャンクは、Teams が受信するとすぐにメッセージにレンダリングされます。
stream.emit への最初の呼び出しの後、有益な更新プログラムは表示されなくなり、stream.updateは効果がなくなります。
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
ctx.stream.update("Stream starting...")
await asyncio.sleep(1)
# Stream messages with delays using ctx.stream.emit
for message in STREAM_MESSAGES:
# Add some randomness to timing
await asyncio.sleep(random())
ctx.stream.emit(message)
サポートされている機能や構文など、拡張 Markdown を使用したストリーミング メッセージの書式設定に関するガイダンスについては、「 エージェント メッセージの書式設定」を参照してください。
REST API を介した Stream メッセージ
エージェント メッセージは、REST API を介してストリーミングできます。 ストリーミング メッセージでは、リッチ テキストと引用がサポートされます。 添付ファイル、AI ラベル、フィードバック ボタン、秘密度ラベルは、最終的なストリーミング メッセージでのみ使用できます。 詳細については、AI によって生成されたコンテンツを含む添付ファイルとエージェント メッセージを参照してください。
エージェントが REST API を介してストリーミングを呼び出す場合は、最初の API 呼び出しから正常な応答を受け取った後にのみ、次のストリーミング API を呼び出すようにしてください。 エージェントが SDK を使用している場合は、送信アクティビティ メソッドから null 応答オブジェクトを受信することを確認して、前の呼び出しが正常に送信されたことを確認します。
エージェントがストリーミング API を呼び出す速度が速すぎると、問題が発生し、ストリーミング エクスペリエンスが中断される可能性があります。 エージェントは、一度に 1 つのメッセージをストリーミングして、一貫したペースでストリーミング API を呼び出すことをお勧めします。 それ以外の場合、要求は調整される可能性があります。 スムーズなストリーミング プロセスを確保するために、モデルからのトークンを 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: An agent 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: An agent 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: An agent 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: An agent 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: An agent 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 状態コード 403 エラー コード ContentStreamNotAllowedエラー メッセージ コンテンツ ストリームはユーザーによって取り消されました。 説明 ストリーミングはユーザーによって停止されました。
応答コード
成功コードとエラー コードを次に示します。
成功コード
| 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 |
エージェントが、現在の メッセージ サイズ 制限を超えるメッセージを送信しました。 |
403 |
ContentStreamNotAllowed |
Content stream was canceled by user |
ストリーミングはユーザーによって停止されました。 |
403 |
ContentStreamNotAllowed |
Request streamed content should contain the previously streamed content |
ストリーム メッセージの受信コンテンツに、既にストリーミングされた内容は含まれません。 |
429 |
該当なし | API calls quota exceeded |
エージェントによってストリーミングされたメッセージの数がクォータを超えました。 |
コード サンプル
| サンプルの名前 | 説明 | Node.js | C# | Python |
|---|---|---|---|---|
| Teams ストリーミング エージェントのサンプル | このサンプル アプリは、個人用に Azure Open AI と Bot Framework v4 を使用する Teams のストリーミング シナリオに使用できます。 | 該当なし | 表示 | 該当なし |
| 会話型ストリーミング エージェント | これは、Teams SDK を使用した会話型ストリーミング エージェントです。 | 表示 | 表示 | 表示 |
関連項目
Platform Docs