Over the last nine parts of this path you have built up the pieces of an agent by hand, at least on paper: a loop that observes, thinks and acts (part 2), tools that the model can call (part 3), a sense of when a fixed workflow beats a free-roaming agent (part 4), ways to break a task into steps (part 5), memory that survives beyond one turn (part 6), the discipline of context engineering (part 7), a plan for errors and stopping conditions (part 8), and places to bring a human into the loop (part 9). None of that required a framework. It required an LLM client, a loop, and some bookkeeping.

So why do frameworks exist, and when should you reach for one instead of writing the loop yourself? That is the question this part answers. It is not a product comparison or a ranking. Framework APIs change every few months, new ones appear, old ones get rewritten, and anything specific enough to be useful today would likely be wrong by the time you read it. Instead, this part gives you the categories of tools that exist, what problem each category solves, and a way of deciding for yourself, project by project, whether a framework earns its place or just adds a layer between you and the thing you are trying to understand.

What a framework actually gives you

It helps to be concrete about what is actually being offered, because "framework" covers a wide range of things, from a thin wrapper around an API call to a full orchestration engine with a visual graph editor. Strip away the marketing and most agent frameworks are selling some combination of the following six things.

1. Loop scaffolding

The observe-think-act loop from part 2 is not complicated, but writing it correctly takes care: you need to send the conversation so far, check whether the model asked for a tool, run the tool, append the result, and send everything back, in a way that does not silently drop messages or lose track of which tool call matches which result. A framework gives you this loop pre-built, usually as a function or a class you configure rather than code you write from scratch.

2. Tool-calling glue

From part 3 you know that a tool needs a name, a description and a schema for its arguments, and that the model's tool call needs to be parsed, validated and dispatched to the right function. Frameworks typically let you decorate or register an ordinary function and they generate the schema for you, validate the arguments the model returned, and route the call. This is one of the genuinely useful, low-risk conveniences frameworks provide, because schema generation is repetitive and easy to get slightly wrong by hand.

3. State and memory management

Part 6 distinguished short-term memory (the running conversation), long-term memory (facts that persist across sessions) and notes (a working scratchpad the agent writes to itself). A framework may offer built-in objects for all three: a conversation buffer, a vector store wrapper for long-term recall, and a scratchpad abstraction. This saves you from reimplementing storage and retrieval, but it also means adopting the framework's idea of what a memory should look like.

4. Multi-agent orchestration

Some tasks are easier to reason about as several specialised agents talking to each other rather than one agent trying to do everything. A planner agent can hand off to a researcher agent, which hands off to a writer agent. Coordinating these handoffs by hand is possible but fiddly: you need to decide who speaks next, how much context each agent sees, and when the conversation is done. Frameworks built around this pattern provide the handoff mechanics so you can describe roles and let the framework manage turn-taking.

5. Observability and tracing

Once an agent makes several tool calls across several turns, a plain print statement stops being enough to understand what happened. Many frameworks come with, or integrate with, a tracing tool that records every prompt sent, every tool call made, every token used and every branch taken, and lets you inspect a run after the fact. This is one of the stronger arguments for a framework once you move past a toy example, because building good tracing yourself is a real, non-trivial piece of engineering.

6. Patterns for retries, stopping conditions and human review

Parts 8 and 9 covered retry logic, loop limits, confirmation gates and escalation to a human. Some frameworks bake in configurable versions of these: a maximum number of steps, a hook that pauses execution and waits for approval, a retry wrapper around tool calls with backoff. Used well, this saves you from reinventing safety rails that are easy to get wrong under time pressure.

Put together, a framework is a bet: it trades some of your control and some of your understanding of the mechanics for speed and for patterns that other people have already debugged. Whether that bet pays off depends entirely on what you are building and where you are in your own learning.

The landscape, in categories

Rather than naming specific products and describing their current APIs, which will drift out of date, it is more durable to understand the shapes that agent frameworks tend to take. Most tools you will encounter fit into one of the following categories, and a few straddle two.

Thin SDKs close to the raw API

These add the smallest possible layer on top of a model provider's API: a loop that runs until the model stops asking for tools, automatic schema generation from your function signatures, and sometimes a lightweight way to hand off between a small number of agents. They deliberately avoid heavy abstractions like graphs or persistent agent objects. If you already understand the loop from part 2, a thin SDK will feel like a tidier version of the code you would otherwise write by hand, rather than a new way of thinking.

Explicit graph or state-machine orchestrators

These frameworks ask you to describe your agent as a graph of nodes and edges: a node might be "call the model", another "run a tool", another "ask a human for approval", and edges define which node runs next based on the output of the previous one. This maps closely to the planning and decomposition ideas from part 5, made explicit and inspectable. The appeal is that the control flow is drawn out rather than buried inside a loop, which makes complex branching, loops-within-loops and long-running, resumable workflows easier to reason about. The cost is that you are now programming in the framework's graph language, and debugging means understanding both your logic and the framework's execution model.

