Risposte in background dell'agente

Microsoft Agent Framework supporta le risposte in background per la gestione delle operazioni a esecuzione prolungata che potrebbero richiedere tempo per il completamento. Questa funzionalità consente agli agenti di avviare l'elaborazione di una richiesta e restituire un token di continuazione che può essere usato per eseguire il polling dei risultati o riprendere i flussi interrotti.

Tip

Per un esempio funzionante completo, vedere l'esempio di risposte in background.

Quando usare le risposte in background

Le risposte in background sono particolarmente utili per:

  • Attività di ragionamento complesse che richiedono tempi di elaborazione significativi
  • Operazioni che possono essere interrotte da problemi di rete o timeout client
  • Scenari in cui si vuole avviare un'attività a esecuzione prolungata e verificare di nuovo i risultati in un secondo momento

Funzionamento delle risposte in background

Le risposte in background usano un meccanismo di token di continuazione per gestire le operazioni a esecuzione prolungata. Quando si invia una richiesta a un agente con risposte in background abilitate, si verifica una delle due operazioni seguenti:

  1. Completamento immediato: l'agente completa rapidamente l'attività e restituisce la risposta finale senza un token di continuazione
  2. Elaborazione in background: l'agente avvia l'elaborazione in background e restituisce un token di continuazione anziché il risultato finale

Il token di continuazione contiene tutte le informazioni necessarie per eseguire il polling per il completamento usando l'API dell'agente non di streaming o riprendere un flusso interrotto con l'API dell'agente di streaming. Un token assente (null in .NET, None in Python o una stringa vuota in Go) indica che l'operazione è stata completata, non è riuscita o non può continuare, ad esempio, quando è necessario l'input dell'utente.

Abilitazione delle risposte in background

Per abilitare le risposte in background, impostare la AllowBackgroundResponses proprietà su true in AgentRunOptions:

using Microsoft.Agents.AI;

AgentRunOptions options = new()
{
    AllowBackgroundResponses = true
};

Annotazioni

Attualmente, solo gli agenti che usano l'API Risposte OpenAI supportano le risposte in background: Agente risposte OpenAI e Agente risposte OpenAI di Azure.

Alcuni agenti potrebbero non consentire il controllo esplicito sulle risposte in background. Questi agenti possono decidere autonomamente se avviare una risposta in background in base alla complessità dell'operazione, indipendentemente dall'impostazione AllowBackgroundResponses .

Risposte in background non in streaming

Per gli scenari non di streaming, quando si esegue inizialmente un agente, potrebbe o meno restituire un token di continuazione. Se non viene restituito alcun token di continuazione, significa che l'operazione è stata completata. Se viene restituito un token di continuazione, indica che l'agente ha avviato una risposta in background ancora in fase di elaborazione e richiederà il polling per recuperare il risultato finale:

using System;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;

AIAgent agent = new AIProjectClient(
    new Uri("<your-foundry-project-endpoint>"),
    new DefaultAzureCredential())
    .AsAIAgent(
        model: "<deployment-name>",
        instructions: "You are a helpful assistant.");

AgentRunOptions options = new()
{
    AllowBackgroundResponses = true
};

AgentSession session = await agent.CreateSessionAsync();

// Get initial response - may return with or without a continuation token.
AgentResponse response = await agent.RunAsync(
    "Write a very long novel about otters in space.",
    session,
    options);

// Continue to poll until the final response is received
while (response.ContinuationToken is not null)
{
    // Wait before polling again.
    await Task.Delay(TimeSpan.FromSeconds(2));

    options.ContinuationToken = response.ContinuationToken;
    response = await agent.RunAsync(session, options);
}

Console.WriteLine(response.Text);

Avvertimento

DefaultAzureCredential è utile per lo sviluppo, ma richiede un'attenta considerazione nell'ambiente di produzione. Nell'ambiente di produzione prendere in considerazione l'uso di credenziali specifiche ,ad esempio ManagedIdentityCredential, per evitare problemi di latenza, probe di credenziali indesiderate e potenziali rischi per la sicurezza dai meccanismi di fallback.

