Bagikan melalui


Menerapkan alur percakapan berurutan

BERLAKU UNTUK: SDK v4

Mengumpulkan informasi dengan mengajukan pertanyaan adalah salah satu cara utama bot berinteraksi dengan pengguna. Pustaka dialog menyediakan fitur bawaan yang berguna seperti kelas prompt yang memudahkan untuk mengajukan pertanyaan dan memvalidasi respons untuk memastikannya cocok dengan jenis data tertentu atau memenuhi aturan validasi kustom.

Anda dapat mengelola alur percakapan linier dan lebih kompleks menggunakan pustaka dialog. Dalam interaksi linier, bot berjalan melalui urutan langkah tetap, dan percakapan selesai. Dialog berguna ketika bot perlu mengumpulkan informasi dari pengguna.

Artikel ini memperlihatkan cara menerapkan alur percakapan linier dengan membuat perintah dan memanggilnya dari dialog air terjun. Untuk contoh cara menulis permintaan Anda sendiri tanpa pustaka dialog, lihat artikel Membuat permintaan Anda sendiri untuk mengumpulkan input pengguna.

Catatan

Untuk membangun agen dengan layanan, orkestrasi, dan pengetahuan AI pilihan Anda, pertimbangkan untuk menggunakan SDK Agen Microsoft 365. Agen SDK memiliki dukungan untuk C#, JavaScript, atau Python. Anda dapat mempelajari lebih lanjut tentang Agen SDK di aka.ms/agents. Jika Anda mencari platform agen berbasis SaaS, pertimbangkan Microsoft Copilot Studio. Jika Anda memiliki bot yang sudah ada yang dibangun dengan Bot Framework SDK, Anda dapat memperbarui bot Anda ke SDK Agen. Anda dapat meninjau perubahan inti dan pembaruan utama pada Panduan migrasi Bot Framework SDK ke Agen SDK. Tiket dukungan untuk Bot Framework SDK tidak akan lagi dilayankan per 31 Desember 2025.

Prasyarat

Tentang sampel ini

Sampel perintah multi-giliran menggunakan dialog air terjun, beberapa perintah, dan dialog komponen untuk membuat interaksi linier yang mengajukan serangkaian pertanyaan kepada pengguna. Kode menggunakan dialog untuk menelusuri langkah-langkah berikut:

Langkah-langkah Jenis perintah
Tanyakan kepada pengguna tentang moda transportasi mereka Perintah pilihan
Tanyakan nama pengguna Petunjuk teks
Tanyakan kepada pengguna apakah mereka ingin memberikan usia mereka Konfirmasi permintaan
Jika mereka menjawab ya, mintalah usia mereka Input angka, dengan validasi untuk hanya menerima usia yang lebih besar dari 0 dan kurang dari 150
Jika mereka tidak menggunakan Microsoft Teams, minta gambar profil kepada mereka Pesan lampiran, dengan validasi untuk memungkinkan lampiran yang hilang
Tanyakan apakah informasi yang dikumpulkan "ok" Gunakan kembali perintah Konfirmasi

Akhirnya, jika mereka menjawab ya, tampilkan informasi yang dikumpulkan; jika tidak, beri tahu pengguna bahwa informasi mereka tidak akan disimpan.

Membuat dialog utama

Untuk menggunakan dialog, instal paket NuGet Microsoft.Bot.Builder.Dialogs .

Bot berinteraksi dengan pengguna melalui UserProfileDialog. Saat membuat kelas bot DialogBot , UserProfileDialog diatur sebagai dialog utamanya. Bot kemudian menggunakan metode pembantu Run untuk mengakses dialog.

Diagram kelas untuk sampel C#.

Dialog\UserProfileDialog.cs

Mulailah dengan membuat UserProfileDialog yang berasal dari ComponentDialog kelas , dan memiliki tujuh langkah.

UserProfileDialog Di konstruktor, buat langkah-langkah air terjun, perintah dan dialog air terjun, dan tambahkan ke kumpulan dialog. Perintah harus berada dalam kumpulan dialog yang sama di mana mereka digunakan.

