Building Agents: Frameworks and Patterns
By October 2026 every major lab and cloud ships an agent framework, and they have converged on the same core ideas: a loop, tools, sessions, MCP for tools and A2A for other agents. This module helps you choose one, build something small that works, and learn what changes when you take it to production.
The framework landscape in 2026
A year ago, frameworks differed a lot in what they could do. Today most of them can run a tool loop, call MCP servers, hand off to sub-agents and pause for a human. The real differences are now who runs the infrastructure, which models are first-class, and how much structure the framework imposes (a free-running loop versus an explicit graph).
| Framework | Status (Oct 2026) | What it is good at |
|---|---|---|
| Claude Agent SDK (Python/TS) | Active; renamed from Claude Code SDK in Sept 2025 | The same harness that powers Claude Code: built-in file and shell tools, subagents, sessions, skills, plugins, hooks, MCP and structured outputs. |
| Claude Managed Agents | Launched April 2026; multi-agent orchestration and outcomes in beta since May 2026 | Anthropic hosts the harness and infrastructure: state, memory, permissions and scheduling. Anthropic suggests prototyping on the SDK, then running on Managed Agents. |
| OpenAI Agents SDK (Python) | 0.24.0 (2026-10-15) | Started as a lightweight handoffs-plus-guardrails loop (Mar 2025); now adds sandbox agents, compaction sessions, durable approvals and MCP support. |
| OpenAI AgentKit / Agents API | AgentKit at DevDay 2025-10-06; Agents API in public beta, with computer use and multi-agent tools added at DevDay 2026-09-29 | Hosted building blocks on OpenAI's platform. The Agents API also runs natively in AWS as Bedrock Managed Agents. |
| Google ADK 2.0 | GA for Python (2026-05-19), Go (2026-06-30) and TS (2026-08-21); google-adk 2.12.0 on PyPI (2026-10-13) | Graph-based Workflow Runtime, built-in human-in-the-loop, SDKs in five languages, and native A2A support. |
| LangGraph / LangChain | 1.0 GA on 2025-10-22; LangGraph 1.2.16 (2026-10-16) | Explicit state graphs with durable execution, create_agent, middleware, and the "Deep Agents" pattern. Model-agnostic. |
| Microsoft Agent Framework | 1.0 GA reported for April 2026 for .NET and Python (secondary sources; check Microsoft's devblogs) | Merges Semantic Kernel and AutoGen. Graph workflows, native MCP and A2A. AutoGen is in maintenance mode. |
| AWS Strands Agents / Bedrock AgentCore | Strands 1.0 and AgentCore Harness GA 2026-06-17; next-gen AgentCore Runtime GA 2026-09-18; AgentCore Evaluations GA 2026-10-15 | Managed runtime on AWS where agents can run for up to 14 days, with A2A support in the runtime. |
| Pydantic AI | 2.0 (2026-06-23) | Type-safe Python agents built around composable "capabilities", with a separate Pydantic AI Harness package. |
| CrewAI | 1.15.x (1.15.0 on 2026-06-25) | Role-based crews plus declarative Flows, a Skills Repository and Crew Studio. |
| goose (Block) | Open source; a project of the Agentic AI Foundation | A local, MCP-native agent you can run and extend rather than a library you embed. |
Library versus platform
Some entries are libraries you run in your own process (Claude Agent SDK, OpenAI Agents SDK, ADK, LangGraph, Pydantic AI, CrewAI). Others are hosted platforms that run the loop for you (Claude Managed Agents, OpenAI's Agents API, Bedrock AgentCore). Many teams prototype with a library and move the same agent onto a platform when they need long-running sessions, scheduling and managed sandboxes.
How to choose
There is no best framework, only a best fit for your constraints. Work through these questions in order. The early answers usually narrow the field to two or three options.
- 1
Which models must you support?
If you are committed to one provider, its own SDK gets new features first (Claude Agent SDK, OpenAI Agents SDK, ADK for Gemini). If you need to swap models or run open-weight ones, favor model-agnostic options like LangGraph, Pydantic AI, Strands or CrewAI.
- 2
Who runs the infrastructure?
If you want state, scheduling and sandboxes handled for you, look at a managed platform (Claude Managed Agents, OpenAI Agents API, Bedrock AgentCore). If data must stay in your environment, use a library and host it yourself.
- 3
Free loop or explicit graph?
Open-ended tasks such as research, coding or triage suit a model-driven loop. Regulated or multi-step business processes suit an explicit graph (LangGraph, ADK 2.0 workflows, Microsoft Agent Framework workflows, CrewAI Flows), where you can see and test every path.
- 4
What does your stack already use?
.NET shops tend to pick Microsoft Agent Framework. AWS-heavy teams tend to pick Strands and AgentCore. Google Cloud teams tend to pick ADK. Fighting your platform costs more than any framework feature saves.
- 5
Does it speak the protocols?
Make sure it can consume MCP servers and can expose or call agents over A2A. Then your tools and agents can outlive the framework choice.
Protocols reduce lock-in
If your tools live behind MCP servers and your agents talk over A2A, switching frameworks later means rewriting the loop, not the integrations. Treat MCP and A2A support as a hard requirement.
Hands-on: a minimal agent with the Claude Agent SDK
The Claude Agent SDK gives you the Claude Code harness as a library. You call query() with a prompt and options, and it streams back messages while the agent works. Custom tools are plain async functions wrapped with @tool and served through an in-process MCP server. The SDK uses MCP even for local tools, so the same tools can later move to a remote server without changing the agent.
import asyncio
from typing import Any
from claude_agent_sdk import (
query, ClaudeAgentOptions, ResultMessage, tool, create_sdk_mcp_server,
)
# 1. A tool is an async function plus a name, description and input schema.
@tool("lookup_order", "Look up an order's status by its ID", {"order_id": str})
async def lookup_order(args: dict[str, Any]) -> dict[str, Any]:
status = {"A100": "shipped", "A101": "delayed"}.get(args["order_id"], "unknown")
return {"content": [{"type": "text", "text": f"Order {args['order_id']}: {status}"}]}
# 2. Serve the tool from an in-process MCP server.
orders = create_sdk_mcp_server(name="orders", version="1.0.0", tools=[lookup_order])
async def main():
options = ClaudeAgentOptions(
system_prompt="You are a concise support agent. Use tools; never guess order status.",
mcp_servers={"orders": orders},
allowed_tools=["mcp__orders__lookup_order"], # auto-approve only this tool
max_turns=6, # stop runaway loops
max_budget_usd=0.50, # stop runaway spend
)
# 3. The SDK runs the loop: model -> tool call -> result -> model ...
async for message in query(prompt="Where is order A101?", options=options):
if isinstance(message, ResultMessage):
print(message.result)
print("cost:", message.total_cost_usd)
asyncio.run(main())- You never write the loop. The SDK decides when to call tools and when to stop. You shape that through the system prompt, the tools and the limits.
allowed_toolsis an approval list, not a sandbox. It auto-approves the tools you name. Usedisallowed_toolsto block a tool entirely, and acan_use_toolcallback (withClaudeSDKClient) for custom approval logic.- Limits are part of the design.
max_turnsandmax_budget_usdturn a possible runaway into a clean error you can handle. - Built-in tools come for free. Tools such as
Read,GrepandBashare available, which makes this SDK a strong fit for agents that work with files and code.
The same idea in the OpenAI Agents SDK
Here is the same support agent in OpenAI's Agents SDK. The vocabulary changes, but the shape does not: an agent is instructions plus tools, and a runner drives the loop. The SDK builds the tool schema from the Python type hints and docstring.
import asyncio
from agents import Agent, Runner
from agents.decorators import tool
@tool
def lookup_order(order_id: str) -> str:
"""Look up an order's status by its ID."""
status = {"A100": "shipped", "A101": "delayed"}.get(order_id, "unknown")
return f"Order {order_id}: {status}"
agent = Agent(
name="Support Agent",
instructions="You are a concise support agent. Use tools; never guess order status.",
tools=[lookup_order],
)
async def main():
result = await Runner.run(agent, "Where is order A101?")
print(result.final_output)
asyncio.run(main())| Concept | Claude Agent SDK | OpenAI Agents SDK |
|---|---|---|
| Run the loop | query() or ClaudeSDKClient | Runner.run() / Runner.run_sync() |
| Define a tool | @tool(name, description, schema) | @tool on a typed, documented function |
| Final answer | ResultMessage.result | result.final_output |
| Delegate work | Subagents (agents= option) | Handoffs, or agents as tools |
| Built-in tools | File, search, shell and web tools from Claude Code | Hosted tools such as web and file search, plus sandbox agents |
Learn the pattern, not the API
Once you can see instructions, tools, loop, limits and result in one SDK, you can read any other framework in an afternoon. The concepts from the agent loop module carry over directly.
Wiring up: tools over MCP, agents over A2A
Real agents rarely live alone. A useful mental model from 2026: MCP is vertical (an agent reaching down to tools and data) and A2A is horizontal (an agent delegating to another, opaque agent that has its own reasoning and state). Both are now governed under the Linux Foundation's Agentic AI Foundation.
Consuming tools over MCP. Instead of writing every tool yourself, connect to an MCP server. Here the OpenAI Agents SDK connects to a remote server over Streamable HTTP and passes along a bearer token:
import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async def main():
async with MCPServerStreamableHttp(
name="orders-mcp",
params={
"url": "https://mcp.example.com/mcp",
"headers": {"Authorization": f"Bearer {os.environ['MCP_TOKEN']}"},
},
cache_tools_list=True,
) as server:
agent = Agent(
name="Support Agent",
instructions="Answer order questions using the MCP tools.",
mcp_servers=[server],
)
result = await Runner.run(agent, "Where is order A101?")
print(result.final_output)
asyncio.run(main())Exposing your agent over A2A. To let other agents call yours, publish it as an A2A server. A2A will then advertise an Agent Card (its name, skills, endpoint and auth requirements) at a well-known URL. Google's ADK can do this in one line with to_a2a(), which builds the card from your agent's definition:
# server: agent.py
from google.adk.agents.llm_agent import Agent
from google.adk.a2a.utils.agent_to_a2a import to_a2a
def lookup_order(order_id: str) -> dict:
"""Look up an order's status by its ID."""
return {"order_id": order_id, "status": "delayed"}
root_agent = Agent(
model="gemini-flash-latest",
name="order_agent",
description="Answers questions about order status.",
instruction="Use lookup_order to answer order questions.",
tools=[lookup_order],
)
a2a_app = to_a2a(root_agent, port=8001)
# run with: uvicorn agent:a2a_app --host localhost --port 8001
# client: another agent that delegates to it
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent, AGENT_CARD_WELL_KNOWN_PATH
order_agent = RemoteA2aAgent(
name="order_agent",
agent_card=f"http://localhost:8001{AGENT_CARD_WELL_KNOWN_PATH}",
)Tool or agent?
Expose something as an MCP tool when it is a deterministic function the caller should control. Expose it as an A2A agent when it needs its own reasoning, keeps state across a long-running task, or belongs to another team or organization. See the MCP module and the A2A module for the protocol details.
Architecture patterns
Anthropic's "Building effective agents" guidance still holds: prefer simple, predictable workflows, and reach for autonomous agents only when the task truly needs open-ended decisions. Most production systems combine a few of these patterns.
Single agent + tools
One loop, a focused toolset. The right default, and much more capable than it was a year ago.
Prompt chain / pipeline
Fixed steps in order, such as extract, then validate, then write. Easy to test, and each step can use a cheaper model.
Router
Classify the request, then send it to a specialized prompt, agent or model. Cheap and effective for mixed traffic.
Orchestrator-workers
A lead agent plans and spawns subagents with their own context windows. Strong for broad, parallel research; costly in tokens.
Evaluator-optimizer
One step produces, another critiques against criteria, and the loop repeats until the work passes. Good when quality is checkable.
Graph workflow
An explicit state machine whose nodes may be agents. Gives you auditability, retries and human checkpoints at known points.
Multi-agent has a price
In Anthropic's research system, agents used about 4x the tokens of chat and multi-agent systems about 15x. Use multiple agents when subtasks are independent and context-heavy, not as a default. The multi-agent module covers the trade-offs.
Production concerns
A demo agent runs once on your laptop. A production agent runs thousands of times, for hours, against real systems and untrusted input. Five concerns separate the two.
Durable execution
Long tasks will hit crashes, deploys and timeouts. Checkpoint state so a run can resume rather than restart. LangGraph's durable execution, ADK workflows, OpenAI's durable approvals and managed runtimes such as AgentCore (runs up to 14 days) exist for this reason.
Sandboxing
Run code and shell tools in an isolated container or VM with no ambient credentials. Hosted options include OpenAI's sandbox agents, Claude Managed Agents and AgentCore; locally, use containers and the SDK's sandbox settings.
Observability
Log every model call, tool call, input, output, token count and decision as a trace. When an agent fails at step 37, you need to replay steps 1 to 36. Most frameworks emit traces you can send to your existing tooling.
Cost control
Cap turns and spend per run, route easy work to smaller models, use prompt caching, and keep context lean. Watch cost per successful task rather than cost per call.
Human approval
Gate irreversible or sensitive actions such as payments, deletes, external emails and production deploys behind an approval step. Make approvals durable, so a run can wait hours for a human without losing state.
Security
Assume any content the agent reads may contain prompt injection. Limit what a single session can both read and do. Securing agents covers this in depth.
Evaluate before you scale
Build a small eval set from real tasks before you add features. Every prompt, tool or model change should be measured against it. The next module, Evaluating agents, shows how.
A "start simple" checklist
Most failed agent projects did not fail because the model was too weak. They failed because the system was too complex too early. Use this checklist on your first build.
- Write down the task and what "done" looks like. If you cannot check success, you cannot improve the agent.
- Try a single prompt or fixed workflow first. Only add a loop if the steps genuinely vary per request.
- Start with one agent and three to five well-described tools. Clear tool names and descriptions matter more than clever prompts.
- Set hard limits on turns, spend and wall-clock time from day one.
- Run tools in a sandbox with least-privilege credentials scoped to this agent.
- Require approval for irreversible actions until the eval data shows you can relax it.
- Turn on tracing and read the transcripts of real runs every week.
- Build 20 to 50 eval cases from real requests and rerun them on every change.
- Only then consider sub-agents, graphs or A2A, when you can name the specific limit you are hitting.
Key takeaways
- Agent frameworks have converged: almost all of them offer a tool loop, sessions, sub-agents, human-in-the-loop, MCP and A2A. Choose based on models, hosting and how much structure you need.
- Libraries (Claude Agent SDK, OpenAI Agents SDK, ADK, LangGraph, Pydantic AI) run in your process. Platforms (Claude Managed Agents, OpenAI Agents API, Bedrock AgentCore) run the loop and infrastructure for you.
- A minimal agent is just instructions, tools, a loop and limits, and that shape is the same in every SDK.
- Use MCP to consume tools and A2A to expose or call agents, so your integrations outlive your framework choice.
- Production readiness means durable execution, sandboxing, observability, cost caps and human approval for risky actions.
- Start with the simplest design that could work, measure it, and add complexity only to fix a limit you can name.
Sources & further reading
- Claude Agent SDK reference: Python
- Claude Managed Agents announcement
- OpenAI Agents SDK documentation
- OpenAI Agents SDK releases
- Google ADK: exposing an agent over A2A
- google-adk on PyPI
- LangChain and LangGraph 1.0
- Amazon Bedrock AgentCore release notes
- Pydantic AI changelog
- CrewAI changelog
- Anthropic: How we built our multi-agent research system