Microsoft Agent Framework 支持后台响应来处理长时间运行的作,这些作可能需要一段时间才能完成。 此功能使代理能够开始处理请求并返回一个延续令牌,该标记可用于轮询结果或恢复中断的流。
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},
)
注释
Python OpenAI 响应 API、Azure OpenAI 响应 API 或 Microsoft Foundry 支持的代理支持后台响应。
使用FoundryChatClient后台响应可以使用提供程序端响应存储()或无状态重播(store=Truestore=False)运行本地函数工具。 轮询时保留相同的会话,以便恢复的响应可以继续本地工具循环。
非流式处理后台响应
对于非流式处理方案,当你最初运行 background=True代理时,它可能会立即使用 a 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项都包含一个用于恢复的continuation_token - 在中断之前存储上次收到的更新中的令牌
- 传递存储的令牌
options={"continuation_token": token}以恢复
启用后台响应
启动运行时传递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_NAMEAzure凭据进行身份验证。 它在轮询完成后打印已完成的响应。 立即完成的响应没有继续标记,不需要轮询。
流式处理后台响应
使用和 agent.AllowBackgroundResponses(true). 启动流式处理运行agent.Stream(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 代理配合使用
Harness 代理仍然是标准 Agent Framework 代理,因此提供程序后台响应使用上面记录的相同每运行选项。 Harness 构造不会自动启用提供程序后台响应:在.NET、 options={"background": True} Python或agent.AllowBackgroundResponses(true)启动运行时在 Go 中设置AllowBackgroundResponses。 当操作必须在进程重启后保留会话并保留继续标记。
这独立于 后台代理,后者将工作委托给子代理,而不是继续一个提供程序请求。
最佳做法
使用后台响应时,请考虑以下最佳做法:
- 实现适当的轮询间隔 以避免服务压倒性
- 如果作花费的时间超过预期,则对轮询间隔使用指数回退
-
检查不存在的继续标记 (
null或None空 Go 字符串)以确定处理何时完成 - 考虑将延续令牌持久存储 为可能跨越用户会话的作
限制和注意事项
- 后台响应依赖于支持长时间运行的作的基础 AI 服务
- 并非所有代理类型都支持后台响应
- 网络中断或客户端重启可能需要特殊处理才能保留延续令牌