Production-ready agents, Part 1.75: Agent frameworks, and where ADK fits
ADK is one agent framework among several. This part explains what an agent framework is, corrects the idea that ADK is internal or Gemini-only, and walks through ADK, LangGraph, CrewAI, the OpenAI Agents SDK, Microsoft Agent Framework and the Claude Agent SDK against the same ten production concerns, with Acme's routing step written in each.
Every part of this series builds on Google’s Agent Development Kit (ADK). When I share the series with partners, the first reply is often a question about that choice: “We already use LangGraph. Is ADK a Google-only tool? Does it only work with Gemini? Would we have to rewrite everything?” Those are fair questions, and the honest answers are short: no, no, and no.
Part 1.5 explained the three foundations under every agent: the harness (the code around the model), the loop (plan, act, observe, stop) and the context (what the model sees on each call). This part takes one step back and asks where those come from in practice. Almost nobody writes them from scratch. They come from an agent framework, and ADK is one framework in a crowded category.
So this post explains what an agent framework is, what ADK is exactly, and how six frameworks (ADK, LangGraph, CrewAI, the OpenAI Agents SDK, Microsoft Agent Framework and the Claude Agent SDK) handle the same ten production concerns. Then it writes Acme’s routing step in each one, shows how agents built in different frameworks can still work together, and explains why this series uses ADK. If you want a broader tour of the patterns underneath frameworks, I wrote one for forward deployed engineers in Forward deployed engineering, Part 6: Agent frameworks compared; this post keeps to the production lens of this series.
The running example is the same as everywhere else: Acme Consumer Brands, whose router agent sends each question to a marketing specialist (BigQuery) or a supply specialist (Databricks). Maria in marketing asks “What did those stockouts cost us?”, and because penalties belong to the supply team, code must send that question to supply.
If you prefer to watch first, here is the heart of this part as a short animated explainer.
Video: what an agent framework is and where ADK fits among six of them, in three minutes. The narration is a synthetic voice; the script and animation are mine.
Where are we in the architecture?
This part compares the frameworks you could write the agent boxes in. Acme uses ADK, and the boxes stay the same whichever you pick. It also adds the market watch agent, a Google-run managed agent the router hands public research questions to. Part 1.25 walks through the whole picture, layer by layer.
where Part 1.75 sits in the Acme architecture: highlighted boxes are the subject of this part, solid boxes come from earlier parts, faded boxes arrive later
What is an agent framework?
Simple definition first: an agent framework is a library that gives you a ready-made harness, loop and context handling, so that you write only the parts that are specific to your problem. In Part 1.5 we looked at what the harness does on every turn. A framework is a harness that someone else has already built, tested and documented.
An everyday example first: opening a restaurant in a bare room versus a fitted kitchen. In the bare room you would have to install the oven, plumb the sink, wire the timers, fit the smoke alarm and start an order book before you cooked anything. In a fitted kitchen all of that is there on day one, and you bring what makes your restaurant yours: the recipes, the ingredients and the house rules. Move to a different fitted kitchen and your recipes come with you; you only learn where the new oven’s dials are.
The fitted kitchen is the framework: the oven is the model client, the timers are the loop limit, the smoke alarm is the hooks, the order book is sessions and tracing. The recipes and ingredients are your instructions, tools and data access. The misconception to drop is that the framework makes the agent smart. It does not; the model does the thinking and your tools supply the facts. The framework only makes the kitchen safe and repeatable.
The more formal version comes from LangChain’s Runtimes, frameworks, and harnesses page, which says that agent frameworks “provide abstractions that make it easier to get started when building with LLMs”, such as “the agent loop, and middleware”. The same page names two neighbouring categories, and the split is useful:
- Agent framework: the abstractions you build with: agents, tools, the loop and hooks.
- Agent runtime: the machinery that runs agents reliably, which that page lists as durable execution, streaming, human-in-the-loop and persistence.
- Agent harness: an opinionated, batteries-included agent with built-in tools such as planning, a file system and subagents.
Real products blur these lines. ADK and Microsoft Agent Framework include runtime features, and Anthropic calls the Claude Agent SDK “the agent harness that powers Claude Code” in its launch post. In this post I use “framework” for all six, because each is a library you import to build an agent.
Broken into parts, a framework packages six things that map straight onto Part 1.5:
- A model client that sends the context to a model and reads back text or a tool call.
- A tool loop that runs the tool the model asked for, returns the result and decides whether to go round again. This is the inner loop from Part 1.5.
- State and sessions, so a conversation can continue across turns.
- Multi-agent patterns, such as graphs, handoffs, crews or subagents. Part 6.5 maps each of these names to the underlying topology.
- Hooks, the places where your code runs before or after a model call or tool call. Guardrails and human approvals live here.
- Tracing and evals, so you can see what happened and test whether it was right.
How does this apply to Acme? Here is the bare room and the fitted kitchen on one question, “How
much did we spend on Acme Pure?”, using the toy get_spend
tool from Part 1. Without a framework, you write the loop yourself. This is pseudocode, with the packaged
item that replaces each line in brackets:
1. Build the context: instruction + question + history (state and sessions)
2. Send it to the model, read back text or a tool call (model client)
3. Model asks for get_spend(brand="Acme Pure"): run it,
append {"status": "ok", "brand": "Acme Pure", "spend_eur": 283590},
call the model again (tool loop)
4. Model returns text: "We spent EUR 283,590 on Acme Pure."
Stop. (tool loop)
5. Check the tool call before it runs (hooks)
6. Save every step so you can debug and test it later (tracing and evals)
7. Give up after N calls so a confused model cannot spin (tool loop limit)
With ADK, you write only get_spend and one instruction, wrap them in an Agent and an App, and Part
1’s runner = InMemoryRunner(app=app) and await runner.run_debug("How much did we spend on Acme Pure?") do all seven lines, printing the tool request, the result and the answer as events. The model still decides to call
get_spend; the framework’s code runs it, records it and stops the loop.
an agent framework packages the harness, loop and context handling as a library: you write the instructions, tools, rules and data access, which stay the same in every framework; the framework gives you the model client, the tool loop, state and sessions, multi-agent patterns, hooks for guardrails and approvals, and tracing and evals; ADK, LangGraph, CrewAI, the OpenAI Agents SDK, Microsoft Agent Framework and the Claude Agent SDK are all members of this one category
Notice what stays yours in every framework: the instructions, the tool functions, the business rules and the data access. That is why moving between frameworks is less work than people fear, and why the ten production concerns from Part 1.5 are a fair way to compare them.
What is ADK exactly?
ADK (Agent Development Kit) is Google’s open-source framework for building, testing and deploying agents. The ADK home page describes it as “the open-source agent development framework that lets you build, debug, and deploy reliable AI agents at enterprise scale”, available in Python, TypeScript, Go, Java and Kotlin. The source is on GitHub under the Apache 2.0 licence, so anyone can read it, change it and use it commercially.
Two misconceptions come up often, and the public documentation answers both.
- “ADK is an internal Google tool.” It is a public project with public releases; the README says
the Python release cadence is “roughly bi-weekly”. You install it with
pip install google-adkornpm install @google/adk, the same way as any other library. - “ADK only works with Gemini.” The README says: “While optimized for Gemini, ADK is
model-agnostic, deployment-agnostic, and compatible with other frameworks.” The
models page lists Gemini, Claude and models hosted on Agent
Platform by name, plus model connectors for Apigee, LiteLLM (a Python library that translates
one API call into many providers’ formats), Ollama, vLLM and LiteRT-LM, and a model routing option with
automatic failover. The LiteLLM connector is Python only.
Suppose you take Acme’s marketing
Agent, keep the same instruction and the sameget_spendtool, and change only its model setting from Gemini to one of the Claude models on that page. “Spend on Acme Pure?” still returns EUR 283,590, because the number comes from the tool, not the model. What can change is the wording around it and how well the model picks the tool.
Deployment is open as well. The deployment page lists Agent Runtime (the managed agent service on Google Cloud), Cloud Run, Google Kubernetes Engine (GKE) and “any environment that supports container images”, including running “offline or disconnected” with no connection to Google Cloud.
On versions: ADK 2.0 moved ADK “from a hierarchical agent executor to a graph-based execution engine”. It reached general availability (GA) in Python on 19 May 2026, in Go on 30 June 2026 and in TypeScript on 21 August 2026. Graph workflows are what Part 5 uses for the router.
Which six frameworks are we comparing?
I picked the six frameworks partners ask me about most. Two come from model providers (OpenAI and Anthropic), two from cloud providers (Google and Microsoft) and two from independent companies (LangChain and CrewAI). After the six, a short section covers Databricks Agent Bricks (formerly the Mosaic AI Agent Framework), which partners on Databricks ask about: it is a platform around a framework rather than a seventh loop library.
six agent frameworks at a glance as of October 2026: ADK from Google, Apache 2.0, in five languages, hosted on Agent Runtime; LangGraph from LangChain, MIT, hosted on LangSmith Deployment; CrewAI, MIT, with crews and flows, hosted on CrewAI AMP; the OpenAI Agents SDK, MIT, which you host yourself; Microsoft Agent Framework, MIT, the successor to AutoGen and Semantic Kernel, hosted on Foundry; and the Claude Agent SDK from Anthropic, used under its Commercial Terms, which you host yourself
Each framework below gets the same treatment: what it is, its building blocks, then the production concerns from Part 1.5 in the same order, and finally when I would choose it. All facts are from each project’s public documentation as of October 2026.
How does each framework handle the production concerns?
The short answer: all six cover the same basics, and they differ in a few edges (long-term memory, built-in evals, a managed place to deploy and A2A support). Each card below answers the same questions in the same order, so you can read one line across all six; if you are short of time, read each card’s Choose it when line first and come back for the detail.
ADK
What it is. Google’s open-source framework, described above. Its core idea since 2.0 is that agents, tools and functions are all nodes in a graph, so deterministic code and model calls sit in the same workflow.
- Building blocks:
Agent(an LLM agent with instructions and tools),Workflow(a graph of nodes and edges), function tools, theRunnerandAppthat make up the harness, session and memory services, callbacks and plugins. - The loop: the Runner runs the inner loop; you cap it with
max_llm_callsinRunConfig. Outer loops are aLoopAgentwithmax_iterations, as Part 1.5 showed. - State and memory: session state with
{key}templating into instructions, context compaction, and a memory service for long-term recall, which Memory Bank on Google Cloud implements (Part 8). - Multi-agent: graph workflows with routes, fan-out and joins
(routes), coordinator agents with
sub_agents, and remote agents over A2A. - Guardrails: callbacks before and after model and tool calls, and plugins that apply across a whole app.
- Human in the loop: a
RequestInputnode in graph workflows, which needs no model, and tool confirmation, which the documentation labels Experimental. - Tracing and evals: observability through logging, metrics and
OpenTelemetry traces, and evaluation with evalset files from the
adk evalcommand line (Part 10). - Deployment: Agent Runtime, Cloud Run, GKE or any container.
- Choose it when your agents will run on Google Cloud and reach users through Gemini Enterprise, or when you want deterministic graphs and model calls in one framework in several languages.
LangGraph
What it is. The LangGraph overview calls it “a low-level orchestration framework and runtime for building, managing, and deploying long-running, stateful agents”. It is from LangChain, MIT licensed, in Python and JavaScript, and it does not require the higher-level LangChain library. LangChain 1.0 and LangGraph 1.0 shipped on 22 October 2025 with a promise of “no breaking changes until 2.0”.
- Building blocks: the Graph API has
three: State (“a shared data structure that represents the current snapshot of your
application”), Nodes (functions that update the state) and Edges (functions that decide which
node runs next), assembled with
StateGraph. - The loop: a graph runs in super-steps, and the recursion limit caps how many it can take
before raising
GraphRecursionError. Since version 1.0.6 the default is 1,000, so set a lower one for narrow agents. - State and memory: persistence comes in two parts: checkpointers save a thread’s state for short-term memory, and stores keep long-term, cross-thread facts such as user preferences.
- Multi-agent: you draw it as a graph, with conditional edges, parallel branches and subgraphs.
- Guardrails: there is no separate guardrail object in LangGraph itself; you write checks as nodes or conditional edges. The higher-level LangChain agent adds guardrails as middleware.
- Human in the loop:
interrupt()pauses a node, saves state through the checkpointer and “waits indefinitely” until you resume withCommand(resume=...). - Tracing and evals: LangSmith, a separate LangChain product, traces and evaluates agents built with any framework.
- Deployment: LangSmith Deployment runs agents in LangChain’s cloud, your cloud or your own infrastructure. On Google Cloud, Agent Runtime can host a LangGraph agent.
- Choose it when you want explicit control of every step with durable, resumable state, and you are happy to build more yourself.
CrewAI
What it is. An open-source Python framework (MIT licence) built around a team metaphor. The introduction describes two layers: Crews, “teams of autonomous agents that collaborate to solve specific tasks”, and Flows, “structured, event-driven workflows that manage state and control execution”.
- Building blocks: an
Agenthas arole,goalandbackstory; aTaskis a unit of work; aCrewruns tasks with aProcess; and aFlowwires methods together with@start,@listenand@routerdecorators. - The loop: each agent has
max_iter(“maximum iterations before the agent must provide its best answer”, default 20), plusmax_execution_timeandmax_rpm(requests per minute). - State and memory: Flow state is a dictionary or a Pydantic model. A
unified
Memoryclass “replaces separate short-term, long-term, entity, and external memory types”, withremember()andrecall(). - Multi-agent: crews run tasks sequentially or hierarchically, where a manager model or manager agent delegates.
- Guardrails: task guardrails validate a task’s output before the next task runs, retrying up
to
guardrail_max_retries(default 3), and execution hooks intercept model and tool calls. - Human in the loop: the
@human_feedbackdecorator pauses a Flow for review (version 1.8.0 or later), and tasks accepthuman_input. - Tracing and evals: built-in tracing through
the CrewAI AMP platform, plus integrations with tools such as MLflow and OpenLIT. The
crewai testcommand scores a crew over several runs, and the documentation says that “the only provider available is OpenAI” for it. - Deployment: CrewAI AMP, the commercial suite, adds managed deployment, observability and governance, in the cloud or on premises. You can also run CrewAI in your own container.
- Choose it when the work naturally splits into roles and tasks and you want a working team of agents quickly, with Flows for the parts that must be predictable.
OpenAI Agents SDK
What it is. OpenAI’s Agents SDK is “a lightweight, easy-to-use package with very few abstractions” and “a production-ready upgrade” of its earlier experiment, Swarm. It is MIT licensed, in Python and TypeScript. The Python package is at version 0.24 on its GitHub releases page, so it still uses pre-1.0 version numbers.
- Building blocks: Agents (“LLMs equipped with instructions and tools”), handoffs and
agents as tools for delegation, guardrails, the
Runner, sessions and tracing. - The loop: the Runner calls the
model, runs any tool calls or handoffs and loops until the model produces a final output with no tool
calls. Past
max_turnsit raisesMaxTurnsExceeded. - State and memory: sessions store conversation history in SQLite, Redis, SQLAlchemy, Dapr, MongoDB or an encrypted wrapper. One honest gap: the pages I read cover session history, and I did not find a long-term memory service like ADK’s or CrewAI’s, so plan to add your own.
- Multi-agent: the orchestration guide describes two ways: “allowing the LLM to make decisions” with handoffs or agents as tools, and “orchestrating via code”.
- Guardrails: three kinds. Input guardrails run “only for the first agent in the chain”, output guardrails “only for the agent that produces the final output”, and tool guardrails on every guarded tool call.
- Human in the loop: mark a tool with
needs_approval; the run pauses with an interruption, and you resume it from the saved run state. - Tracing and evals: tracing is “enabled by default” and sends traces to OpenAI’s dashboard; you can add your own trace processors, and tracing is unavailable under a Zero Data Retention policy. The testing utilities run workflows in memory with no model calls.
- Models: OpenAI models through the Responses or Chat Completions API, and other providers through LiteLLM or Any-LLM adapters.
- Deployment: the SDK has no managed home of its own; you run it in your own service or container.
- Choose it when you use OpenAI models and want the smallest set of primitives to learn.
Microsoft Agent Framework
What it is. Microsoft’s open-source framework (MIT licence) for agents and multi-agent workflows in Python and .NET, with Go in public preview. It is the successor to both AutoGen and Semantic Kernel. The version 1.0 announcement on 3 April 2026 says Microsoft set out “to unify the enterprise-ready foundations of Semantic Kernel with the innovative orchestrations of AutoGen into a single, open-source SDK”, and calls 1.0 “the production-ready release: stable APIs, and a commitment to long-term support”. The AutoGen repository now tells new users to start with Microsoft Agent Framework.
- Building blocks: the overview lists agents, workflows, integrations and a “Harness Agent”, built on model clients, an agent session for state, context providers for memory, middleware and MCP clients.
- The loop: an agent runs its own tool loop; you stop it early with termination and guardrail middleware.
- State and memory:
AgentSessionholds conversation state, and context providers plug in memory backends; the 1.0 post names Foundry Agent Service memory, Mem0, Redis and Neo4j. - Multi-agent: graph workflows of executors and edges, with checkpointing, plus five ready-made orchestrations: sequential, concurrent, handoff, group chat and Magentic.
- Guardrails: middleware of three types, around agent runs, function calls and chat client calls.
- Human in the loop: workflows pause on
request ports, and a
tool can require approval with
approval_mode="always_require". - Tracing and evals: OpenTelemetry
following the GenAI semantic conventions, and an
evaluation framework with
evaluate_agent()andevaluate_workflow(), scored locally or in Microsoft Foundry. - Models: connectors for Microsoft Foundry, Azure OpenAI, OpenAI, Anthropic Claude, Amazon Bedrock, Google Gemini and Ollama. The Gemini page covers the Gemini Developer API and Gemini Enterprise Agent Platform.
- Deployment: the hosting guide says Microsoft Foundry Hosted Agents is generally available and the Python self-hosting packages are prerelease. Several features shipped as preview at 1.0, including DevUI and AG-UI support.
- Choose it when your team works in .NET or Microsoft Foundry, or you are moving off AutoGen or Semantic Kernel.
Claude Agent SDK
What it is. Anthropic’s SDK for building agents on the same engine as Claude Code. Anthropic renamed
the Claude Code SDK to the Claude Agent SDK on 29 September 2025 “to reflect this broader vision”,
and the migration guide lists the new
packages, claude-agent-sdk for Python and @anthropic-ai/claude-agent-sdk for TypeScript. The
overview says it gives you “the same tools, agent
loop, and context management that power Claude Code”. On licensing, the overview says use is governed by
Anthropic’s Commercial Terms of Service; the Python repository on GitHub shows an MIT licence for its
code.
- Building blocks: the
query()function, an options object (ClaudeAgentOptionsin Python), built-in tools for files, commands and web search, custom tools, hooks, permissions, subagents, sessions, skills and plugins. - The loop: the agent loop runs until Claude
stops calling tools.
max_turnscounts tool-use round trips andmax_budget_usdstops at an estimated spend; both default to no limit, so set them. - State and memory: sessions can be resumed
or forked, and the SDK compacts history automatically when the context window fills. Persistent rules
belong in a
CLAUDE.mdfile, which is “re-injected on every request”. - Multi-agent: subagents defined with
AgentDefinition, each with its own prompt, tools and model, to isolate context or run work in parallel. - Guardrails: hooks such as
PreToolUseandPostToolUse, and permission rules and modes (default,dontAsk,acceptEdits,bypassPermissions,planandauto). - Human in the loop: the
canUseToolcallback fires when Claude needs permission for a tool or asks a clarifying question. - Tracing and evals: OpenTelemetry export of traces, metrics and events. One honest gap: I found no evaluation feature in the SDK documentation, so evals come from a separate tool. One that works with any framework is Google’s Gen AI evaluation service, which accepts a “custom agent function” that returns the agent’s response and trajectory, and then scores both.
- Models: built for Claude models, through the Anthropic API, Amazon Bedrock, Google Cloud’s Agent Platform or Microsoft Foundry.
- Deployment: you host it. The hosting guide
explains that the SDK “spawns and supervises a
claudeCLI subprocess” with its own shell, working directory and session files, one per session. Anthropic’s separate Managed Agents product hosts an agent loop for you instead. - Choose it when the agent’s job involves files, commands and long autonomous tasks, and Claude is your model.
Databricks Agent Bricks (formerly Mosaic AI Agent Framework): a platform, not another loop
Partners on Databricks often ask where Databricks’ agent offering fits in this list. You will hear two
names for it: Databricks used to call it the Mosaic AI Agent Framework, and its current
documentation says
“Agent Bricks is the Databricks agent developer platform” (as of October 2026; the documentation URLs
still say agent-framework). Either way, the honest answer is that it is not a seventh loop library. Databricks’ own
deployment guide describes a deployed agent in three
layers, and only leaves the first one to you:
Layer What it does On Databricks (as of October 2026)
Framework or harness runs the agent loop: calls models and tools "Any framework or harness, such as
and decides what to do next LangGraph or the OpenAI Agents SDK"
Agent server wraps the loop in an HTTP server: the DurableAgentServer (recommended),
invocation API, connections, durability legacy agent servers, or your own
Agent runtime runs the server on managed compute: Agent Runtime on Databricks Apps
hosting, identity, scaling
So Agent Bricks is the platform around whichever framework you pick, much as Google’s Agent Platform (Agent Runtime, agents-cli, Agent Gateway) is the platform around ADK:
- Building blocks: you write the agent in any framework and wrap it in MLflow’s
ResponsesAgentinterface; the authoring page lists templates for LangGraph and the OpenAI Agents SDK, and clients call it through the OpenAI Responses API at/responsesor the invocation API. - Tooling: the
Agent Bricks CLI (
agentbricks) scaffolds, runs and deploys an agent. Itsagent.tomlis “the declarative source of truth for all Databricks-managed resources your agent depends on”: tool bindings (managed MCP services, Genie, Unity Catalog functions) and memory and session stores. Databricks marks the CLI and the custom agent APIs it uses as experimental. Agents deployed the older way, on Model Serving withdatabricks.agents.deploy(), still work; Databricks now recommends the CLI for new agents. - Durability:
DurableAgentServerkeeps run state so a turn survives a restart; the documentation contrasts it with the MLflowAgentServer, which “doesn’t provide the persistent run state, crash recovery, idempotent invocations, or ordered sessions”. - Tracing and evals: MLflow Tracing records “each step that an agent takes”, and MLflow evaluation measures quality “with LLM judges, custom scorers, and expert feedback”.
- Governance: Unity Gateway governs “access to models, MCP servers, and skills, with guardrails, rate limits, and usage tracking”, and Databricks-provided MCP servers use Unity Catalog permissions.
- Choose it when your data and your team already live in Databricks and the agent’s job is mostly about that data, so it can sit next to Unity Catalog’s permissions instead of reaching across a cloud boundary.
For Acme, this is a real option for one box, not the whole system. Suppose the supply team wanted to own
its specialist end to end inside Databricks: a LangGraph agent, served by DurableAgentServer on Agent
Runtime on Databricks Apps, reading supply_service under Unity Catalog permissions. The router would
not care, as long as the specialist answered over A2A, either natively or through a thin A2A wrapper
around its invocation API (the wrapping pattern from the agent-first SDKs below). The ownership rule,
the number check and the identity flow from the rest of the series stay exactly the same.
How do they compare across the production concerns?
Here are the ten concerns from Part 1.5, plus deployment and interoperability, in one grid. The labels are short; the sections above have the detail and links.
the ten production concerns from Part 1.5 plus deployment and A2A and MCP interop, compared across ADK, LangGraph, CrewAI, the OpenAI Agents SDK, Microsoft Agent Framework and the Claude Agent SDK: every framework has a harness, a loop limit, state, tools, multi-agent patterns, guardrail hooks, a human approval mechanism and tracing; they differ most in long-term memory, built-in evals, managed deployment and A2A support
Three things stand out when I read the grid as a whole:
- Every framework covers the basics. All six have a harness, a loop limit, state, tools, a multi-agent pattern, guardrail hooks, a human approval mechanism and tracing. None of these is a reason to pick one framework over another on its own.
- Loop limits differ by orders of magnitude. CrewAI stops an agent at 20 iterations by default, LangGraph at 1,000 super-steps, ADK at 500 model calls, and the Claude Agent SDK has no limit unless you set one. Whatever you choose, set the limit yourself.
- The real differences are around the edges: built-in long-term memory, built-in evals, a managed place to deploy, and A2A support. Those are also the concerns that cost the most to add later.
To see why the loop limit matters, start with a phone. You ring a shop and the line is engaged. A sensible person tries again a few times and then gives up and sends an email. An auto-redial set to “keep trying” rings all night, and if each call cost money you would find out in the morning. Every retry is reasonable on its own; the problem is the missing rule for when to stop. The redial setting is the framework’s default loop limit, and the person deciding to send an email instead is your code catching the stop.
How does this apply to Acme? Suppose the Databricks warehouse is down, so get_penalties returns
{"status": "error", "message": "warehouse unavailable"} every time, and the model keeps retrying. This
is how many trips the supply specialist could make before each framework’s default stops it
(illustrative; the units differ, but the orders of magnitude are the point):
CrewAI agent stops after 20 iterations (max_iter default)
ADK Runner stops after 500 model calls (max_llm_calls default)
LangGraph graph stops after 1,000 super-steps (recursion limit default)
Claude Agent SDK never stops (max_turns default: no limit)
With max_turns=5 stops after 5 turns (as in the OpenAI and Claude panels below)
With max_turns=5, the failure costs five model calls. Your code catches the stop (in the OpenAI Agents
SDK, MaxTurnsExceeded) and tells Maria “supply data is unavailable right now”. The model never decides
when to give up; the limit in code does.
Human approval also looks different in each framework but behaves the same. The everyday version is a
company payment over a set amount: the clerk can prepare it, but the bank holds it until a second
person signs, and if nobody signs, no money moves. The clerk is the model, the held payment is the
paused run, and the signature is the person’s yes. Take Acme’s one write tool,
trigger_sop_replan from Part 9, which starts a Databricks job that writes a new supply plan:
1. The model asks for trigger_sop_replan(...).
2. The run pauses before the tool runs: a RequestInput node or tool confirmation in ADK,
interrupt() in LangGraph, needs_approval in the OpenAI Agents SDK,
approval_mode="always_require" in Microsoft Agent Framework.
3. The signed-in user sees a prompt such as "Approve replan? yes/no" and clicks yes.
4. The run resumes from saved state (in LangGraph, Command(resume=...)) and the job starts.
If the answer is no, the write never runs.
The model can only ask for the write; a person decides, and code enforces the pause.
What does the same step look like in each framework?
The short answer: the rule is identical in all six; only the furniture around it changes. Think of a post room. Letters are sorted by a written rule, the postcode, and nobody opens a letter to guess where it should go. One post room uses pigeonholes, another a conveyor belt, a third a clerk with a list, but the same letter always ends up in the same tray. The sorting rule is Acme’s ownership rule in code, and the pigeonholes, belts and clerks are each framework’s way of writing a route.
How does this apply to Acme? Acme’s router does one thing that matters for this comparison: code decides which specialist answers, and only then does a model run. The diagram shows that step and what each framework calls its two halves.
the same step in six frameworks: a question arrives, a route step written in code picks the supply specialist with no model call, the specialist answers; in ADK the route is a function node and a dict edge, in LangGraph a routing function with add_conditional_edges, in CrewAI a router method and a listener, in the OpenAI Agents SDK and the Claude Agent SDK plain Python before the run, and in Microsoft Agent Framework a switch-case edge group
The six panels below are illustrative. Each is 10 to 15 lines and uses only APIs from the current
public documentation, but they are not complete programs. In every panel, owner_of(question) stands in
for the ownership rule from
Part 1, returning "marketing" or
"supply", and get_spend and get_penalties stand in for the narrow tools from
Part 2.
All six panels do the same thing when they run. Here is one trace that holds for every one of them (figures from Part 1; the tool results are illustrative, and the tool’s arguments are left out because the panels don’t define them):
Question A: "What did those stockouts cost us?"
1. Route (code): owner_of(...) returns "supply". No model call, no tokens.
2. Act (model): the supply specialist calls get_penalties(...)
3. Observe (tool): {"status": "ok", "service_penalty_eur": 36026, "region": "Western Europe"}
4. Answer (model): "Stockouts cost EUR 36,026 in retailer penalties in Western Europe
(EUR 51,331 across both campaign regions)."
Question B: "How much did we spend on Acme Pure?"
1. Route (code): owner_of(...) returns "marketing".
2. Act (model): the marketing specialist calls get_spend(brand="Acme Pure")
3. Observe (tool): {"status": "ok", "brand": "Acme Pure", "spend_eur": 283590}
4. Answer (model): "We spent EUR 283,590 on Acme Pure."
Code made the routing decision in step 1, so the same question always reaches the same specialist. The model only chose the tool call and wrote the sentence, and the number came from the tool.
ADK. A function node sets a route value and a dict edge maps it to the specialist, as in Part 5.
# Illustrative: ADK 2.x graph workflow
from google.adk import Agent, Event, Workflow
supply = Agent(name="supply", model="gemini-flash-latest",
instruction="Answer supply questions using only your tools.", tools=[get_penalties])
marketing = Agent(name="marketing", model="gemini-flash-latest",
instruction="Answer marketing questions using only your tools.", tools=[get_spend])
def route(node_input: str):
"""Plain Python: no model call, same answer every time."""
return Event(output=node_input, route=owner_of(node_input))
root_agent = Workflow(name="acme_router", edges=[
("START", route),
(route, {"marketing": marketing, "supply": supply}),
])
LangGraph. A routing function on a conditional edge from START returns the name of the next node.
The ask_* helpers are your own code that calls each specialist.
# Illustrative: LangGraph 1.x
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
question: str
answer: str
builder = StateGraph(State)
builder.add_node("marketing", lambda s: {"answer": ask_marketing(s["question"])})
builder.add_node("supply", lambda s: {"answer": ask_supply(s["question"])})
builder.add_conditional_edges(START, lambda s: owner_of(s["question"])) # code decides
builder.add_edge("marketing", END)
builder.add_edge("supply", END)
graph = builder.compile()
CrewAI. A @router method returns a label, and the method that listens for that label runs the
specialist agent directly with kickoff().
# Illustrative: CrewAI Flow
from crewai import Agent
from crewai.flow.flow import Flow, listen, router, start
supply = Agent(role="Supply analyst", goal="Answer supply questions from Acme's data",
backstory="You work in Acme's supply team.", tools=[get_penalties])
class AcmeFlow(Flow):
@start()
def take_question(self):
return self.state["question"]
@router(take_question)
def route(self):
return owner_of(self.state["question"]) # code decides: "marketing" or "supply"
@listen("supply")
def ask_supply(self):
return supply.kickoff(self.state["question"]).raw
OpenAI Agents SDK. This is the guide’s “orchestrating via code”: plain Python picks the agent, then the Runner runs it with a turn limit.
# Illustrative: OpenAI Agents SDK
from agents import Agent, Runner
supply = Agent(name="Supply", instructions="Answer supply questions using only your tools.",
tools=[get_penalties])
marketing = Agent(name="Marketing", instructions="Answer marketing questions using only your tools.",
tools=[get_spend])
async def answer(question: str) -> str:
specialist = supply if owner_of(question) == "supply" else marketing # code decides
result = await Runner.run(specialist, question, max_turns=5)
return result.final_output
Microsoft Agent Framework. A start executor turns the question into an agent request, and a
switch-case edge group sends it on. supply_agent and marketing_agent are agents created with a chat
client’s as_agent().
# Illustrative: Microsoft Agent Framework (Python)
from agent_framework import (AgentExecutor, AgentExecutorRequest, Case, Default, Message,
WorkflowBuilder, WorkflowContext, executor)
@executor(id="take_question")
async def take_question(question: str, ctx: WorkflowContext[AgentExecutorRequest]) -> None:
msg = Message(role="user", contents=[question])
await ctx.send_message(AgentExecutorRequest(messages=[msg], should_respond=True))
def goes_to_supply(req: AgentExecutorRequest) -> bool:
return owner_of(req.messages[-1].text) == "supply" # code decides
workflow = (WorkflowBuilder(start_executor=take_question)
.add_switch_case_edge_group(take_question, [
Case(condition=goes_to_supply, target=AgentExecutor(supply_agent, id="supply")),
Default(target=AgentExecutor(marketing_agent, id="marketing"))])
.build())
Claude Agent SDK. Plain Python picks the specialist; each specialist is a query() with its own
system prompt, its tool in an in-process MCP server, the built-in tools it must not use removed, and a
turn limit. get_penalties here is defined with the SDK’s @tool decorator.
# Illustrative: Claude Agent SDK (Python)
from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, create_sdk_mcp_server, query
supply_tools = create_sdk_mcp_server(name="supply", version="1.0.0", tools=[get_penalties])
supply_options = ClaudeAgentOptions(
system_prompt="Answer supply questions using only your tools.",
mcp_servers={"supply": supply_tools},
allowed_tools=["mcp__supply__get_penalties"],
disallowed_tools=["Bash", "Write", "Edit"],
max_turns=5,
)
async def ask_supply(question: str) -> str:
async for message in query(prompt=question, options=supply_options):
if isinstance(message, ResultMessage):
return message.result
Two patterns appear. ADK, LangGraph, CrewAI and Microsoft Agent Framework each have a graph or flow object where the route is a first-class step, so it shows up in traces and diagrams. The OpenAI Agents SDK and the Claude Agent SDK are agent-first: they run one agent loop very well, and you write the route in ordinary Python around it. Both work. The difference is how much of the system the framework can see, trace and resume for you. In the post room picture, the graph frameworks draw the sorting desk on the floor plan; the agent-first ones leave it in your pocket.
On question A, that difference shows up in the trace. In ADK, LangGraph, CrewAI and Microsoft Agent
Framework, the framework’s trace has a route step labelled supply before the supply specialist runs.
In the OpenAI Agents SDK and Claude Agent SDK versions, the trace starts with the supply specialist’s
run; the if/else that chose it is invisible unless you log it yourself.
What if I don’t want to run the loop myself? Managed agents
So far we have assumed you run the agent reasoning loop yourself: your Python code calls the model, receives a tool call, executes it locally, and sends the result back. You provision the environment, you isolate the sandbox, and you secure the local tool execution.
But what if you want a ready-made agent without running that execution infrastructure yourself? This is where Google’s managed agents come in.
The short answer: a managed agent is an agent whose loop, tools and sandbox someone else runs; you send it a task and get back finished work. Back in the kitchen from earlier, there are three ways to feed a party. You can cook everything yourself but buy one ready-made sauce. You can rent a commercial kitchen by the hour and cook there with your own recipes. Or you can hire a caterer who brings their own kitchen, staff and equipment: you give them the brief and the budget, and the food arrives. The caterer is the managed agent. The trade is control: you do not choose their pans, and you would not hand them the keys to your safe.
How does this apply to Acme? Acme’s specialists are the cook-it-yourself option, because their ingredients (governed data) never leave the building; a managed agent suits jobs where the ingredients are public.
Supported in ADK Python v2.4.0 (in Preview as of October 2026), the ManagedAgent class lets you connect to a managed agent, such as the Antigravity agent, by its agent_id. In this pattern, Google runs the reasoning loop, the tools, and the execution environment on its servers. You provide the instruction, you supply the bounds, and you stream the results back into your application. Instead of declaring functions and writing execution code locally, you connect to a pre-built agent that already knows how to run its own tools.
These managed agents are available through two backends: the Gemini API (which you authenticate using a standard Gemini API key) or the Agent Platform backend (which you authenticate using Google Cloud credentials).
What is the sandbox a managed agent works in?
The word sandbox comes up in every description of managed agents, so here is what it means. A sandbox is an isolated environment: a walled-off place where code or an agent’s actions run, so that a mistake, a bug or a malicious instruction cannot reach anything outside it. The word is used for two different sizes of thing, and the difference matters:
Code execution sandbox runs one piece of code the model wrote and returns the output.
(Part 3.5) Example: Acme's analyst computes CTR from three rows; the snippet runs,
prints 1.01, and the sandbox is done. It is a calculator with a wall
around it.
Environment sandbox a whole isolated computer for one agent session: an operating system,
(the agent's workspace) a filesystem, a shell, installed packages and network rules. Code runs
there, but so do file edits, downloads and web browsing, and files
stay between turns. It is an office with a wall around it.
Managed agents use the second kind. Google’s
agents overview says “A single API call provisions a
Linux sandbox where the agent reasons, executes code, manages files, and browses the web
autonomously”, and that “Every agent runs in a sandboxed environment that is isolated at the OS
level”. The Antigravity agent page adds
that “Files persist across interactions”. So when the market watch agent writes brief.md, it writes
it to that isolated Linux environment, not to any Acme machine.
Does the managed agent run inside the sandbox? In Google’s words, yes: the agent reasons and acts there. A useful way to picture it is the split from Part 11.75: the harness (the loop, the model calls, the state) is the vendor’s control plane, and the sandbox is the compute where the agent’s actions land. Either way, from Acme’s side the answer is the same: nothing runs in our process or on our network, and every command, file and download the agent produces stays inside that environment.
Is it a coding sandbox? It includes one, but it is bigger. Running code is one thing the agent does
inside the environment (the code_execution tool); reading web pages, writing files and installing a
package are others. Part 3.5’s code sandbox is the small kind; a managed agent’s sandbox is the large
kind.
Two things a sandbox does not do. It does not decide what the agent may reach: Google’s overview says the sandbox “has unrestricted outbound network access by default”, so you narrow it with an allowlist. And it does not decide where it runs: Anthropic and OpenAI also offer self-hosted sandboxes, the same kind of environment run on your own infrastructure while the vendor still runs the loop (see the ladder below).
The ADK client application invokes a ManagedAgent, which streams a request to the Interactions API on Google Cloud. The reasoning, tools, and execution sandbox run remotely on Google's infrastructure rather than inside the ADK process.
For example, using the ADK Python framework, you can connect to a managed agent and use its remote web search tools like this:
import os
from google.adk.agents import ManagedAgent
from google.adk.tools import google_search
managed_search_agent = ManagedAgent(
name='managed_search_agent',
description='Answers questions that need fresh, grounded information from the web.',
agent_id=os.environ["MANAGED_AGENT_ID"],
environment={'type': 'remote'},
tools=[google_search],
)
Notice the environment configuration: environment={'type': 'remote'}. The agent uses built-in server-side tools like google_search or code execution, and they run entirely on Google’s servers.
When you invoke a ManagedAgent, ADK works entirely on the data plane via the Interactions API. The reasoning, tools, and execution all run in Google’s managed environment rather than in your ADK process. The remote interaction maintains the session state, the execution environment, and the context limits.
There are important limits to keep in mind, especially while this feature is in Preview. Because execution happens remotely, client-side function tools and Model Context Protocol (MCP) tools are not supported. If we look at our running example, Acme Consumer Brands, the marketing and supply specialists use custom, narrow tools to query private Databricks and BigQuery instances. Since those are client-side function tools running inside Acme’s own network, the specialist agents must stay as regular ADK agents.
At Acme, the two sides look like this:
- Fits a managed agent: Acme wants to ask “What are retailers saying publicly about refill
packs?” The
managed_search_agentabove, withtools=[google_search], can answer it, because the only tool it needs runs on Google’s servers. - Does not fit: giving the same
ManagedAgenttools=[get_penalties]. That is a client-side function that reads Acme’s private Databricks data, which the Preview does not support, so the supply specialist stays a regular ADKAgentlike the one in the ADK panel above.
That second bullet is why the managed agent appears in Acme’s architecture diagram as the market watch box on the right, with a dashed arrow from the router: it is there for public tasks, never for the governed data path. The use case is below.
How is a managed agent different from Google Search or a plain Gemini API call?
All three run on Google’s servers, so they are easy to confuse. The difference is how much of the work Google does in one request, and therefore who runs the loop.
Picture three ways of getting an answer at a library. You ask the librarian at the desk, who answers from memory. You ask them to look it up, and a minute later they read you the answer with its sources. Or you commission a researcher for the afternoon, who pulls ten books, takes notes and hands you a written brief. Memory is the plain call, the quick look-up is grounding with Google Search, and the researcher is the managed agent. How does this apply to Acme? The four bullets below map each one, plus Acme’s own agents, which are the only ones allowed into Acme’s private archive.
- A plain Gemini API call (
generateContent, no tools) is one request and one response. The model knows only its training data and what you sent, cannot look anything up, and remembers nothing afterwards (Prerequisite 3). Anything more, such as calling a tool, checking a figure or trying again, is a loop your code writes. - A Gemini API call with Google Search turns on the
google_searchtool, which is grounding: still one request, but the model may search the web before it answers. Google’s grounding page says “the model handles the entire workflow of searching, processing, and citing information automatically”, and the response comes back with sources. It is one smart step, not a project: no files, no code, no plan that runs on after the response. - A managed agent takes a task, not a prompt. Its own loop runs for many steps, often minutes: it searches, reads pages, writes and runs code, and keeps files in its own sandbox, and the server keeps the state between your turns. You get back finished work, such as a brief with sources or a chart.
- Your own ADK agent, for comparison, is the loop you write and run yourself, with your own tools, which is what Acme’s specialists are. Only this one can use Acme’s private, narrow tools.
The same question four ways, “What are UK supermarkets saying about refill packs this month?”:
Plain Gemini API call one call. The model answers from training data: general, undated, and
possibly out of date. It cannot know what happened this month.
Gemini + Google Search one call. The model searches, then answers in a paragraph with citations.
Good for a quick, current answer inside a step you control.
Managed agent one task. Over a few minutes it searches, reads six pages, compares them,
writes brief.md with four cited links and checks it. Good for a piece of
work, not just an answer.
Your own ADK agent your loop. Useful only if the answer needs Acme's own tools and data,
which this question does not.
A simple test:
- Use a plain call when the model needs nothing it does not already have: rewriting a question, as Acme’s extract step does (Part 5).
- Use grounding with Google Search when you need one current, cited answer inside a step you control.
- Use a managed agent when the job needs many steps and a workspace, and you are happy for someone else’s loop to choose those steps.
- Use your own agent whenever private tools or governed data are involved.
In ADK, google_search is a built-in tool you add to an Agent, while a ManagedAgent implements the
same BaseAgent contract as any other agent, so the router can hand it work like any other step.
What else can you hand to a managed agent?
Web search is only the start. Google’s
Antigravity agent page lists its default
tools as code_execution (shell commands in “bash, Python, Node”), google_search and url_context
(“fetch and read web pages”), plus filesystem tools that switch on when you give it an environment.
The agents overview also lists a Deep Research agent
“for use cases like market analysis, due diligence, and literature reviews”. That opens up several
kinds of job, each shown here as an Acme task on public or non-confidential data:
- Analysis that needs code. “Here is a CSV of last year’s public category sales figures. Work out the growth by country and chart it.” The agent writes Python, runs it in its sandbox, fixes errors and returns the chart. (Part 3.5 runs one code step in a sandbox we control; here the whole job runs in Google’s.)
- Reading specific pages. “Summarise the packaging rules on these three retailers’ supplier
pages.”
url_contextreads exactly those URLs instead of searching. - Producing files. “Turn this research into a one-page brief as a PDF.” The agent writes and converts files in its sandbox’s filesystem and hands the file back.
- Multi-step research. “Due diligence on a new retailer partner: public news, store footprint, stated sustainability goals.” This is what the Deep Research agent is built for.
- Small coding jobs. “Write and test a script that cleans our weekly agency export into one tidy CSV.” The agent writes the script, runs it on the sample file, and returns both.
All five share three traits: the task is self-contained, the data can leave Acme, and the steps are better chosen by a capable general agent than scripted by us. Three cautions apply to every one of them, as of October 2026:
- The network is open by default. The agents overview says the sandbox “has unrestricted outbound network access by default” and that you can restrict it with an allowlist. Restrict it.
- The data leaves your boundary. Never hand a managed agent
service_costrows, tokens or anything you would not email to Google support. For private data, see the self-hosted sandboxes below. - ADK’s wrapper is narrower than the API. The Gemini API lets the Antigravity agent call your own
custom functions, but ADK’s
ManagedAgent(Preview) raisesNotImplementedErrorfor client-side and MCP tools, works only with streaming, and on the Agent Platform backend is served only from thegloballocation.
Acme’s use case: the market watch agent
Here is the job Acme gives a managed agent. Maria’s questions are not only about Acme’s own numbers. She also asks “What are UK supermarkets saying publicly about refill packs this month?”, and the weekly leadership summary from Part 1.5 needs a short “what the market is saying” paragraph. Today someone spends an hour on that every Monday: searching retailer news, reading supplier pages and competitor announcements, and writing it up with links.
That job passes every test from the list above. The data is public, the work takes many steps
(search, read, compare, write), and the steps are better chosen by a capable general agent than
scripted by us. So the design adds a market watch agent: a ManagedAgent that Google runs, which
the router calls only for public questions. This is a design extension; it is not yet in the build.
import os
from google.adk.agents import ManagedAgent
from google.adk.tools import google_search
from google.genai import types
market_watch = ManagedAgent(
name="market_watch",
description="Researches public retailer, competitor and press news about Acme's categories.",
agent_id=os.environ["MANAGED_AGENT_ID"],
environment={"type": "remote"},
tools=[google_search, types.Tool(url_context=types.UrlContext())], # search, then read pages
)
(Illustrative. The google_search and raw types.Tool pattern follows ADK’s managed agents page;
check the Preview’s current tool list before you rely on url_context.)
In the router’s graph it is one more destination. The routing rule stays code: a question that names
no measure in the semantic registry but matches the public-market topics (retailers, competitors,
press, regulation) gets the label public and the route market. Here is Maria’s question end to end:
1. extract (model) "Public UK supermarket commentary on refill packs, October 2026"
2. route (code) no Acme measure in the registry; topic is public market => route "market"
the task text is built by code from a template: category, region, month.
No Acme figures, plans or tokens ever go into it.
3. market_watch runs on Google's side: searches, reads six retailer and press pages,
(Google-run) writes brief.md in its sandbox, returns the brief with four cited links
4. writer (model) "From public sources: two of the big four are expanding refill aisles [1][2];
one trade paper reports shoppers rejecting higher refill prices [3] ..."
5. checks (code) every claim carries a link from the brief; every figure appears in the brief;
the answer is labelled "public sources, not Acme data"
And when Maria asks a mixed question, such as “How does that compare with our Verde campaign?”, code splits it: the public half goes to market watch, the Verde spend goes to the marketing agent as before, and the writer keeps the two clearly apart.
Five controls make it safe, each from an earlier or later part of the series:
- Nothing private goes in. The task text comes from a code template with public words only, so a prompt injection in Maria’s question cannot smuggle Acme data into Google’s sandbox.
- The network is narrowed. The agent’s network allowlist names the retailer, trade press and regulator domains it needs, instead of the open default.
- Its output is untrusted data. Web pages can contain instructions, so the brief passes the same audit plugin and Model Armor screen as any tool result (Part 9), and it can never trigger an action.
- It has a budget. Each run gets a cost and time cap, and a failure means the answer says the market view is unavailable rather than guessing (Part 11.5).
- It never touches governed data. It cannot call Acme’s tools (the Preview has no client-side tools), it sits outside Agent Gateway’s allowed destinations for BigQuery and Databricks, and the number check still guards every Acme figure.
The Monday job reuses the same agent. A scheduled run asks for “This week in refill packs: five points with sources”, and the brief becomes one input to the leadership summary’s drafter, while the summary’s checker (the outer loop in Part 1.5) confirms every market claim still carries its link.
How do other platforms offer managed agents?
Every major vendor now offers the same idea, and the clearest way to compare them is a three-level ladder of how much of the agent the vendor runs:
Level 1 Hosted tools one call runs on the vendor's servers; your loop decides everything
Gemini: google_search, code execution, url_context
OpenAI Responses API: web search, file search and other built-in tools
Level 2 Managed agents the vendor runs the loop, the state and the sandbox; you send a task
Google: Antigravity and Deep Research agents (Preview), ADK ManagedAgent
Anthropic: Claude Managed Agents (Beta)
OpenAI: the Agents API (the Codex harness, managed by OpenAI)
AWS: AgentCore Harness
Microsoft: Foundry prompt agents ("let Foundry run it")
Level 3 Hosted runtimes the vendor runs the servers; your own code is the loop
Google: Agent Runtime (where Acme's agents run, Part 11)
AWS: AgentCore Runtime; Microsoft: Foundry hosted agents
LangGraph: LangSmith Deployment; CrewAI: CrewAI AMP
In the kitchen terms from the start of this section: level 1 is the ready-made sauce, level 2 is the caterer, and level 3 is the rented commercial kitchen where you still do the cooking.
In their own words:
- Anthropic. Claude Managed Agents (Beta) is “best for workloads that need” long-running execution (“tasks that run for minutes or hours with multiple tool calls”). Each session runs in an environment: “an Anthropic-managed cloud sandbox, or a self-hosted sandbox on your own infrastructure”.
- OpenAI. The Agents API “gives your application access to the Codex harness through an OpenAI-managed API”. OpenAI “manages sessions, orchestration, context compaction, and recovery while your application provides tools and chooses its execution environment”, with OpenAI-hosted or self-hosted sandboxes.
- AWS. AgentCore Harness is “a managed agent loop that lets you define and invoke AI agents with a single API call”, where “each session runs in an isolated microVM with filesystem and shell access”. AWS names code generation, data analysis and deep research as uses.
- Microsoft. Foundry Agent Service lets you “define a prompt agent or a voice-based prompt agent and let Foundry run it, package your own code as a hosted agent, or call the Responses API from an agent you already run elsewhere”. The first is level 2, the second level 3.
- The open-source frameworks. LangGraph, CrewAI, the OpenAI Agents SDK, Microsoft Agent Framework and the Claude Agent SDK are libraries for writing your own loop, so they sit at level 3 when hosted. None of them is itself a vendor-run agent, though your agent can call one (for example over its API, or over A2A).
Two differences matter more than the names. First, where the work runs: Anthropic and OpenAI let the vendor run the loop while the sandbox runs on your infrastructure, which is the only way a managed agent could ever touch data like Acme’s. Second, launch stage: Google’s managed agents are in Preview and Claude Managed Agents are in Beta (as of October 2026), so check each vendor’s current status page before you build on one.
Acme sits on two levels at once. The router and the specialists are level 3: our own ADK code on Agent Runtime, because every number they return comes from governed data and is checked by our code. The optional managed agent box is level 2, for the public research jobs above. Part 11.75 looks at the same trend from the platform side, in What is a sandbox-based agent? The same part covers two Google products that sit on this ladder, Gemini Enterprise for CX and the industry editions, with Acme use cases for each.
My view: choose a managed agent when you have a self-contained task that relies heavily on built-in server-side tools, such as web research or running sandboxed code (which Part 3.5 covers), without the operational overhead of securing and scaling a local sandbox. But choose a self-hosted ADK agent when you need fine-grained control over the model, the prompt, custom client-side function tools, or MCP integrations. The ladder above shows how the other vendors draw the same line.
Can agents from different frameworks work together?
Yes, and for a large organisation this matters more than the choice of framework. Acme’s supply team might prefer LangGraph while marketing uses ADK. Two open protocols make that workable.
A simple example first: phones. An iPhone and an Android phone, on different networks, made by different companies, call each other without either knowing what the other is. Both follow the same public standards, so all you need is the number. You look the number up in a directory, dial, talk, and hang up, and you never learn what is inside the other handset. In agent terms, the shared standard is A2A, the directory entry is the agent card, and the handset’s insides are the other agent’s framework. The misconception is that agents must share a framework to cooperate; they only need to share a protocol.
How does this apply to Acme? The diagram shows the same idea with the router and its specialists.
agents from different frameworks work together over A2A and reach tools over MCP: Gemini Enterprise calls the router built with ADK on Agent Runtime; the router calls the marketing and supply agents over A2A after reading their agent cards, and the supply agent could be built with LangGraph, CrewAI or Microsoft Agent Framework; each specialist reaches BigQuery or Databricks tools through an MCP server
- A2A (Agent2Agent) is how one agent calls another as a remote service. Each agent publishes an agent card (a small JSON document that says what it can do and where to reach it), and the caller sends tasks and messages over HTTP without seeing the other agent’s internals. The A2A project says the protocol “was originally developed by Google and donated to the Linux Foundation”, and it is Apache 2.0 licensed. Part 6 builds Acme’s A2A calls in detail.
- MCP (Model Context Protocol) is how an agent reaches tools. An
MCP server lists tools, and any MCP client can call them. All six
frameworks can use MCP tools, although LangChain’s MCP module is
still marked beta.
The current MCP revision,
2026-07-28(often called “MCP 2.0”), made the protocol stateless, and a newer alternative, UTCP, calls existing APIs directly without an MCP server; Part 2 explains both.
Here is A2A on Acme’s supply question, in a scenario where the router is built with ADK and the supply agent with LangGraph. The supply agent’s card, simplified from the one in Part 6 (illustrative values):
{
"name": "acb_demo_supply",
"description": "Supply specialist for ACB: OTIF, unmet demand and service penalties for Acme Pure, Verde and Harvest Row",
"version": "0.1.0",
"supportedInterfaces": [
{"url": "https://.../a2a/app", "protocolBinding": "JSONRPC", "protocolVersion": "1.0"}
]
}
1. The router (ADK) reads the card at /.well-known/agent-card.json and learns where to send work.
2. Code routes "What did those stockouts cost us?" to supply and sends it as an A2A message,
with Maria's identity in the request metadata, never in the prompt.
3. The supply agent (LangGraph) runs its own loop and calls its own tools.
4. It replies with the answer: "EUR 36,026 in retailer penalties in Western Europe."
The router never sees LangGraph, only the card and the reply. If the supply team rewrote its agent in ADK tomorrow, the router code would not change.
Support for A2A is where the six differ most, as of October 2026:
- ADK consumes and exposes A2A agents natively (ADK A2A), and MCP tools are built in.
- LangGraph agents get an A2A endpoint in Agent Server when deployed with LangSmith.
- CrewAI treats A2A “as a first-class delegation primitive”, both as a client and as a server (A2A in CrewAI).
- Microsoft Agent Framework wraps a remote A2A agent as an ordinary agent with
A2AAgent(A2A integration) and can host its own agents over A2A. - The OpenAI Agents SDK and the Claude Agent SDK support MCP, but I found no A2A support in their
documentation. To put one of them behind A2A, wrap it in an A2A server with one of the official
A2A SDKs (for Python,
a2a-sdk): your server code receives the A2A request, calls the agent, and returns its answer as an A2A response, so callers never see which framework is inside. For example, with the Claude panel’sask_supply(question): an A2A request arrives with the text “What did those stockouts cost us?”, your server callsawait ask_supply(text), gets back “EUR 36,026 in Western Europe” and returns it as the A2A response. The ADK router sees one more remote agent and never learns that Claude is underneath.
The Google Cloud side is open too. Gemini Enterprise can register ADK agents hosted on Agent Runtime and A2A agents built with any framework, and Agent Runtime documents how to deploy ADK, A2A, LangChain, LangGraph, AG2, LlamaIndex and custom agents. It works in the other direction as well: the LangSmith Deployment page describes deploying ADK, Claude Agent SDK and CrewAI agents.
How do I choose?
Start from where the agent will run and who will use it, then from the team that will maintain it. Here is how I would choose, as a decision guide.
The most common mistake is to start from features. Every framework has a feature list long enough to win a demo, and as the grid showed, the basics are the same in all six. Ask these questions in order instead; most teams have their answer by question 2:
1. Do you need your own loop at all? A plain call, grounding or a managed agent may do the
job with no framework (the managed agents test above).
2. Where will it run, and where do users The platform usually picks the framework: Gemini
meet it? Enterprise on Google Cloud points to ADK, Microsoft
Foundry to Microsoft Agent Framework.
3. What does the team already know? A framework the team can debug at 2am beats a better
one they cannot.
4. Which edge concern costs most to add? Long-term memory, evals, managed deployment or A2A:
pick the framework that has yours built in.
5. Only then compare the rest of the feature list.
how I would choose an agent framework, my view as of October 2026: ADK when agents ship to Gemini Enterprise on Google Cloud; LangGraph for explicit graphs with durable state on any cloud; CrewAI when work splits into roles and tasks; the OpenAI Agents SDK for OpenAI models and the fewest primitives; Microsoft Agent Framework for .NET and Microsoft Foundry teams or AutoGen and Semantic Kernel users; the Claude Agent SDK for agents that work in files and a shell with Claude; when several apply, let the platform decide and connect the rest over A2A
My view: why this series uses ADK. This series ends in Part 12 with Acme’s router published to Gemini Enterprise, where employees already work, running on Agent Runtime with Agent Identity, Memory Bank and Model Armor around it. ADK is the shortest path to that platform: Gemini Enterprise registers ADK agents hosted on Agent Runtime directly, and the same ADK code deploys to Agent Runtime, Cloud Run or GKE. ADK 2.0’s graph workflows also suit the series’ design rule, models read and write language, code makes the decisions, because the route, the number check and the human approval are ordinary nodes in the same graph as the model calls. And because ADK is model-agnostic and speaks A2A, a partner’s LangGraph or CrewAI agent can join Acme’s system as a specialist without a rewrite. If your platform is Microsoft Foundry, I would make the mirror-image argument for Microsoft Agent Framework.
What can go wrong
- Choosing a framework for its demo. Most frameworks look alike in a ten-line demo. Compare them on the concerns that cost most later: loop limits, approvals, evals, tracing and where they deploy.
- Keeping the default loop limit. The defaults range from 20 iterations to no limit at all. Set a limit that fits each agent’s job, and keep cost limits as a backstop.
- Letting a model route when code could. Every framework makes model-driven delegation easy, with handoffs, managers or coordinators. For a decision with a business rule behind it, route in code, as every panel above does.
- Forgetting that connectors are dependencies. ADK’s LiteLLM page carries a security advisory:
unauthorised code was found in LiteLLM versions 1.82.7 and 1.82.8 on PyPI on 24 March 2026. Pin and
scan third-party model connectors like any other dependency. For example, an unpinned
litellmline inrequirements.txt, installed on 24 March 2026, could have pulled 1.82.7. A pinned version that you have reviewed, installed with hashes (pip install --require-hashes), installs the same audited build every time. - Building on a preview feature without knowing it. ADK’s tool confirmation is experimental, LangChain’s MCP module is beta, and several Microsoft Agent Framework features are preview. Check the label before a feature carries production traffic.
- Rewriting a working agent to standardise. If another team’s agent works, put it behind A2A and call it. A rewrite costs months and adds nothing for users.
What code did we write in this part?
Every part ends with the same map of Acme’s build: which files exist so far, and the code this part added, explained line by line. The map grows with each part.
This part adds no code to Acme’s build. The snippets compare the same routing step in six frameworks and are all marked illustrative; the market watch ManagedAgent is a design extension that the post says is not yet in the build.
Where does it live?
marketing/ the marketing specialist, on BigQuery
app/agent.py P1 marketing Agent with its tools, wrapped in an App
app/tools.py P1 query_marketing_measures, the marketing tool on BigQuery
shared/ code all three services share
routing.py P1 classify: picks the specialist in code, no model
semantic.yaml P1 semantic registry: each measure, its owner and access
+ added in this part ~ changed in this part Pn = the parts that touched the file
What did we learn?
- An agent framework is a library that packages the harness, loop and context handling, so you write only instructions, tools, rules and data access.
- ADK is Google’s open-source framework, Apache 2.0 licensed, in five languages; it works with Gemini, Claude and other models through connectors, and deploys to Agent Runtime, Cloud Run, GKE or any container.
- ADK, LangGraph, CrewAI, the OpenAI Agents SDK, Microsoft Agent Framework and the Claude Agent SDK all cover the basic production concerns; they differ most in long-term memory, built-in evals, managed deployment and A2A support.
- Routing in code works in every framework: as a graph step in ADK, LangGraph, CrewAI and Microsoft Agent Framework, and as plain Python around the run in the two agent-first SDKs.
- A managed agent (ADK’s
ManagedAgent, Preview) lets Google run the whole loop and sandbox, unlike a tool such asgoogle_search, which is one call inside your loop. It suits self-contained public jobs (research, analysis with code, reading pages, producing files); governed data tools stay in ADK agents. Anthropic, OpenAI, AWS and Microsoft offer the same level under their own names. - A2A connects agents built in different frameworks and MCP shares tools between them, so teams can pick different frameworks and still build one system.
- This series uses ADK because Acme’s router ships to Gemini Enterprise on Agent Runtime, and ADK’s graph workflows let code make the decisions.
What comes next?
With the framework question settled, one more foundation comes before we build:
Production-ready agents, Part 1.9: How agents connect: MCP, A2A and UTCP
explains the three kinds of connection behind every arrow in the architecture. Then
Part 2: Your first agent: one job, narrow tools
builds Acme’s marketing specialist in ADK. It uses the building blocks from this post (an Agent, its
tools and the Runner) and the harness, loop and context from Part 1.5, and it shows why narrow tools
matter in every framework.
Sources
- ADK documentation home
- ADK Python on GitHub (Apache 2.0 licence, README)
- ADK: AI models for ADK agents
- ADK: LiteLLM model connector and security advisory
- ADK: Deploying your agent
- Welcome to ADK 2.0 (GA dates)
- ADK: Runtime configuration (RunConfig)
- ADK: Memory
- ADK: Build graph routes
- ADK: Types of callbacks
- ADK: Plugins
- ADK: Human input for agent workflows
- ADK: Tool confirmation
- ADK: Observability
- ADK: Evaluation
- ADK: A2A protocol
- ADK: Model Context Protocol tools
- LangChain: Runtimes, frameworks, and harnesses
- LangGraph overview
- LangGraph: Graph API overview (recursion limit, conditional edges)
- LangGraph: Persistence
- LangGraph: Interrupts
- LangChain: Guardrails
- LangChain: Model Context Protocol (MCP)
- LangChain blog: LangChain and LangGraph reach v1.0 (22 October 2025)
- LangSmith Deployment
- LangSmith: A2A endpoint in Agent Server
- CrewAI: Introduction
- CrewAI: Agents
- CrewAI: Tasks (guardrails)
- CrewAI: Processes
- CrewAI: Flows
- CrewAI: Memory
- CrewAI: Execution hooks
- CrewAI: Human feedback in Flows
- CrewAI: Tracing
- CrewAI: Testing
- CrewAI: Agent-to-Agent (A2A) protocol
- OpenAI Agents SDK (Python)
- OpenAI Agents SDK (TypeScript)
- OpenAI Agents SDK: Running agents
- OpenAI Agents SDK: Sessions
- OpenAI Agents SDK: Agent orchestration
- OpenAI Agents SDK: Guardrails
- OpenAI Agents SDK: Human-in-the-loop
- OpenAI Agents SDK: Tracing
- OpenAI Agents SDK: Testing
- OpenAI Agents SDK: Models
- Microsoft Agent Framework overview
- Microsoft Agent Framework Version 1.0 (3 April 2026)
- AutoGen on GitHub (successor note)
- Microsoft Agent Framework: Termination and guardrails
- Microsoft Agent Framework: Workflow edges
- Microsoft Agent Framework: Agent middleware
- Microsoft Agent Framework: Human-in-the-loop
- Microsoft Agent Framework: Tool approval
- Microsoft Agent Framework: Observability
- A2A: Official SDKs
- Google Cloud: Evaluate agents with the Gen AI evaluation service
- Microsoft Agent Framework: Evaluation
- Microsoft Agent Framework: Google Gemini
- Microsoft Agent Framework: Hosting
- Microsoft Agent Framework: A2A
- Anthropic: Building agents with the Claude Agent SDK (29 September 2025)
- Claude Agent SDK overview
- Claude Agent SDK: Migrate to Claude Agent SDK
- Claude Agent SDK: How the agent loop works
- Claude Agent SDK: Sessions
- Claude Agent SDK: Subagents
- Claude Agent SDK: Hooks
- Claude Agent SDK: Permissions
- Claude Agent SDK: Handle approvals and user input
- Claude Agent SDK: Observability with OpenTelemetry
- Claude Agent SDK: Hosting
- A2A protocol
- Model Context Protocol
- Gemini Enterprise: Register and manage ADK agents hosted on Agent Runtime
- Gemini Enterprise: Register and manage A2A agents
- Agent Runtime: Use a LangGraph agent
- Agent Runtime: Use a custom agent
- ADK: Managed agents
- Databricks: Deploy agents on Databricks
- Databricks: Author an agent (app templates)
- Databricks: Agent Bricks CLI
- Databricks: Deploy an agent on Model Serving (legacy path)
- Databricks: Develop agents on Databricks
- Databricks: MCPs
- Gemini API: Agents overview
- Gemini API: Antigravity agent
- Claude Managed Agents overview
- OpenAI: Agents API
- OpenAI: Using tools
- Amazon Bedrock AgentCore: overview
- Microsoft Foundry Agent Service: overview
Opinions are my own. Every fact in this post comes from the public documentation linked above. Acme Consumer Brands and its data are fictional.