Evalgent
Back to Blog
Voice AI Evaluation

Jev for Tool Calling in AI Voice Agents

Deepesh Jayal
Updated
18 min read
Jev for Tool Calling in AI Voice Agents
On this page

Tool calling is where voice agents get useful. It is also where they break. A hallucinated tool name can drop a call. A wrong argument can charge the wrong card or book the wrong slot.

Jev takes a different path. It launched on September 15, 2026, in early access. TypeSafe AI calls it the first "System One Model". It is not an LLM and does not generate text. TypeSafe's own framing is short: think of Jev as a frontier-intelligence function call.

This guide is hands-on. You will see a real tool-selection request and response. You will see how to fill enumerable arguments, how to handle more than 255 tools, and a hybrid Python loop. We close with a latency budget and the metrics to log. This is how jev tool calling voice agents work in practice, including where Jev does not help.

What tool calling asks of a voice agent

Every tool call is really four decisions in a row.

First, does this turn need a tool at all? A greeting does not. A refund request does.

Second, which tool fits? You may have five tools or five hundred. The agent has to pick one.

Third, is this call safe to run now? Some tools only read data. Others move money or cancel orders. Risky tools need a check.

Fourth, are the arguments valid and correct? The tool name must exist. The types must match the schema. A JSON Schema defines what "valid" means. Correct is a harder bar than valid.

Get any of the four wrong and the call fails. In voice, the failure is loud. The caller hears a stall, a wrong action, or an apology. Our guide on tool calling for voice agents covers the concepts in depth.

DecisionFailure if wrongWhat the caller hears
Is a tool needed?Unneeded lookup, or a missed actionA pause, or "I can't see that"
Which tool?Wrong system touchedA refund when they asked to reschedule
Is it safe now?High-impact action without consent"Your order has been canceled"
Are args right?Valid call, wrong valueA booking on the wrong day

The type-safety argument, in depth

TypeSafe's launch post makes a pointed claim. Hallucination and type safety are intrinsically related. A tool call that names a missing function is a hallucination. It is also a type error. The output left the set of allowed values.

The post then draws a line between settings. A hallucinated tool call is inconvenient in a chat agent. It becomes a deal-breaker inside a system with latency guarantees. It is also a deal-breaker buried several layers deep in a dependency chain. TypeSafe adds that existing models, no matter how smart, still hallucinate and have type errors.

A voice agent is exactly that kind of system. It runs on a latency budget. Its tool calls feed booking engines, payment APIs, and CRMs. One bad value can cascade. The caller is still on the line while it does.

Type safety: a guarantee that a value always belongs to its declared type. See type safety for the general idea. For tool calls, it means the tool name and each typed field can only take allowed values.

How an LLM produces a tool call

An LLM writes a tool call as tokens. Structured-output modes and JSON Schema constraints help a lot. But the model is still generating. It can name a tool that is close to a real one. It can pass `"tomorrow"` where an ISO date belongs. It can add a field the schema never had.

TypeSafe's comparison chart shows non-zero error rates for current LLMs on this kind of task. The rates vary by model. TypeSafe sourced those LLM figures from OpenRouter data and notes they may carry bias. We do not repeat per-model numbers here. The point is the shape: smarter models reduce the rate, they do not reach zero.

How Jev produces a decision

Jev never writes a tool call as free text. You define the possible outputs in advance. A Choice question lists the options. A Noul question returns a probability. A Score question returns a score. Jev fills in a value from that fixed shape.

So the type-error rate is 0% by construction. That is not a benchmark result. It follows from schema matching. The response can only contain an option you listed. A tool named `refund_ordr` cannot come back, because you never defined it.

Type errors in tool calls: existing LLMs have non-zero hallucination and type-error rates that vary by model, while Jev's schema-constrained outputs make type errors impossible by construction

Be precise about what this guarantees. Zero type errors does not mean zero wrong answers. Jev can still pick `issue_refund` when the caller wanted `reschedule_appointment`. The pick is valid. It may not be correct. That gap is what evaluation must measure.

A real tool-selection request

Here is a concrete case. A dental clinic runs a voice agent with four tools. The caller has just said they want to move their cleaning.

You send Jev one request to `POST https://api.typesafe.ai/v1/systemone`. It carries the call state and three questions. Jev answers all three in one call.

