CAMPUX learn / ai / 04
Project 04 of 09
The approval step actually blocks.

Multi-agent workflow

A triage agent that hands the customer to a warranty specialist or a refund specialist, built on Microsoft Agent Framework, where the refund tool cannot run until a supervisor says yes, even if the process restarts while it waits.

build time
6 to 8 hours
cost
Under $8 if torn down the same day3
services
Microsoft Agent Framework, Foundry Agent Service, Azure Functions, Cosmos DB, Entra ID, Application Insights
assumes
Project 01. The warranty specialist is that agent, unchanged.
exams
Overlaps AI-103, AI-200
vocabulary
Orchestration, handoff, specialist, tool approval, request info, checkpoint, human-in-the-loop

The problem

The Warranty Desk now gets asked for refunds. One agent doing warranty lookups, policy quotes and refunds is one agent with too many instructions and too much power.

The head of support wants three things that are, at first, hard to have together. Customers should talk to one thing, not pick a department. Refunds over fifty dollars need a supervisor to approve them, and "approve" has to mean the money cannot move without the click. And the approval has to survive lunch: if the supervisor comes back in an hour and the service restarted in between, the pending refund is still pending, not lost and not silently paid.

definition
Handoff. One agent passing the conversation to another, with context, and control coming back to the customer when the receiving agent has nothing more to hand off. In Agent Framework this is an orchestration you build, not a prompt you hope works.

The architecture

Three agents, one conversation, and a tool that waits for a person.

Multi-agent workflow architecture: a customer talks to a triage agent that hands off to a warranty or refund specialist under Agent Framework handoff orchestration; the refund tool requires approval, the request waits in checkpoints in Cosmos DB, a supervisor approves, and only then does the Azure Function issue the refund. the approval step blocks. The refund tool cannot run without a person. CLIENT MICROSOFT FOUNDRY PROJECT · WORKFLOW APPROVAL AND ACTION Customerweb browser Container AppsStreamlit UIEntra sign-in Triage agentAgent Framework handoff orchestration Warranty specialistProject 01's agent Refund specialistone tool, gated issue_refund toolapproval_mode: always_requireemits a function approval request Checkpointspending approval survives a restart Application Insightsone trace across three agents Support supervisorapproves over $50separate Entra role Refund APIAzure Functionsruns only after approval Microsoft Entra IDworkflow identity calls the Function · supervisor role approves · support role can only see · no keys 1 2 3 4 5 6 7 8
livepress play to follow one refund from request to approval
Figure 7 Three agents, one conversation. The approval is a property of the tool, so the model cannot talk its way past it, and the checkpoint means a restart does not lose it.
  1. Ask. The customer asks for a refund in plain words.
  2. Triage. The triage agent decides refund, not warranty, and hands off a summary.
  3. Or warranty. A coverage question would have gone to the warranty specialist, Project 01's agent.
  4. Compute. The refund specialist reads the order and computes the eligible amount.
  5. Gate. The refund tool requires approval; it emits a request instead of running.
  6. Approve. A supervisor, in a separate role, sees the request and approves or declines.
  7. Act. Only now does the Azure Function issue the refund, once, keyed on the request ID.
  8. Survive. The pending request lived in Cosmos DB checkpoints; a restart re-emits it.
Service map, for readers coming from AWS
JobAWS versionThis buildSame idea?
OrchestrationBedrock multi-agent collaborationAgent Framework handoff orchestration1Yes. Here the handoff is explicit code
SpecialistsCollaborator agentsFoundry agents, one per jobYes
Approval gateStep Functions wait for callbackTool approval, approval_mode="always_require"Yes. Here it is a property of the tool
Durable waitStep Functions stateWorkflow checkpoints in Cosmos DBYes
Refund actionLambdaAzure Functions, managed identityYes

The build

