MicrosoftMicrosoft Certified: Multi-Agent AI Solutions Expert2026-103.3 Design and implement observability and monitoring for multi-agent solutions
Connect decisions to their execution traces
Completed by the knowledge check
Learning objective
Correlate traces and structured decision metadata across agent and service boundaries
Core idea
A distributed trace explains which operations participated in a request and how they relate. Structured decision metadata explains which observable choice the application made: the selected specialist, accepted result, policy outcome, or recovery path. You need both to reconstruct a multi-agent execution without collecting private model reasoning.
For architects and senior engineers, correlation is a contract across instrumentation, transport, and storage. A business request identifier alone does not establish parentage, and a trace alone does not explain a policy decision. See 1.2.7 for evidence retention and replay design. This lesson focuses on preserving causality and attaching concise decision records to the actual execution path.
How it works
Separate the identifiers
OpenTelemetry spans have a trace identifier and a span identifier. Related spans share the trace identifier, while each span identifies its own operation. A parent relationship expresses nested work; a span link expresses a causal relationship without asserting that one operation executed inside the other.
Application Insights stores correlation fields in its telemetry model. operation_Id in the Application Insights query schema maps to OperationId in the Log Analytics schema and groups telemetry across components. operation_ParentId maps to ParentId and identifies the immediate parent. Choose the field spelling for the query surface you use; a schema mismatch can look like missing correlation even when ingestion worked.
Keep a logical business request ID alongside these identifiers when your application needs it. That custom ID can span retries, deferred work, or several traces, but it does not replace trace context. Label it as application metadata and define its lifetime explicitly. Otherwise, one retry might appear to be a different business request or several attempts might look like one nested operation.
Preserve context across the service call
Instrument the caller, outgoing operation, and receiving service so the receiving operation can continue the incoming context. Use the configured OpenTelemetry propagation mechanism rather than copying a visible trace ID into a custom log field. A copied identifier can support a manual search, but it does not create the span relationships needed for a distributed trace.
In Python, Agent Framework injects active OpenTelemetry context into params._meta on tools/call requests for client-opened MCP sessions, including MCPStreamableHTTPTool, MCPStdioTool, and MCPWebsocketTool. Hosted or provider-managed connectors such as FoundryChatClient.get_mcp_tool(...) and Foundry hosted-agent toolboxes do not receive this injection because the provider runtime issues the call. See 1.2.7 for the MCP transport mechanism, including the default W3C traceparent and tracestate propagation.
The receiving MCP service still needs instrumentation that extracts and uses the supplied context. Do not assume an arbitrary HTTP client, queue consumer, or remote agent follows that path. For each integration, test that the receiver appears in the expected trace or has the intended link. A transport carrying metadata and a receiver using that metadata are separate requirements.
Represent workflow causality accurately
Agent Framework workflows deliberately use links for message delivery. message.send is a child of the source executor.process span, but the target executor.process is linked to the send span rather than made its child. The target execution is not a nested call. edge_group.process also links to source send spans, supporting fan-in from multiple contributors.
Inspect links when an apparently disconnected executor consumes a message. Forcing every edge into a parent-child tree loses the meaning of concurrent and asynchronous work. A fan-in may have several contributing send spans; choosing one as its sole parent does not capture all contributors.
Use workflow attributes such as workflow.id, executor.id, message.source_id, and message.target_id where their SDK-language scope documents them. Python also documents message.destination_executor_id on message.send, while source and target IDs appear on edge processing. Do not build a query that assumes every attribute exists on every span or in every language.
Attach observable decision metadata
In Python, create an application span with Agent Framework’s get_tracer().start_as_current_span() when the coordinator applies a deterministic acceptance or routing decision. OpenTelemetry span attributes hold structured properties; span events record timed occurrences. Retain the trace and span association when exporting a separate decision record.
A proposed application schema can include decision.kind, decision.outcome, policy.version, agent.version, result.contract_version, and an evidence identifier. These names are application-defined, not standard Foundry attributes. Keep values bounded and explain what each outcome means. Record that the coordinator accepted a result because its contract validator passed, rather than asking a model to narrate an unobservable internal thought process.
See 1.2.7 for decision-record minimization and the distinction from private reasoning. Here, attach each observable verdict to the span that applied it: proposed tool call, completed execution, and accepted output are separate points. Include the tool name, validation outcome, and version reference. See 2.3.10 for result validation; the trace association identifies which execution supplied the accepted or rejected result.
Verify collection and minimize content
Connect Application Insights to the Foundry project and exercise a known agent request before relying on portal trace views. Foundry documents tracing as generally available for prompt and hosted agents, with workflow and external-agent tracing in preview. That status does not determine whether your own OpenTelemetry instrumentation emits spans.
The Python ENABLE_SENSITIVE_DATA setting and content-collection safeguards are covered in 1.2.7. For correlation, verify that decision records retain the trace ID and the exact deciding span ID after export. A record joined only by business request ID can otherwise attach a retry’s rejection to a different attempt’s accepted result. Check query-surface field mappings and version associations without requiring raw payload capture.
Key distinctions and trade-offs
Trace context versus business metadata: Context creates execution relationships. A custom request ID supports business-level joins across executions. Neither substitutes for the other.
Parent versus link: A parent expresses nesting. A link preserves causality for nonnested work and multiple contributors. Agent Framework workflow messages use the latter for downstream execution.
Decision record versus reasoning transcript: A decision record captures the observable choice and supporting checks. It need not contain a model’s private reasoning or entire input.
Adding metadata improves attribution, but uncontrolled content increases exposure and storage. Prefer stable version references and bounded outcomes; keep individual evidence identifiers in diagnostic records rather than aggregate metric dimensions.
Architecture / decision scenario
An incident-summary coordinator calls a retrieval specialist, which invokes a remote MCP search service. The classification specialist runs concurrently. All return successful results, but the coordinator rejects the summary because the evidence contract is incomplete.
The retrieval specialist uses the client-opened Python MCPStreamableHTTPTool. The team starts a root application span, verifies MCP propagation through params._meta, and checks that the receiving service extracts the context. Workflow links identify both contributions to the fan-in; the team does not flatten those links into a fabricated call chain. Application Insights OperationId groups the stored operations on the Log Analytics surface.
The coordinator attaches application-defined decision.outcome=reject and the contract version to its acceptance span, with an evidence reference rather than raw search results. Investigators can distinguish a successful service call from a rejected business result and locate the relevant specialist version. If the MCP span appears in a separate trace, they repair propagation or extraction before interpreting the gap as an agent failure.
Common exam traps
- Copying a trace ID into text and assuming distributed parentage exists.
- Treating a downstream workflow executor as a child of every send span.
- Using
operation_IdandOperationIdinterchangeably across query schemas. - Assuming all remote-agent and service integrations propagate context automatically.
- Presenting custom decision attribute names as built-in Foundry fields.
- Enabling full sensitive-content capture merely to obtain correlation.
What to remember
Preserve trace context across calls, inspect workflow links for nonnested causality, and attach minimized decision metadata to the operation that made the choice. Verify both sender propagation and receiver extraction. Correlation explains execution; explicit policy and contract outcomes explain acceptance.
Knowledge check
A caller’s instrumentation sends a traceparent header on its outgoing request, but the receiving service’s spans still start a new trace. Both services log the same business request ID. Which change establishes the distributed execution relationship?
A workflow executor consumes messages from two concurrent producers. Investigators want the trace to keep both contributors. How does Agent Framework’s workflow instrumentation relate the receiving execution to the producers’ message.send spans?
message.send is a child of its sending executor.process , while the receiving execution and edge_group.process link to the send spans, so a fan-in keeps every contributor. A single parent or a single link would drop the other producer.A Python agent changes from MCPStreamableHTTPTool to a provider-managed Foundry MCP connector. The team relies on Agent Framework’s automatic params._meta trace-context injection. What must it reassess?
Two attempts share a business request ID: the coordinator rejects one result and accepts the other. What should a separately exported acceptance record retain to tie its verdict to the right attempt?
References
- Microsoft, Observability in Agent Framework
- Microsoft, Microsoft Agent Framework workflows: Observability
- Microsoft, Application Insights telemetry data model
- Microsoft, Set up tracing for AI agents in Microsoft Foundry
- OpenTelemetry, Traces