Microsoft 代理程式架構支援背景回應,以處理可能需要時間才能完成的長時間執行作業。 此功能可讓代理程式開始處理要求,並傳回可用來輪詢結果或繼續中斷串流的延續權杖。
Tip
如需完整的工作範例,請參閱 背景回應範例。
何時使用背景回應
背景回應特別適用於:
- 需要大量處理時間的複雜推理任務
- 可能因網路問題或用戶端逾時而中斷的作業
- 您想要啟動長時間執行的工作,稍後再回來查看結果的案例
背景回應的運作方式
背景回應會使用 接續權杖 機制來處理長時間執行的作業。 當您將請求傳送給已啟用背景回應的客服專員時,會發生以下兩種情況之一:
- 立即完成:代理程式快速完成任務並傳回最終回應,無需延續權杖
- 背景處理:代理程式在背景開始處理,並傳回延續權杖,而不是最終結果
接續權杖包含所有必要的資訊,以使用非串流代理程式 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)
重點
- 每個
AgentResponseUpdateS 都包含 一個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 服務
- 並非所有客服專員類型都支援背景回應
- 網路中斷或用戶端重新啟動可能需要特殊處理才能保存接續權杖