{
  "model": "jev-latest",
  "state": "Agent: Thanks for calling Brightside Dental. How can I help?\nCaller: Hi, I have a cleaning on Thursday at 10 but I can't make it. Can I move it to next week?\nContext: caller_verified=true; upcoming_appointments=[{id: A-4471, type: cleaning, time: Thu 10:00}]",
  "questions": {
    "needs_tool": {
      "type": "noul",
      "instructions": "Does the agent need to call a backend tool to handle the caller's latest request?"
    },
    "tool": {
      "type": "choice",
      "instructions": "Pick the single tool that best serves the caller's latest request.",
      "criteria": {
        "lookup_order": "desc: Read-only. Look up an order or appointment status.",
        "reschedule_appointment": "desc: Move an existing appointment to a new time.",
        "issue_refund": "desc: Refund a payment to the caller's card. Moves money.",
        "transfer_to_human": "desc: Hand the call to a live staff member.",
        "none": "desc: No tool is needed. The agent should just reply."
      }
    },
    "risky_action": {
      "type": "noul",
      "instructions": "Would running the chosen tool now be a high-impact or irreversible action without explicit caller confirmation?"
    }
  }
}

A few design notes. The `criteria` keys are your tool names. The values describe each tool in plain words. Including `none` gives Jev an honest way out. The risk question is phrased so "yes" means "hold and confirm".

A realistic response looks like this. The numbers are illustrative.

{
  "answers": {
    "needs_tool": { "type": "noul", "noul": 0.97 },
    "tool": {
      "type": "choice",
      "choice": "reschedule_appointment",
      "confidence": 0.93,
      "probabilities": {
        "lookup_order": 0.03,
        "reschedule_appointment": 0.93,
        "issue_refund": 0.00,
        "transfer_to_human": 0.02,
        "none": 0.02
      }
    },
    "risky_action": { "type": "noul", "noul": 0.18 }
  },
  "usage": { "input_tokens": 312, "output_tokens": 0 }
}

Read it top to bottom. A tool is needed. The tool is `reschedule_appointment`, with high confidence. The action is low risk, since the caller asked for it directly. The agent can proceed to slot selection.

Output tokens are free on Jev, and input is priced at $0.042 per million tokens. At 312 input tokens, this call costs a tiny fraction of a cent. That math is illustrative, but it shows why a check on every turn is affordable.

The same call through the Python SDK looks like this. Check the quickstart for exact argument names.

from typesafe_sdk import Choice, Noul, TypeSafeClient

client = TypeSafeClient()  # reads your API key from the environment

TOOLS = {
    "lookup_order": "desc: Read-only. Look up an order or appointment status.",
    "reschedule_appointment": "desc: Move an existing appointment to a new time.",
    "issue_refund": "desc: Refund a payment to the caller's card. Moves money.",
    "transfer_to_human": "desc: Hand the call to a live staff member.",
    "none": "desc: No tool is needed. The agent should just reply.",
}

result = client.system_one(
    model="jev-latest",
    state=call_state,
    questions={
        "needs_tool": Noul(instructions="Does the agent need a backend tool for the latest request?"),
        "tool": Choice(instructions="Pick the tool that best serves the latest request.", criteria=TOOLS),
        "risky_action": Noul(instructions="Is running the chosen tool now high-impact without explicit confirmation?"),
    },
)

Filling enumerable arguments with Choice and Score

Picking the tool is half the job. The tool still needs arguments. This is where you must be honest about what Jev can and cannot do.

Jev selects and validates. It does not free-generate a value from nothing. It will not invent a street address or write a note. But many voice-agent arguments are not free-form. They come from a short list the system already knows.

Enumerable argument: a tool argument whose valid values are a known, finite list at call time. Examples: the caller's saved cards, the slots you just offered, or a set of reason codes.

Which saved card?

Say the caller has three cards on file. They say "use the one ending in 42, the work card." That is a Choice over three known cards.

{
  "model": "jev-latest",
  "state": "Caller: Put it on my work card, the one ending in 42.\nContext: saved_cards=[card_1: Visa ending 1187 (personal), card_2: Amex ending 0942 (work), card_3: Visa ending 5520 (expired)]",
  "questions": {
    "payment_card": {
      "type": "choice",
      "instructions": "Which saved card did the caller ask to use? Pick unclear if it is ambiguous.",
      "criteria": {
        "card_1": "desc: Visa ending 1187, labeled personal.",
        "card_2": "desc: Amex ending 0942, labeled work.",
        "card_3": "desc: Visa ending 5520, expired.",
        "unclear": "desc: The caller's words do not identify one card."
      }
    }
  }
}

