Framework or Raw SDK? The Test Is Whether You Can Print the Exact Prompt

The framework debate is usually argued on taste. There's a faster test: build a two-tool agent and try to dump the exact request it sends on turn four. How hard that is predicts your next six months of debugging.

Framework or Raw SDK? The Test Is Whether You Can Print the Exact Prompt

The framework-versus-SDK argument is usually fought on taste: abstraction is elegant, abstraction is bloat, round and round. There's a sharper test, and it takes about twenty minutes to run. Pick any agent framework you're considering, build a two-tool agent with it, and then try to dump the exact bytes it sends to the model on turn four — full system prompt, full serialized tool schemas, full message history, verbatim.

How hard that is tells you more about your next six months than any benchmark on the project's README.

Run the test on turn four, not turn one

Turn one is easy everywhere. Your system prompt goes in, your two tool definitions go in, the user's message goes in. Nothing has happened yet.

Turn four is where frameworks earn their keep and hide their bugs. By then the runtime has done things you did not write:

  • Appended tool results in some format it chose — JSON blob, XML-ish wrapper, plain string, truncated at some limit.
  • Possibly dropped or summarized older turns because a context budget tripped.
  • Possibly injected retrieved memories, scratchpad state, or a re-stated goal.
  • Possibly repaired a malformed tool call by re-prompting, leaving an extra exchange in the history you never see in the logs.
  • Re-serialized your tool schemas, maybe reordering them, maybe stripping descriptions it considered redundant.

Every item on that list is a legitimate feature. Every item is also a place where your agent's behavior stops being a function of code you wrote. When the agent starts calling the wrong tool on long conversations, the difference between a two-hour fix and a two-week fix is whether you can read what it was actually asked.

The three outcomes

One line of setup. The framework has a hook, a callback, a debug flag, or a middleware slot that hands you the outgoing request object before it goes over the wire. You serialize it to a file. Done.

# the shape you want to exist
agent.on_request(lambda req: Path("turn4.json").write_text(req.to_json()))

Spelunking. No hook exists, so you reach for HTTP-level interception — a proxy, a patched transport, monkeypatching the client. It works, but you're now reading the framework's internals to understand your own agent, and every upgrade can move the floor.

Impossible or lossy. The prompt is assembled inside a hosted service, or across three layers of class inheritance where the final string is a local variable. You can see what went in and what came out, never the middle.

Outcome one is the buy signal. Outcome three is the walk-away signal, no matter how good the demo looked. Outcome two is a judgment call that depends on how much you'll be debugging — and you will be debugging.

What you're actually choosing between

Framing this as "framework versus raw SDK" flattens the real decision, because a framework bundles at least five separable things:

  1. The agent loop — call model, parse tool calls, execute, append results, repeat until done.
  2. Prompt assembly — how system text, history, tool schemas, and tool results become one request.
  3. Tool plumbing — turning a typed function into a schema, validating arguments, dispatching.
  4. Reliability wrapping — retries, timeouts, backoff, malformed-output repair, streaming.
  5. Observability — traces, spans, token accounting, replay.

Items 1 and 2 are your product. They are where your agent's personality, cost profile, and failure modes live, and they are also, by a wide margin, the easiest to write yourself. The agent loop is a while-loop with a switch statement. Prompt assembly is string concatenation with a truncation policy you should be choosing deliberately anyway.

Items 3, 4, and 5 are the boring, genuinely tedious parts — schema generation from type hints, exponential backoff that handles rate-limit headers correctly, span plumbing that survives async. Writing those from scratch is where "we'll just use the SDK directly" turns into a six-week detour.

The middle path most teams land on

Own the loop and the prompt. Import the plumbing.

your code:        loop, prompt assembly, truncation policy, tool registry
library code:     schema generation, retries, tracing, streaming, provider clients

This is not a compromise position, it's the one that matches where the risk actually is. You keep the two layers you'll be debugging at 2 a.m. as plain, readable code in your repo. You delegate the two layers that are annoying but well-defined, and whose bugs surface as exceptions rather than as subtly worse answers.

Practically, that means preferring libraries that are decomposable — where you can use the tool-schema generator without adopting the orchestrator, or the tracing without the memory abstraction. A framework that only works as a whole is a bet that all five of its opinions match yours.

🔍 A short adoption checklist

Before committing to any agent framework, confirm you can do each of these without forking it:

  • ✅ Print the full outgoing request at an arbitrary turn.
  • ✅ Change what happens when the context budget is exceeded — and know what the current policy is.
  • ✅ Control the exact text format of a tool result.
  • ✅ Insert your own message into history mid-run.
  • ✅ Run the loop one step at a time, from a test, with a stubbed model.
  • ❌ If any of these requires reading source you didn't expect to read, that's your future debugging experience, previewed.

That last item is the honest one. The cost of a framework is rarely the abstraction itself. It's that the abstraction was designed against a mental model of agents that may not be yours, and the day you discover the mismatch is the day something is broken in production.

The takeaway

Pick the framework whose abstractions you could delete. If you can see the prompt, you can fix the agent — and if you can see the prompt, you can also, eventually, replace the layer that built it. Opacity is the only property that isn't reversible later.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.