Role-based multi-agent frameworks

These frameworks organise an application as a small team of named agents, each with a role, a goal and a set of tools, who converse with each other to complete a task: a researcher, a writer, a critic. The framework manages the conversation between them. This can be a natural fit for tasks that genuinely decompose into distinct roles with different tools and different prompting needs. It can also be a way of making a simple task look more impressive than it needs to be, since three agents chatting to produce one paragraph is usually slower, more expensive and harder to debug than one well-prompted agent with a checklist.

Retrieval-centric frameworks

Some frameworks grew out of retrieval-augmented generation (RAG) and still carry that focus: they are strongest at chunking documents, building indexes, running retrieval, and wrapping all of that into a tool an agent can call. If your agent's main job is to search and answer from a body of documents, as in the research assistant project coming in part 12, a retrieval-centric framework can save real time on the indexing and retrieval plumbing, even if you handle the agent loop itself separately or by hand.

Enterprise integration frameworks

A few frameworks exist mainly to let agent logic plug into an existing software stack: a particular programming language ecosystem, a particular cloud platform, a particular set of enterprise connectors. Their value is less about the agent loop itself and more about fitting into infrastructure, security and deployment processes that already exist in a company. If you are working inside such a stack, this category may be chosen for you by constraints that have nothing to do with how elegant the agent code is.

None of these categories is strictly better than the others. A graph orchestrator is a poor fit for a five-line agent that answers one kind of question. A thin SDK is a poor fit for a genuinely complex, branching, long-running process that needs to be paused and resumed over days. The categories exist because the problems they solve are different, and matching the category to your actual problem matters more than picking the most popular name.

What "no framework" actually means

It is worth being precise about this, because "no framework" does not mean no libraries at all. In practice it means: you use the official client library for your model provider to send and receive messages, you write the loop from part 2 yourself, you define your tools as plain functions with a hand-written or lightly automated schema as in part 3, and you manage memory, retries and stopping conditions with ordinary data structures and control flow, as covered in parts 6 and 8. You are still using software other people wrote. You are just not handing over the loop, the state, or the control flow to a layer designed to do that for you.

To make this concrete, here is the shape of a no-framework agent loop. This is a sketch to illustrate the idea, not the full implementation; part 11 builds a complete, runnable version step by step.

🐍Python
# Conceptual sketch only - see part 11 for a complete, runnable version.
messages = [{"role": "user", "content": user_question}]
tools = {"calculator": run_calculator, "search": run_search}

for step in range(MAX_STEPS):
    response = client.chat(messages=messages, tools=tool_schemas)

    if response.tool_call is None:
        final_answer = response.text
        break

    messages.append(response.raw_message)
    tool_name = response.tool_call.name
    tool_args = response.tool_call.arguments
    result = tools[tool_name](**tool_args)
    messages.append({"role": "tool", "name": tool_name, "content": str(result)})
else:
    final_answer = "Stopped: too many steps."

Every part of this is something you already understand from earlier in the path: the message list is short-term memory, the for loop with MAX_STEPS is the stopping condition from part 8, and the tool dispatch is the function-calling pattern from part 3. There is no hidden machinery. If something goes wrong, you can put a print statement anywhere in this loop and see exactly what the model was sent and exactly what it sent back. That transparency is the entire case for writing it this way, and it is a real advantage, not a nostalgic one.

The real trade-off: control versus speed

Set aside brand names and look at the trade-off underneath. Choosing a framework is choosing to spend less time writing plumbing and more time trusting someone else's plumbing. Choosing no framework is the reverse. Both are reasonable choices depending on circumstances. Here is what each side actually costs and buys.

What you gain from a framework

  • Speed to a working prototype, especially for patterns the framework has already solved, like multi-agent handoffs or retrieval pipelines.
  • Built-in tracing and observability, which is genuinely hard to build well yourself and very useful once an agent has more than a couple of tools.
  • Community examples and documented patterns for things like confirmation gates (part 9) or retry policies (part 8), so you are not designing them from first principles.
  • Some protection against mistakes, since widely used frameworks have often had their error handling, rate-limit handling and edge cases hardened by many other users hitting the same problems.
  • Easier onboarding for a team, if everyone already knows the same framework, since new members read the framework's documentation rather than your bespoke loop.

