MicrosoftMicrosoft Certified: Multi-Agent AI Solutions Expert2026-104.2 Design and implement guardrails for multi-agent solutions
Turn domain rules into enforced verdicts
Completed by the knowledge check
Learning objective
Build custom guardrails for domain rules, escalation thresholds, and exception handling.
Core idea
A custom guardrail translates a domain rule into an executable decision at the point where it matters. “Follow the refund policy” is an instruction. Checking the proposed refund against an authoritative balance and returning a blocking verdict is enforcement. The model can propose a result; trusted application code decides whether that proposal is permitted.
Separate the rule from its integration. A rule takes a candidate and trusted facts and returns an explicit outcome. The integration applies that outcome before the guarded operation proceeds. This separation lets you test the same policy against specialist outputs, final responses, and tool proposals without embedding different policy interpretations in each agent’s prompt.
In Foundry, a custom guardrail is a configured risk/action policy assigned to an agent; see 4.2.1. Here, a custom guardrail means application code enforcing a domain rule.
See 4.2.5 for output acceptance and 4.2.3 for tool authorization. This lesson focuses on custom decisions, escalation, and exception handling. Failure-mode selection belongs to 4.2.7.
How it works
Define the rule’s inputs and outcomes
Begin with authoritative inputs: the acting principal, tenant, resource, candidate identifier, policy version, and relevant business state. Distinguish a model-proposed amount from a balance read from the account system. Missing required facts should produce an explicit unresolved result, not a permissive default such as a zero balance or an unrestricted limit.
Define decision cases that the application can implement. For example, a company policy might permit refunds up to the unused balance, require supervisor approval above a company-selected amount, and prohibit refunds for an ineligible purchase. These thresholds are organization policy, not Microsoft product limits. Include the comparison operator, currency, rounding rule, and policy version so a threshold has the same meaning in every agent.
A useful application decision record contains the rule identifier, verdict, reason, candidate identifier, and trusted state version. Those are application-defined fields. Do not present them as reserved Microsoft API fields. They give the caller enough information to route a denial or escalation without returning the sensitive source record.
Attach the decision to an enforcement surface
Use agent and function middleware for custom rules outside the Python Agent Hooks contract; see 2.4.15 for the layers. Python middleware can set context.result and raise MiddlewareTermination to stop the normal execution path. In .NET function middleware, FunctionInvocationContext.Terminate = true stops the function-calling loop from sending results back to inference after invocation; it does not undo the invoked function. Enforce a pre-action rule before calling that function. Go provides the run-level agent.Middleware interface, registered through agent.Config.Middlewares. Ordinary middleware requires you to implement the enforcement behavior; it does not inherit Agent Hooks’ coordinated streaming and persistence guarantees.
Python Agent Framework supports Agent Hooks through create_agent_hooks_middleware(). The capability is experimental and the factory emits ExperimentalWarning; .NET and Go do not implement it. An interceptor receives agent_hooks.AgentContext and returns a verdict. This context differs from agent_framework.AgentContext, which is used by ordinary agent middleware.
Choose the interception point by the guarded operation. input covers incoming requests; pre_model_call covers messages sent to the model; post_model_call covers completed model responses; pre_tool_call covers framework-executed tool arguments; post_tool_call covers tool results; output covers the final response. Use the narrowest point that receives the required facts before the consequence occurs.
Agent Hooks does not intercept provider-hosted tools at the framework’s function-invocation seam. Their calls and outputs appear at post_model_call, but pre_tool_call cannot prevent their server-side execution. If a domain rule must authorize a write before it happens, enforce it in a controllable execution path or the downstream service; an after-the-fact result check is insufficient.
Install one intact bundle on each guarded Agent, first in its middleware list. Microsoft rejects stacked bundles and documents that middleware placed before the bundle sits outside its enforcement coverage. Give nested agents their own bundle when their internal model and tool activity also requires interception.
Return a precise verdict
Agent Hooks exposes ALLOW, Verdict.deny(...), Verdict.warn(...), and Verdict.escalate(...). A warning permits execution and adds a record; it is not a denial. A transform uses Decision.TRANSFORM and Transform(...) to rewrite the guarded value, and the framework writes that value back into execution.
Use mode="enforce" when decisions must change behavior. In mode="evaluate_only", every action continues and transforms are not applied. That mode can measure how a proposed rule behaves, but cannot satisfy an enforcing policy requirement.
A denial at a run or model point raises InterceptionBlocked. At a tool point, a policy denial blocks the tool action or discards its result and returns a control error with the reason, without the denied payload, to the model. The loop can continue. This distinction matters when a denied action should lead to a harmless alternative rather than be confused with an infrastructure failure.
Escalate only an eligible exception
Verdict.escalate(...) represents a liftable denial. The resolver configured on create_agent_hooks_middleware() connects it to an approval channel; without a resolver, the denial remains effective. Reserve escalation for rules that explicitly allow an authorized reviewer to permit the request. Do not make an absolute prohibition overridable merely because an approval service exists.
Bind the approval request to the actual candidate and trusted facts. If the amount, destination, or policy changes while approval is pending, require a fresh decision. An approver’s permit for one proposal does not authorize every proposal in the session. See 2.4.6 for durable workflow approval and resumption.
Agent Hooks’ default composition is sequential first_deny, with approval configured to stop the fold. Put controls that must always run before controls that can request approval. Otherwise, an early escalation can prevent a later mandatory check from executing. Decide how several rule results combine instead of assuming every registered rule always runs.
Keep operational exceptions visible
A rule denial means the policy was evaluated and rejected the operation. An interceptor exception means it could not complete that evaluation. Agent Hooks fails closed on interceptor and enforcement failures. See 4.2.7 for the timeout setting and the availability consequences of failed evaluation.
Function middleware normally converts an ordinary exception into a tool-error result so the model loop can continue. If safe continuation is impossible, raise MiddlewareFailure from agent_framework and preserve it through outer middleware. Catching it and continuing changes the intended failure behavior; see 2.4.15.
Use record_sink for InterceptionRecord audit evidence. The records contain verdict, reason, mode, identity, and sequence without copying the intercepted payload. Interceptors still receive the content needed to decide, so register trusted code and minimize what your own diagnostics retain.
Key distinctions and trade-offs
Custom rules and built-in safety controls solve different problems. A general content classifier does not know a customer’s refund eligibility. A deterministic business check does not classify every harmful phrase. Compose them, and keep their reasons distinguishable.
Deterministic comparisons are suitable for exact domain limits. Semantic judgments need calibration and explicit uncertainty handling. A model’s self-reported confidence is not an authoritative eligibility value. Additional remote policy calls also add dependencies; decide what happens when trusted facts cannot be retrieved rather than letting a timeout choose policy accidentally.
Architecture / decision scenario
An expense agent proposes reimbursement. Company policy permits an eligible receipt up to its verified amount, requires manager approval above a company-defined threshold, and prohibits a duplicate reimbursement. A rule evaluator checks the receipt identifier against authoritative payment records before returning a verdict.
A duplicate receives Verdict.deny(...); a permitted high-value proposal receives Verdict.escalate(...) through the configured resolver. If the payment-records lookup fails or times out, the evaluator reports an operational exception rather than inferring that the receipt was not paid. Mandatory duplicate and eligibility checks run before the escalation rule under first_deny composition.
The tool-stage check prevents an unauthorized payment proposal from executing through the framework. The output-stage check prevents the final writer from falsely claiming that an unapproved reimbursement completed. The audit record distinguishes rejection, pending approval, approval, and failed evaluation so support can explain the outcome without exposing the receipt content.
Common exam traps
- Treating a domain instruction as an executable policy check.
- Using
Verdict.warn(...)when the action must stop. - Treating
evaluate_onlyas enforced governance. - Assuming a resolver can override every denial.
- Catching
MiddlewareFailureand continuing the model loop. - Expecting framework hooks to block provider-hosted tool execution.
What to remember
Build custom guardrails from authoritative inputs, exact rule comparisons, and explicit verdicts. Place mandatory checks before escalation, bind approval to the actual proposal, and distinguish policy denials from evaluation failures. The enforcement surface must run before the consequence it is intended to control.
Knowledge check
Company policy prohibits duplicate reimbursements and permits manager approval for eligible high-value reimbursements. Which verdict mapping enforces that distinction in experimental Python Agent Hooks?
Verdict.escalate(...) , a liftable denial resolved through the configured resolver . Escalating a duplicate makes the prohibition overridable, and a warning lets execution continue.An Agent Hooks bundle uses the default first_deny composition. Its rule that can request manager approval is registered before the mandatory duplicate check. A duplicate high-value reimbursement is escalated, a manager approves it, and it is paid. What explains the outcome?
first_deny , approval is configured to stop the fold, so the early escalation ended evaluation before the duplicate check executed. Controls that must always run belong before any control that can request approval.A domain rule must stop a provider-hosted tool’s write before it happens. The client agent uses experimental Python Agent Hooks. Where should the rule be enforced?
pre_tool_call interceptor on the client agentpost_model_call interceptor on the client agentpost_model_call , but no client hook can stop the server-side execution. An instruction is not enforcement, so the rule belongs in a path the application controls, such as the service that performs the write.Function middleware raises MiddlewareFailure after a policy dependency fails and safe continuation is impossible. How should outer middleware handle it?
MiddlewareFailure is the signal that the run must abort rather than continue. Catching it — whether to convert it, log it, or retry and carry on — lets the loop continue and turns fail-closed behaviour into fail-open behaviour.References
Microsoft, Agent hooks
Microsoft, Agent Middleware
Microsoft, Guardrails and controls overview in Microsoft Foundry