Planning every provider call before the first one runs

Answering a real question takes several API calls, and most of them exist only to turn one identifier into the next. KIRHA's planner writes the whole graph down before any of it runs.

Ask a model a question about the real world and it will reach for a search engine. That works when the answer is written on a page somewhere. It stops working when the answer has to be assembled: the latest tenders above 10 million euros in two countries, the delay on one specific flight, the largest holders of one token contract. Those live in registries and APIs, not in prose.

Our benchmark puts numbers on the gap. Across 100 queries in company data, insurance and crypto, querying sources directly scores 87 out of 100 against 61 for web search, and it gets there on 233,920 tokens of context instead of 4,604,853, roughly 95% less, because a structured answer does not arrive wrapped in a page. Web search still wins where the answer really is written up somewhere, which is why KIRHA falls back to it when no source covers the domain, and the scoring is done by a model rather than a person, so it reads as a direction more than a measurement.

Going direct moves the difficulty rather than removing it. A search engine takes a sentence. An API takes an identifier, and almost never the one you have. Ask for the largest USDC holder on Base and their profit and loss and 5 calls stand between the question and its answer, of which only 2 are about anything a person asked for. The chain has to be resolved to an id, the token symbol to a coin, the coin to a contract address on that chain, and only then can holders be listed and a wallet be priced.

execution graphchainIdcoins.0.idcontractAddressholders.0.addressqueryplannergetChainIdsearchCoingetCoinPlatformInfogetTokenHoldersgetWalletPnLresults
The plan for that question. Boxes are calls, labels beside the edges are the values passed between them. 3 of the 5 calls exist only to carry an identifier to the next one. Hover a call to see everything it had to wait for.

So the hard part of using real sources is not reasoning, it is plumbing. An agent that discovers this pipeline one call at a time pays a full round trip through the model for every identifier hop, and has to hold the shape of the whole pipeline in its head while doing it. Nothing about the route is known until it has already been walked, so the question cannot be priced, checked or repeated.

Deciding the route before running it

An agent works one call at a time. It emits a call, the result comes back into its context, and it decides again from what it now knows. That loop is exploratory by construction, because a tool's description says what it is for, not what it returns. Which fields come back is unknown until the call has been made, so the only way to find out whether a call gets you closer is to spend it.

That has three costs. Every intermediate result is now in the context window, so the prompt grows with each hop. Every hop is a full round trip through the model, so latency is the number of calls multiplied by the time to think about each one. And when a guess does not pay, the call was still made, still paid for, and still in the context. The walk fans out into branches that had to be tried and then abandoned.

The part that is hardest to live with is that none of it is predictable. You cannot say in advance which providers a question will touch, or how many calls it will take, so you cannot quote a price, cap a budget, or promise the same answer twice. The same question asked twice takes two different routes.

What breaks the loop is knowing what comes back. Every KIRHA provider is written with a declared output as well as an input, and the two are designed to fit each other: an output that names an identifier another tool accepts is what makes the pair composable at all. With both halves declared, a planner can see that one call produces the field the next one needs, and write the whole chain without running any of it. This is why the catalogue is authored rather than wrapped.

Explored, one call per turn

6 round trips, and 2 sources reached twice

Planned, one turn, then all four at once

1 round trip, 4 calls, nothing called twice

The same question, answered two ways. On the left the line is followed one call at a time, in the order the numbers give, and a source that had to be called again simply appears again. On the right a single turn decides all four, and the two lanes run at once. Hover a call, or the planned route.

With the route settled up front, a plan is a value you hold before anything happens rather than a trace of something that already did, and the things you could not do before become ordinary.

The planner model

All of this rests on something not yet accounted for: a model that can write the whole plan at once, correctly, against a catalogue it has never seen. That is not what a general model does. Instruction tuning teaches it to call one tool and look at the result, which is the loop we are trying to leave, and nothing in it teaches a model to emit a graph of calls with the dependencies between them already resolved. So the question becomes how you get a plan out of a model in one pass.

Our answer is a model that does nothing else. It is a fine-tune of Qwen3.6-35B-A3B, a mixture of experts with roughly 3B parameters active for any given token, so capacity stays large while a forward pass stays cheap. It returns a think block with its reasoning and a plan block holding the steps, each naming a tool, its arguments, and a reference where a value does not exist yet: a step needing the first coin id from step zero writes {0.coins.0.id} and moves on.

The training set is built on several hundred tools that do not exist, and that is the part that matters. A model shown real provider names learns those names, and what we need is one that plans against tools it has never met, including yours. Teaching it on invented catalogues forces it to work from the shape of a schema rather than from recognition. From there it learns in two phases: supervised fine-tuning first, to fix the structure of a plan, then reinforcement learning to sharpen the composition, wiring one call's output into the next and leaving alone the tools a question does not need.

Choosing from a large catalogue

A plan is only as good as the tools the planner was allowed to consider, and it considers what is in its prompt. That is where this stops being free. Put 800 tool definitions in a context window and the model gets worse, not better: a longer prefill costs latency before a single token is generated, and a model reasoning across hundreds of descriptions reasons longer and less well, because most of what it is weighing has nothing to do with the question.

KIRHA's catalogue is already past 800 tools and every provider we add makes it larger. Handing the planner everything was never going to hold, so the size of the catalogue had to stop being the planner's problem.

800+ tools in the catalogue, and it only grows

20 or so reach the planner

narrowing the catalogueplanner
A retrieval pass runs first and keeps 20 or so tools out of the catalogue. Only those are put in front of the planner. Hover one to follow it into the bundle.

So the context is capped at roughly 20 tools, chosen by a retrieval pass that runs before the planner sees anything. Those 20 come with the tools they compose with, which matters more than it sounds: a tool can be exactly what a question needs and describe itself in words the question never uses, and it earns its place because a neighbour matched.

How that shortlist is built is a piece of work in its own right, and a necessary one for any of the above to function. It has its own write-up: semantic search over a tool catalogue.