tl;dr
If you’re building automated workflows that sometimes must pause for human judgment (approvals, moderation, triage), Microsoft Agent Framework provides first‑class HITL primitives: typed RequestPorts, durable suspended execution, emitted RequestInfoEvents, and automatic routing of responses back to the correct workflow executor.简而言之:如果你正在构建的自动化工作流有时需要暂停以等待人工判断(如审批、审核、分类),Microsoft Agent Framework 提供了原生的人机协作(HITL)原语:类型化的 RequestPorts、持久化挂起执行、RequestInfoEvent 事件触发,以及将响应自动路由回正确工作流执行器的机制。

This article explains the runtime mechanics (what happens when a workflow asks a human for input), the developer experience (what you write), concrete examples (C# + JSON contracts), integration patterns with Bot Framework/contact centers, failure modes, and testing strategies.本文将解释运行时机制(当工作流请求人工输入时会发生什么)、开发体验(你需要编写的内容)、具体示例(C# + JSON 契约)、与 Bot Framework/联络中心的集成模式、故障模式以及测试策略。
A concise scenario
An LLM suggests a $50,000 refund to a customer. If your automation approves it automatically you risk fraud and compliance violations; if you block it you frustrate customers and increase manual work. The correct middle ground is a durable, auditable workflow that pauses, sends a precise task to a human reviewer, and reliably resumes once the reviewer responds. Microsoft Agent Framework makes that pattern a core primitive instead of an ad‑hoc add‑on.一个简要场景:大语言模型(LLM)建议向客户退款 50,000 美元。如果你自动批准,则面临欺诈和合规风险;如果直接拦截,则会引起客户不满并增加手动工作量。正确的折中方案是一个持久化、可审计的工作流:它会暂停,向人工审核员发送精确的任务,并在审核员响应后可靠地恢复。Microsoft Agent Framework 将该模式作为核心原语,而非临时添加的插件。
Overview: what Agent Framework gives you for HITL概览:Agent Framework 为人机协作提供的功能
- Typed RequestPorts: define strongly typed request and response schemas so humans and automation agree on payload shapes.类型化 RequestPorts:定义强类型的请求和响应模式,确保人类与自动化系统对负载结构达成一致。
- Durable suspend/resume: when an executor issues a request, the workflow branch is suspended durably until a response arrives (survives restarts).持久化挂起/恢复:当执行器发出请求时,工作流分支会被持久化挂起,直到收到响应(支持节点重启后恢复)。
- RequestInfoEvent emission: the framework emits a structured event the agent hub or any subscriber can consume to present tasks to humans.RequestInfoEvent 事件触发:框架会触发一个结构化事件,代理中心(Agent Hub)或任何订阅者均可消费该事件,以便将任务呈现给人类。
- Automatic routing & correlation: responses include metadata that the framework uses to match the response to the exact waiting executor, avoiding much manual correlation code.自动路由与关联:响应包含元数据,框架利用这些元数据将响应匹配到准确的等待执行器,从而避免了大量的手动关联代码。
- Orchestration & handoff primitives: the workflow language supports approval nodes, escalations, timeouts, and integration points for agent hubs or contact centers.编排与移交原语:工作流语言支持审批节点、升级处理、超时设置以及与代理中心或联络中心的集成点。
Request lifecycle: step‑by‑step请求生命周期:分步解析
Declare RequestPort(s) in the workflow在工作流中声明 RequestPort(s)
- A RequestPort is a typed channel (request type, response type). Example: RequestPort.RequestPort 是一个类型化通道(包含请求类型和响应类型)。示例:RequestPort。
Executor issues a request执行器发出请求
- Inside an executor (HandleAsync or equivalent), the code calls the framework API (e.g., context.SendRequestAsync) to send the request payload. The call returns only when the response is received or the request is cancelled/timeout occurs.在执行器内部(HandleAsync 或同等方法),代码调用框架 API(例如 context.SendRequestAsync)来发送请求负载。仅在收到响应或请求被取消/超时后,该调用才会返回。
Workflow branch is suspended工作流分支挂起
- The framework persists the suspended state. The executor essentially awaits the response; the workflow instance remains durable in storage (so node restarts or transient failures won’t lose the wait).框架会持久化挂起状态。执行器本质上是在等待响应;工作流实例在存储中保持持久化(因此节点重启或瞬时故障不会导致等待丢失)。
RequestInfoEvent is emitted触发 RequestInfoEvent
- The framework publishes an event that includes request metadata, the typed payload, timestamps, TTL, and any contextual fields the workflow author supplied. External systems subscribe and surface the task to human operators.框架发布一个包含请求元数据、类型化负载、时间戳、TTL 以及工作流作者提供的任何上下文字段的事件。外部系统订阅该事件并将任务呈现给人工操作员。
Human reviews and posts a response人工审核并发布响应
- The human operator uses an agent hub UI (built-in or custom) to inspect context and submit a response. The agent hub posts the typed response back to the Agent Framework through a Response Ingest API or SDK call.人工操作员使用代理中心 UI(内置或自定义)检查上下文并提交响应。代理中心通过 Response Ingest API 或 SDK 调用将类型化响应发回 Agent Framework。
Framework routes response back to waiting executor框架将响应路由回等待中的执行器
- Using request id + workflow instance id (and port name/type), the framework finds the suspended executor and delivers the typed response. The executor resumes and the workflow continues.框架使用请求 ID + 工作流实例 ID(以及端口名称/类型)找到挂起的执行器并交付类型化响应。执行器恢复运行,工作流继续执行。
Developer view: what you author
At a high level you:开发者视角:你需要编写的内容。总体而言,你需要:
- Define RequestPorts and response types.定义 RequestPorts 和响应类型。
- Write executors that call context.SendRequestAsync (or RequestPort.Send).编写调用 context.SendRequestAsync(或 RequestPort.Send)的执行器。
- Subscribe to RequestInfoEvents or integrate Event Grid/Service Bus to route tasks to your agent hub/UIs.订阅 RequestInfoEvents 或集成 Event Grid/Service Bus,以便将任务路由到你的代理中心/UI。
- Implement a response ingest endpoint (secured) that posts typed responses back to the framework.实现一个响应接收端点(需安全保护),将类型化响应发回框架。
Concise C# worked example (end‑to‑end sketch)
Below is a minimal, runnable‑style illustration (API names adapted to the docs’ conceptual forms). This shows the RequestPort declaration, the executor sending a request, emitting an event handled by the agent hub, and the response ingest flow.简明 C# 示例(端到端草图)。以下是一个最小化的、可运行的说明(API 名称已根据文档的概念形式进行调整)。它展示了 RequestPort 的声明、执行器发送请求、触发由代理中心处理的事件,以及响应接收流程。
1) Define request/response types
public record ContentModerationRequest(string Content, string UserId, string ConversationId);
public record ContentModerationResponse(bool Approved, string ReviewerId, string Notes);1) 定义请求/响应类型:public record ContentModerationRequest(string Content, string UserId, string ConversationId); public record ContentModerationResponse(bool Approved, string ReviewerId, string Notes);
2) Create a RequestPort and wire into a workflow
var contentModerationPort = RequestPort.Create(“ContentModeration”);2) 创建 RequestPort 并将其连接到工作流:var contentModerationPort = RequestPort.Create(“ContentModeration”);
var workflow = new WorkflowBuilder(contentModerationPort)
.AddEdge(inputSource, contentModerationExecutor)
.AddEdge(contentModerationExecutor, continueExecutor)
.Build();var workflow = new WorkflowBuilder(contentModerationPort).AddEdge(inputSource, contentModerationExecutor).AddEdge(contentModerationExecutor, continueExecutor).Build();
3) Executor sends request and awaits response
3) 执行器发送请求并等待响应
internal sealed class ContentModerationExecutor : Executor
{
public override async ValueTask HandleAsync(ContentItem message, IWorkflowContext context, CancellationToken ct)
{
var request = new ContentModerationRequest(message.Text, message.UserId, message.ConversationId);
// SendRequestAsync emits a RequestInfoEvent and suspends until the human response arrives
ContentModerationResponse response = await context.SendRequestAsync(contentModerationPort, request, ct);
if (response.Approved)
{
// proceed with publishing, optionally using edited content from notes
await context.ScheduleAsync(new PublishMessage(response.ReviewerId, message.Id), ct);
}
else
{
// handle rejection path
await context.ScheduleAsync(new NotifyUserDecline(message.UserId), ct);
}
}
}
Notes:注意:
- SendRequestAsync returns a typed response object (ContentModerationResponse) when the human submits their decision.当人类提交决定时,SendRequestAsync 会返回一个类型化的响应对象(ContentModerationResponse)。
- While awaiting, the workflow’s state is persisted so the process is durable.在等待期间,工作流的状态会被持久化,以确保过程的持久性。
Agent hub responsibilities and the RequestInfoEvent
When SendRequestAsync is called, the framework emits a RequestInfoEvent. The agent hub subscribes (Event Grid, Service Bus, or a SDK event callback) and must implement:代理中心的职责与 RequestInfoEvent。当调用 SendRequestAsync 时,框架会触发 RequestInfoEvent。代理中心进行订阅(通过 Event Grid、Service Bus 或 SDK 事件回调),并必须实现:
- Task display: show request details, provenance (workflow id, request id), attachments, and relevant context (conversation transcript, policy guidance).任务显示:展示请求详情、来源(工作流 ID、请求 ID)、附件以及相关上下文(对话记录、策略指南)。
- Claiming model: accept/claim or pick-from-queue semantics to avoid double-work.认领模型:实现接受/认领或从队列中挑选的语义,以避免重复工作。
- Response posting: a secure call to the Response Ingest API that returns success or a clear error (with appropriate HTTP status codes).响应发布:对 Response Ingest API 进行安全调用,该调用应返回成功或明确的错误(带有适当的 HTTP 状态码)。
Sample RequestInfoEvent payload (JSON)
{
“requestId”: “req-abc123”,
“workflowInstanceId”: “wf-987”,
“portName”: “ContentModeration”,
“requestPayload”: {
“content”: “AI-generated reply…”,
“userId”: “user-42”,
“conversationId”: “conv-77”
},
“createdAt”: “2026-09-14T12:34:56Z”,
“ttlSeconds”: 3600,
“metadata”: { “priority”: “high”, “origin”: “chatbot-01” }
}RequestInfoEvent 负载示例(JSON):{“requestId”: “req-abc123”,“workflowInstanceId”: “wf-987”,“portName”: “ContentModeration”,“requestPayload”: {“content”: “AI-generated reply…”,“userId”: “user-42”,“conversationId”: “conv-77”},“createdAt”: “2026-09-14T12:34:56Z”,“ttlSeconds”: 3600,“metadata”: { “priority”: “high”, “origin”: “chatbot-01” }}
Response ingest contract (what the agent hub posts back)
POST /api/agent/responses
Headers:
Authorization: Bearer
Body:
{
“requestId”: “req-abc123”,
“workflowInstanceId”: “wf-987”,
“responsePayload”: {
“approved”: true,
“reviewerId”: “agent-007”,
“notes”: “Approved; removed PII”
},
“submittedAt”: “2026-09-14T12:40:01Z”
}响应接收契约(代理中心发回的内容):POST /api/agent/responses Headers: Authorization: Bearer Body: {“requestId”: “req-abc123”,“workflowInstanceId”: “wf-987”,“responsePayload”: {“approved”: true,“reviewerId”: “agent-007”,“notes”: “Approved; removed PII”},“submittedAt”: “2026-09-14T12:40:01Z”}
Expected responses:预期响应:
- 200 OK — response accepted and routed to the executor.200 OK — 响应已接受并路由至执行器。
- 400 Bad Request — malformed payload or schema mismatch.400 Bad Request — 负载格式错误或模式不匹配。
- 404 Not Found — request id not found (possibly expired or already completed).404 Not Found — 未找到请求 ID(可能已过期或已完成)。
- 409 Conflict — duplicate or conflicting response (depending on your policy).409 Conflict — 重复或冲突的响应(取决于你的策略)。
- 410 Gone — request timed out or was cancelled.410 Gone — 请求超时或已被取消。
Correlation, routing, and metadata best practices
What the framework provides:关联、路由和元数据的最佳实践。框架提供的内容:
- requestId: unique per request invocation.requestId:每次请求调用唯一。
- workflowInstanceId: identifies the workflow instance.workflowInstanceId:标识工作流实例。
- portName (and port type): identifies the RequestPort.
With those, most routing is automatic. Practical guidance:portName(及端口类型):标识 RequestPort。有了这些,大多数路由都是自动完成的。实践建议: - Always include requestId in your response ingest calls. requestId is the primary, unambiguous handle for routing.始终在响应接收调用中包含 requestId。requestId 是路由的主要且明确的句柄。
- Port name/type adds another safety layer, useful if your agent hub sees many types of requests.端口名称/类型增加了另一层安全性,如果你的代理中心处理多种类型的请求,这非常有用。
- Capture and surface workflowInstanceId in the agent UI for audit and troubleshooting.在代理 UI 中捕获并显示 workflowInstanceId,以便进行审计和故障排除。
- Store and emit reviewer identity and timestamps in responses for compliance.在响应中存储并发出审核员身份和时间戳,以满足合规性要求。
Handling duplicates, late responses, and concurrency处理重复、延迟响应和并发
- First‑wins vs quorum: by default a single response satisfies the waiting executor. If you need multiple approvals or consensus, model it explicitly—create multiple RequestPorts or a response type that supports aggregation and implement quorum logic in the workflow.先到先得与法定人数:默认情况下,单个响应即可满足等待中的执行器。如果需要多次审批或达成共识,请显式建模——创建多个 RequestPorts 或支持聚合的响应类型,并在工作流中实现法定人数逻辑。
- Duplicate submissions: agent hub should make the ingest POST idempotent. The server should accept the first valid response and return 409 or 200 for subsequent duplicates, depending on your semantics.重复提交:代理中心应使接收 POST 请求具有幂等性。服务器应接受第一个有效响应,并根据你的语义对后续重复请求返回 409 或 200。
- Late arrivals: responses for cancelled or timed‑out requests should be rejected with 410 Gone and the agent hub should surface a clear explanation and allow re‑issuing (create a new request).延迟到达:对于已取消或超时的请求,响应应被拒绝并返回 410 Gone,代理中心应显示清晰的解释并允许重新提交(创建一个新请求)。
- Concurrency: if two human agents submit different responses simultaneously, the framework decides based on request id ordering; design the workflow to verify critical transitions—e.g., accept only responses signed by an approver role, or require a reconciliation step.并发:如果两个人工代理同时提交不同的响应,框架将根据请求 ID 的顺序进行决策;设计工作流时应验证关键转换——例如,仅接受由审批角色签名的响应,或要求进行核对步骤。
Timeouts, fallbacks, and alternate flows
Long human latency blocks user experience. Your workflows should:超时、回退和替代流程。较长的人工延迟会阻塞用户体验。你的工作流应该:
- Configure sensible TTLs on RequestPorts (e.g., 30m for routine approvals, 24h for slower approvals, two minutes if the user is on hold!).在 RequestPorts 上配置合理的 TTL(例如,常规审批为 30 分钟,较慢的审批为 24 小时,若用户在等待则为两分钟!)。
- Define fallback flows for timeouts: reassign to escalation queue, auto‑approve/deny under defined policies, or create a notification to a manager.定义超时的回退流程:重新分配到升级队列、根据既定策略自动批准/拒绝,或向经理发送通知。
- Emit interim events (e.g., “pending too long”) to monitoring and alerting systems.向监控和警报系统发出中间事件(例如“挂起时间过长”)。
Orchestration patterns: single approval, parallel approvals, and SAGA compensation编排模式:单次审批、并行审批和 SAGA 补偿
- Single approval: the workflow issues one request and continues when it receives a single response.单次审批:工作流发出一个请求,并在收到单个响应后继续执行。
- Parallel approvals (n of m or quorum): create multiple requests in parallel and wait for N responses or a consensus step. Example:并行审批(n 选 m 或法定人数):并行创建多个请求,并等待 N 个响应或达成共识。示例:
- Spawn three RequestPorts (or the same port with multiple request instances) and gather responses. Resume when at least two are approvals.生成三个 RequestPorts(或具有多个请求实例的同一端口)并收集响应。当至少有两个审批时恢复执行。
- SAGA / compensation: if the human rejects a step that has already triggered side effects, model compensating actions in the workflow (reverse a debit, revoke a provisional publish). Combine timeouts with compensation to avoid leaving inconsistent state.SAGA / 补偿:如果人类拒绝了已经触发副作用的步骤,请在工作流中对补偿动作进行建模(撤销扣款、撤销临时发布)。将超时与补偿相结合,以避免留下不一致的状态。
Integrating with Bot Framework and contact centers
Agent Framework HITL and Bot Framework are complementary:与 Bot Framework 和联络中心集成。Agent Framework HITL 与 Bot Framework 是互补的:
- Bot as trigger: a conversational bot collects context and triggers a workflow that may create a RequestPort task for human approval.机器人作为触发器:对话机器人收集上下文并触发一个工作流,该工作流可能会为人工审批创建一个 RequestPort 任务。
- Bot as proxy: once a human accepts, Bot Framework’s handoff patterns (bot-as-proxy) can connect a human agent into the live conversation while the workflow continues to manage business-level approvals.机器人作为代理:一旦人类接受,Bot Framework 的移交模式(bot-as-proxy)可以将人工代理连接到实时对话中,同时工作流继续管理业务层面的审批。
- Agent hub integration: use Omnichannel for Dynamics or an agent hub service to surface tasks to Teams, Dynamics agents, or third‑party contact centers.代理中心集成:使用 Dynamics 全渠道(Omnichannel)或代理中心服务,将任务呈现给 Teams、Dynamics 代理或第三方联络中心。
A concrete flow (bot + Agent Framework + Teams)具体流程(机器人 + Agent Framework + Teams)
- Bot collects issue and calls a workflow API to start a warranty claim workflow.机器人收集问题并调用工作流 API 以启动保修索赔工作流。
- Workflow evaluates risk. If high, it calls SendRequestAsync on a ClaimApprovalRequestPort.工作流评估风险。如果风险较高,它会在 ClaimApprovalRequestPort 上调用 SendRequestAsync。
- The Agent Framework emits RequestInfoEvent and routes it to Event Grid.Agent Framework 触发 RequestInfoEvent 并将其路由至 Event Grid。
- Event Grid forwards to an agent hub that posts a message in a Teams queue or Dynamics Omnichannel.Event Grid 将其转发至代理中心,代理中心在 Teams 队列或 Dynamics 全渠道中发布消息。
- An agent reviews in Teams, submits the approval via the agent hub (which calls the Response Ingest API).代理在 Teams 中进行审核,通过代理中心提交审批(调用 Response Ingest API)。
- Agent Framework resumes the workflow and posts the outcome back to the bot (or directly to the user).Agent Framework 恢复工作流并将结果发回给机器人(或直接发给用户)。
Security and compliance安全与合规
- Authentication: secure the Response Ingest API with OAuth 2.0 (Azure AD Bearer tokens) or mutual TLS. Agent hub should authenticate as a service principal with least privilege.身份验证:使用 OAuth 2.0(Azure AD Bearer 令牌)或双向 TLS 保护 Response Ingest API。代理中心应以具有最小权限的服务主体身份进行验证。
- Authorization: enforce RBAC so only authorized roles can approve certain request types (finance team for refunds).授权:实施 RBAC,确保只有授权角色才能审批特定类型的请求(例如财务团队负责退款)。
- PII removal: redact or mask sensitive fields in RequestInfoEvent payloads and in agent UIs. If full PII is required, limit retention and access logs.PII 移除:在 RequestInfoEvent 负载和代理 UI 中编辑或掩码敏感字段。如果需要完整的 PII,请限制保留期限和访问日志。
- Audit trails: persist request/response payloads, reviewer identity, timestamps, and any changes. Use immutable storage or append‑only logs for compliance.审计追踪:持久化请求/响应负载、审核员身份、时间戳及任何变更。为合规起见,请使用不可变存储或仅追加日志。
Observability and operational metrics
Track and alert on:可观测性与运营指标。跟踪并设置警报:
- Pending request count per port.每个端口的挂起请求数。
- Average and P95 human response time.平均和 P95 人工响应时间。
- SLA (Service Level Agreement) breaches (e.g., pending_response_time > SLA).SLA(服务水平协议)违规(例如,pending_response_time > SLA)。
- Request churn (creates, cancels, re‑issues).请求流失(创建、取消、重新发布)。
- Approval rates and reviewer throughput.审批率和审核员吞吐量。
Note P95 indicates 95th percental latency between when a task is presented to a human and when they respond.注:P95 指任务呈现给人类到人类响应之间的第 95 百分位延迟。
Suggested alerts:建议的警报:
- Pending requests > threshold for > X minutes (escalate).挂起请求数 > 阈值且持续时间 > X 分钟(升级)。
- Average response time rising > 2x baseline (investigate agent hub throughput/availability).平均响应时间上升 > 基准的 2 倍(调查代理中心吞吐量/可用性)。
- Rejected requests spike > typical baseline (potential model drift or policy change).拒绝请求数激增 > 典型基准(潜在的模型漂移或策略变更)。
Testing and CI/CD strategies测试与 CI/CD 策略
- Unit testing executors: mock SendRequestAsync to simulate human responses and assert branching logic.执行器单元测试:模拟 SendRequestAsync 以模拟人类响应并断言分支逻辑。
- Integration tests: test full path — executor sends request → event emitted → simulate agent hub response → workflow resumes.集成测试:测试完整路径——执行器发送请求 → 触发事件 → 模拟代理中心响应 → 工作流恢复。
- Load testing agent hub: simulate spikes of RequestInfoEvent to confirm queueing behavior and UI scaling.代理中心负载测试:模拟 RequestInfoEvent 的峰值,以确认队列行为和 UI 扩展性。
- Chaos testing: simulate delayed responses, duplicate responses, and timeout conditions to verify fallback flows and compensation logic.混沌测试:模拟延迟响应、重复响应和超时条件,以验证回退流程和补偿逻辑。
Common pitfalls and how to avoid them常见陷阱及规避方法
- Missing context in the agent UI: always surface the workflowInstanceId, requestId, and relevant transcript attachments. Humans need context to make fast decisions.代理 UI 中缺少上下文:始终显示 workflowInstanceId、requestId 和相关的对话记录附件。人类需要上下文来快速做出决策。
- Assuming low latency: design timeouts and fallback behavior; don’t block user interfaces waiting indefinitely.假设低延迟:设计超时和回退行为;不要无限期地阻塞用户界面进行等待。
- Weak correlation design: require requestId in responses. Avoid relying on human-entered identifiers that can be mistyped.关联设计薄弱:要求在响应中包含 requestId。避免依赖可能输错的人工输入标识符。
- Lack of auditability: store reviewer identity and notes; consider signing responses or using immutable logs for compliance.缺乏可审计性:存储审核员身份和备注;考虑对响应进行签名或使用不可变日志以满足合规要求。
