您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

FormFlow 的基本功能Basic features of FormFlow

备注

本主题适用于 SDK v3 版本。This topic applies to SDK v3 release. 可以在此处找到最新版 SDK (v4) 的文档。You can find the documentation for the latest version of the SDK v4 here.

对话是很强大且很灵活的功能,但处理引导式聊天(例如订购三明治)仍需很大周折。Dialogs are very powerful and flexible, but handling a guided conversation such as ordering a sandwich can require a lot of effort. 在聊天中,每个时间点接下来要发生的事情都有许多可能性。At each point in the conversation, there are many possibilities of what will happen next. 例如,可能需要澄清某个不清楚的地方、提供帮助、返回或显示进度。For example, you may need to clarify an ambiguity, provide help, go back, or show progress. 通过在 Bot Framework SDK for .NET 中使用 FormFlow,可以大大简化管理此类引导式聊天的过程。By using FormFlow within the Bot Framework SDK for .NET, you can greatly simplify the process of managing a guided conversation like this.

FormFlow 可以根据指定的准则,自动生成管理引导式聊天所需的对话。FormFlow automatically generates the dialogs that are necessary to manage a guided conversation, based upon guidelines that you specify. 虽然与自行创建和管理对话相比,使用 FormFlow 会牺牲一些灵活性,但使用 FormFlow 设计引导式聊天可以大大缩短开发机器人所需的时间。Although using FormFlow sacrifices some of the flexibility that you might otherwise get by creating and managing dialogs on your own, designing a guided conversation using FormFlow can significantly reduce the time it takes to develop your bot. 另外,在构建机器人时,可以组合使用 FormFlow 生成的对话和其他类型的对话。Additionally, you may construct your bot using a combination of FormFlow-generated dialogs and other types of dialogs. 例如,可以通过 FormFlow 对话引导用户执行完成窗体的过程,同时通过 LuisDialog 评估用户输入,以便确定意向。For example, a FormFlow dialog may guide the user through the process of completing a form, while a LuisDialog may evaluate user input to determine intent.

本文介绍如何创建一个机器人,以便使用 FormFlow 的基本功能从用户处收集信息。This article describes how to create a bot that uses the basic features of FormFlow to collect information from a user.

窗体和字段Forms and fields

若要使用 FormFlow 创建机器人,必须指定机器人需要从用户处收集的信息。To create a bot using FormFlow, you must specify the information that the bot needs to collect from the user. 例如,如果机器人的目的是获取用户的三明治订单,则必须定义一个窗体,其中包含的字段对应于机器人履行订单所需的数据。For example, if the bot's objective is to obtain a user's sandwich order, then you must define a form that contains fields for the data that the bot needs to fulfill the order. 可以通过创建 C# 类来定义窗体,该类包含一个或多个公共属性,表示机器人将要从用户处收集的数据。You can define the form by creating a C# class that contains one or more public properties to represent the data that the bot will collect from the user. 每个属性必须是以下数据类型之一:Each property must be one of these data types:

  • 整形(sbyte、byte、short、ushort、int、uint、long、ulong)Integral (sbyte, byte, short, ushort, int, uint, long, ulong)
  • 浮点值(float、double)Floating point (float, double)
  • StringString
  • DateTimeDateTime
  • 枚举Enumeration
  • 枚举列表List of enumerations

任何数据类型都可能为 null,这可以用来针对字段没有值的情况建模。Any of the data types may be nullable, which you can use to model that the field does not have a value. 如果某个窗体字段所依据的枚举属性不可为 null,则枚举中的值 0 表示 null(表示字段没有值),枚举值应从 1 开始。If a form field is based on an enumeration property that is not nullable, the value 0 in the enumeration represents null (i.e., indicates that the field does not have a value), and you should start your enumeration values at 1. FormFlow 忽略所有其他的属性类型和方法。FormFlow ignores all other property types and methods.

对于复杂对象,必须为顶级 C# 类创建一个窗体,并为复杂对象创建另一个窗体。For complex objects, you must create a form for the top-level C# class and another form for the complex object. 可以使用典型的对话语义将窗体组合在一起。You can compose the forms together by using typical dialog semantics. 也可直接定义一个窗体,方法是实现 Advanced.IField,或者使用 Advanced.Field 并填充其中的字典。It is also possible to define a form directly by implementing Advanced.IField or using Advanced.Field and populating the dictionaries within it.

