Pola aplikasi berbasis agen

Ada dua pendekatan umum untuk membangun aplikasi agenik dengan AI:

  • Alur kerja deterministik — Kode Anda menentukan alur kontrol. Anda menulis urutan langkah, percabangan, paralelisme, dan penanganan kesalahan menggunakan konstruksi pemrograman standar. LLM melakukan pekerjaan di dalam setiap langkah tetapi tidak mengontrol alur keseluruhan.
  • Alur kerja yang diarahkan agen (perulangan agen) — LLM mendorong alur kontrol. Agen memutuskan alat mana yang akan dipanggil, dalam urutan apa, dan kapan tugas selesai. Anda menyediakan alat dan instruksi, tetapi agen menentukan jalur eksekusi saat runtime.

Kedua pendekatan mendapat manfaat dari eksekusi tahan lama dan dapat diimplementasikan menggunakan model pemrograman Tugas Tahan Lama. Artikel ini memperlihatkan cara membuat setiap pola dengan sampel kode siap pakai di C#, Python, JavaScript/TypeScript, dan Java.

Petunjuk / Saran

Prerequisites: Sebelum menggunakan pola ini, siapkan Durable Task SDK atau Durable Functions. Lihat gambaran umum SDK atau gambaran umum Durable Functions untuk memulai.

Pada halaman ini:

  • Prompt chaining — Langkah-langkah LLM berurutan dengan gerbang validasi
  • Perutean — Mengklasifikasikan dan mengirimkan ke agen khusus
  • Paralelisasi — Fan-out/fan-in untuk subtugas independen
  • Orchestrator-workers — Delegasi subtugas dinamis yang direncanakan LLM
  • Pengoptimal evaluator — Pembuatan berulang dan perulangan penyempurnaan
  • Perulangan agen — Perulangan panggilan alat yang dipandu oleh LLM (berbasis orkestrasi atau berbasis entitas)

Petunjuk / Saran

Pola-pola ini selaras dengan desain alur kerja agenik yang dijelaskan dalam Agen Efektif Bangunan Anthropic. Model pemrograman Tugas Tahan Lama memetakan secara alami ke pola-pola ini: orkestrasi menentukan alur kontrol alur kerja dan secara otomatis dicentang, sementara aktivitas membungkus operasi non-deterministik seperti panggilan LLM, pemanggilan alat, dan permintaan API.

Pilih pendekatan

Tabel berikut ini membantu Anda memutuskan kapan harus menggunakan setiap pendekatan.

Gunakan alur kerja deterministik ketika... Gunakan perulangan agen ketika...
Urutan langkah-langkah diketahui sebelumnya. Tugas ini terbuka dan langkah-langkahnya tidak dapat diprediksi.
Anda memerlukan pagar pembatas eksplisit atas perilaku agen. Anda ingin LLM memutuskan alat mana yang akan digunakan dan kapan.
Kepatuhan atau auditabilitas memerlukan alur kontrol yang dapat ditinjau. Agen perlu menyesuaikan pendekatannya berdasarkan hasil perantara.
Anda ingin menggabungkan beberapa kerangka kerja AI dalam satu alur kerja. Anda sedang membangun agen percakapan dengan kemampuan memanggil alat.

Kedua pendekatan menyediakan cek poin otomatis, kebijakan ulang coba, penskalaan terdistribusi, dan dukungan human-in-the-loop melalui eksekusi berkelanjutan.

Pola alur kerja deterministik

Dalam alur kerja deterministik, kode Anda mengontrol jalur eksekusi. LLM dipanggil sebagai langkah dalam alur kerja tetapi tidak memutuskan apa yang terjadi selanjutnya. Model pemrograman Durable Task sesuai secara alami dengan pendekatan ini.

  • Orkestrasi menentukan alur kontrol alur kerja (urutan, percabangan, paralelisme, penanganan kesalahan) dan secara otomatis dicentang.
  • Aktivitas membungkus operasi non-deterministik seperti panggilan LLM, pemanggilan alat, dan permintaan API. Aktivitas dapat berjalan pada instans komputasi yang tersedia.

Contoh berikut menggunakan Durable Functions, yang berjalan pada Azure Functions dengan hosting tanpa server.

Contoh berikut menggunakan SDK Tugas portabel Durable, yang berjalan pada komputasi host apa pun termasuk Azure Container Apps, Kubernetes, komputer virtual, atau secara lokal.

