# Why Make an LLM Do the Grunt Work? After Jev, Who Should Handle an Agent’s Tool Work?

> Source: <https://dev.to/momolandnacy2del/why-make-an-llm-do-the-grunt-work-after-jev-who-should-handle-an-agents-tool-work-3nm3>
> Published: 2026-09-19 16:39:47+00:00

Jev has been getting a lot of attention lately.

When I first saw it, my immediate reaction was: finally, someone is here to take this job.

Anyone who has used agents for long-running tasks probably knows the loop. The model looks at the current state, gets called to choose a tool, receives the result, gets called again to fill a few arguments, and then gets called yet again when something goes wrong.

Some of those steps genuinely require careful reasoning. But many of them amount to much smaller decisions: choose A or B, continue or stop, call this interface or that one.

We spend enormous amounts of money training something that increasingly resembles a scientist, and then ask it to spend all day moving chairs around the laboratory.

I object to this arrangement, mostly because I am the one paying for the chair-moving.

I am a freelance writer. I use agents to research material, edit documents, publish content, make videos, and work across different platforms and domains. My first solution was brutally simple: whenever the agent lacked a capability, I added another tool.

Eventually, I built more than 600 tools.

They were useful. Very useful. But the tool descriptions kept growing, the bills kept growing, and tasks kept getting slower. I wanted to free my hands; instead, I found myself sitting in front of a computer watching an expensive frontier model figure out how to do grunt work.

So I started trying to reduce the cost.