public UserProfileDialog(UserState userState)
    : base(nameof(UserProfileDialog))
{
    _userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");

    // This array defines how the Waterfall will execute.
    var waterfallSteps = new WaterfallStep[]
    {
        TransportStepAsync,
        NameStepAsync,
        NameConfirmStepAsync,
        AgeStepAsync,
        PictureStepAsync,
        SummaryStepAsync,
        ConfirmStepAsync,
    };

    // Add named dialogs to the DialogSet. These names are saved in the dialog state.
    AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
    AddDialog(new TextPrompt(nameof(TextPrompt)));
    AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
    AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
    AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
    AddDialog(new AttachmentPrompt(nameof(AttachmentPrompt), PicturePromptValidatorAsync));

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

Selanjutnya, tambahkan langkah-langkah yang digunakan dialog untuk meminta input. Untuk menggunakan perintah, panggil dari langkah dalam dialog Anda dan ambil hasil perintah dalam langkah berikut menggunakan stepContext.Result. Di balik layar, perintah adalah dialog dua langkah. Pertama, perintah meminta input. Kemudian mengembalikan nilai yang valid, atau dimulai kembali dari awal dengan proses ulang hingga menerima input yang valid.

Anda harus selalu mengembalikan nilai yang bukan null DialogTurnResult dari langkah air terjun. Jika tidak, dialog Anda mungkin tidak berfungsi seperti yang dirancang. Ditunjukkan di bawah ini adalah implementasi untuk NameStepAsync dalam dialog air terjun.

private static async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;

    return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
}

Dalam AgeStepAsync, tentukan permintaan coba lagi ketika input pengguna gagal divalidasi, baik karena dalam format yang tidak dapat diurai oleh perintah, atau input gagal dalam kriteria validasi. Dalam hal ini, jika tidak ada prompt ulang yang disediakan, prompt akan menggunakan teks prompt awal untuk meminta kembali input dari pengguna.

private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    if ((bool)stepContext.Result)
    {
        // User said "yes" so we will be prompting for the age.
        // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
        var promptOptions = new PromptOptions
        {
            Prompt = MessageFactory.Text("Please enter your age."),
            RetryPrompt = MessageFactory.Text("The value entered must be greater than 0 and less than 150."),
        };

        return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
    }
    else
    {
        // User said "no" so we will skip the next step. Give -1 as the age.
        return await stepContext.NextAsync(-1, cancellationToken);
    }
}

UserProfile.cs

Mode transportasi, nama, dan usia pengguna disimpan dalam instans UserProfile kelas.

public class UserProfile
{
    public string Transport { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public Attachment Picture { get; set; }
}

Dialog\UserProfileDialog.cs

Pada langkah terakhir, periksa stepContext.Result yang dikembalikan oleh dialog yang dipanggil pada langkah waterfall sebelumnya. Jika nilai pengembalian benar, aksesor profil pengguna mendapatkan dan memperbarui profil pengguna. Untuk mendapatkan profil pengguna, panggil GetAsync lalu atur nilai properti userProfile.Transport, userProfile.Name, userProfile.Age, dan userProfile.Picture. Terakhir, ringkas informasi untuk pengguna sebelum memanggil EndDialogAsync, yang mengakhiri dialog. Mengakhiri dialog akan mengeluarkannya dari antrian dialog dan mengembalikan hasil opsional ke dialog induk. Dialog atau metode induk adalah yang memulai dialog yang baru saja selesai.

    else
    {
        msg += $" Your profile will not be kept.";
    }

    await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);

    // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is the end.
    return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}

private async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    stepContext.Values["picture"] = ((IList<Attachment>)stepContext.Result)?.FirstOrDefault();

    // Get the current profile object from user state.
    var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);

    userProfile.Transport = (string)stepContext.Values["transport"];
    userProfile.Name = (string)stepContext.Values["name"];
    userProfile.Age = (int)stepContext.Values["age"];
    userProfile.Picture = (Attachment)stepContext.Values["picture"];

    var msg = $"I have your mode of transport as {userProfile.Transport} and your name as {userProfile.Name}";

    if (userProfile.Age != -1)
    {
        msg += $" and your age as {userProfile.Age}";
    }

    msg += ".";

    await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);

    if (userProfile.Picture != null)
    {
        try
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Attachment(userProfile.Picture, "This is your profile picture."), cancellationToken);
        }
        catch
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Text("A profile picture was saved but could not be displayed here."), cancellationToken);

Jalankan dialog

Bot\DialogBot.cs

Handler OnMessageActivityAsync menggunakan RunAsync metode untuk memulai atau melanjutkan dialog. OnTurnAsync menggunakan objek manajemen status bot untuk mempertahankan perubahan status apa pun pada penyimpanan. Metode ini ActivityHandler.OnTurnAsync memanggil berbagai metode penanganan aktivitas, seperti OnMessageActivityAsync. Dengan cara ini, status disimpan setelah handler pesan selesai tetapi sebelum proses itu sendiri selesai.

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
    await base.OnTurnAsync(turnContext, cancellationToken);

    // Save any state changes that might have occurred during the turn.
    await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    Logger.LogInformation("Running dialog with Message Activity.");

    // Run the Dialog with the new message Activity.
    await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}