备注

可以使用 C# 类或 JSON 架构来定义窗体。You can define a form by using either a C# class or JSON schema. 本文介绍如何使用 C# 类来定义窗体。This article describes how to define a form using a C# class. 有关如何使用 JSON 架构的详细信息,请参阅使用 JSON 架构定义窗体For more information about using JSON schema, see Define a form using JSON schema.

简单的三明治机器人Simple sandwich bot

以简单的三明治机器人为例,该机器人旨在获取用户的三明治订单。Consider this example of a simple sandwich bot that is designed to obtain a user's sandwich order.

创建窗体Create the form

SandwichOrder 类定义窗体,枚举定义生成三明治所需的选项。The SandwichOrder class defines the form and the enumerations define the options for building a sandwich. 此类还包括静态的 BuildForm 方法,该方法使用 FormBuilder 创建窗体并定义简单的欢迎消息。The class also includes the static BuildForm method that uses FormBuilder to create the form and define a simple welcome message.

若要使用 FormFlow,必须先导入 Microsoft.Bot.Builder.FormFlow 命名空间。To use FormFlow, you must first import the Microsoft.Bot.Builder.FormFlow namespace.

using Microsoft.Bot.Builder.FormFlow;
using System;
using System.Collections.Generic;

// The SandwichOrder class represents the form that you want to complete 
// using information that is collected from the user. 
// It must be serializable so the bot can be stateless. 
// The order of fields defines the default sequence in which the user is asked questions.

// The enumerations define the valid options for each field in SandwichOrder, and the order
// of the values represents the sequence in which they are presented to the user in a conversation.

namespace Microsoft.Bot.Sample.SimpleSandwichBot
{
    public enum SandwichOptions
    {
        BLT, BlackForestHam, BuffaloChicken, ChickenAndBaconRanchMelt, ColdCutCombo, MeatballMarinara,
        OvenRoastedChicken, RoastBeef, RotisserieStyleChicken, SpicyItalian, SteakAndCheese, SweetOnionTeriyaki, Tuna,
        TurkeyBreast, Veggie
    };
    public enum LengthOptions { SixInch, FootLong };
    public enum BreadOptions { NineGrainWheat, NineGrainHoneyOat, Italian, ItalianHerbsAndCheese, Flatbread };
    public enum CheeseOptions { American, MontereyCheddar, Pepperjack };
    public enum ToppingOptions
    {
        Avocado, BananaPeppers, Cucumbers, GreenBellPeppers, Jalapenos,
        Lettuce, Olives, Pickles, RedOnion, Spinach, Tomatoes
    };
    public enum SauceOptions
    {
        ChipotleSouthwest, HoneyMustard, LightMayonnaise, RegularMayonnaise,
        Mustard, Oil, Pepper, Ranch, SweetOnion, Vinegar
    };

    [Serializable]
    public class SandwichOrder
    {
        public SandwichOptions? Sandwich;
        public LengthOptions? Length;
        public BreadOptions? Bread;
        public CheeseOptions? Cheese;
        public List<ToppingOptions> Toppings;
        public List<SauceOptions> Sauce;

        public static IForm<SandwichOrder> BuildForm()
        {
            return new FormBuilder<SandwichOrder>()
                    .Message("Welcome to the simple sandwich order bot!")
                    .Build();
        }
    };
}

将窗体连接到框架Connect the form to the framework

若要将窗体连接到框架,必须将其添加到控制器。To connect the form to the framework, you must add it to the controller. 在此示例中,Conversation.SendAsync 方法调用静态的 MakeRootDialog 方法,后者反过来调用 FormDialog.FromForm 方法来创建 SandwichOrder 窗体。In this example, the Conversation.SendAsync method calls the static MakeRootDialog method, which in turn, calls the FormDialog.FromForm method to create the SandwichOrder form.

internal static IDialog<SandwichOrder> MakeRootDialog()
{
    return Chain.From(() => FormDialog.FromForm(SandwichOrder.BuildForm));
}

