You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C#的Microsoft Bot Framework:FormFlow后实现多输入循环问询

嘿,我懂你现在的困扰——FormFlow走完后要循环问用户一堆属性还得存下来,光看官方瀑布流教程确实容易摸不着头绪。其实把FormFlow和瀑布流(Waterfall Dialog)结合起来就能完美解决,我给你捋个可行的实现方案,代码都给你写好啦:

整体思路

核心逻辑是:FormFlow流程完成后,跳转到一个专门处理循环问询的瀑布流Dialog。我们用一个状态类来追踪当前询问到第几个属性、已收集的回答,再通过瀑布流的步骤循环调用自己,直到所有属性都收集完毕。

具体实现步骤

1. 定义待询问的属性集合

先把你需要问的属性列出来,比如:

// 替换成你实际需要询问的属性名称
private readonly List<string> _requiredUserProperties = new List<string>
{
    "项目编号",
    "文件描述",
    "联系电话"
};

2. 修改FormFlow的OnCompletion逻辑

让FormFlow完成后自动跳转到循环问询的瀑布流,同时传递当前的UploadFile状态:

return new FormBuilder<UploadFile>()
    .OnCompletion(async (context, state) =>
    {
        // 先执行你原来的processOrder逻辑
        await processOrder(context, state);
        
        // 初始化循环状态,跳转到循环问询Dialog
        var loopState = new PropertyLoopTrackingState
        {
            UploadState = state,
            CurrentPropertyIndex = 0
        };
        await context.BeginDialogAsync(nameof(PropertyLoopDialog), loopState);
    })
    // 你原来的Field定义保持不变
    .Field(new FieldReflector<UploadFile>(nameof(UploadFile.Str))
        .SetType(null)
        .SetDefine((state, field) => {
            foreach (string str in listStr)
                field
                    .AddDescription(str, str)
                    .AddTerms(str, str);
            return Task.FromResult(true);
        })
        .SetNext((value, state) => {
            // 这里保留你原来的保存逻辑
            return new NextStep();
        }))
    .Build();

3. 创建循环状态追踪类

这个类用来保存循环过程中的所有关键数据,避免状态丢失:

// 用于追踪循环问询的状态
public class PropertyLoopTrackingState
{
    // 保存FormFlow阶段的UploadFile状态
    public UploadFile UploadState { get; set; }
    // 当前询问到第几个属性
    public int CurrentPropertyIndex { get; set; }
    // 存储用户的所有回答
    public Dictionary<string, string> CollectedAnswers { get; set; } = new Dictionary<string, string>();
}

4. 实现循环问询的瀑布流Dialog

这个Dialog是核心,通过两步实现循环:第一步询问当前属性,第二步保存回答并判断是否继续循环:

public class PropertyLoopDialog : WaterfallDialog
{
    private readonly List<string> _propertiesToAsk;

    public PropertyLoopDialog(string dialogId, List<string> propertiesToAsk) : base(dialogId)
    {
        _propertiesToAsk = propertiesToAsk;

        // 第一步:检查是否还有属性要问,若有则发起询问
        AddStep(async (stepContext, cancellationToken) =>
        {
            var loopState = stepContext.Options as PropertyLoopTrackingState;
            
            // 所有属性都问完了,结束循环
            if (loopState.CurrentPropertyIndex >= _propertiesToAsk.Count)
            {
                await stepContext.Context.SendActivityAsync("所有信息已收集完成!");
                // 这里可以把CollectedAnswers和UploadState合并处理,比如保存到数据库
                return await stepContext.EndDialogAsync(loopState);
            }

            // 获取当前要询问的属性
            var currentProp = _propertiesToAsk[loopState.CurrentPropertyIndex];
            await stepContext.Context.SendActivityAsync($"请输入{currentProp}:");
            // 用文本Prompt接收用户输入,需要提前注册这个Prompt
            return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions());
        });

        // 第二步:保存用户回答,更新索引,重新进入循环
        AddStep(async (stepContext, cancellationToken) =>
        {
            var loopState = stepContext.Options as PropertyLoopTrackingState;
            var currentProp = _propertiesToAsk[loopState.CurrentPropertyIndex];
            
            // 保存当前属性的回答
            loopState.CollectedAnswers[currentProp] = (string)stepContext.Result;
            
            // 索引加1,准备询问下一个属性
            loopState.CurrentPropertyIndex++;
            
            // 替换当前Dialog,重新执行第一步,实现循环
            return await stepContext.ReplaceDialogAsync(nameof(PropertyLoopDialog), loopState);
        });
    }
}

5. 注册Dialog到Bot

在Bot的初始化代码里(比如构造函数或ConfigureServices),把循环Dialog和文本Prompt注册进去:

// 注册循环问询Dialog
Dialogs.Add(new PropertyLoopDialog(nameof(PropertyLoopDialog), _requiredUserProperties));
// 注册文本Prompt,用于接收用户输入
Dialogs.Add(new TextPrompt(nameof(TextPrompt)));

关键细节说明

  • 循环实现:用ReplaceDialogAsync代替BeginDialogAsync,避免Dialog栈无限叠加,同时传递更新后的状态,实现循环逻辑。
  • 状态管理:PropertyLoopTrackingState统一管理所有状态,确保在循环过程中不会丢失FormFlow的数据和已收集的回答。
  • 灵活扩展:如果需要询问不同类型的输入(比如数字、日期),可以把TextPrompt换成对应的NumberPrompt、DateTimePrompt,还能给Prompt添加验证逻辑(比如检查电话格式)。

内容的提问来源于stack exchange,提问作者MaLa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:41:59