惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
G
Google Developers Blog
B
Blog RSS Feed
A
About on SuperTechFans
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
C
Check Point Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 司徒正美
D
Docker
F
Fortinet All Blogs
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
H
Help Net Security
WordPress大学
WordPress大学
MyScale Blog
MyScale Blog
博客园 - Franky
人人都是产品经理
人人都是产品经理
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
LangGraph vs Microsoft Agent Framework: Design Your State...
Ali · 2026-04-28 · via DEV Community

At some point in building an agentic system, you will hit the same wall. An agent workflow needs to pause, wait for a human decision, and resume. The implementation seems straightforward but then you realise: what happens to the state during the pause? Where does it live? Who owns it? How does the resumed execution know what it was doing?

That question is where LangGraph and Microsoft Agent Framework make fundamentally different architectural choices. Everything else, the feature comparison, the ecosystem fit, the vendor landscape, follows from how each framework answers it.


The widely repeated comparison is correct and useless.

The received wisdom is that LangGraph is for Python teams and Microsoft Agent Framework is for Microsoft shops. This is roughly true, but it is also the least interesting thing about either framework.

Both now offer graph-based workflows, typed nodes and edges, checkpointing, human-in-the-loop interruption, multi-agent orchestration, and MCP tool support. The feature table between them is, at this point, nearly identical. Comparing features tells you almost nothing about which one will produce a maintainable system twelve months from now.

The question worth asking is not "which framework has the features I need?" Both do. The question is: when does your system have to know what its state looks like?

In LangGraph, the answer is before the first line of agent code runs. In Microsoft Agent Framework, the answer is whenever you decide it matters.

Call it the state contract; LangGraph makes you sign it at design time while MAF lets you negotiate it later. These positions, therefore, produce different systems and different failure modes.


What the state contract looks like in practice

In LangGraph, you define a typed state schema before anything else. Every node in the graph receives that state and returns a partial update. The compiled graph, not the node functions, owns the execution model. You cannot compile without a schema; you cannot run without compiling.

The example below is a three-step document review pipeline: an AI reviewer reads the document, a human approves or rejects it, and the result routes to publish or reject. In LangGraph, the shape of the data flowing through those steps is the first thing you write.

from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt

class ReviewState(TypedDict):
    document: str
    reviewer_decision: str

def ai_review(state: ReviewState):
    # In a real pipeline this node calls an LLM; simplified here for clarity
    return {"reviewer_decision": "pending"}

def human_approval(state: ReviewState):
    # interrupt() serialises state to the checkpointer and pauses execution here.
    # The caller receives the document, supplies a decision, and execution resumes.
    decision = interrupt({"document": state["document"]})
    return {"reviewer_decision": decision}

def route(state: ReviewState):
    return "publish" if state["reviewer_decision"] == "approve" else "reject"

def publish(state: ReviewState):
    return {"document": f"[PUBLISHED] {state['document']}"}

def reject(state: ReviewState):
    return {"document": f"[REJECTED] {state['document']}"}

graph = StateGraph(ReviewState)
graph.add_node("ai_review", ai_review)
graph.add_node("human_approval", human_approval)
graph.add_node("publish", publish)
graph.add_node("reject", reject)
graph.add_edge(START, "ai_review")
graph.add_edge("ai_review", "human_approval")
graph.add_conditional_edges("human_approval", route)
graph.add_edge("publish", END)
graph.add_edge("reject", END)

app = graph.compile(checkpointer=InMemorySaver())

Enter fullscreen mode Exit fullscreen mode

Before a single prompt fires, you have defined exactly what flows through this system: a document and a decision. When the graph hits interrupt(), it serialises the full state to the checkpointer and halts. The caller retrieves the saved state, presents it to a human, and resumes execution by passing the decision back in. The graph picks up from the exact checkpoint, with all prior state intact.

The cost of explicit; you cannot prototype quickly without thinking about state. On a trivial workflow, the schema ceremony could appear as disproportionate.


What the alternative looks like

Microsoft Agent Framework separates two concepts from the start: an Agent that drives autonomous, LLM-guided behaviour, and a Workflow that enforces a deterministic execution path.

The same three-step document review pipeline looks like this in MAF. An Executor is MAF's equivalent of a LangGraph node: a typed processing unit that receives a message, does work, and forwards a result. WorkflowBuilder wires executors together with edges.

from agent_framework import Agent, Executor, WorkflowBuilder, WorkflowContext, handler
from agent_framework.openai import OpenAIChatClient

# The agents that do the LLM work
reviewer_agent = Agent(
    client=OpenAIChatClient(),
    instructions="Review this document. Return a brief assessment.",
)

# Executors are the nodes of the graph
class ReviewExecutor(Executor):
    @handler
    async def run(self, document: str, ctx: WorkflowContext) -> None:
        result = await reviewer_agent.run(document)
        await ctx.send_message(result.text)  # forwards to the next executor

class PublishExecutor(Executor):
    @handler
    async def run(self, review: str, ctx: WorkflowContext) -> None:
        await ctx.yield_output(f"[PUBLISHED] Review: {review}")

class RejectExecutor(Executor):
    @handler
    async def run(self, review: str, ctx: WorkflowContext) -> None:
        await ctx.yield_output(f"[REJECTED] Review: {review}")

# Wire the executors with edges — same concept as add_node + add_edge in LangGraph
review = ReviewExecutor(id="review")
publish = PublishExecutor(id="publish")
reject = RejectExecutor(id="reject")