The answer can only be one of four IDs. Your code maps `card_2` to the real token server-side. The card details never need to leave your system as free text. Include `unclear` so the agent can ask again rather than guess.

Which appointment slot?

The agent offered three slots. The caller replied "the Tuesday one, but later if you have it." Here a Choice picks the slot. A Score can rate how well each offer matches.

{
  "questions": {
    "slot": {
      "type": "choice",
      "instructions": "Which offered slot did the caller accept?",
      "criteria": {
        "slot_tue_0900": "desc: Tuesday 9:00 AM",
        "slot_tue_1500": "desc: Tuesday 3:00 PM",
        "slot_wed_1100": "desc: Wednesday 11:00 AM",
        "none_accepted": "desc: The caller has not accepted any offered slot."
      }
    }
  }
}

"Later on Tuesday" points to `slot_tue_1500`. If confidence is low, the agent confirms: "Tuesday at 3, is that right?"

What Jev cannot fill

Some arguments have no list. A delivery note, a new email address, or a spelled-out name are open values. For those, use an LLM or a constrained extraction step. Then use Jev to check the result against what the caller said.

ArgumentEnumerable?Fill with
Tool nameYesJev Choice
Saved card IDYes, at call timeJev Choice
Offered slotYes, at call timeJev Choice
Refund reason codeYesJev Choice
Urgency or priorityOrdinalJev Score
Refund amountOnly if tied to a line itemChoice over line items, else extraction
Free-text noteNoLLM or constrained extraction
New email addressNoExtraction plus confirm-back

For argument accuracy in depth, see tool argument accuracy and function schema validation testing.

The 255-option limit and the two-stage approach

A Choice question supports up to 255 options. Most voice agents fit easily. A clinic might expose ten tools. A contact center might expose forty.

Some systems are bigger. A retailer might map each intent to a catalog action. An enterprise agent might wrap hundreds of internal APIs. Past 255, TypeSafe recommends a two-stage system. First, score each candidate independently. Then run an explicit choice over the best few.

Stage one uses many Score questions in one call. Each rates one candidate against the state. Stage two sends a Choice over the top candidates, plus `none`.

def select_from_large_catalog(client, state, catalog, top_k=8):
    # Stage 1: score every candidate independently (batch if the catalog is large)
    scores = client.system_one(
        model="jev-latest",
        state=state,
        questions={
            name: Score(instructions=f"How well does this action fit the caller's request? {desc}")
            for name, desc in catalog.items()
        },
    )
    ranked = sorted(catalog, key=lambda n: scores.answers[n].score, reverse=True)[:top_k]

    # Stage 2: explicit choice over the shortlist
    shortlist = {n: catalog[n] for n in ranked}
    shortlist["none"] = "desc: None of these actions fit."
    final = client.system_one(
        model="jev-latest",
        state=state,
        questions={"tool": Choice(instructions="Pick the best action.", criteria=shortlist)},
    )
    return final.answers["tool"]

A practical alternative is a category hop. First choose a domain, such as billing or scheduling. Then choose a tool inside it. Both stages stay well under 255. Our post on Jev model routing uses the same layering for routing.

Whichever you pick, log both stages. A miss in stage one means the right tool never reached the shortlist. That failure looks very different from a wrong final pick.

The hybrid pattern: LLM proposes, Jev validates

Jev does not replace the LLM. The strongest pattern pairs them. The LLM proposes a tool call with arguments. Jev validates the proposal before anything runs.

Jev asks three questions about the proposal. Is a tool needed at all? Is this the right tool? Are the arguments consistent with what the caller confirmed? A fourth question flags risk. Then your code decides: execute, confirm with the caller, or reject.

A validated tool call in a voice agent: the LLM proposes a tool call, Jev checks whether a tool is needed, whether it is the right tool, and whether it is risky, then the call executes, asks for confirmation or is rejected

Here is the loop in Python. It calls the REST endpoint directly, so the request shape matches the one above. Confirm the auth header in the TypeSafe docs.

import json, os, requests

JEV_URL = "https://api.typesafe.ai/v1/systemone"
HEADERS = {"Authorization": f"Bearer {os.environ['TYPESAFE_API_KEY']}"}
RISKY_TOOLS = {"issue_refund", "cancel_order", "transfer_to_human"}

