← All Blogs

Why you shouldn't use Jev for coding agents and routing

By AI/ML Engineer
Published Read Time: 5 min

Jev is the most interesting model release in a while. But I hate to break it to you: if you were planning to drop Jev into a coding harness and expect better routing, you've got some work to do.

Some context first, because it changes how much of this transfers to you. By routing, I mean deciding which model handles each call an agent makes. I'm specifically talking about coding-agent traffic: agents running in a loop, mostly making tool calls, reading files, editing and running tests. At Weave, we've been running a small classifier in front of that traffic for about five months, picking the model for each turn.

In those five months we've tried a lot of approaches, models and architectures. Almost all of the improvement came from one thing: giving the router the state of the session, meaning what the agent has already done. That's also why Jev doesn't change much for us.

What Jev gets right

Jev doesn't generate text. You hand it a state blob and a set of typed questions (pick from these options, score against these levels, is this true?), and it returns typed values with probabilities attached, all in a single pass.

For routing, this sounds like a no-brainer. Load up your favorite models and their capabilities, then let Jev cook. If you're paying frontier-model prices just to get back the word "urgent," you should be paying attention.

LangChain's launch post names model routing as the flagship Jev use case: classify how hard the task is, send easy things to cheap models and hard things to capable ones. That's exactly the shape of what we run. So when a model showed up that makes that decision 400x cheaper and 200x faster than a frontier LLM, we wanted to know what it would change for us.

What we tried

Most of our early experiments tried to work out, from the prompt, what a turn needed:

  • Clustering prompts. We embedded nearly a million prompts and looked for natural groups we could map to models.
  • Skill taxonomy. We tagged each request with how much it demanded of eight capabilities, then scored models against that demand minus a price penalty. This is almost exactly the design Jev makes trivial to build.
  • Turn taxonomy. We classified each turn as planning, a tool call, a confirmation, a refinement, and so on. This worked for telling us what kind of turn we were looking at, but not which model it needed.
  • Escalation. We started on a smaller model, watched for signs of failure, and escalated to a frontier model.

We also kept swapping the architecture underneath: centroids plus a classifier, an LLM, XGBoost, and back and forth a few more times. None of those swaps made a meaningful difference either. Whatever gave the best quality within our ~200ms latency budget won and the gap between them was small.

Where the gains actually came from

The router we run now predicts the agent's next action, out of six possibilities, and routes on that. Here's how much each input contributes:

Adding simple features about what happened on the previous calls took accuracy from 0.28 to 0.61. That's roughly double, from history alone.

Adding the prompt embedding on top of that moved band-AUC from 0.860 to 0.879.

Reading the prompt carefully helps a little. Knowing where the agent is in its loop helps a lot.

It makes sense once you look at real traffic. In ours, edit calls produce more output than any other action, more even than reasoning calls, which sound like the expensive kind of thinking. You can't tell that from reading an edit prompt. You can tell it instantly if you know the agent has already read four files and is now writing. How hard a call is depends mostly on what came before it, and that isn't in the text of the call.

What our feature layout looks like now

The clearest statement of what we believe is the feature vector we actually serve. Alongside the embedding, every routing decision reads:

  • how many tool calls, tool results, and tool errors came before this turn
  • what the current intent is (explore, edit, run a test, and so on)
  • which harness is sending the request (Claude Code, Codex, and so on)
  • a block of belief dynamics from the filter: entropy, movement, expected dwell, and the change in turn log-likelihood

That last one needs explaining. We run a filter over the hidden session state, so at every turn the router carries a belief about what phase the session is in and how confident it is in that belief. Those get fed back in as features. The router's own uncertainty about where the session is turns out to predict what comes next.

Almost none of this is in the prompt, and most of it can't be. It's a property of the trajectory, not the message.

So what does Jev change?

Jev makes the classifier nearly free and instant. But the classifier was never where our gains came from. Swapping architectures barely mattered for us, and Jev is one more architecture. Its cost advantage is also measured against frontier LLMs, and ours was already small, cheap and fast.

What Jev can't do is build the state. If you already have a good state representation, Jev may be a cheaper way to serve a classifier over it, and you should probably try it. If you're planning to hand it the user's message and ask how hard the task is, expect something close to the majority-class baseline, just 200x faster.

So if you're building a router, with Jev or without it, spend your time on state. Start by logging:

  • the full trajectory, every tool call and result in order
  • tool errors, separately from tool calls
  • how deep into the session each turn is
  • the harness and the tools available on it
  • downstream outcomes, so you have something real to check your labels against