Cheat sheets

Agent Frameworks Compared

Pick LangGraph, CrewAI, AutoGen, Agno, Mastra, an agent SDK or plain Python by problem shape, state and routing cost.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Comparisons
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

Orchestration frameworks side by side#

FactorLangGraphCrewAIAutoGenAgno
Core abstractionStateGraphCrewConversableAgent pairAgent
Mental modelState machineTeam of specialistsChatAgent with batteries included
StateTyped state, checkpointerStrings through contextChat historySession store through storage=
Who branchesYou, with conditional edgesManager, or you at build timeAgents, through chatThe next tool call
Routing tokensOnly where you write llm.invokeHierarchical manager spends tokensGroupChatManager spends tokensThin single-agent path
Best fitTyped state, human interruptsShort role-driven plansProposer-critic dialogueSingle agent, sessions, memory
Worst fitUnknown topologyComplex branchingKnown DAG, durable stateDeep branched graphs

Agent SDKs and runtimes side by side#

FactorOpenAI Agents SDKClaude Agent SDKAutoGen v0.4Mastra
PrimitivesAgent, Handoff, Guardrail, Session, TracingTools, MCP, hooks, subagents, session storeCore, AgentChat, ExtensionsAgents, Tools, Workflows
DelegationTool named transfer_to_<agent_name>Subagents with their own contextMessages to an actor inboxWorkflow steps
StateSession in SQLite, Redis, customappend, load, delete with cascadePrivate actor stateComposite storage
TracingOn by defaultW3C trace context into the CLIA span for each messageMastra Studio
Use forOpenAI-first productsClaude-first productsActor concurrency, fault isolationTypeScript, Next.js or Vercel

Run the projects#

CommandWhat it does
python3 scripts/project_test.py <project> --stage 1 --path <dir> --strictGrade one stage
python3 scripts/project_test.py <project> --all --solution --optional --strictRun the real SDK tests. A SKIP fails
node --experimental-strip-types cli.ts --ticket fixtures/ticket.json --out workflow-outputScratch workflow. Writes a checkpoint when approval is required
node --experimental-strip-types optional-mastra/cli.ts --ticket fixtures/ticket.json --db ./runs.db --out pending-outputDurable Mastra run. Reports a runId
python3 main.py --ticket fixtures/ticket.json --out support-outputOffline support review in index.html
main.py --ticket YOUR_TICKET.json --adk --out support-adk-outputSame ticket through real ADK agents

Troubleshooting#

SymptomCauseFix
A hands off to B, B hands back to AHandoff driftAdd a hop counter
Built-in tool skips the checkTool guardrails fire on function tools onlyAdd a separate policy
Task N+1 ad-libs on free textBrittle handoffsSet output_pydantic on Task N
Crew costs too many tokensManager-LLM token taxSwitch to Sequential
Context gone before the first tool callLong backstoriesKeep backstories under 200 words
Overhead dominates tiny tasksSubagent over-spawnBatch the tasks
Sessions grow without limitSession bloatUse list_sessions and an expiry policy
Resume fails before the toolWrong ticket or digest in approvalKeep ticketId and planHash unchanged

Use X when#

LangGraph
typed state, approvals, resume, Send fanout.
CrewAI
a Flow that calls Crew.kickoff() in a step.
AutoGen
proposer-critic dialogue.
Agno
many short-lived Python agents, FastAPI.
Mastra
TypeScript, Next.js or Vercel, Zod-typed tools.
Plain Python
two LLM calls and a tool.

Decision tree: recommend(p)#

1plain pythontotal_llm_calls 2 or fewer. No roles, dialogue,resume, fan-out or human interrupt.2langgraphneeds_resume, needs_human_interrupt orhas_parallel_fanout.3autogenhas_dialogue without has_typed_state.4crewaihas_roles without has_typed_state.5agnoneeds_session_memory, no roles, no dialogue.6langgraphhas_typed_state, and the fallback.

Actor runtime (AutoGen v0.4 shape)#

sendstartreviewreviewreview_resultcrash_me raisesclient__user__sends startqueueRuntime queueMessage dequeprocessChecklistAgentsends three reviewsstoredead_lettersfailed messagesprocessReviewerAgentsends review_resultsendstartreviewreviewreview_resultcrash_me raisesclient__user__sends startqueueRuntime queueMessage dequeprocessChecklistAgentsends three reviewsstoredead_lettersfailed messagesprocessReviewerAgentsends review_result

SDK tasks in code#

TaskCode
Ask the recommenderpython main.py --ask
Hand off to an agenttransfer_to_<agent_name>
Turn off tracingOPENAI_AGENTS_DISABLE_TRACING=1
Fan spans to your backendadd_trace_processor(processor)
Run with stored historyRunner.run(agent, input, session=session)
Force a typed task outputoutput_pydantic=MyModel
List subagent sessionslist_subkeys(session_id)

Suspend and resume in Mastra#

const workflow = createWorkflow({ id: "ticket-triage", inputSchema: ticketSchema, outputSchema: resultSchema })
.then(classifyStep)intent read or write
.then(planStep)lookup or update action
.then(executeStep)suspends before an update
.commit();
if (!resumeData?.approved)
return suspend({ ticketId: plan.ticket.id, planHash: digest });digest = planHash(plan)
const { workflow, storage } = await persistentWorkflow(tool, "file:" + resolve(args["--db"]));
const run = await workflow.createRun({ runId: args["--resume"] });fresh process, same file
result = await run.resume({ step: "execute", resumeData });approved, ticketId, planHash

What the projects build and check#

Mastra builds
a typed approval workflow. It suspends before an update and resumes from SQLite.
Mastra output
workflow.json, plus approval.json with approved=false.
Mastra check
matching approval gives one tool call. A wrong hash gives zero calls.
ADK builds
a redacted support reply or a human escalation, then the same rules in real ADK agents.
ADK output
an HTML review page and support.json.
ADK check
invoice login ties billing and access, so it escalates.

Defaults and limits#

SettingDefaultNote
Runner max_hops3Hop counter against handoff drift
Runtime max_messages100Messages for each run_until_idle
HierarchicalCrew max_steps5Manager rounds before stop
Guardrail modeParallelLower tail latency, wastes tokens on a trip
executePlan maxCalls3Allowed range 1 to 100
executePlan maxAttempts2Allowed range 1 to 10

Questions#

Why is a handoff a tool?
The model calls transfer_to_billing_agent. The runtime switches agents.
Why do actors isolate faults?
send(agent_b, msg) only queues. The runtime catches handler crashes.
Can the model change the ADK route?
No. It raises ValueError.