Punti chiave:

  • La chiamata iniziale può essere completata immediatamente (nessun token di continuazione) o avviare un'operazione in background (con token di continuazione)
  • Se non viene restituito alcun token di continuazione, l'operazione viene completata e la risposta contiene il risultato finale
  • Se viene restituito un token di continuazione, l'agente ha avviato un processo in background che richiede il polling
  • Usare il token di continuazione della risposta precedente nelle chiamate di polling successive
  • Quando ContinuationToken è null, l'operazione è stata completata

Streaming delle risposte in background

Negli scenari di streaming, le risposte in background funzionano in modo molto simile alle risposte di streaming regolari: l'agente trasmette tutti gli aggiornamenti ai consumer in tempo reale. Tuttavia, la differenza principale è che se il flusso originale viene interrotto, gli agenti supportano la ripresa del flusso tramite token di continuazione. Ogni aggiornamento include un token di continuazione che acquisisce lo stato corrente, consentendo al flusso di essere ripreso esattamente da dove è stato interrotto passando questo token alle chiamate API di streaming successive:

using System;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;

AIAgent agent = new AIProjectClient(
    new Uri("<your-foundry-project-endpoint>"),
    new DefaultAzureCredential())
    .AsAIAgent(
        model: "<deployment-name>",
        instructions: "You are a helpful assistant.");

AgentRunOptions options = new()
{
    AllowBackgroundResponses = true
};

AgentSession session = await agent.CreateSessionAsync();

AgentResponseUpdate? latestReceivedUpdate = null;

await foreach (var update in agent.RunStreamingAsync(
    "Write a very long novel about otters in space.",
    session,
    options))
{
    Console.Write(update.Text);

    latestReceivedUpdate = update;

    // Simulate an interruption
    break;
}

// Resume from interruption point captured by the continuation token
options.ContinuationToken = latestReceivedUpdate?.ContinuationToken;
await foreach (var update in agent.RunStreamingAsync(session, options))
{
    Console.Write(update.Text);
}

Punti chiave:

  • Ogni AgentResponseUpdate contiene un token di continuazione che può essere usato per la ripresa
  • Archiviare il token di continuazione dall'ultimo aggiornamento ricevuto prima dell'interruzione
  • Usare il token di continuazione archiviato per riprendere il flusso dal punto di interruzione

Tip

Per un esempio funzionante completo, vedere l'esempio di risposte in background.

Abilitazione delle risposte in background

Per abilitare le risposte in background, passare l'opzione background quando si chiama agent.run():

session = agent.create_session()
response = await agent.run(
    messages="Your prompt here",
    session=session,
    options={"background": True},
)

Annotazioni

Python agenti supportati dall'API Risposte OpenAI, Azure API Risposte OpenAI o Microsoft Foundry supportano le risposte in background.

Con FoundryChatClient, le risposte in background possono eseguire strumenti di funzione locali con l'archiviazione delle risposte lato provider (store=True) o la riproduzione senza stato (store=False). Mantenere la stessa sessione durante il polling in modo che la risposta ripresa possa continuare il ciclo dello strumento locale.

Risposte in background non in streaming

Per gli scenari non di streaming, quando si esegue inizialmente un agente con background=True, può restituire immediatamente con .continuation_token Se continuation_token è None, l'operazione è stata completata. In caso contrario, eseguire il polling passando di nuovo il token nelle chiamate successive:

import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

agent = Agent(
    name="researcher",
    instructions="You are a helpful research assistant.",
    client=OpenAIChatClient(model="o3"),
)

session = agent.create_session()

# Start a background run — returns immediately
response = await agent.run(
    messages="Briefly explain the theory of relativity in two sentences.",
    session=session,
    options={"background": True},
)

# Poll until the operation completes
while response.continuation_token is not None:
    await asyncio.sleep(2)
    response = await agent.run(
        session=session,
        options={"continuation_token": response.continuation_token},
    )