Pola penghubungan prompt

Rantai prompt adalah pola agenik paling sederhana. Anda memecah tugas kompleks menjadi serangkaian interaksi LLM berurutan, di mana setiap langkah output mengumpan ke input langkah berikutnya. Karena setiap panggilan aktivitas secara otomatis diperiksa, crash di tengah alur tidak memaksa Anda untuk memulai ulang dari awal dan mengonsumsi kembali token LLM yang mahal — eksekusi dilanjutkan dari langkah terakhir yang selesai.

Anda juga dapat menyisipkan gerbang validasi terprogram di antara langkah-langkah. Misalnya, setelah menghasilkan kerangka, Anda dapat memverifikasi bahwa kerangka memenuhi batasan panjang atau topik sebelum meneruskannya ke langkah penyusunan.

Pola ini memetakan langsung ke pola penautan fungsi dalam model pemrograman Durable Task.

Kapan menggunakan: Alur pembuatan konten, pemrosesan dokumen multi-langkah, pengayaan data berurutan, alur kerja yang memerlukan gerbang validasi menengah.

Nota

Dalam semua contoh berikut, status orkestrasi secara otomatis dicentang di setiap await/yield pernyataan. Jika proses host mengalami crash atau VM di-recycle, proses orkestrasi dilanjutkan dari langkah terakhir yang selesai daripada memulai kembali.

[Function(nameof(PromptChainingOrchestration))]
public async Task<string> PromptChainingOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var topic = context.GetInput<string>();

    // Step 1: Generate research outline
    string outline = await context.CallActivityAsync<string>(
        nameof(GenerateOutlineAgent), topic);

    // Step 2: Write first draft from outline
    string draft = await context.CallActivityAsync<string>(
        nameof(WriteDraftAgent), outline);

    // Step 3: Refine and polish the draft
    string finalContent = await context.CallActivityAsync<string>(
        nameof(RefineDraftAgent), draft);

    return finalContent;
}
[DurableTask]
public class PromptChainingOrchestration : TaskOrchestrator<string, string>
{
    public override async Task<string> RunAsync(
        TaskOrchestrationContext context, string topic)
    {
        // Step 1: Generate research outline
        string outline = await context.CallActivityAsync<string>(
            nameof(GenerateOutlineAgent), topic);

        // Step 2: Write first draft from outline
        string draft = await context.CallActivityAsync<string>(
            nameof(WriteDraftAgent), outline);

        // Step 3: Refine and polish the draft
        string finalContent = await context.CallActivityAsync<string>(
            nameof(RefineDraftAgent), draft);

        return finalContent;
    }
}

Pengaturan Rute

Perutean menggunakan langkah klasifikasi untuk menentukan agen atau model hilir mana yang harus menangani permintaan. Orkestrasi memanggil aktivitas pengklasifikasi terlebih dahulu, lalu bercabang ke handler yang sesuai berdasarkan hasilnya. Pendekatan ini memungkinkan Anda menyesuaikan permintaan, model, dan toolset setiap handler secara independen — misalnya, mengarahkan pertanyaan penagihan ke agen khusus dengan akses ke API pembayaran sambil mengirim pertanyaan umum ke model yang lebih ringan.

Kapan menggunakan: Triase dukungan pelanggan, klasifikasi niat untuk agen khusus, pemilihan model dinamis berdasarkan kompleksitas tugas.

[Function(nameof(RoutingOrchestration))]
public async Task<string> RoutingOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var request = context.GetInput<SupportRequest>();

    // Classify the request type
    string category = await context.CallActivityAsync<string>(
        nameof(ClassifyRequestAgent), request.Message);

    // Route to the appropriate specialized agent
    return category switch
    {
        "billing" => await context.CallActivityAsync<string>(
            nameof(BillingAgent), request),
        "technical" => await context.CallActivityAsync<string>(
            nameof(TechnicalSupportAgent), request),
        "general" => await context.CallActivityAsync<string>(
            nameof(GeneralInquiryAgent), request),
        _ => await context.CallActivityAsync<string>(
            nameof(GeneralInquiryAgent), request),
    };
}
[DurableTask]
public class RoutingOrchestration : TaskOrchestrator<SupportRequest, string>
{
    public override async Task<string> RunAsync(
        TaskOrchestrationContext context, SupportRequest request)
    {
        // Classify the request type
        string category = await context.CallActivityAsync<string>(
            nameof(ClassifyRequestAgent), request.Message);

        // Route to the appropriate specialized agent
        return category switch
        {
            "billing" => await context.CallActivityAsync<string>(
                nameof(BillingAgent), request),
            "technical" => await context.CallActivityAsync<string>(
                nameof(TechnicalSupportAgent), request),
            _ => await context.CallActivityAsync<string>(
                nameof(GeneralInquiryAgent), request),
        };
    }
}

