Agent Pipeline

An Agent is a layered pipeline — knowing the layers tells you exactly where to plug in.

Part 15 of 72 Microsoft Agent Framework Python — Every Lesson

What it demonstrates

An Agent is not a single function call — it’s a layered pipeline every request flows through, built by class composition:

Agent (outer)                     ← what you construct
  ├─ Agent Middleware + Telemetry ← wraps run(); logging/validation/spans
  ├─ RawAgent                     ← core logic; invokes context providers
  └─ Context Providers            ← history + extra context, per-run
ChatClient (separate, swappable)
  ├─ FunctionInvocation           ← the tool-calling loop
  ├─ Chat Middleware + Telemetry  ← runs per model call
  └─ RawChatClient                ← provider-specific LLM comms (Foundry here)

A request descends the Agent layers, crosses into the ChatClient pipeline, and the response flows back up.

The code

@agent_middleware
async def tracing_middleware(context: AgentContext, call_next) -> None:
    print("  [agent-middleware] entering pipeline — request handed to RawAgent")
    await call_next()  # descend: context providers -> ChatClient -> LLM -> back up
    print("  [agent-middleware] leaving pipeline — response has flowed back up")

Agent(..., middleware=[tracing_middleware], context_providers=[InMemoryHistoryProvider()]) wires the outermost layer and the context layer. Turn 1 stores a name; turn 2 recalls it because the history provider replays turn 1 into the request before it reaches the ChatClient.

The gotcha

Middleware is attached at construction (Agent(..., middleware=[fn])) and both history and RAG/context providers live in one unified context_providers=[...] list — there’s no separate history argument. Providers run in list order and can even attach per-invocation chat/function middleware, which the agent flattens before entering the ChatClient pipeline.

Azure / MAF mapping

The ChatClient is a separate, interchangeable component: swapping Foundry (FoundryChatClient + AzureCliCredential) for another provider changes only RawChatClient — the outer Agent layers are unchanged.

Run it

uv run tutorial/02-agents/07_agent_pipeline.py — needs Foundry creds. It worked if turn 2 recalls ‘Pratik’ and the middleware enter/leave lines bracket each run.


Next: Multimodal

Sources & References

The Python SDK this lesson exercises
The agent run pipeline and its layers