def validate_proposal(state: str, proposal: dict, tools: dict) -> dict:
    proposed = json.dumps(proposal)
    body = {
        "model": "jev-latest",
        "state": f"{state}\nProposed tool call: {proposed}",
        "questions": {
            "needs_tool": {"type": "noul",
                "instructions": "Does the caller's latest request require a backend tool?"},
            "tool": {"type": "choice",
                "instructions": "Which tool best serves the caller's latest request?",
                "criteria": tools},
            "args_consistent": {"type": "noul",
                "instructions": "Do the proposed arguments match what the caller said and confirmed?"},
            "risky_action": {"type": "noul",
                "instructions": "Is running this call now high-impact without explicit confirmation?"},
        },
    }
    resp = requests.post(JEV_URL, headers=HEADERS, json=body, timeout=1.0)
    resp.raise_for_status()
    return resp.json()["answers"]

def decide(proposal: dict, a: dict) -> str:
    if a["needs_tool"]["noul"] < 0.5:
        return "reject"                      # unnecessary call
    if a["tool"]["choice"] != proposal["name"]:
        return "reject" if a["tool"]["confidence"] >= 0.85 else "confirm"
    if a["args_consistent"]["noul"] < 0.80:
        return "confirm"                     # read the values back to the caller
    if a["risky_action"]["noul"] > 0.30 or proposal["name"] in RISKY_TOOLS:
        return "confirm"
    return "execute"

The thresholds are illustrative. Tune them on your own traffic. Note the timeout of one second. If Jev does not answer in time, fail safe: confirm with the caller rather than execute.

The actions map to three spoken outcomes:

  • Execute: run the tool and speak the result.
  • Confirm: read the key values back. "I'll refund $40 to the Amex ending 0942. Shall I go ahead?"
  • Reject: drop the proposal and let the LLM reply or re-plan. Log the disagreement.

The LangChain AutoModeMiddleware shortcut

If you build on LangChain, you can skip much of the wiring. LangChain's `AutoModeMiddleware` uses Jev to check tool calls for risky decisions. It blocks them before execution. The pattern is described in LangChain's harness post.

from langchain.agents import create_agent
from langchain_typesafe.experimental.middleware import AutoModeMiddleware

guardrail = AutoModeMiddleware(tools=[lookup_order, reschedule_appointment, issue_refund])
agent = create_agent("openai:gpt-5.6-luna", middleware=[guardrail])

The module path includes `experimental`. Treat the API as subject to change. The middleware covers the risk gate. You still own the right-tool and argument checks, plus the evaluation. For jailbreak-style risks, see Jev guardrails.

When to flip the order

A second pattern starts with Jev. Jev selects the tool with a Choice question. Enumerable arguments come from more Choice questions. An LLM fills only the free-form fields. This path skips the LLM entirely for simple turns. It suits agents where most turns are lookups and reschedules.

LLM tool calls versus Jev: the decision table

Each tool-calling decision has an LLM approach and a Jev approach. The table maps them side by side.

Tool-calling decisionLLM approachJev approach
Is a tool needed?Infers from context; may over-call or skipNoul question; calibrated probability
Which tool to callGenerates the name; can hallucinate oneChoice over up to 255 defined tools
Is this call risky?Reasons inline; can be inconsistentNoul gate or AutoModeMiddleware
Enumerable argumentsGenerates the value; can mistypeChoice or Score over known values
Free-form argumentsStrong fitNot a fit; validate after the LLM
Type errorsNon-zero, varies by model0% by construction
Speed per decisionTypeSafe lists 3 to 329s on its tasks70 to 500ms
CostStandard token pricingInput $0.042 per MTok; output free

The pattern is clear. Use the LLM for open-ended language. Use Jev for fast, typed decisions.

The latency budget for a voice turn

Text chat forgives a slow tool step. Voice does not. A caller notices a gap of a second or two. Speech-to-text, the decision, the tool, and speech-out all share that window. See latency (engineering)) for the general idea.

Here is an illustrative budget for one turn. Your stack will differ. The Jev range is TypeSafe's published 70 to 500ms. The other rows are placeholder figures for a typical cascade.

StageWithout validationWith Jev validation
Speech-to-text final200ms200ms
LLM proposes tool call400ms400ms
Jev validation (4 questions, one call)0ms70 to 500ms
Tool execution300ms300ms
Text-to-speech first audio200ms200ms
Total to first audioabout 1.1sabout 1.2 to 1.6s

Two tactics shrink the added cost. First, batch all questions in one call, as shown. Second, start a filler phrase while Jev runs, such as "Let me check that." Many agents already speak a filler during tool execution.

You can also skip validation for read-only tools. A `lookup_order` call is cheap to get wrong. A refund is not. Spend the budget where the risk lives.