Paralelisasi

Ketika Anda memiliki beberapa subtugas independen, Anda dapat mengirimkannya sebagai panggilan aktivitas paralel dan menunggu semua hasil sebelum melanjutkan. Penjadwal Tugas Tahan Lama mendistribusikan aktivitas ini di semua instans komputasi yang tersedia secara otomatis, yang berarti menambahkan lebih banyak pekerja secara langsung mengurangi total waktu jam dinding.

Varian umum adalah pemungutan suara multi-model: Anda mengirim perintah yang sama ke beberapa model (atau model yang sama dengan suhu yang berbeda) secara paralel, lalu mengagregasi atau memilih dari respons. Karena setiap cabang paralel secara independen dicheckpoint, kegagalan transien di satu cabang tidak memengaruhi yang lain.

Pola ini memetakan langsung ke pola fan-out/fan-in dalam Durable Task.

Kapan menggunakan: Analisis batch dokumen, panggilan alat paralel, evaluasi multi-model, moderasi konten dengan beberapa peninjau.

[Function(nameof(ParallelResearchOrchestration))]
public async Task<string> ParallelResearchOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var request = context.GetInput<ResearchRequest>();

    // Fan-out: research multiple subtopics in parallel
    var researchTasks = request.Subtopics
        .Select(subtopic => context.CallActivityAsync<string>(
            nameof(ResearchSubtopicAgent), subtopic))
        .ToList();
    string[] researchResults = await Task.WhenAll(researchTasks);

    // Aggregate: synthesize all research into a single summary
    string summary = await context.CallActivityAsync<string>(
        nameof(SynthesizeAgent),
        new { request.Topic, Research = researchResults });

    return summary;
}
[DurableTask]
public class ParallelResearchOrchestration : TaskOrchestrator<ResearchRequest, string>
{
    public override async Task<string> RunAsync(
        TaskOrchestrationContext context, ResearchRequest request)
    {
        // Fan-out: research multiple subtopics in parallel
        var researchTasks = request.Subtopics
            .Select(subtopic => context.CallActivityAsync<string>(
                nameof(ResearchSubtopicAgent), subtopic))
            .ToList();
        string[] researchResults = await Task.WhenAll(researchTasks);

        // Aggregate: synthesize all research into a single summary
        string summary = await context.CallActivityAsync<string>(
            nameof(SynthesizeAgent),
            new { request.Topic, Research = researchResults });

        return summary;
    }
}

Pola orkestrator-pekerja

Dalam pola ini, orkestrator pusat terlebih dahulu memanggil LLM (melalui aktivitas) untuk merencanakan pekerjaan. Berdasarkan output LLM, orkestrator kemudian menentukan subtugas apa yang diperlukan. Orkestrator kemudian mengirimkan subtugas tersebut ke orkestrasi pekerja khusus. Perbedaan utama dari paralelisasi adalah bahwa sekumpulan subtugas tidak tetap saat perancangan; orkestrator menentukannya secara dinamis saat waktu berjalan.

Pola ini menggunakan sub-orkestrasi, yang merupakan alur kerja anak yang di-checkpoint secara independen. Setiap orkestrasi pekerja dapat dengan sendirinya berisi beberapa langkah, percobaan ulang, dan paralelisme berlapis.

Kapan menggunakan: Alur penelitian mendalam, alur kerja agen pengkodian yang memodifikasi beberapa file, kolaborasi multi-agen di mana setiap agen memiliki peran yang berbeda.

