客服專員背景回應

Microsoft 代理程式架構支援背景回應,以處理可能需要時間才能完成的長時間執行作業。 此功能可讓代理程式開始處理要求,並傳回可用來輪詢結果或繼續中斷串流的延續權杖。

Tip

如需完整的工作範例,請參閱 背景回應範例。

何時使用背景回應

背景回應特別適用於:

  • 需要大量處理時間的複雜推理任務
  • 可能因網路問題或用戶端逾時而中斷的作業
  • 您想要啟動長時間執行的工作,稍後再回來查看結果的案例

背景回應的運作方式

背景回應會使用 接續權杖 機制來處理長時間執行的作業。 當您將請求傳送給已啟用背景回應的客服專員時,會發生以下兩種情況之一:

  1. 立即完成:代理程式快速完成任務並傳回最終回應,無需延續權杖
  2. 背景處理:代理程式在背景開始處理,並傳回延續權杖,而不是最終結果

接續權杖包含所有必要的資訊,以使用非串流代理程式 API 輪詢完成,或使用串流代理程式 API 繼續中斷的串流。 缺少令牌(null在 .NET、 None Python 或 Go 中為空字串)表示操作已完成、失敗,或無法繼續,例如當需要使用者輸入時。

啟用背景回應

若要啟用背景回應,請將AllowBackgroundResponses屬性設定true為 AgentRunOptions :

using Microsoft.Agents.AI;

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

備註

目前,只有使用 OpenAI 回應 API 的代理程式支援背景回應: OpenAI 回應代理程式 和 Azure OpenAI 回應代理程式。

某些代理程式可能不允許明確控制背景回應。 這些代理程式可以根據操作的複雜性自主決定是否啟動後台響應,無論設置如何 AllowBackgroundResponses 。

非串流背景回應

針對非串流案例,當您一開始執行代理程式時,它可能會或可能不會傳回接續權杖。 如果未傳回接續權杖,則表示作業已完成。 如果傳回接續權杖,則表示代理程式已起始仍在處理中的背景回應,且需要輪詢才能擷取最終結果:

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);

Warning

DefaultAzureCredential 開發方便,但在生產過程中需謹慎考量。 在生產環境中,建議使用特定的憑證(例如 ManagedIdentityCredential),以避免延遲問題、意外的憑證探測,以及備援機制帶來的安全風險。

重點:

  • 初始呼叫可能會立即完成 (沒有接續權杖) 或啟動背景作業 (使用接續權杖)
  • 如果未傳回任何延續權杖,則作業已完成,且回應包含最終結果
  • 如果傳回接續權杖,則代理程式已啟動需要輪詢的背景程式
  • 在後續輪詢呼叫中使用先前回應的接續權杖
  • 當 ContinuationToken 時, null操作完成

串流背景回應

在串流案例中,背景回應的運作方式與一般串流回應非常相似 - 代理程式會將所有更新即時串流回取用者。 不過,主要差異在於,如果原始串流中斷,代理程式會透過延續權杖支援串流恢復。 每個更新都包含一個接續權杖,可擷取目前狀態,透過將此權杖傳遞至後續的串流 API 呼叫,允許從中斷的位置繼續串流:

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);
}

重點:

  • 每個 AgentResponseUpdate 都包含可用於恢復的接續權杖
  • 儲存中斷前上次收到更新的接續權杖
  • 使用儲存的接續權杖從中斷點繼續串流

Tip

完整可執行範例請參閱 .NET 範例 。

Tip

如需完整的工作範例,請參閱 背景回應範例。

啟用背景回應

要啟用背景回應,請在呼叫background時傳遞選項agent.run():

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

備註

由 OpenAI 回應 API、Azure OpenAI 回應 API 或 Microsoft Foundry 支援的 Python 代理程式支援背景回應。

背景 FoundryChatClient回應可透過提供者端回應儲存(store=True)或無狀態重播(store=False)執行本地函式工具。 輪詢時保持同一個會話,讓恢復的回應能繼續本地工具迴圈。

非串流背景回應

對於非串流情境,當你最初運行一個代理人時 background=True,它可能會立即返回 continuation_token。 若 continuation_token , None則操作完成。 否則,透過後續呼叫回傳權杖來輪詢:

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)

重點

  • 初始呼叫可能會立即完成 (沒有接續權杖) 或啟動背景作業 (使用接續權杖)
  • 在後續的投票呼叫中,請使用前一個回應的選項continuation_token
  • 當 continuation_token 時, None操作完成

串流背景回應

在串流情境中,背景回應的運作方式類似一般串流——客服會即時回傳更新。 主要差異在於每次更新都包含一個 continuation_token,若連線中斷,則可恢復串流:

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

恢復中斷串流

如果串流中斷,請用最後一個 continuation_token 從中止點繼續:

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)

重點

  • 每個 AgentResponseUpdate S 都包含 一個 continuation_token ,用於恢復
  • 將中斷前最後一次收到的更新的權杖存入
  • 將儲存的權杖傳遞以 options={"continuation_token": token} 繼續

啟用背景回應

在開始執行時 Pass agent.AllowBackgroundResponses(true) ,並透過 重複使用一個明確的會話 agent.WithSession(session)。 提供者與部署必須支援背景執行;設定這個選項並不會讓每個代理都變成非同步。

非串流背景回應

啟動操作,然後在還沒空的時候輪詢 response.ContinuationToken 。 繼續時,非a.Run(ctx, nil, ...)RunText:續接呼叫不得包含新訊息。

維護的 Azure OpenAI 回應範例會限制操作時間,投票間隔等待,取消後會立即停止:

// 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)
}

設定 AZURE_OPENAI_ENDPOINT 和 AZURE_OPENAI_DEPLOYMENT_NAME,並在執行此範例前使用 Azure 憑證進行認證。 投票結束後,它會列印完成的回應。 立即完成的回應沒有延續標記,也不需要輪詢。

串流背景回應

開始一個串流跑,和agent.Stream(true)agent.AllowBackgroundResponses(true)。 保留你收到的最後更新的續集標記。 若連線中斷,請繼續且不發送新訊息:

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())
}

只有當儲存的代幣不是空的時才繼續。 若操作必須在程序重啟後存活,請將會話與令牌同時保存在應用程式儲存中。

使用背景回應搭配 Harness Agent

Harness Agent 仍是標準的 Agent Framework 代理,因此提供者背景回應使用上述相同的每次執行選項。 利用架構不會自動啟用提供者背景回應:在 .NET、 options={"background": True} Python agent.AllowBackgroundResponses(true) 或 Go 中啟動執行時設定AllowBackgroundResponses。 當操作必須在程序重啟後存活時,保留會話並持續使用延續標記。

這與 背景代理人是分開的,背景代理人會將工作委派給兒童代理人,而非持續單一提供者的請求。

最佳做法

使用背景回應時,請考慮下列最佳實務:

  • 實作適當的輪詢間隔 ,以避免服務不堪重負
  • 如果作業花費的時間比預期長,請使用指數輪詢間隔
  • 檢查是否有缺少延續標記 (null、 None,或空的 Go 字串),以判斷處理是否完成
  • 請考慮持續儲存接續權杖 ,以取得可能跨越使用者工作階段的作業

限制與注意事項

  • 背景回應取決於支援長時間執行作業的基礎 AI 服務
  • 並非所有客服專員類型都支援背景回應
  • 網路中斷或用戶端重新啟動可能需要特殊處理才能保存接續權杖

下一步