What it costs you

  • Abstraction leakage: when something goes wrong, you often have to understand both your own logic and the framework's internals to find the bug, which is two mental models instead of one.
  • Version churn: agent frameworks are young and change quickly; code that works today may need updating in a few months for reasons unrelated to your project.
  • A learning curve that teaches you the framework's vocabulary and mental model, which may or may not transfer to the next framework, as opposed to learning the underlying loop, which transfers to every framework and to no framework at all.
  • Harder debugging for subtle issues, because a stack trace through several layers of orchestration code is less informative than a stack trace through your own fifteen-line loop.
  • A tendency to reach for heavier patterns than the task needs, since a framework built for multi-agent orchestration makes it easy, even tempting, to add a second or third agent to a task that a single well-prompted agent, or a plain workflow as in part 4, would have handled more simply and more cheaply.
  • Lock-in, not in a contractual sense but a practical one: a codebase built deeply around one framework's abstractions takes real effort to move to another approach later.

Notice that almost every item in the cost list is a form of indirection. That is the honest summary of what a framework is: indirection, purchased with your time and your API spend, in exchange for not writing some code yourself. Indirection is sometimes a very good deal. It is a bad deal when the thing you are trying to do is small, when you are still learning how the loop works, or when the specific pattern you need is not the pattern the framework is built around.

A decision checklist

Rather than a single rule, use the following questions as a checklist for a specific project. None of them has a universally right answer; they are meant to surface what matters for the task in front of you.

  • Do you understand the agent loop well enough to debug it blind? If you are still building that intuition, write it by hand first, even if you plan to use a framework later. You cannot evaluate what a framework is hiding from you until you know what is normally there.
  • Is this one agent or several? A single agent with a handful of tools rarely needs more than a thin SDK or no framework at all. Several agents genuinely dividing labour is where orchestration frameworks start to earn their complexity.
  • Is this a workflow or an agent? Revisit part 4. If the steps and their order are mostly fixed and only a few decision points are dynamic, a plain script with conditional branches, possibly calling an LLM at specific steps, is simpler and more reliable than any agent framework, orchestrated or not.
  • Will this run once, occasionally, or continuously in production? A one-off script or a weekend project rarely justifies the setup cost of an orchestration framework. A system that will run unattended every day benefits from built-in retries, tracing and resumability.
  • How much do you need to inspect a failed run? If debugging by reading raw logs you wrote yourself is acceptable, you may not need a framework's tracing tool. If several people need to inspect runs after the fact, a framework with a dashboard can pay for itself quickly.
  • Does your team already standardise on a framework? If colleagues maintain agents in a particular framework already, consistency across the codebase is often worth more than the marginal benefit of a different tool for your piece.
  • How much does long-term flexibility matter? If you expect to swap model providers, change the shape of memory, or rework the tool set significantly, less framework-specific code means less to rewrite.
  • Is the task mostly retrieval over documents? If so, weigh a retrieval-centric framework for the indexing and search parts specifically, even if you keep the agent loop itself plain.
  • What is the cost of being wrong? A framework adopted for a quick prototype is cheap to abandon. A framework adopted as the foundation of a production system is a multi-month commitment; treat that decision with the weight it deserves.

A useful habit is to answer these questions in writing before starting, even briefly, rather than defaulting to whichever framework appeared most recently in a blog post or a conference talk. Popularity is a weak signal for fit. A framework can be excellent and still be the wrong choice for your specific agent, and a framework can be niche and still be exactly right for a specific, narrow job like document retrieval.

The same small agent, three ways

To make the differences concrete without pretending to give you working code for every tool on the market, consider one small, fixed task: an agent that answers a question and, if the question requires arithmetic, calls a calculator tool before answering. This is simple enough to implement in any of the three approaches below in well under fifty lines, which is exactly the point: at this scale, the choice of approach barely matters for speed, and matters a great deal for how much you learn and how easy debugging is.

As plain Python

You write the loop shown earlier, define a calculator function, hand its schema to the model, and handle the tool call yourself. Every message the model sees and every value returned by the tool is visible in your own code. If the model calls the calculator with malformed arguments, you see the raw arguments and decide how to handle it, following the error-handling habits from part 8. There is no translation layer between what you wrote and what runs.

As a thin SDK agent

You still define the calculator as a plain function, but instead of writing the loop, you register the function with an agent object and call a single method such as agent.run(question). The SDK generates the schema from your function's type hints, runs the loop internally, and returns the final answer along with a record of what happened. The code is shorter. What you give up is visibility into the exact loop: if the agent calls the calculator twice instead of once, or stops one step too early, you are reading the SDK's trace output rather than your own print statements to find out why.

The exact method and object names vary by SDK and by version, so treat the shape below as illustrative rather than copyable:

🐍Python
# Illustrative shape only, not a specific library's real syntax or version.
def calculator(expression: str) -> float:
    """Evaluate a basic arithmetic expression."""
    return safe_eval(expression)

agent = Agent(model="some-model", tools=[calculator],
              instructions="Answer the user's question. Use the calculator for arithmetic.")
result = agent.run(question)
print(result.final_output)
print(result.trace)  # record of each tool call the SDK made internally

As a graph