Skip to lesson

MicrosoftMicrosoft Certified: Multi-Agent AI Solutions Expert2026-104.2 Design and implement guardrails for multi-agent solutions

Screen tool evidence before admitting context

Completed by the knowledge check

Learning objective

Screen untrusted tool responses for indirect prompt injection, sensitive data, and policy violations before adding them to agent context.

Core idea

A tool result is external evidence, even when the tool authenticates successfully and returns a schema-valid object. Its content can redirect the agent, disclose data the next agent should not receive, or violate application policy. The security screen must run before the result becomes model context, shared history, or durable memory.

Separate this admission decision from functional validation. See 2.3.10 for result structure, provenance, and usefulness. Here the question is whether the actual content may enter a particular consumer’s context. A final-answer filter is too late to establish that the agent never consumed the unsafe material.

How it works

Choose a pre-context enforcement path

Microsoft Foundry’s Tool response (Preview) intervention point inspects content before it is added to agent memory or returned to the user. The documented indirect-injection configuration is Indirect attacks → Tool response → Annotate and block. On detection, the agent stops and the malicious content is prevented from being saved.

Agent guardrails are preview, and tool moderation requires integration support. Use the supported-tool check in 4.2.1 before relying on native coverage. A remote MCP tool absent from that documented set needs an application-owned screen. Assigning a guardrail to the agent is not evidence that every returned tool payload was moderated.

For application-executed Python Agent Framework tools, Agent Hooks provides post_tool_call, emitted after a tool succeeds or fails, with the tool result as the transform target. Install the bundle with create_agent_hooks_middleware() and use mode="enforce" for active control. mode="evaluate_only" records decisions but allows execution and does not enforce blocking or transforms.

Agent Hooks is experimental in Python and emits an ExperimentalWarning; it is not implemented in the .NET or Go SDKs. Its tool seams also exclude provider-executed hosted tools. Those calls and outputs appear at post_model_call, but post_tool_call cannot intercept the server-side execution. Design the screen around the execution owner rather than assuming a client hook wraps all tools.

Detect indirect instructions separately

Use Azure AI Content Safety’s POST /contentsafety/text:shieldPrompt?api-version=2024-09-01 to analyze an uncovered tool’s returned text as a document. Read documentsAnalysis[*].attackDetected and retain the association with the submitted result. See 4.2.2 for direct versus indirect attack handling and the request contract.

When an attack is detected, withhold the payload rather than append it with a warning asking the model not to obey it. A model that receives the instruction has already crossed the admission point. Replacing an attack-bearing result with a minimal policy error lets the agent explain missing evidence without receiving the malicious instructions themselves.

An authenticated connector can return user-generated data, a compromised web page, or a hostile email. Therefore, connector trust and content trust need separate decisions. Do not promote a result’s text to system instructions merely because it came through an approved tool.

Screen sensitive data before sharing it

For text returned by an application-executed tool, Azure Language’s Python TextAnalyticsClient.recognize_pii_entities() detects personally identifiable information. A successful document result exposes entities with category and confidence_score, plus redacted_text. The quickstart also checks document errors through is_error; an error is not a clean result.

Map detected entities to the consumer’s data policy. For example, if a downstream summarizer needs the case issue but not customer contact details, permit only the redacted representation after screening it. If removal makes the evidence unusable or the data must not be processed by that consumer at all, deny admission instead. The classifier detects entities; your application decides whether those entities are permitted in this use.

Do not substitute Foundry’s model-output PII filter for an arbitrary pre-context tool screen. Its dedicated page describes scanning LLM completions and distinguishes Annotate from Annotate and Block, which blocks the entire output. The guardrail overview marks PII preview. These statements do not establish a generic tool-result redaction guarantee.

PII detection also does not express every confidentiality rule. A private product plan can violate policy without containing a person’s name or identifier. Enforce source classification and consumer permissions in trusted application logic, and avoid shipping prohibited text to a consumer simply because no PII entity was found.

Apply content policy and enforce the verdict

For harmful text, the standalone Content Safety operation is POST /contentsafety/text:analyze?api-version=2024-09-01. Its categories values include Hate, Sexual, SelfHarm, and Violence. Read each categoriesAnalysis entry’s category and severity; do not collapse all categories into one unexplained score.

outputType="FourSeverityLevels" returns values 0,2,4,6, while "EightSeverityLevels" returns 0 through 7. Define policy thresholds against the selected scale. blocklistNames attaches configured text blocklists, and the response’s blocklistsMatch records matches. If haltOnBlocklistHit=true, the API can skip further harmful-content analysis after a hit, so absence of those later scores must not be treated as evidence of safety.

Combine the detector results and application rules into a specific admission outcome. In Python Agent Hooks, Verdict.deny(...) at a tool seam discards the result and returns a control error with the reason but without the denied target payload. A Decision.TRANSFORM verdict with Transform(...) rewrites the native result that execution uses; transform paths start at $target. Invalid transforms fail closed instead of passing the original content onward.

Use transform only when the resulting evidence remains authorized and meaningful. Re-screen the transformed representation before admission, and store or forward that accepted representation. If screening fails or times out, an enforced Agent Hooks interceptor fails closed. Do not turn detector unavailability into an implicit allow result.

Key distinctions and trade-offs

Result validation versus security screening: A well-formed object can still contain an injection or forbidden data. Run both gates before consumption.

Detection versus admission: Services provide attack flags, entity matches, severity scores, or blocklist hits. A native blocking control or application verdict determines whether the consumer receives the content.

Redaction versus rejection: Redaction preserves useful evidence when removing restricted fields is sufficient. Rejection is necessary when the remaining material still violates policy or no longer supports the task.

Screening adds service calls and can withhold evidence through false positives. Measure that trade-off with representative tool results, but keep incomplete screening distinct from a clean result. Include denial reasons and correlation identifiers in operational records without copying the rejected sensitive payload into routine logs.

Architecture / decision scenario

A support workflow uses a Python Agent Framework tool to fetch case notes from a private MCP service. A post_tool_call interceptor runs before the result is offered to the next model call. Three results demonstrate independent risks.

The first embeds an instruction to export private records. Its Prompt Shields document analysis flags an attack, so the interceptor returns a deny verdict and only a control error reaches the agent. The second contains useful notes plus customer contact details. The PII screen yields redacted_text; the interceptor admits a re-screened transformed result because the summarizer’s policy permits that representation.

The third contains a phrase in a configured prohibited-content blocklist. text:analyze reports a blocklistsMatch, and the application denies it under its content policy even though no prompt attack was detected. If any required analysis is unavailable, the enforced interceptor withholds the result. The workflow never appends the raw text and waits for an output filter to repair the decision.

Common exam traps

  • Treating schema validity or authenticated transport as content clearance.
  • Screening after the tool result has entered model history or memory.
  • Using a model-output PII filter as proof of tool-result redaction.
  • Reading numeric severity without checking outputType.
  • Assuming evaluate_only enforces an Agent Hooks deny.
  • Claiming experimental Python hooks cover provider-hosted execution or every SDK.

What to remember

Inspect the actual result before its first context admission. Injection, sensitive data, and content policy require distinct signals. Enforce deny or a validated transform on the representation the next stage receives, and keep failure or missing moderation support from becoming implicit clearance.

Knowledge check

References