Module 9
18 min read

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).

FrameworkStatus (Oct 2026)What it is good at
Claude Agent SDK (Python/TS)Active; renamed from Claude Code SDK in Sept 2025The same harness that powers Claude Code: built-in file and shell tools, subagents, sessions, skills, plugins, hooks, MCP and structured outputs.
Claude Managed AgentsLaunched April 2026; multi-agent orchestration and outcomes in beta since May 2026Anthropic 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 APIAgentKit at DevDay 2025-10-06; Agents API in public beta, with computer use and multi-agent tools added at DevDay 2026-09-29Hosted building blocks on OpenAI's platform. The Agents API also runs natively in AWS as Bedrock Managed Agents.
Google ADK 2.0GA 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 / LangChain1.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 Framework1.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 AgentCoreStrands 1.0 and AgentCore Harness GA 2026-06-17; next-gen AgentCore Runtime GA 2026-09-18; AgentCore Evaluations GA 2026-10-15Managed runtime on AWS where agents can run for up to 14 days, with A2A support in the runtime.
Pydantic AI2.0 (2026-06-23)Type-safe Python agents built around composable "capabilities", with a separate Pydantic AI Harness package.
CrewAI1.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 FoundationA local, MCP-native agent you can run and extend rather than a library you embed.
Versions and dates from release notes and vendor posts as of October 2026. Version numbers move quickly; check the linked changelogs before you pin one.

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. 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. 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. 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. 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. 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())
A support-ticket agent with one custom tool, a turn cap and a budget cap. Based on the Claude Agent SDK Python reference (pip install claude-agent-sdk).
  • 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_tools is an approval list, not a sandbox. It auto-approves the tools you name. Use disallowed_tools to block a tool entirely, and a can_use_tool callback (with ClaudeSDKClient) for custom approval logic.
  • Limits are part of the design. max_turns and max_budget_usd turn a possible runaway into a clean error you can handle.
  • Built-in tools come for free. Tools such as Read, Grep and Bash are 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())
The same agent with the OpenAI Agents SDK (pip install openai-agents). Based on the current quickstart, which uses the tool decorator from agents.decorators.
ConceptClaude Agent SDKOpenAI Agents SDK
Run the loopquery() or ClaudeSDKClientRunner.run() / Runner.run_sync()
Define a tool@tool(name, description, schema)@tool on a typed, documented function
Final answerResultMessage.resultresult.final_output
Delegate workSubagents (agents= option)Handoffs, or agents as tools
Built-in toolsFile, search, shell and web tools from Claude CodeHosted tools such as web and file search, plus sandbox agents
Different names, same building blocks.

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())
Attaching a remote MCP server to an agent. Adapted from the OpenAI Agents SDK MCP guide.

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}",
)
Exposing an ADK agent over A2A, then consuming it from another ADK agent. Based on the ADK A2A quickstarts.

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.

  1. Write down the task and what "done" looks like. If you cannot check success, you cannot improve the agent.
  2. Try a single prompt or fixed workflow first. Only add a loop if the steps genuinely vary per request.
  3. Start with one agent and three to five well-described tools. Clear tool names and descriptions matter more than clever prompts.
  4. Set hard limits on turns, spend and wall-clock time from day one.
  5. Run tools in a sandbox with least-privilege credentials scoped to this agent.
  6. Require approval for irreversible actions until the eval data shows you can relax it.
  7. Turn on tracing and read the transcripts of real runs every week.
  8. Build 20 to 50 eval cases from real requests and rerun them on every change.
  9. 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