workflow = WorkflowBuilder(start_executor=review).add_edge(review, publish).build()

Enter fullscreen mode Exit fullscreen mode

Notice what is absent: a state schema. The data contract between executors is the message type passed between them, not a shared typed dict declared before anything runs.

For human-in-the-loop, MAF uses a different model than LangGraph's checkpoint-and-pause. Rather than halting in-place, the workflow emits an event and you re-run it with the human's response. Using SequentialBuilder with with_request_info, a pipeline pauses after a nominated agent runs, surfaces its output for human review, and resumes when you feed the response back in:

from agent_framework.orchestrations import SequentialBuilder, AgentRequestInfoResponse

pipeline = (
    SequentialBuilder(participants=[reviewer_agent, publisher_agent])
    .with_request_info(agents=["reviewer"])  # pause after reviewer, before publisher
    .build()
)

# First run: reviewer fires, workflow emits a request_info event
stream = pipeline.run(document_text, stream=True)
pending = await collect_approvals(stream)  # your handler surfaces the review to a human

# Resume: feed the human's decision back in
if pending:
    stream = pipeline.run(stream=True, responses=pending)
    await collect_approvals(stream)

Enter fullscreen mode Exit fullscreen mode

The emit-and-rerun model is a genuine architectural difference from LangGraph's interrupt. LangGraph's state is serialised at the exact point of pause and restored on resume: the graph does not restart, it continues. MAF's request-response model re-runs the workflow from the current position with the human response as an input. For most approval workflows the behaviour looks the same from the outside. For long-running workflows with complex branching, the difference in how state is maintained across the pause matters more.

The appeal of MAF's layered approach is real; build the agent behaviour first, run it, understand what actually flows through the system, and _then _add workflow structure once you know what it needs to look like. No schema ceremony on day one.

However, the cost of this position may surface later in a complex production system; needing a workflow that coordinates multiple agents, each maintaining its own session state, and you need consistent state across a human approval step; you will be working across two abstractions that were designed separately. It is possible, but is more work than it looks on day one.


Where the learning curve actually lives

Most comparisons describe LangGraph as steep and MAF as approachable. This is accurate for the first week of development and inaccurate for the first six months.

LangGraph's learning cost concentrates at the start. There are four concepts to internalise:

  • the state schema and how reducers merge concurrent updates;

  • the compiled graph as a distinct artefact from the node functions;

  • the checkpointer pattern and how thread IDs isolate independent conversations; and

  • conditional edges versus routing functions.

These are genuinely non-obvious the first time. Once learned, the model is consistent everywhere. A LangGraph graph written by someone else is readable without context because the state contract is explicit and the execution path can be traced from the compiled artefact before running a single call.

MAF's learning cost distributes differently. The simple agent is genuinely simple. The workflow API is learnable. The composition challenge, combining an autonomous agent with checkpointed workflows and multi-step human approval inside a single pipeline, arrives later and hits harder. The migration guides from AutoGen and Semantic Kernel exist precisely because neither of those predecessor APIs composed cleanly either. Microsoft unified them in part to solve this problem; how well the composition works in practice is still being tested in production.

The practical upshot is if you prototype a simple agent in both frameworks today, MAF will feel faster. If you build a complex production workflow in both frameworks over three months, LangGraph will have fewer surprises. The inflection point depends on how complex your workflow actually is. For most workflows that require branching, human approval, and fault recovery, it arrives before month three.


The ecosystem reality

LangGraph has a substantially larger open-source community, a deeper ecosystem of integrations, and a set of verified production deployments at scale. Python is the dominant language in AI development and LangGraph is Python-first. Community answers are easier to find. The production evidence, from companies running agent workloads against tens of millions of users, exists and is documented.

MAF is backed by Microsoft. This matters in specific contexts: a documented migration path from AutoGen and Semantic Kernel brings existing practitioners in without a full rewrite; the Azure AI Foundry integration is the default agentic path for teams in the Azure ecosystem; and enterprise procurement conversations are easier when the framework vendor can offer a support contract.

Neither of these is a technical argument, but they are arguments about where default momentum points when a team is choosing a framework without strong prior opinions. For Python-first AI teams without Azure commitments, the momentum is toward LangGraph. For teams inside the Azure ecosystem or migrating from predecessor Microsoft frameworks, it is toward MAF. That is not a reason to override the architectural fit assessment; it is a reason to notice where friction will be lower.


The recommendation

There is one question that is more predictive than any feature comparison:

when you build a system, do you prefer to define the schema first and let the implementation follow, or do you prefer to build the implementation and formalise the schema once you know what it needs to be?

If you are a schema-first developer, LangGraph fits your mental model. The state contract is not overhead; it is how you think. The compiled graph is a readable specification. The investment in state design up front pays back in debugging, resumability, and the ability to hand the codebase to a new engineer without a lengthy explanation.

If you are a behaviour-first developer, MAF's layered approach fits you better. Build the agent, run it, understand what it actually does, then add workflow structure where the process needs it. The simple agent requires no architecture decisions at all to start.

The ecosystem considerations are secondary to this. Teams have shipped complex agentic systems with both frameworks in both the Python and .NET ecosystems. The architectural fit determines whether the system is a joy or a grind to maintain. The ecosystem determines where you will find help when you get stuck. Both matter, and they matter in that order.