Mendaftarkan layanan untuk bot

Bot ini menggunakan layanan berikut:

  • Layanan dasar untuk bot: penyedia info masuk, adaptor, dan implementasi bot.
  • Layanan untuk mengelola status: penyimpanan, status pengguna, dan status percakapan.
  • Dialog yang akan digunakan bot.

Startup.cs

Daftarkan layanan untuk bot di Startup. Layanan ini tersedia untuk bagian lain dari kode melalui injeksi dependensi.

{
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpClient().AddControllers().AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
        });

        // Create the Bot Framework Authentication to be used with the Bot Adapter.
        services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

        // Create the Bot Adapter with error handling enabled.
        services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

        // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
        services.AddSingleton<IStorage, MemoryStorage>();

        // Create the User state. (Used in this bot's Dialog implementation.)
        services.AddSingleton<UserState>();

        // Create the Conversation state. (Used by the Dialog system itself.)
        services.AddSingleton<ConversationState>();

Catatan

Penyimpanan memori hanya digunakan untuk tujuan pengujian dan tidak ditujukan untuk penggunaan produksi. Pastikan untuk menggunakan jenis penyimpanan yang persisten untuk bot di lingkungan produksi.

Menguji bot

  1. Jika Anda belum melakukannya, instal Bot Framework Emulator.
  2. Jalankan sampel secara lokal di komputer Anda.
  3. Mulai Emulator, sambungkan ke bot Anda, dan kirim pesan seperti yang ditunjukkan di bawah ini.

Contoh transkrip percakapan dengan bot prompt multi-giliran.

Informasi Tambahan

Tentang dialog dan status bot

Dalam bot ini, didefinisikan dua pengakses properti status:

  • Satu dibuat dalam konteks status percakapan untuk properti status dialog. Keadaan dialog melacak di mana pengguna berada dalam rangkaian dialog, dan diubah oleh konteks dialog, seperti ketika metode mulai dialog atau lanjutkan dialog dipanggil.
  • Satu dibuat dalam status pengguna untuk properti profil pengguna. Bot menggunakan ini untuk melacak informasi yang dimilikinya tentang pengguna, dan Anda harus secara eksplisit mengelola status ini dalam kode dialog.

Metode dapatkan dan atur aksesor properti status mendapatkan dan mengatur nilai properti dalam cache objek manajemen status. Cache diisi pertama kali nilai properti status diminta secara bergantian, tetapi harus dipertahankan secara eksplisit. Untuk mempertahankan perubahan pada kedua properti status ini, panggilan ke metode simpan perubahan , dari objek manajemen status yang sesuai, dilakukan.

Sampel ini memperbarui status profil pengguna dari dalam dialog. Praktik ini dapat berfungsi untuk beberapa bot, tetapi tidak akan berfungsi jika Anda ingin menggunakan kembali dialog di seluruh bot.

Ada berbagai opsi untuk menjaga langkah-langkah dialog dan status bot terpisah. Misalnya, setelah dialog mengumpulkan informasi lengkap, Anda dapat:

  • Gunakan metode dialog akhir untuk menyediakan data yang dikumpulkan sebagai nilai pengembalian kembali ke konteks induk. Ini bisa menjadi penangan giliran bot atau dialog aktif sebelumnya pada tumpukan dialog. Seperti itulah cara kelas prompt dirancang.
  • Buat permintaan ke layanan yang sesuai. Ini mungkin berfungsi dengan baik jika bot Anda bertindak sebagai antarmuka dari layanan yang lebih besar.

Definisi metode validator perintah

UserProfileDialog.cs

Di bawah ini adalah contoh kode validator untuk AgePromptValidatorAsync definisi metode. promptContext.Recognized.Value berisi nilai yang diurai, di sini nilainya adalah bilangan bulat untuk permintaan angka. promptContext.Recognized.Succeeded menunjukkan apakah prompt dapat mengurai input pengguna atau tidak. Validator harus mengembalikan false untuk menunjukkan bahwa nilai tidak diterima dan dialog prompt harus meminta ulang pengguna; jika tidak, kembalikan true untuk menerima input dan keluar dari dialog prompt. Anda dapat mengubah nilai dalam validator per skenario Anda.

    }

    // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
    return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Is this ok?") }, cancellationToken);
}

Langkah berikutnya