Compare that with a second LLM pass as the validator. TypeSafe lists LLMs at 3 to 329 seconds on its comparison tasks. Even a fast model would add a full generation step. Jev keeps the check inside the turn.

What to log and evaluate

Jev gives you a typed decision and a confidence number. It does not tell you the decision was right. That is a separate question, and it decides production quality.

Log one record per tool decision. Keep it structured.

{
  "call_id": "c-20260928-0193",
  "turn": 4,
  "state_hash": "9f2c1e",
  "llm_proposal": { "name": "issue_refund", "args": { "card": "card_2", "amount": 40.0 } },
  "jev": {
    "needs_tool": 0.96,
    "tool": { "choice": "issue_refund", "confidence": 0.91 },
    "args_consistent": 0.88,
    "risky_action": 0.74
  },
  "action": "confirm",
  "caller_confirmed": true,
  "tool_result": { "status": 200, "refund_id": "r-5531" },
  "latency_ms": { "jev": 142, "tool": 310 }
}

From those records, track these metrics per tool, not as one blended average:

MetricDefinitionWhy it matters
Wrong-tool rateExecuted tool differs from the correct toolCore tool call accuracy
Unnecessary-call rateA tool ran when none was neededWastes latency; can leak data
Missed-call rateNo tool ran when one was neededThe caller's task silently fails
Blocked-risky rateRisky calls held or rejectedChecks the gate is doing work
False-block rateSafe calls held needlesslyAdds friction and hang-ups
Argument error rateRight tool, wrong valueValid type, wrong outcome
Silent failure rateTool returned success but did nothing usefulSee silent tool failures
Calibration gapStated confidence vs observed accuracyTells you if thresholds hold

The calibration gap deserves attention. TypeSafe reports calibrated confidence. Calibrated is not the same as correct on your data. If Jev says 0.9 on your traffic, is it right 90% of the time? Bucket decisions by confidence and check. If a bucket drifts, move the threshold.

Where Evalgent fits

This is the work Evalgent does. Evalgent is an independent, third-party evaluator for AI voice agents. We do not build your agent or sell you a model. We measure whether your tool calls were right, on your own calls.

We label the correct tool and arguments for each turn. We compare them with what the agent and Jev did. We report wrong-tool, unnecessary-call, blocked-risky, and silent-failure rates per tool. We also test whether Jev's confidence stays calibrated on your traffic.

Independent measurement is the point. A vendor grading its own tool calls is not a check. See why in our post on independent voice AI evaluation. Our broader work on voice agent evaluation, voice agent testing, and testing versus evaluation covers the rest. For the model itself, start with Jev for voice agents.

How to add Jev to a voice agent's tool-calling path

Follow these steps to put Jev on the tool path of a live voice agent.

1. List your tools as Choice criteria. Use each tool name as a key and a short description as the value. Add `none`.

2. Check your count. Under 255 options, use one Choice. Above it, use the two-stage score-then-choose approach.

3. Capture the call state. Pass the running transcript plus structured context. Jev works on text and state, not raw audio.

4. Ask the tool-need question. Use a Noul question. Skip the tool path on a confident no.

5. Select or validate the tool. Use a Choice question, or validate the LLM's proposal against it.

6. Fill enumerable arguments with Choice or Score. Saved cards, offered slots, and reason codes fit. Add an `unclear` option.

7. Fill free-form arguments with an LLM or extraction. Then ask Jev if they match what the caller said.

8. Gate risky calls. Ask a Noul risk question, or use `AutoModeMiddleware` on LangChain.

9. Set thresholds and a fail-safe. Pick bars per tool. On timeout or low confidence, confirm rather than execute.

10. Batch the questions. Send all questions for a turn in one call to protect the latency budget.

11. Log every decision. Store the state, proposal, Jev answers, action, and tool result.

12. Evaluate independently. Score tool and argument accuracy per tool on real calls, and recheck calibration.

Honest limits of Jev for tool calling

Jev is powerful, but it is not magic. Be clear about the edges.

Jev selects and validates. It does not write free-form arguments from nothing. For a new string value, you still need an LLM or a constrained extraction step. The hybrid pattern exists for this reason.

Zero type errors is not zero errors. Jev can pick a valid but wrong tool. It can pick the wrong card from a valid list. Only labeled evaluation catches that.

Jev works on the transcript and structured state. It does not read raw audio. A weak transcript can mislead a good decision. Speech-to-text quality still shapes the input.

