LangChain, LangGraph, Claude Agent SDK, OpenAI Agents SDK, Flue, Pydantic AI, and NVIDIA's NeMo Agent Toolkit — compared through a hybrid self-hosting lens, with the marketing stripped off.
The seven contenders aren't the same kind of thing — integration glue, orchestration graphs, full autonomous harnesses, and a fleet layer above them. The study sorts every contender onto a layer, then scores twelve decision axes through one concrete lens: a hybrid setup where your own GPUs and cloud APIs both have to work.
You want cloud APIs today and your own GPUs tomorrow, without rewriting the agent in between. Build the same ~32-line agent, point it at an OpenAI-compatible endpoint, and prove the exit is a config change — not a migration.
We built the identical ~32-line tool-calling agent in LangGraph, the OpenAI Agents SDK, and Pydantic AI; each passed against an OpenAI-compatible endpoint with a one-line base-URL swap.
Boundary — passing means the wire protocol carries you, not that the frameworks' features are equal.
A "which framework?" debate that never converges, because the candidates are not the same kind of thing. Place each on its layer — glue, orchestration, harness, fleet — before scoring a feature, and most of the argument evaporates.
The study mapped all seven onto four layers and scored twelve axes; the maturity check cut exactly along layer lines — orchestration is past 1.0 with stability commitments, every harness and vendor SDK is not.
Boundary — layer tells you the kind of thing; it won't rank two tools on the same rung.
Two frameworks look equivalent until you install them and one brings 271 friends. Dependency count and install size are risk numbers you can get in minutes — and they separate the field more sharply than any feature list.
Measured on our bench: Sandcastle 7 packages in 15 MB · LangChain 34 in 95 MB · Flue 271 in 210 MB · pydantic-ai's full bundle 147 in 406 MB.
Boundary — install weight is a risk signal, not a quality verdict; small can still be underpowered.
If you run one play tonight, build the 32-line portability probe against your own stack. Point it at an OpenAI-compatible endpoint, swap the base_url, and run it. Now you know for certain whether your exit is a config change or a rewrite — instead of guessing from a docs page.
client = OpenAI(base_url="https://your-nim-endpoint/v1") # build it in LangGraph, OpenAI Agents SDK, or Pydantic AI — all passed