# Done — response.text contains the final result
print(response.text)

Punti chiave

  • La chiamata iniziale può essere completata immediatamente (nessun token di continuazione) o avviare un'operazione in background (con token di continuazione)
  • Usare dalla continuation_token risposta precedente nelle chiamate di polling successive
  • Quando continuation_token è None, l'operazione è stata completata

Streaming delle risposte in background

Negli scenari di streaming, le risposte in background funzionano come lo streaming normale, ovvero l'agente trasmette gli aggiornamenti in tempo reale. La differenza principale è che ogni aggiornamento include un continuation_token, abilitando la ripresa del flusso se la connessione viene interrotta:

session = agent.create_session()

# Start a streaming background run
last_token = None
stream = agent.run(
    messages="Briefly list three benefits of exercise.",
    stream=True,
    session=session,
    options={"background": True},
)

# Read chunks — each update carries a continuation_token
async for update in stream:
    last_token = update.continuation_token
    if update.text:
        print(update.text, end="", flush=True)
    # If interrupted (e.g., network issue), break and resume later

Ripresa di un flusso interrotto

Se il flusso viene interrotto, usare l'ultimo continuation_token per riprendere da dove è stato interrotto:

if last_token is not None:
    stream = agent.run(
        stream=True,
        session=session,
        options={"continuation_token": last_token},
    )
    async for update in stream:
        if update.text:
            print(update.text, end="", flush=True)

Punti chiave

  • Ognuno AgentResponseUpdate contiene un oggetto continuation_token per la ripresa
  • Archiviare il token dall'ultimo aggiornamento ricevuto prima dell'interruzione
  • Passare il token archiviato tramite options={"continuation_token": token} per riprendere

Abilitare le risposte in background

Passare agent.AllowBackgroundResponses(true) quando si avvia un'esecuzione e riutilizzare una sessione esplicita tramite agent.WithSession(session). Il provider e la distribuzione devono supportare l'esecuzione in background; l'impostazione dell'opzione non rende asincrono ogni agente.

Risposte in background non in streaming

Avviare l'operazione, quindi eseguire il polling mentre response.ContinuationToken non è vuoto. Continuare con a.Run(ctx, nil, ...), non RunText: le chiamate di continuazione non devono contenere nuovi messaggi.

L'esempio di risposte OpenAI gestite Azure delimita l'operazione con un timeout, attende tra i sondaggi e si arresta immediatamente all'annullamento:

// Copyright (c) Microsoft. All rights reserved.

// This sample demonstrates long-running agent operations using the OpenAI
// Responses API "background" option. A background run returns quickly with a
// continuation token instead of the final answer; the caller then polls with
// that token until the operation completes.
//
// Ported from the Python getting-started "background responses" sample.
package main

import (
    "context"
    "time"

    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/examples/internal/demo"
    "github.com/microsoft/agent-framework-go/provider/openaiprovider"
    "github.com/openai/openai-go/v3"
    "github.com/openai/openai-go/v3/azure"
    "github.com/openai/openai-go/v3/option"
)

var logger = demo.NewLogger(
    "Background Responses",
    "Starts a background Responses run and polls with the continuation token until it completes.",
    "Model", demo.Deployment,
)