[Function(nameof(OrchestratorWorkersOrchestration))]
public async Task<string> OrchestratorWorkersOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var request = context.GetInput<ResearchRequest>();

    // Central orchestrator: determine what research is needed
    string[] subtasks = await context.CallActivityAsync<string[]>(
        nameof(PlanResearchAgent), request.Topic);

    // Delegate to worker orchestrations in parallel
    var workerTasks = subtasks
        .Select(subtask => context.CallSubOrchestratorAsync<string>(
            nameof(ResearchWorkerOrchestration), subtask))
        .ToList();
    string[] results = await Task.WhenAll(workerTasks);

    // Synthesize results
    string finalReport = await context.CallActivityAsync<string>(
        nameof(SynthesizeAgent),
        new { request.Topic, Research = results });

    return finalReport;
}
[DurableTask]
public class OrchestratorWorkersOrchestration : TaskOrchestrator<ResearchRequest, string>
{
    public override async Task<string> RunAsync(
        TaskOrchestrationContext context, ResearchRequest request)
    {
        // Central orchestrator: determine what research is needed
        string[] subtasks = await context.CallActivityAsync<string[]>(
            nameof(PlanResearchAgent), request.Topic);

        // Delegate to worker orchestrations in parallel
        var workerTasks = subtasks
            .Select(subtask => context.CallSubOrchestratorAsync<string>(
                nameof(ResearchWorkerOrchestration), subtask))
            .ToList();
        string[] results = await Task.WhenAll(workerTasks);

        // Synthesize results
        string finalReport = await context.CallActivityAsync<string>(
            nameof(SynthesizeAgent),
            new { request.Topic, Research = results });

        return finalReport;
    }
}

Pola evaluator-pengoptimal

Pola pengoptimal evaluator memasangkan agen generator dengan agen evaluator dalam perulangan perbaikan. Generator menghasilkan output, evaluator menilainya terhadap kriteria kualitas dan memberikan umpan balik, dan perulangan berulang sampai output lolos atau jumlah perulangan maksimum tercapai. Karena setiap iterasi perulangan disimpan, kerusakan sistem setelah tiga putaran penyempurnaan yang berhasil tidak akan menghilangkan kemajuan tersebut.

Pola ini sangat berguna ketika kualitas dapat diukur secara terprogram — misalnya, memvalidasi kompilasi kode yang dihasilkan, atau bahwa terjemahan mempertahankan entitas bernama.

Kapan menggunakan: Pembuatan kode dengan tinjauan otomatis, terjemahan sastra, penyempurnaan konten berulang, tugas pencarian kompleks yang memerlukan beberapa putaran analisis.

[Function(nameof(EvaluatorOptimizerOrchestration))]
public async Task<string> EvaluatorOptimizerOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var request = context.GetInput<ContentRequest>();
    int maxIterations = 5;
    string content = "";
    string feedback = "";

    for (int i = 0; i < maxIterations; i++)
    {
        // Generate or refine content
        content = await context.CallActivityAsync<string>(
            nameof(GenerateContentAgent),
            new { request.Prompt, PreviousContent = content, Feedback = feedback });

        // Evaluate quality
        var evaluation = await context.CallActivityAsync<EvaluationResult>(
            nameof(EvaluateContentAgent), content);

        if (evaluation.MeetsQualityBar)
            return content;

        feedback = evaluation.Feedback;
    }

    return content; // Return best effort after max iterations
}
[DurableTask]
public class EvaluatorOptimizerOrchestration : TaskOrchestrator<ContentRequest, string>
{
    public override async Task<string> RunAsync(
        TaskOrchestrationContext context, ContentRequest request)
    {
        int maxIterations = 5;
        string content = "";
        string feedback = "";

        for (int i = 0; i < maxIterations; i++)
        {
            // Generate or refine content
            content = await context.CallActivityAsync<string>(
                nameof(GenerateContentAgent),
                new { request.Prompt, PreviousContent = content, Feedback = feedback });

            // Evaluate quality
            var evaluation = await context.CallActivityAsync<EvaluationResult>(
                nameof(EvaluateContentAgent), content);

            if (evaluation.MeetsQualityBar)
                return content;

            feedback = evaluation.Feedback;
        }

        return content; // Return best effort after max iterations
    }
}

Perulangan agen

Dalam implementasi agen AI yang khas, LLM dipanggil berulang kali, memanggil alat dan membuat keputusan sampai tugas selesai atau kondisi penghentian tercapai. Tidak seperti alur kerja deterministik, jalur eksekusi tidak ditentukan sebelumnya. Agen menentukan apa yang harus dilakukan pada setiap langkah berdasarkan hasil dari langkah-langkah sebelumnya.