In this order. Step 6 is the one that makes "human in the loop" mean something; test it by pulling the plug.

  1. Three agents

    Triage: decides warranty or refund, nothing else. Warranty specialist: the Project 01 agent, untouched. Refund specialist: reads the order, computes the eligible amount, and has one tool, issue_refund(orderId, amount).

    Each agent answers in the playground on its own, with its own instructions file in the repo.
  2. Handoff orchestration

    With Agent Framework, build a handoff workflow: triage can hand to either specialist; specialists can hand back to triage. When an agent replies without handing off, control returns to the customer.

    "My dishwasher broke and I want my money back" reaches the refund specialist; "is it still covered" reaches the warranty specialist; both come back to the customer without a second prompt from you.
  3. The refund tool, gated

    Mark issue_refund with approval_mode="always_require". When the refund specialist calls it, the workflow emits a function approval request instead of running the tool.

    Ask for a $120 refund. The tool does not run; the response carries a pending function-approval request with the order ID and amount, and your side-effect log stays empty. Verified: in our run the gated tool was never executed. Keep that log; it is the evidence.4
  4. The supervisor screen

    A small page that lists pending approval requests and has Approve and Decline. Approving sends the approval response back into the workflow; the tool runs; the Function issues the refund.

    Approve from the screen; the refund Function logs one call with the right amount. Decline; it logs nothing and the customer is told.
  5. The threshold

    Refunds under $50 do not need approval. Implement that as code around the tool, not as a sentence in the prompt: the tool decides whether to require approval based on the amount.

    $40 refunds run straight through; $60 refunds wait. Tell the model the threshold is $500 in the prompt and confirm it still waits at $60.
  6. Checkpoints, then pull the plug

    Add checkpoint storage backed by Cosmos DB. Ask for a $120 refund, see the pending request, then kill the process. Start it again and restore from the last checkpoint.

    The pending request is re-emitted after restart. Approve it now; exactly one refund is issued, not zero and not two.
  7. Identity

    The refund Function accepts only the workflow's managed identity. The supervisor screen requires the supervisor role in Entra ID; a support agent role can see requests but not approve.

    Signed in as a support agent, the Approve control is not there and the API says 403.
  8. Trace the handoffs

    Turn on tracing. Run a conversation that goes triage to refund to approval to Function and read it in Application Insights as one trace.

    One trace shows three agents, one approval wait, and one tool call, in order, with timings.
  9. Tear it down
    azd down

    Then delete the Cosmos account by hand if you created it outside the template.

    The resource group is empty. Today's cost is under $8.

Where it breaks

Cause each one on purpose. Multi-agent failures are quiet and expensive.

The trade-offs

Three agents, or one agent with a longer prompt?
One agent is simpler until it has the power to refund and the instructions to quote policy in the same context. Splitting gives each agent one job and one set of tools, so the refund specialist cannot quote policy wrong and the warranty specialist cannot move money.
Handoff, or a fixed sequence?
A sequential workflow is predictable and cannot route on what the customer said. Handoff routes, and needs a hop limit. Customer conversations route.
Approval in code, or in the prompt?
In the prompt, the model decides whether to ask. In code, the tool refuses to run. Money moves on the second kind only.
Checkpoints, or accept the loss?
Checkpoints add a store and an idempotency rule. Without them, a restart can drop or duplicate a pending refund. For refunds, that is not a trade-off.

In the interview

"Tell me about a multi-agent system you built."

  • decisionTriage plus two specialists with Agent Framework handoff, each agent with one job and one tool set.
  • reasonSplitting power: the agent that quotes policy cannot move money.
  • watchedHandoff loops; I added a hop limit after seeing one.

"How does the human approval work?"

  • decisionThe refund tool requires approval as a property; the workflow emits a request and waits.
  • reasonA prompt instruction can be talked out of; a tool gate cannot.
  • watchedRestarting the process with a request pending and confirming exactly one refund after approval.

"What if the service restarts while waiting?"

  • decisionCheckpoints in Cosmos DB; pending requests are re-emitted on restore.
  • reasonA lost approval is a broken promise; a duplicated one is a lost refund.
  • watchedThe request ID as the idempotency key on the Function.

Evidence

One trace
Triage to refund specialist to approval wait to Function, with timings.
The plug-pull
A short recording or three screenshots: pending request, process killed, request re-emitted, one refund.
The repo
Three instructions files, the orchestration code, the gated tool, and the supervisor page.
One sentence for the résumé
"Built a multi-agent support workflow with Microsoft Agent Framework: triage and specialist handoffs, a tool-level human approval gate for refunds, and durable checkpoints so pending approvals survive restarts without duplicate payments."

Next

Notes

  1. Checked against Microsoft Learn on 2 September 2026. Agent Framework's handoff orchestration returns control to the user when an agent replies without handing off; tools marked approval_mode="always_require" emit a function approval request; checkpoints persist pending requests, which are re-emitted on restore. Names may move; the Learn pages win.
  2. Foundry's own workflow agents exist too and are worth knowing; at the time of writing they did not support outbound network isolation, which matters for Project 05. This project builds the orchestration in Agent Framework code so every step is visible.
  3. "Under $8" assumes serverless Cosmos DB for checkpoints, a Consumption Function, small models, and teardown the same day.
  4. The approval gate was tested in a real subscription on 3 September 2026 with agent-framework 1.17.0 for Python and gpt-5-mini. With @tool(approval_mode="always_require") the tool never executed and the run surfaced a pending function-approval request; the same tool with only a prompt instruction executed on a claimed supervisor identity in five runs out of five. One thing moved between the docs and the package: the agent class is Agent, not ChatAgent, and a conversation is agent.create_session(), not get_new_thread(). Expect that kind of drift and read the package, not just the page.