Calibrated is not guaranteed. Calibration is a statistical property, not a promise on any single call. That is why you measure the gate on your own data.

Jev is in early access as of September 2026. Treat it as new. Pilot it, measure it, and keep a fallback path. For a broader comparison, see Jev vs LLM for voice agents and the wider Jev use cases. The routing side is covered in Jev routing and escalation.

Jev can't abstain: always include an escape option

Jev always returns one of the options you define. It has no built-in "I don't know." When a call transcript holds no evidence for any option, such as a two-word turn, a dropped call or a caller talking about something else, Jev still picks the least-wrong option, and that label looks just like a confident answer. TypeSafe's own Choice docs recommend adding an "other" or "none of the above" option when the list may not cover every input.

For tool calls the safe default matters most. A tool gate needs an option like `ask_caller_to_confirm` or `missing_required_argument`, so a turn that lacks the order number does not get forced into `call_lookup_order` with an invented argument.

Four rules keep this from hurting you on live calls:

  • Add an explicit escape option such as `not_enough_information`, `not_applicable` or `none_of_the_above` to every Choice question where evidence can be missing. Describe it as concretely as the real options, because Jev reads only the descriptions, not your option keys.
  • Ask whether the evidence exists first. A Noul like "does the caller state a reason for calling?" before the Choice question separates "no evidence" from "evidence for option B".
  • Check the distribution, not just the label. In one independent edge-case test, a forced choice with no valid option still returned a pick at 0.52 probability but only 0.04 confidence (jev-exploration). The numbers flagged the problem; the label did not. Set your human-review cutoff from your own labeled calls, because an independent study on data unlike Jev's training found its confidence can run high (jev-ood-calibration).
  • Track the escape-option rate. If it climbs, your transcripts, STT or option set have drifted away from what callers actually say.

Frequently asked questions

Can Jev hallucinate a tool name in a voice agent?

No. Jev picks a tool with a Choice question over options you defined in advance, up to 255. The returned name is always one of those options. Type errors are 0% by construction, through schema matching, not by benchmark. Jev can still pick a valid but wrong tool, so you must measure correctness separately.

How is Jev different from an LLM for tool calls?

An LLM generates the tool call as tokens. Current LLMs show non-zero hallucination and type-error rates that vary by model. Jev does not generate text. It returns typed, calibrated answers to Choice, Score, and Noul questions whose shapes you set. Use the LLM for free-form language and Jev for fast, typed decisions.

How does Jev decide whether a tool is needed?

You ask a Noul question, such as "does the latest request need a backend tool?" Jev returns a probability. Above your threshold, the agent enters the tool path. Below it, the agent just replies. Logging this answer lets you track unnecessary calls and missed calls per tool.

Can Jev block a risky tool call before it runs?

Yes. Ask a Noul risk question about the proposed call, then hold or confirm above a threshold. On LangChain, AutoModeMiddleware uses Jev to check tool calls for risky decisions and block them before execution. Pair either approach with a confirm-back step, so the caller approves refunds or cancellations.

How fast is Jev for tool-calling decisions?

TypeSafe reports Jev latency of 70 to 500ms per call. TypeSafe lists LLMs at 3 to 329 seconds on its comparison tasks. Jev also answers many questions in one call. Tool need, tool choice, argument consistency, and risk can return together inside a single voice turn.

Does Jev replace the LLM in the tool-calling path?

Not fully. Jev decides whether a tool is needed, which tool, and whether a call is risky. It can fill enumerable arguments like a saved card or an offered slot. It does not generate free-form values. The common pattern is hybrid: the LLM proposes, and Jev validates before execution.

What does structured tool calls with Jev mean?

It means every output fits a shape you defined before the call. A Choice returns one of your listed options. A Noul returns a probability. A Score returns a score. There is no fragile parsing step. A tool name or enumerable value outside your list cannot appear in the response.

How do you evaluate Jev tool calls?

Log each decision with state, proposal, Jev answers, action, and tool result. Then label the correct tool and arguments. Evalgent measures wrong-tool, unnecessary-call, blocked-risky, argument-error, and silent-failure rates per tool. We also check whether Jev's confidence stays calibrated on your own live traffic.

The bottom line

Jev removes hallucinated tool names and type errors by construction and adds its checks in 70 to 500ms. It still needs an LLM for free-form values and an independent evaluator to prove the calls were right.

Evalgent measures whether your Jev-driven tool calls actually served callers. Book a demo to audit tool selection, argument accuracy, and risk gating on your own calls.

Related Articles