func main() {
    // Bound the whole sample so a run that never completes (stuck queued, a bad
    // continuation token, etc.) cannot hang indefinitely.
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
    defer cancel()

    token := demo.AzureTokenCredential()

    client := openai.NewClient(
        option.WithBaseURL(demo.Endpoint),
        azure.WithTokenCredential(token),
    )

    researcher := openaiprovider.NewResponsesAgent(
        client,
        openaiprovider.AgentConfig{
            Model:        demo.Deployment,
            Instructions: "You are a helpful research assistant. Be concise.",
            Config: agent.Config{
                Name:        "Researcher",
                Middlewares: []agent.Middleware{logger},
            },
        },
    )

    // Background runs are tied to a session so that follow-up polls target the
    // same operation.
    session, err := researcher.CreateSession(ctx)
    if err != nil {
        demo.Panic(err)
    }

    // Start a background run. It returns quickly with a continuation token
    // rather than the final answer. (If the model or endpoint does not support
    // background execution, the run simply completes inline with no token.)
    resp, err := researcher.RunText(ctx,
        "Briefly explain the theory of relativity in two sentences.",
        agent.WithSession(session),
        agent.AllowBackgroundResponses(true),
    ).Collect()
    if err != nil {
        demo.Panic(err)
    }

    // Poll until the operation completes — i.e. until a run no longer returns a
    // continuation token. Continuation runs must not carry any messages, so use
    // Run with a nil message slice.
    for resp.ContinuationToken != "" {
        // Wait between polls, but stop promptly if the context is cancelled or
        // its deadline is reached rather than sleeping through it.
        select {
        case <-ctx.Done():
            demo.Panic(ctx.Err())
        case <-time.After(2 * time.Second):
        }
        resp, err = researcher.Run(ctx, nil,
            agent.WithSession(session),
            agent.WithContinuationToken(resp.ContinuationToken),
        ).Collect()
        if err != nil {
            demo.Panic(err)
        }
    }

    // The final response holds the completed result.
    demo.Response(resp, nil)
}

Impostare AZURE_OPENAI_ENDPOINT e AZURE_OPENAI_DEPLOYMENT_NAMEe eseguire l'autenticazione con una credenziale Azure prima di eseguire questo esempio. Stampa la risposta completata al termine del polling. Una risposta immediatamente completata non ha token di continuazione e non richiede il polling.

Streaming delle risposte in background

Avviare un'esecuzione di streaming con agent.Stream(true) e agent.AllowBackgroundResponses(true). Mantenere il token di continuazione dall'ultimo aggiornamento ricevuto. Se la connessione viene interrotta, riprendere senza nuovi messaggi:

for update, err := range a.Run(
    ctx,
    nil,
    agent.WithSession(session),
    agent.WithContinuationToken(lastToken),
    agent.Stream(true),
) {
    if err != nil {
        panic(err)
    }
    lastToken = update.ContinuationToken
    fmt.Print(update.String())
}

Riprendere solo quando il token salvato non è vuoto. Mantenere sia la sessione che il token nell'archiviazione dell'applicazione se l'operazione deve sopravvivere a un riavvio del processo.

Usare le risposte in background con l'agente Harness

Un agente Harness rimane un agente di Agent Framework standard, quindi le risposte in background del provider usano le stesse opzioni per esecuzione documentate in precedenza. La costruzione di harness non abilita automaticamente le risposte in background del provider: impostate AllowBackgroundResponses in .NET, options={"background": True} in Python o agent.AllowBackgroundResponses(true) in Go all'avvio dell'esecuzione. Mantenere la sessione e rendere persistenti i token di continuazione quando l'operazione deve sopravvivere a un riavvio del processo.

Questa operazione è separata dagli agenti in background, che delegano il lavoro agli agenti figlio anziché continuare una richiesta del provider.

Migliori pratiche

Quando si lavora con le risposte in background, prendere in considerazione le procedure consigliate seguenti:

  • Implementare intervalli di polling appropriati per evitare di sovraccaricare il servizio
  • Usare il backoff esponenziale per gli intervalli di polling se l'operazione richiede più tempo del previsto
  • Verificare la presenza di un token di continuazione assente (null, Noneo una stringa Go vuota) per determinare quando l'elaborazione è stata completata
  • Prendere in considerazione l'archiviazione permanente dei token di continuazione per le operazioni che possono estendersi su sessioni utente

Limitazioni e considerazioni

  • Le risposte in background dipendono dal servizio di intelligenza artificiale sottostante che supporta le operazioni a esecuzione prolungata
  • Non tutti i tipi di agente possono supportare risposte in background
  • Le interruzioni di rete o i riavvii del client possono richiedere una gestione speciale per rendere persistenti i token di continuazione

Passaggi successivi

RAG