Stream机器人消息

注意

  • 流式处理机器人消息仅适用于一对一聊天和公共 开发人员预览版
  • 流式处理机器人消息不适用于函数调用和 OpenAI o1 模型。
  • Android) 支持在 Web、桌面和移动 (流式处理机器人消息。 iOS 不支持它。

可以流式传输机器人消息,以将机器人的响应作为小更新传递给用户,同时生成完整的响应以增强用户体验。 通常,机器人需要很长时间来生成响应而不更新用户界面,从而导致不太吸引人的体验。

当用户观察机器人实时处理其请求时,它可以提高他们的满意度和信任度。 这种感知到的响应能力和透明度可增强用户参与度,并减少与机器人的对话放弃。

流式处理机器人消息有两种类型的更新:

  • 信息性更新:信息性更新显示为聊天底部的蓝色进度栏。 它会在生成响应时通知用户机器人正在进行的操作。

    屏幕截图显示了流式传输的机器人信息更新。

  • 响应流式处理:响应流式处理显示为键入指示器。 在生成完整响应时,它会向用户显示机器人的响应作为小更新。

    屏幕截图显示了机器人响应流式处理。

可以通过以下方法之一在应用中实现流式处理机器人消息:

通过 Teams AI 库Stream消息

Teams AI 库为 AI 支持的机器人提供流式传输消息的功能。 流式处理机器人消息有助于缓解响应时间延迟,而大型语言模型 (LLM) 生成完整的响应。 导致响应时间缓慢的主要因素包括多个预处理步骤,例如 Retrieval-Augmented 生成 (RAG) 或函数调用,以及 LLM 生成完整响应所需的时间。

注意

流式处理机器人消息不适用于函数调用。

通过流式处理,AI 支持的机器人可以提供吸引用户且响应迅速的体验。 为 AI 驱动的应用配置以式处理消息的功能:

  1. 为 AI 支持的机器人启用流式处理

    机器人消息可以通过 AI SDK 进行流式传输。 AI 支持的机器人在模型生成响应时向用户发送区块。 流式处理消息支持文本。 但是,附件、AI 标签、反馈循环和敏感度标签仅适用于最终流式处理消息。

  2. 设置信息性消息

    可以为 AI 支持的机器人定义信息性消息。 每当机器人发送更新时,都会向用户显示此消息。 下面是可在应用中设置的信息性消息的一些示例:

    • 扫描文档
    • 汇总内容
    • 查找相关工作项

    以下示例显示了 AI 支持的机器人中的信息更新:

    图像显示 AI 支持的机器人中流式传输的信息更新。

  3. 设置最终流式处理消息的格式

    使用 AI SDK,可以在进行流式传输时设置短信和简单 markdown 的格式。 但是,对于自适应卡片、图像或丰富的 HTML,可以在最终消息完成后应用格式设置。 机器人只能在最终流式处理区块中发送附件。

    以下示例显示了 AI 支持的机器人中的流式处理响应:

    图像显示 AI 支持的机器人中的流式处理响应。

    以下示例显示了 AI 支持的机器人中最终的流式处理响应:

    图像显示 AI 驱动的机器人中最终流式处理响应。

  4. 为最终消息启用 AI 支持的功能

    可以为机器人发送的最终消息启用以下 AI 支持的功能:

    • 引文:Teams AI 库自动在机器人的响应中包含引文。 它提供机器人用于生成响应的源的引用。 它允许用户通过文本内引文和引用来引用源。
    • 敏感度标签:使用敏感度标签帮助用户了解邮件的机密性。
    • 反馈循环:这允许用户对机器人消息提供正面或负面反馈。
    • 由 AI 生成:Teams AI 库在机器人的响应中自动包含 由 AI 生成的 标签。 此标签可帮助用户识别消息是使用 AI 生成的。

    有关设置 AI 支持的机器人消息格式的详细信息,请参阅 使用 AI 生成的内容设置机器人消息

配置流式处理机器人消息

按照以下步骤配置流式处理机器人消息:

  1. 为 AI 支持的机器人启用流式处理

    a. DefaultAugmentation使用 文件中的 类config.json,并在机器人应用的以下main应用程序类之一中使用:

    • 对于 C# 机器人应用:更新 Program.cs
    • 对于 JavaScript 应用:更新 index.ts
    • 对于 Python 应用:更新 bot.py

    b. 在OpenAIModel声明中设置为 stream true。

  2. 设置信息性消息:使用StartStreamingMessage配置在ActionPlanner声明中指定信息性消息。

  3. 设置最终流式处理消息的格式

    • 在应用声明中的 AIOptions 对象中设置反馈循环开关,并指定处理程序。
      • 对于使用 Python 生成的机器人应用,除 AIOptions 对象外,在 ActionPlannerOptions 对象中设置反馈循环切换。
    • 在声明内使用 EndStreamHandler 设置最后一个区块中的 ActionPlanner 附件。

以下代码片段显示了流式处理机器人消息的示例:

    // 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 是用于将响应流式传输到客户端的帮助程序类。 它允许你在单个响应中发送一系列更新,使交互更加流畅。 如果使用自己的自定义模型,可以轻松使用此类无缝流式传输响应。 这是让用户保持参与的好方法。

流式处理机器人消息必须使用以下顺序:

  • queueInformativeUpdate()
  • queueTextChunk()
  • endStream()

模型调用 endStream()后,流结束,机器人无法发送任何进一步的更新。

下面是可用于自定义应用体验的其他方法的列表:

  • setAttachments
  • setSensitivityLabel
  • setFeedbackLoop
  • setGeneratedByAILabel

Azure OpenAI 或 OpenAI 的限制

  • 当机器人调用流式处理 API 的速度过快时,可能会导致问题并中断流式处理体验。 若要避免这种情况,请以一致的速度一次流式传输一条消息。 否则,请求可能会受到限制。 缓冲模型中的令牌 1.5 到 2 秒,以确保顺利流式处理。
  • AI 支持的功能(如引文、敏感度标签、反馈循环和 AI 标签 生成 )仅在最终区块中受支持。 按排队的每个文本区块设置引文。
  • 只能流式传输格式文本。
  • 只能设置一条信息性消息。 机器人每次更新都会重复使用此消息。 示例包括:
    • 扫描文档
    • 汇总内容
    • 查找相关工作项
  • 模型仅在从 LLM 返回的每条消息的开头呈现信息性消息。
  • 附件只能在最后一个区块中发送。
  • AI SDK 的函数调用和 AOAI 或 OAI o1 模型尚不支持流式处理。
  • 下面是用于 streamSequence AI SDK 的要求:
    • 序列必须以数字“1”开头。
    • 除最终) 外,后续数字 (必须是单调递增整数, (例如 1-2-3>>) 。
    • 对于最终消息, streamSequence 不得设置。

通过 REST API Stream消息

机器人消息可以通过 REST API 进行流式传输。 流式处理消息支持格式文本和引文。 附件、AI 标签、反馈按钮和敏感度标签仅适用于最终流式处理消息。 有关详细信息,请参阅带有 AI 生成内容的附件和机器人消息。

当机器人通过 REST API 调用流式处理时,请确保仅在收到来自初始 API 调用的成功响应后调用下一个流式处理 API。 如果机器人使用 SDK,请验证是否从发送活动方法收到 null 响应对象,以确认已成功传输上一次调用。

当机器人调用流式处理 API 的速度过快时,可能会遇到问题,并且流式处理体验可能会中断。 我们建议机器人一次流式传输一条消息,以确保它以一致的速度调用流式处理 API。 否则,请求可能会受到限制。 将令牌从模型缓冲 1.5 到 2 秒,以确保流式处理顺利进行。 我们建议机器人一次流式传输一条消息,以确保它以一致的速度调用流式处理 API。 否则,请求可能会受到限制。 将令牌从模型缓冲 1.5 到 2 秒,以确保流式处理顺利进行。

以下是流式处理机器人消息的属性:

属性 必需 说明
type ✔️ 支持的值为 typingmessage
typing:流式处理消息时使用。
message:用于最终流式处理的消息。
text ✔️ 要流式传输的消息的内容。
entities.type ✔️ 必须是 streamInfo
entities.streamId ✔️ streamId 从初始流式处理请求 开始流式处理
entities.streamType 流式处理更新的类型。 支持的值为 informativestreamingfinal。 默认值为 streamingfinal 仅在最终消息中使用。
entities.streamSequence ✔️ 每个请求的增量整数。

注意

下面是使用 REST API 的要求 streamSequence

  • 第一个必须为数字“1”。
  • 除最终) 外,后续数字 (必须是单调递增整数, (例如 1-2-3>>) 。
  • 对于最终消息, streamSequence 不得设置 。

若要在机器人中启用流式处理,请执行以下步骤:

  1. 开始流式处理
  2. 继续流式处理
  3. 最终流式处理

开始流式处理

机器人可以发送信息性消息或流式消息作为其初始通信。 响应包括 , 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) 。 将这些令牌追加到以前的消息版本,然后将其发送给用户。

当机器人调度流式处理请求时,请确保机器人以每秒一个请求的最小速率发送请求。


// 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. 机器人未能在严格的两分钟时限内完成流式处理。
403 ContentStreamNotAllowed Message size too large 机器人发送的消息超出了当前 消息大小 限制。
429 不适用 API calls quota exceeded 机器人流式传输的消息数已超出配额。

代码示例

示例名称 Description Node.js C# Python
Teams 流式处理机器人示例 此代码示例演示如何生成连接到 LLM 的机器人并通过 Teams 发送消息。 不适用 View 不适用
对话流式处理机器人 这是一个具有 Teams AI 库的对话流式处理机器人。 View View View

另请参阅