Perulangan agen sangat cocok untuk tugas di mana jumlah atau urutan langkah tidak dapat diprediksi. Contoh umum termasuk agen pengodean terbuka, penelitian otonom, dan bot percakapan dengan kemampuan panggilan alat.

Ada dua pendekatan yang direkomendasikan untuk menerapkan perulangan agen dengan model pemrograman Durable Task.

Pendekatan Deskripsi Kapan digunakan
Berbasis orkestrasi Perulangan agen adalah orkestrasi kokoh. Panggilan alat adalah kegiatan; masukan manusia melibatkan kejadian eksternal. Kontrol halus, kebijakan coba lagi per alat, eksekusi alat terdistribusi, penelusuran kesalahan IDE.
Berbasis entitas Setiap instans agen adalah entitas yang tahan lama. Kerangka agen mengendalikan siklus; entitas memastikan ketahanan sesi. Anda menggunakan kerangka kerja (seperti Microsoft Agent Framework) yang sudah memiliki perulangan agen dan Anda ingin menambahkan durabilitas dengan perubahan minimal.

Loop agen berbasis orkestrasi

Perulangan agen berbasis orkestrasi menggabungkan beberapa kemampuan Durable Task: orkestrasi kekal (lanjutkan sebagai baru) untuk menjaga memori tetap terikat, fan-out/fan-in untuk eksekusi alat paralel, dan peristiwa eksternal untuk interaksi human-in-the-loop. Setiap iterasi dari perulangan

  1. Mengirim konteks percakapan saat ini ke LLM melalui aktivitas atau entitas stateful.
  2. Menerima respons LLM, yang mungkin mencakup panggilan alat.
  3. Menjalankan pemanggilan alat apa pun sebagai aktivitas (didistribusikan di seluruh sumber daya komputasi yang tersedia).
  4. Secara opsional menunggu input manusia menggunakan peristiwa eksternal.
  5. Melanjutkan perulangan dengan status yang diperbarui, atau akan selesai ketika agen memberi sinyal bahwa tugas sudah selesai.
[Function(nameof(AgentLoopOrchestration))]
public async Task<string> AgentLoopOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    // Get state from input (supports continue-as-new)
    var state = context.GetInput<AgentState>() ?? new AgentState();

    int maxIterations = 100;
    while (state.Iteration < maxIterations)
    {
        // Send conversation history to the LLM
        var llmResponse = await context.CallActivityAsync<LlmResponse>(
            nameof(CallLlmAgent), state.Messages);

        state.Messages.Add(llmResponse.Message);

        // If the LLM returned tool calls, execute them in parallel
        if (llmResponse.ToolCalls is { Count: > 0 })
        {
            var toolTasks = llmResponse.ToolCalls
                .Select(tc => context.CallActivityAsync<ToolResult>(
                    nameof(ExecuteTool), tc))
                .ToList();
            ToolResult[] toolResults = await Task.WhenAll(toolTasks);

            foreach (var result in toolResults)
                state.Messages.Add(result.ToMessage());
        }
        // If the LLM needs human input, wait for it
        else if (llmResponse.NeedsHumanInput)
        {
            string humanInput = await context.WaitForExternalEvent<string>("HumanInput");
            state.Messages.Add(new Message("user", humanInput));
        }
        // LLM is done
        else
        {
            return llmResponse.FinalAnswer;
        }

        state.Iteration++;

        // Periodically continue-as-new to keep the history bounded
        if (state.Iteration % 10 == 0)
        {
            context.ContinueAsNew(state);
            return null!; // Orchestration will restart with updated state
        }
    }

    return "Max iterations reached.";
}
[DurableTask]
public class AgentLoopOrchestration : TaskOrchestrator<AgentState, string>
{
    public override async Task<string> RunAsync(
        TaskOrchestrationContext context, AgentState? state)
    {
        state ??= new AgentState();

        int maxIterations = 100;
        while (state.Iteration < maxIterations)
        {
            // Send conversation history to the LLM
            var llmResponse = await context.CallActivityAsync<LlmResponse>(
                nameof(CallLlmAgent), state.Messages);

            state.Messages.Add(llmResponse.Message);

            // If the LLM returned tool calls, execute them
            if (llmResponse.ToolCalls is { Count: > 0 })
            {
                var toolTasks = llmResponse.ToolCalls
                    .Select(tc => context.CallActivityAsync<ToolResult>(
                        nameof(ExecuteTool), tc))
                    .ToList();
                ToolResult[] toolResults = await Task.WhenAll(toolTasks);

                foreach (var result in toolResults)
                    state.Messages.Add(result.ToMessage());
            }
            // If the LLM needs human input, wait for it
            else if (llmResponse.NeedsHumanInput)
            {
                string humanInput = await context.WaitForExternalEvent<string>("HumanInput");
                state.Messages.Add(new Message("user", humanInput));
            }
            // LLM is done
            else
            {
                return llmResponse.FinalAnswer;
            }

            state.Iteration++;

            // Periodically continue-as-new to keep the history bounded
            if (state.Iteration % 10 == 0)
            {
                context.ContinueAsNew(state);
                return null!;
            }
        }

        return "Max iterations reached.";
    }
}

