MicrosoftMicrosoft Certified: Multi-Agent AI Solutions Expert2026-102.4 Implement multi-agent orchestration
Choose where composition becomes workflow orchestration
Completed by the knowledge check
Learning objective
Implement LangChain agent/chain composition and compare its orchestration boundary with LangGraph and Agent Framework.
Core idea
For an architect choosing an orchestration framework, distinguish composing an operation from owning the lifecycle of a business process. A chain can transform input through several components. An agent can decide which tools to invoke. A workflow can coordinate these components with explicit state, branches, and resumption.
LangChain agents are built on LangGraph. The distinction is therefore the interface you choose to control, not an assertion that LangChain lacks an execution runtime. Use LangChain’s agent interface for a configured reasoning-and-tools loop, runnable composition for a defined data transformation, and an explicit workflow when the application needs to own routing and durable process state.
Microsoft Agent Framework provides another explicit workflow abstraction, with typed executors and message-routing edges. Choose the outer orchestration owner according to the process contract, then expose inner components through small input/output contracts. Avoid having two frameworks independently manage the same approval or recovery decision.
How it works
Compose chains through runnable interfaces
A RunnableSequence passes each component’s output to the next component as input. Construct it directly or use the | operator with runnable operands. Wrap an ordinary function with RunnableLambda when it needs to participate in this interface.
The sequence supports synchronous invocation with invoke(), asynchronous invocation with ainvoke(), and multi-input processing with batch() or abatch(). Batching applies each component’s batch method in sequence. It is a processing interface, not an instruction to turn each input into an autonomous agent.
This complete example makes an application-defined normalization contract visible:
from langchain_core.runnables import RunnableLambda
normalize = RunnableLambda(lambda text: {"text": text.strip()})
measure = RunnableLambda(
lambda request: {
"text": request["text"],
"characters": len(request["text"]),
}
)
chain = normalize | measure
print(chain.invoke(" claim "))The printed result is {'text': 'claim', 'characters': 5}. The second component consumes the dictionary produced by the first. If you change that shape, update the next component’s contract rather than assuming composition repairs it.
Use RunnableParallel when several components consume the same input concurrently and return a mapping of outputs. A dictionary of runnables inside a sequence also constructs this parallel composition. It differs from a sequence, where later components consume preceding outputs. See 2.4.2 for application quorum and partial-failure decisions; a parallel output mapping alone does not specify those decisions.
Preserve streaming intentionally
A RunnableSequence preserves component streaming when its components implement transform, which maps a streaming input to streaming output. A component without that method blocks streaming until it finishes; with multiple blocking components, streaming begins after the last one.
RunnableLambda does not support transform by default. A small formatting function placed after a model can therefore change time to first visible output, even when the model itself streams. Calling stream() or astream() on the sequence is not proof that every intermediate stage streams incrementally.
Choose whether your component produces a complete validated object or incremental content. A complete object can simplify validation, while incremental output can improve perceived latency. Measure the composed behavior instead of extrapolating from one model call. This is an interface decision, not a reason to discard validation.
Configure an agent loop
Use langchain.agents.create_agent with model=, tools=, and system_prompt= to configure the agent. The model and tools define what the loop can do; instructions describe its task. Use middleware= to extend the harness for concerns that belong inside that loop.
Invoke the agent with a state update containing messages, for example a user-role message. When conversation persistence is required, configure checkpointer= and pass configurable.thread_id in invocation configuration. The same thread ID continues that conversation; a different ID addresses another thread.
The documentation uses InMemorySaver in demonstrations, but RAM storage does not survive a process restart. See 2.4.12 for persistent checkpointers, conditional edges, and interrupts. An agent’s use of LangGraph makes those capabilities available through its configured runtime; it does not remove the need to choose and operate storage.
LangChain documents Subagents as a main agent coordinating specialists as tools: routing passes through the main agent. Its Router pattern classifies input, directs it to one or more specialist agents, and synthesizes their results. Its Custom workflow pattern uses LangGraph to combine deterministic and agentic execution, embedding other patterns as nodes. This is the documented transition from agent composition to explicit workflow ownership.
Keep tools narrow when composing agents. A specialist operation should receive the task data it needs and return a result the caller can validate. The calling agent’s ability to select a tool is separate from the business process’s decision that the result is acceptable.
Assign the outer process to one owner
LangGraph’s StateGraph exposes node registration, state reducers, conditional edges, and checkpointed resumption directly. Use it when the process requires explicit branches or cycles around several agents and deterministic operations. A LangChain agent can participate as a component inside that process; the graph owns the cross-component state and routing.
Agent Framework’s WorkflowBuilder connects executors and agents through typed message edges. AgentExecutor adapts an agent to the workflow protocol; ctx.send_message() advances processing and ctx.yield_output() exposes results. See 2.4.11 for that protocol. If you integrate a LangChain operation into such a workflow, use an application adapter that maps input and output explicitly, rather than treating a LangChain message as an Agent Framework message.
Microsoft Foundry hosted agents run bring-your-own-framework code, including LangGraph and Agent Framework. Hosting runtime and orchestration owner are separate choices; see 1.2.1 for hosting selection. The hosted-agent durable state store can hold framework checkpoints, but it is preview and available only to hosted agents; the application must write its state explicitly.
These are architecture choices, not claims about automatic cross-framework interoperability. Define which framework owns process checkpoints, which owns an inner conversation, and which reports the accepted result. A persisted inner conversation is not a substitute for an outer purchase or claims state machine.
Key distinctions and trade-offs
The following comparison identifies the control surface you implement:
| Interface | Primary composition unit | Decision you control |
|---|---|---|
| LangChain runnable chain | Sequence or parallel mapping of runnables | Input/output transformation and execution mode |
| LangChain agent | Configured model-and-tools harness | Agent instructions, tools, middleware, and conversation persistence |
| LangGraph graph | Nodes over explicit state | Conditional routing, reducers, checkpoints, and interrupts |
| Agent Framework graph | Typed executors connected by edges | Message routing, agent adaptation, and workflow output selection |
A chain is compact for a known transformation. An agent handles tool selection inside a reasoning loop. An explicit graph adds process definitions and storage responsibilities, but makes cross-component decisions inspectable. The best choice is the smallest interface that expresses the required control.
Architecture / decision scenario
A support operation normalizes a request, asks a research agent for evidence, and sends sensitive adjustments for approval. Compose normalization and evidence formatting as runnable sequences. Configure the research specialist with create_agent, its permitted tools, and a conversation checkpointer where continuity is needed. Use the Subagents pattern when a main support agent invokes this specialist as a tool; use Router when input classification selects one or more specialists for synthesis.
If the service uses LangGraph, place the specialist behind a node and use explicit conditional edges for normal completion versus approval. The graph owns the adjustment state and interrupt resumption. The specialist’s conversation remains an inner concern.
If the surrounding service uses Agent Framework, implement an executor adapter for the research operation. It emits a typed evidence result to a validation executor; graph edges route the validated outcome. Agent Framework owns the outer approval lifecycle. Neither design places a business approval inside a formatting lambda or assumes that the specialist’s successful tool loop authorizes the adjustment.
Common exam traps
- Saying that LangChain agents are independent of LangGraph.
- Treating a runnable chain as an autonomous tool-selection loop.
- Confusing parallel shared input with sequential output-to-input composition.
- Assuming a streaming model makes every composed function stream.
- Expecting
InMemorySaverto survive worker restarts. - Letting inner-agent and outer-workflow recovery both own the same side effect.
What to remember
Use runnable composition for transformations and create_agent for an agent harness. Use LangGraph or Agent Framework explicitly when the application owns cross-component routing and resumption. Name one outer process owner and define adapters between component protocols.
Knowledge check
Two runnables must analyze the same normalized request concurrently and return named results. Neither consumes the other’s output. Which composition fits?
create_agent loop exposing both analyses as selectable toolsRunnableParallel mapping names to the two analysesRunnableSequence batching the two analyses as separate inputsRunnableSequence connecting the first analysis to the secondRunnableParallel supplies the same input to its components and returns a mapping of their outputs. A sequence passes one component’s output into the next, and batching applies to several inputs rather than several components; an agent harness adds model-driven tool selection the task does not need. The mapping does not itself define acceptance or partial-failure policy.A streaming model is followed by a RunnableLambda formatter in a RunnableSequence. Visible content arrives only after formatting completes. Which diagnosis fits the composition contract?
stream() rather than astream()transform interfacetransform , and RunnableLambda does not support it by default, so the formatter blocks until its input completes even though the model streams. The synchronous and asynchronous stream methods share that contract, and batching is a multi-input interface rather than a streaming buffer.An Agent Framework service uses a LangChain research specialist. The outer service must own approval and recovery for case adjustments. Which integration preserves that ownership?
A LangChain process must route among several agents and deterministic steps through explicit branches, and resume at an approval point after a restart. Which interface should own that process?
StateGraph with a persistent checkpointercreate_agent harness with a persistent checkpointerRunnableSequence with a persistent checkpointerRunnableParallel with a persistent checkpointerStateGraph exposes nodes, reducers, conditional edges and checkpointed resumption, so the application owns cross-component routing. LangChain agents run on LangGraph, but create_agent exposes a model-and-tools loop and conversation persistence rather than process branches; runnable chains compose a known transformation. Choose the smallest interface that expresses the required control.References
LangChain, LangChain overview
LangChain, Agents
LangChain, RunnableSequence
LangChain, RunnableParallel
LangChain, Graph API
Microsoft, Executors
Microsoft, Agent Executor
LangChain, Multi-agent
Microsoft, Hosted agents
Microsoft, Durable state store for Microsoft Foundry hosted agents (preview)