[ResponseType(typeof(void))]
public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
{
    if (activity != null)
    {
        switch (activity.GetActivityType())
        {
            case ActivityTypes.Message:
                await Conversation.SendAsync(activity, MakeRootDialog);
                break;

            case ActivityTypes.ConversationUpdate:
            case ActivityTypes.ContactRelationUpdate:
            case ActivityTypes.Typing:
            case ActivityTypes.DeleteUserData:
            default:
                Trace.TraceError($"Unknown activity type ignored: {activity.GetActivityType()}");
                break;
        }
    }
    ...
}

在操作中查看See it in action

只需使用 C# 类定义窗体并将其连接到框架,即可通过 FormFlow 自动管理机器人和用户之间的聊天。By simply defining the form with a C# class and connecting it to the framework, you have enabled FormFlow to automatically manage the conversation between bot and user. 下面显示的示例交互演示了使用 FormFlow 的基本功能创建的机器人的功能。The example interactions shown below demonstrate the capabilities of a bot that is created by using the basic features of FormFlow. 在每个交互中, > 符号表示在该处用户输入了一个响应。In each interaction, a > symbol indicates the point at which the user enters a response.

显示第一个提示Display the first prompt

此窗体填充 SandwichOrder.Sandwich 属性。This form populates the SandwichOrder.Sandwich property. 此窗体自动生成提示“请选择三明治”,提示中的“三明治”一词派生自属性名称 SandwichThe form automatically generates the prompt, "Please select a sandwich", where the word "sandwich" in the prompt derives from the property name Sandwich. SandwichOptions 枚举定义显示给用户的选项,每个枚举值都会在大小写变化和出现下划线时自动拆分成单词。The SandwichOptions enumeration defines the choices that are presented to the user, with each enumeration value being automatically broken into words based upon changes in case and underscores.

Please select a sandwich
1. BLT
2. Black Forest Ham
3. Buffalo Chicken
4. Chicken And Bacon Ranch Melt
5. Cold Cut Combo
6. Meatball Marinara
7. Oven Roasted Chicken
8. Roast Beef
9. Rotisserie Style Chicken
10. Spicy Italian
11. Steak And Cheese
12. Sweet Onion Teriyaki
13. Tuna
14. Turkey Breast
15. Veggie
>

提供指导Provide guidance

在聊天过程中,用户可以随时输入“帮助”,获取有关如何填写窗体的指导。The user can enter "help" at any point in the conversation to get guidance with filling out the form. 例如,如果用户在出现三明治提示时输入“帮助”,则机器人会使用以下指导内容进行响应。For example, if the user enters "help" at the sandwich prompt, the bot will respond with this guidance.

> help
* You are filling in the sandwich field. Possible responses:
* You can enter a number 1-15 or words from the descriptions. (BLT, Black Forest Ham, Buffalo Chicken, Chicken And Bacon Ranch Melt, Cold Cut Combo, Meatball Marinara, Oven Roasted Chicken, Roast Beef, Rotisserie Style Chicken, Spicy Italian, Steak And Cheese, Sweet Onion Teriyaki, Tuna, Turkey Breast, and Veggie)
* Back: Go back to the previous question.
* Help: Show the kinds of responses you can enter.
* Quit: Quit the form without completing it.
* Reset: Start over filling in the form. (With defaults from your previous entries.)
* Status: Show your progress in filling in the form so far.
* You can switch to another field by entering its name. (Sandwich, Length, Bread, Cheese, Toppings, and Sauce).

转到下一提示Advance to the next prompt

如果用户输入“2”来响应初始的三明治提示,则机器人会显示一个提示,要求提供窗体定义的下一属性:SandwichOrder.LengthIf the user enters "2" in response to the initial sandwich prompt, the bot then displays a prompt for the next property that is defined by the form: SandwichOrder.Length.

Please select a sandwich
 1. BLT
 2. Black Forest Ham
 3. Buffalo Chicken
 4. Chicken And Bacon Ranch Melt
 5. Cold Cut Combo
 6. Meatball Marinara
 7. Oven Roasted Chicken
 8. Roast Beef
 9. Rotisserie Style Chicken
 10. Spicy Italian
 11. Steak And Cheese
 12. Sweet Onion Teriyaki
 13. Tuna
 14. Turkey Breast
 15. Veggie
> 2
Please select a length (1. Six Inch, 2. Foot Long)
> 

返回到上一提示Return to the previous prompt