Perulangan agen berbasis entitas

Jika Anda menggunakan kerangka kerja agen yang sudah menerapkan perulangan agennya sendiri, Anda dapat membungkusnya dalam entitas yang tahan lama untuk menambahkan durabilitas tanpa menulis ulang logika perulangan. Setiap instans entitas mewakili sesi agen tunggal. Entitas menerima pesan, mendelegasikan ke kerangka kerja agen secara internal, dan mempertahankan status percakapan di seluruh interaksi.

Keuntungan utama dari pendekatan ini adalah kesederhanaan: Anda menulis agen Anda menggunakan kerangka kerja pilihan Anda dan menambahkan durabilitas sebagai masalah hosting daripada mendesain ulang alur kontrol agen. Entitas bertindak sebagai pembungkus tahan lama, menangani persistensi sesi dan pemulihan secara otomatis.

Contoh berikut menunjukkan cara membungkus SDK agen yang ada sebagai entitas yang tahan lama. Entitas mengekspos operasi message yang dipanggil klien untuk mengirim input pengguna. Secara internal, entitas mendelegasikan ke kerangka agen, yang mengelola loop pemanggilan alatnya sendiri.

// Define the entity that wraps an existing agent SDK
public class ChatAgentEntity : TaskEntity<ChatAgentState>
{
    private readonly IChatClient _chatClient;

    public ChatAgentEntity(IChatClient chatClient)
    {
        _chatClient = chatClient;
    }

    // Called by clients to send a message to the agent
    public async Task<string> Message(string userMessage)
    {
        // Add the user message to the conversation history
        State.Messages.Add(new ChatMessage(ChatRole.User, userMessage));

        // Delegate to the agent SDK for the LLM call (with tool loop)
        ChatResponse response = await _chatClient.GetResponseAsync(
            State.Messages, State.Options);

        // Persist the response in the entity state
        State.Messages.AddRange(response.Messages);

        return response.Text;
    }

    // Azure Functions entry point for the entity
    [Function(nameof(ChatAgentEntity))]
    public Task RunEntityAsync([EntityTrigger] TaskEntityDispatcher dispatcher)
    {
        return dispatcher.DispatchAsync<ChatAgentEntity>();
    }
}
// Define the entity that wraps an existing agent SDK
[DurableTask(Name = "ChatAgent")]
public class ChatAgentEntity : TaskEntity<ChatAgentState>
{
    private readonly IChatClient _chatClient;

    public ChatAgentEntity(IChatClient chatClient)
    {
        _chatClient = chatClient;
    }

    // Called by clients to send a message to the agent
    public async Task<string> Message(string userMessage)
    {
        // Add the user message to the conversation history
        State.Messages.Add(new ChatMessage(ChatRole.User, userMessage));

        // Delegate to the agent SDK for the LLM call (with tool loop)
        ChatResponse response = await _chatClient.GetResponseAsync(
            State.Messages, State.Options);

        // Persist the response in the entity state
        State.Messages.AddRange(response.Messages);

        return response.Text;
    }
}

Ekstensi Tugas Durable untuk Microsoft Agent Framework menggunakan pendekatan ini. Ini membungkus Microsoft Agent Framework sebagai entitas yang stabil, menyediakan sesi persisten, titik pemeriksaan otomatis, dan titik akhir API bawaan hanya dengan satu baris konfigurasi.

Langkah berikutnya