1. Tool Search: If You Need Something, Go Find It
My first attempt was straightforward: expose only a small set of common tools and keep everything else behind search. Surely that was better than dumping documentation for 600 tools into the context at the beginning of every session.
In practice, the model often did not know what existed in the library, so it started guessing search terms. I once watched it spend three minutes looking for tools without making any progress on the actual task. I stopped it.
The tool descriptions no longer blew up the context immediately. They simply accumulated gradually through repeated search. I had removed the giant directory at startup and replaced it with exploration during execution.
So the next version had to give the model enough tools to actually begin working.
2. Dynamic Recommendation: Pick the Tools for It, but Don’t Keep Changing Them
I first tried a Frozen tool set: select the relevant tools at the beginning of the task and keep them fixed. That worked well at first, but when a new requirement appeared halfway through, the necessary capability was not there.
Next came One Promotion, which allowed the model to expand the tool set once during execution. That helped with missing capabilities, but the context cost I cared about did not improve much.
So I tried the obvious next step: why not recommend a new tool set on every round based on the current state of the task?
That became the Dynamic version. The task could be completed, but when I looked at the bill, the economics were ugly. Constantly changing the tool set also changed the context prefix, which interfered with one of the most valuable properties of long agent sessions: cache reuse.
The principle I eventually kept was simple:
Select dynamically at the boundary of a task or work unit, then keep the set stable inside that work unit.
But that raised the next question: if you only select once, how do you make sure the selected tools are actually sufficient?
3. Working Set: Relevant Tools Are Not Necessarily a Complete Set
Suppose the user says, “Modify this project.” A write tool is obviously relevant, but finding the file, reading the original source, running the program, and checking the resulting page may all be necessary as well.
A simple Top-K relevance search can easily miss those supporting capabilities. So I stopped recommending individual tools and started recommending capability groups instead. I built a catalog that recorded domains, groups, roles, and retrieval tags; a task would first match the relevant groups, then expand the full set of capabilities inside them.
For one programming workload, my working set contained three groups and sixteen operations: files, command execution, and browser interaction. They remained available throughout the work unit, while the model still decided exactly how to use them.
That solved the “missing tools” problem. It did not solve the tool-work problem.
The model could still read an entire file when it only needed ten lines. It could retrieve the same information repeatedly. It could modify the project and forget to verify the result.
Having the right tools does not make the tool work disappear.
At that point, I stopped asking only, “What tools should I give the model?” and started asking a different question:
“What is the model actually doing with them?”
4. Tool University: Teach It When Necessary, but Teaching Once Does Not Mean It Learned Forever
I called the next idea Tool University.
If the model did not know what capabilities existed, it could query runtime.find. If it found a capability but did not understand how to use it, it could call runtime.describe. If it already knew the tool, it could simply use it.
Tools also had to be cleaned up before entering the catalog. Their purpose, parameters, outputs, and scope controls needed to be explicit. When the system observed repeated calls or unnecessarily broad reads, it could provide targeted guidance about a better usage pattern, then stop reminding the model once it adopted that behavior.
This actually worked. In one earlier batch-processing experiment, after a single targeted instruction, the model kept using the batch pattern across the next 58 applicable opportunities in the same session.
Later experiments with bounded reads were less comforting. The model could adopt a better pattern in the short term, then drift back to its previous behavior over a longer run.
So I kept the catalog, on-demand documentation, and capability-admission standards. I did not keep stuffing more teaching material into the context.
And even when the model knew how to use its tools, I noticed that it was still repeatedly doing something else: writing small programs on the fly.
5. Skill-Owned Operators: The Program Is Reusable, but Who Is Still Organizing the Calls?
Fetch some material: write a script. Save the result: write another script. Parse a few fields: write another one.
The task changed and the parameters changed, but much of the actual procedure was reusable. So I packaged deterministic procedures into reusable Operators inside the Skill execution layer. The model supplied the current source and requirements; the Operator handled fetching, saving, parsing, and similar work, then returned a compact result.
That reduced repeated program generation. But the work between calls remained.
Which Operator should be used? What input should it receive? Is the result sufficient? What should happen after an error? What comes next?
Some arguments depended on information obtained in the previous step. Some failures required a different approach. You can keep wrapping deterministic procedures forever, but you cannot turn every one of these decisions into static code.
At that point, I finally noticed that one worker had never changed.
The frontier model was still responsible for finding capabilities, understanding how to use them, preparing arguments, chaining calls, handling local failures, and deciding whether the work was complete.
But does the frontier model really need to do all of that itself?
6. Hand Off the Entire Tool Job
That led me to a different idea: train a specialized model.
The frontier model would tell it what needed to be accomplished, provide the necessary material, define the allowed scope, and specify the expected result. The specialized model would then find tools, read their contracts, prepare arguments, operate inside its own loop, observe results, make local corrections, and eventually return with the finished work.
Simply helping the frontier model select a tool was not enough. If the frontier model still had to deal with arguments, errors, follow-up calls, and final checking, then all we had built was another recommender.
I wanted to hand off the entire tool job.
I also did not want another general-purpose model with a different system prompt pretending to be a sub-agent. The delegation relationship could remain, but I wanted to change the specialization of the model itself.
My starting assumption was a local model in the few-billion-parameter range, trained specifically around tool work. Spend its capacity there. Let it become extremely good at that one job.
I imagined a specialized labor model sitting in a little back room all day, surrounded by tools, arguments, return values, and error messages. The frontier model hands a task in; the worker finds the tools, fills the parameters, does the work, fixes mistakes, checks the result, and hands the finished job back.
Because of that rather undignified occupation, I gave it a name:
Xiaoheigong (小黑工)
Think of it as a backroom tool worker.
The name is unserious. The job description is not.
Suppose I say:
Extract these fields from these documents, organize them into a table, and save the result to this directory.
The frontier model should specify the fields, format, scope, and result requirements. It should not have to discover the read tool, prepare every argument, plan each save operation, and arrange every intermediate check.
If the frontier model has already done all of that, then the expensive part of the work was never really delegated.
The Xiaoheigong receives the task and inspects the available capabilities. It finds the relevant tools, reads the necessary schemas and usage contracts, and turns the supplied material into valid inputs.
It cannot simply memorize the names of my original 600 tools. It needs to understand unfamiliar tools from their contracts. If a necessary capability does not exist, it should report the gap instead of inventing an imaginary API.
The capability catalog, on-demand documentation, and admission standards I had built earlier still matter. The difference is that this specialized worker becomes their primary consumer.
Once a tool executes, the worker also needs to inspect the result. If the next step depends on information returned by the previous step, it continues the chain. If the arguments are invalid, it repairs them. If one local approach fails, it tries another approach within the delegated scope.
Those small problems should not require the frontier model to come back, reread the entire context, and issue another corrected call.
But if the goal is ambiguous, critical material is missing, or the task requires expanding its original scope, the worker should escalate. Taking over tool work does not mean taking over the user’s intent.
And what comes back should not be a pile of logs waiting for the frontier model to clean up.
Saving a file successfully does not mean the requested fields are correct. An API returning success does not mean the user’s task was accomplished. The worker needs to inspect the artifact and return the result, completion status, necessary evidence, and unresolved problems.
Intermediate searches, argument repairs, and retries can remain on the execution side unless they need investigation. The frontier model can then decide whether this delivery satisfies the larger task and what should happen next.
The execution environment has its own responsibility too: actually calling tools, preserving state, and returning facts. The Xiaoheigong organizes tool calls and makes local decisions; it does not get to invent reality because it feels like reporting success.
At this point, its cognitive role is basically clear. It does not need to discuss the meaning of life with me, and it does not need to write beautiful prose. If it can reliably and cheaply complete this tool work, it has already done enough.
There was only one problem.
I could not afford to hire this worker.
The tool organization, interfaces, and execution programs were things I could build piece by piece. Specialized model training was different. Data, compute, evaluation, iteration: that was beyond what I could realistically do by myself.
I started this entire project because agent bills were too high. I somehow ended up with a proposal that required me to spend money training a worker whose job was to save me money.
That was awkward.
So I put the idea aside. Would a few-billion-parameter model actually be enough? How well could it understand unfamiliar tools? Would long tasks degrade into endless local corrections? How much money would it really save?
I had no way to answer those questions.
A job description is not evidence that the employee can actually do the job.
7. Jev Made Me Open the Job Description Again
Then I saw Jev.
It hit one of the most important pieces of that shelved architecture idea: an entire class of local decisions inside tool work now had a model specifically designed to handle them.
I do not want to claim that Jev “implemented my architecture.” TypeSafe says it spent two years developing this work behind the scenes. That research and implementation is theirs.
I am explaining my own path because it explains why seeing Jev excited me so much.
Jev is not yet the complete Xiaoheigong described above. It receives state and typed questions, then returns structured decisions and probabilities. Selection, classification, routing, and many decisions that can be converted into typed choices are natural candidates for it; free-form generation still belongs elsewhere.
But that already attacks the part that bothered me most: the frontier model no longer needs to re-enter the loop personally for every small local choice.
And the gap between “answer one decision” and “own the whole tool job” is already being filled by different pieces of the surrounding system. Jev handles structured decisions. Harnesses maintain state and execution loops. Ordinary code owns side effects and hard constraints. Generative models supply open-ended content.
Even more interestingly, this ecosystem is moving quickly. Within days of Jev’s release, function selection, closed-set argument binding, dynamic skill filtering, multi-step execution, retry, and completion decisions were already beginning to appear across different projects.
browser-use/jev-ultrafast is a good example. It observes the current page, generates indexed elements and compatible actions, lets Jev select the operation and target, calls a separate generative model when free text is required, and then executes the action in code. The candidate set changes with each observation; it is not following a site-specific click script.
That made me realize something important:
The worker I could not afford to train may not need to be a single model at all.
Jev can make decisions. A generative model can supply open-ended content. An execution system can do the actual work. Put together, those pieces can gradually take over the same job.
So what I want to see next is no longer just:
How quickly can Jev pick the right button?
I want to know whether we can hand a task to this system, let it handle the normal tool details on its own, recover from local problems, and eventually receive a result we can actually inspect.
Take the document-processing example again. Selecting the right read tool from a candidate list is one part of the job. Preparing input from the material, chaining the next operation, noticing that a field is missing, retrieving more information, and finally checking the delivered artifact is the whole job.
The latter is what I want the frontier model to stop supervising step by step.
I believe this kind of Xiaoheigong will appear. If it can perform these tasks reliably, it could take over a significant amount of Tool Calling work that we currently assign to expensive frontier models.
And I no longer have to bet the entire idea on training one model myself.
Six hundred tools once gave me a headache. But my real goal was never to keep the number of tools permanently small.
I want two thousand tools.
Or more.
The number of available capabilities should increase what an agent can accomplish. It should not proportionally increase how much tool bureaucracy the most expensive model has to manage personally.
Jev has already shown that low-level semantic decisions can be much cheaper than many of us were used to assuming.
But Jev today is not yet the complete Xiaoheigong.
Different parts of the job are already being picked up separately: capability filtering, closed-set argument binding, multi-step loops, and local recovery are moving quickly. Open-ended content, semantic understanding of unfamiliar tools, real execution, and final factual verification still have different owners.
That is exactly what interests me.
The next thing I want is not another 50 milliseconds shaved off Jev’s latency. I want to see when these scattered responsibilities converge into a cheap Worker that can take ownership of the entire tool job.
At that point, perhaps the frontier Agent no longer needs to “use tools” at all.
It only needs to say:
Get this done.
And leave the rest to the Xiaoheigong.
There is, of course, a larger question beyond that.
Today these Workers operate through Browsers, APIs, MCP, Accessibility, and different Harnesses that provide them with observable and executable environments.
If one day we expect an Agent to enter an environment where nobody has already defined its action language for it, that is another article.