在聊天过程中,如果用户此时输入“返回”,机器人会返回到上一提示。If the user enters "back" at this point in the conversation, the bot will return the previous prompt. 提示会显示用户当前的选择(“黑森林汉堡”);用户可以输入另一数字来更改该选择,也可输入“c”确认该选择。The prompt shows the user's current choice ("Black Forest Ham"); the user may change that selection by entering a different number or confirm that selection by entering "c".

> back
Please select a sandwich(current choice: Black Forest Ham)
 1. BLT
 2. Black Forest Ham
 3. Buffalo Chicken
 4. Chicken And Bacon Ranch Melt
 5. Cold Cut Combo
 6. Meatball Marinara
 7. Oven Roasted Chicken
 8. Roast Beef
 9. Rotisserie Style Chicken
 10. Spicy Italian
 11. Steak And Cheese
 12. Sweet Onion Teriyaki
 13. Tuna
 14. Turkey Breast
 15. Veggie
> c
Please select a length (1. Six Inch, 2. Foot Long)
> 

澄清用户输入Clarify user input

如果用户在进行选择时使用文本(而不是数字)进行响应,而该输入与多个选项匹配,机器人会自动要求用户进行澄清。If the user responds with text (instead of a number) to indicate a choice, the bot will automatically ask for clarification if user input matches more than one choice.

Please select a bread
 1. Nine Grain Wheat
 2. Nine Grain Honey Oat
 3. Italian
 4. Italian Herbs And Cheese
 5. Flatbread
> nine grain
By "nine grain" bread did you mean (1. Nine Grain Honey Oat, 2. Nine Grain Wheat)
> 1

如果用户输入没有直接匹配到任何有效选项,机器人会自动提示用户进行澄清。If user input does not directly match any of the valid choices, the bot will automatically prompt the user for clarification.

Please select a cheese (1. American, 2. Monterey Cheddar, 3. Pepperjack)
> amercan
"amercan" is not a cheese option.
> american smoked
For cheese I understood American. "smoked" is not an option.

如果用户输入为某个属性指定了多个选项,而机器人并不理解任何指定的选项,它会自动提示用户进行澄清。If user input specifies multiple choices for a property and the bot does not understand any of the specified choices, it will automatically prompt the user for clarification.

Please select one or more toppings
 1. Banana Peppers
 2. Cucumbers
 3. Green Bell Peppers
 4. Jalapenos
 5. Lettuce
 6. Olives
 7. Pickles
 8. Red Onion
 9. Spinach
 10. Tomatoes
> peppers, lettuce and tomato
By "peppers" toppings did you mean (1. Green Bell Peppers, 2. Banana Peppers)
> 1

显示当前状态Show current status

如果用户在订购过程中的任何时间点输入“状态”,则机器人的响应会指示哪些值已指定,哪些值尚未指定。If the user enters "status" at any point in the order, the bot's response will indicate which values have already been specified and which values remain to be specified.

Please select one or more sauce
 1. Honey Mustard
 2. Light Mayonnaise
 3. Regular Mayonnaise
 4. Mustard
 5. Oil
 6. Pepper
 7. Ranch
 8. Sweet Onion
 9. Vinegar
> status
* Sandwich: Black Forest Ham
* Length: Six Inch
* Bread: Nine Grain Honey Oat
* Cheese: American
* Toppings: Lettuce, Tomatoes, and Green Bell Peppers
* Sauce: Unspecified  

确认选择Confirm selections

当用户完成窗体时,机器人会要求用户确认所做的选择。When the user completes the form, the bot will ask the user to confirm their selections.

Please select one or more sauce
 1. Honey Mustard
 2. Light Mayonnaise
 3. Regular Mayonnaise
 4. Mustard
 5. Oil
 6. Pepper
 7. Ranch
 8. Sweet Onion
 9. Vinegar
> 1
Is this your selection?
* Sandwich: Black Forest Ham
* Length: Six Inch
* Bread: Nine Grain Honey Oat
* Cheese: American
* Toppings: Lettuce, Tomatoes, and Green Bell Peppers
* Sauce: Honey Mustard
>

如果用户在响应时输入“否”,机器人会允许用户更新此前所做的任何选择。If the user responds by entering "no", the bot allows the user to update any of the prior selections. 如果用户在响应时输入“是”,则窗体完成,控制返回到调用对话。If the user responds by entering "yes", the form has been completed and control is returned to the calling dialog.

Is this your selection?
* Sandwich: Black Forest Ham
* Length: Six Inch
* Bread: Nine Grain Honey Oat
* Cheese: American
* Toppings: Lettuce, Tomatoes, and Green Bell Peppers
* Sauce: Honey Mustard
> no
What do you want to change?
 1. Sandwich(Black Forest Ham)
 2. Length(Six Inch)
 3. Bread(Nine Grain Honey Oat)
 4. Cheese(American)
 5. Toppings(Lettuce, Tomatoes, and Green Bell Peppers)
 6. Sauce(Honey Mustard)
> 2
Please select a length (current choice: Six Inch) (1. Six Inch, 2. Foot Long)
> 2
Is this your selection?
* Sandwich: Black Forest Ham
* Length: Foot Long
* Bread: Nine Grain Honey Oat
* Cheese: American
* Toppings: Lettuce, Tomatoes, and Green Bell Peppers
* Sauce: Honey Mustard
> y

处理退出和异常Handling quit and exceptions

如果用户在窗体中输入“退出”,或者在聊天的某个时间点发生异常,机器人需了解事件发生在哪一步、事件发生时窗体的状态,以及事件发生前窗体的哪些步骤已成功完成。If the user enters "quit" in the form or an exception occurs at some point in the conversation, your bot will need to know the step in which the event occurred, the state of the form when the event occurred, and which steps of the form were successfully completed prior to the event. 窗体通过 FormCanceledException<T> 类返回该信息。The form returns this information via the FormCanceledException<T> class.

此代码示例演示如何捕获异常并根据已发生的事件显示一条消息。This code example shows how to catch the exception and display a message according to the event that occurred.

internal static IDialog<SandwichOrder> MakeRootDialog()
{
    return Chain.From(() => FormDialog.FromForm(SandwichOrder.BuildLocalizedForm))
        .Do(async (context, order) =>
        {
            try
            {
                var completed = await order;
                // Actually process the sandwich order...
                await context.PostAsync("Processed your order!");
            }
            catch (FormCanceledException<SandwichOrder> e)
            {
                string reply;
                if (e.InnerException == null)
                {
                    reply = $"You quit on {e.Last} -- maybe you can finish next time!";
                }
                else
                {
                    reply = "Sorry, I've had a short circuit. Please try again.";
                }
                await context.PostAsync(reply);
            }
        });
}

摘要Summary

本文介绍如何使用 FormFlow 的基本功能创建一个具有下述功能的机器人:This article has described how to use the basic features of FormFlow to create a bot that can:

  • 自动生成和管理聊天Automatically generate and manage the conversation
  • 提供明确的指导和帮助Provide clear guidance and help
  • 理解数字和文本条目Understand both numbers and textual entries
  • 就理解和不理解的内容向用户提供反馈Provide feedback to the user regarding what is understood and what is not
  • 必要时要求用户澄清问题Ask clarifying questions when necessary
  • 允许用户在步骤之间导航Allow the user to navigate between steps

虽然基本的 FormFlow 功能在某些情况下已足够,但也不妨考虑将 FormFlow 的部分更高级功能纳入机器人中,这样可能会为你带来很大优势。Although basic FormFlow functionality is sufficient in some cases, you should consider the potential benefits of incorporating some of the more advanced features of FormFlow into your bot. 有关详细信息,请参阅 FormFlow 的高级功能使用 FormBuilder 自定义窗体For more information, see Advanced features of FormFlow and Customize a form using FormBuilder.

代码示例Sample code

有关演示如何使用 Bot Framework SDK for .NET 实现 FormFlow 的完整示例,请参阅 GitHub 中的多对话机器人示例Contoso Flowers 机器人示例For complete samples that show how to implement FormFlow using the Bot Framework SDK for .NET, see the Multi-Dialog Bot sample and the Contoso Flowers Bot sample in GitHub.

后续步骤Next steps

FormFlow 可简化对话开发。FormFlow simplifies dialog development. FormFlow 的高级功能可用于自定义 FormFlow 对象的行为。The advanced features of FormFlow let you customize how a FormFlow object behaves.

其他资源Additional resources