Top
Best
New

Posted by bashbjorn 14 hours ago

Jev in 25 Lines of Python(www.nobodywho.ai)
590 points | 190 comments
sigmoid10 13 hours ago|
Going directly for the logprobs is always icky when you use a chat model as base, because they are trained to write prose as output. So your "choice" tokens and thus their probabilities might get diluted in whatever else it wanted to say. If you have to do it in the same way as this post, at least add clear system instructions and a carefully worded beginning to the assistant output section of the prompt to lower the chances of it wandering off immediately.

I've found that using structured outputs solves this problem much better. Instead of letting a model generate only "A", "B" or "C" and looking at the probs, have it directly generate "Legitimate", "Spam" or "Phishing" or any other pre-defined option from a set of multi-token sequences. Behind the scenes it boils down to something quite similar, but you're not running into the risk that the model actually wanted to say "A phishing attempt seems likely, so answer (C) is correct.", which would lead "A" to have the highest probability in the first token. You can even use a reasoning budget this way either via inherent reasoning or a free-form part preceding the remaining output structure. You can also have it assign probabilities (either in words or numbers) using more complex output structures, but I would not rely on them much more than the token logprobs (they can still be quite good though).

dTal 12 hours ago||
The whole point is the quantified output. If you just ask an LLM to type out its confidence "manually", it'll make up some nonsense. The logprob numbers are more reliable.

I got this technique to work extremely reliably last year. However there were a bunch of caveats: 1) Firstly, you must institute a check that the multiple choice tokens dominate the output distribution. They should sum to 95% or more, ideally 99%, or the LLM is not following instructions properly. This is also the problem with constrained decoding - if the LLM really doesn't want to output a valid answer, the one you extract will not be high quality. 2) You need to ask it multiple times, permuting which option corresponds to which letter, and average the results. LLMs are surprisingly biased towards picking "A", especially if they're otherwise not sure. 3) For the same reason, performance improves if you frame the prompt as if it were the middle of a quiz. "Question 1" carries baggage that "Question 12" doesn't. 4) You must be exceedingly careful with tokenization.

But when all was said and done, I got a general purpose A/B classifier that gave high resolution quantitative output for the cost of a couple dozen tokens ingested and a couple inference passes.

sigmoid10 10 hours ago|||
>The whole point is the quantified output. If you just ask an LLM to type out its confidence "manually", it'll make up some nonsense. The logprob numbers are more reliable.

The whole point of my argument is that neither is good, but from a technical perspective logprobs is probably the worst unless you train a model on specific outputs. In which case you'd throw out the generality again, so when I think about it more, it's actually the worst overall. In my experiments, having the model simply assign "high" or "low" probability in a structured output generally performs best. You can try numbers, but you will never get anything close to what you could expect from traditional ML. And most certainly not from logprobs.

nostrebored 3 hours ago||
Yes, for vision classifiers we have in prod, I've seen a huge difference between A, B, C, 1, 2, 3 style answers and emitting a string. Even from just base model behavior pre-sft/rl. It was one of those obvious in retrospect moments.
TeMPOraL 10 hours ago||||
> LLMs are surprisingly biased towards picking "A"

GP pointed at a causal explanation for this: almost every sentence in English that's a statement will start with "A" or "An", so "biased towards picking ''A''" will include most attempts at saying anything long-form for any reason.

dTal 10 hours ago|||
I don't think that's the source of the bias I saw. I am confident that my prompting strategy eliminated attempts to generate long form content - specifically, I took care to wrap (A) and (B) in parentheses, so the completion looked like "Answer: (" - with this scheme an LLM is very unlikely to want to write "Answer: (A sentence goes here...". I know this, quantitatively, because I reliably got 99% distribution coverage with only A+B - that is, no inclination to write "The" or other common sentence starter. That's the beauty of the scheme - you can pretty directly and quantitatively validate how well the LLM understood the instructions. You expect it to only output A or B - so does it?

Meanwhile, the bias could be as much as 70% in favor of A in ambiguous cases - a signal completely drowning the <1% inclination to violate the format.

podocarp 9 hours ago||||
What about switching to numbers or just some random Unicode character like smiley faces. Could be interesting if someone tested what LLMs like to say on a "cold start" lol.
LoganDark 9 hours ago|||
I would also note that models aren't people and don't think like people, so it's also possible that (at least for autoregressive ones) it could just be more likely to say "A" than "B" at that point, not necessarily because of "want" or "reason" but simply because that's what it was trained to do (such as in English writing).
boredumb 8 hours ago||||
> LLMs are surprisingly biased towards picking "A", especially if they're otherwise not sure.

Not nearly as sophisticated as myself who would mutter "When in doubt - Charlie out" before marking C.

dragonwriter 7 hours ago|||
Sure, it was high resolution (precise), how was accuracy compared to Jev (or existing open source implementations of the same concept, like laya)?

Also, Jev/laya do it in one forward pass, for multiple questions about the same state, rather than multiple passes for one question about that state. Well, for the usual multilingual configuration, two forward passes through different small models for laya, but that's because one is the router which chooses which model should do the real work, but still.

dTal 3 hours ago||
I never claimed that what I did was comparable to these modern options - I didn't validate it in more than an ad-hoc way anyway, and it used an off-the-shelf LLM rather than something specially trained. I didn't consider it worth releasing or making a big fuss of.

I contribute my experience here only because I've seen a lot of chatter lately about doing exactly this sort of thing, and I thought I'd share how I made it work for me. There are a lot of ways it can silently fail and give bad numbers if you aren't careful, and I wouldn't want people to think it doesn't work just because they used a vibe coded GitHub project from the last 48 hours that doesn't take these things into account.

ainch 13 hours ago|||
In my experience as well using logprobs to try to quantify uncertainty, LLMs are a poor fit. Neural nets in general struggle with 'calibration' --- ie. if a prediction is truly 50/50, neural nets are often prone to predicting overconfidently [0].

I ran some tests using GPT-4 to do some basic classification a couple years ago. On ambiguous options which had to be escalated to a human, the LLM would regularly output something like a 99.8% probability, compared to 99.99% for a correct answer.

0: https://arxiv.org/pdf/1706.04599

nautilus50 13 hours ago|||
+1, llama.cpp has a --grammar parameter which you can pass a BNF style grammar file to constrain generation. It can be used in Python llama.cpp wrapper

https://til.simonwillison.net/llms/llama-cpp-python-grammars

porridgeraisin 12 hours ago||
Yes. But even then, the probabilities are not calibrated. In jev/laya, they are (well, relatively anyways).
foo12bar 10 hours ago|||
If we're talking about running it locally, what about passing a partial response as part of the input?

Prompt part: "What is better, toast or bread?"

Incomplete answer part: "The answer to this question is "

and then have the LLM finish the answer. I did this with subtitle translation using llama.cpp (with Python) and had great success. Just past 5 already translated subtitles as the incomplete answer, and the LLM infallibly just continues to translate. No markdown, and usually no talkback if the subtitles contain nasty subjects like bioweapons or nuclear stuff. It just works.

_davide_ 13 hours ago|||
Agreed, it's a real issue, but it can probably be vastly reduced by having the schema in the system prompt and by giving the model an expectation of a fixed value: no decent modern would pick a prose ligament over a provided value.

To completely squash the issue, a few cheap LoRa iterations will do the trick just fine.

wongarsu 13 hours ago||
Sure, you can fix that in a couple lines. Then a couple more lines for evaluating multiple questions on the same answer in parallel. Then a couple more lines for the confidence score (which is trivial to compute from all we have, but missing regardless). Then a harness to fine-tune an existing model to perform better on this specific task, and a collection of training data to use for that

I think we can all agree that Jev is not rocket science. It's a good idea executed well, with marketing that might have been a tad too bold

porridgeraisin 12 hours ago||
The confidence score is not trivial to compute. That is the whole point of the model. Even if you are using a proper scoring function such as NLL, it is not enough to ensure calibration in deep nets. So you have to do good post training to ensure it. These are all known techniques, but they are far from trivial, especially on large scale datasets.
wongarsu 12 hours ago||
Their docs at https://docs.typesafe.ai/confidence state "confidence is a statistic computed from the probability distribution the answer already gives you. TypeSafe computes it for you"

And further down "TypeSafe computes confidence from how the probability is spread across the options. All of it on one option gives 1.0; the more evenly it spreads, the lower the confidence. This demo uses (3 × largest probability − 1) / 2 to approximate confidence for three options."

So while we don't know the exact formula they use, it is just a function over the probabilities

I am open to the argument that this does not work well if you just plug in a qwen model instead of a model that is trained to output more statistically useful token distributions

kantahayashi 8 hours ago|||
For N options, it's (N x Max Probability - 1) / (N - 1). It's verified in this article: https://bernoulli.app/articles/is-jev-confident

It means confidence is just a converted max probability and not an independent signal.

porridgeraisin 12 hours ago|||
> I am open to the argument

we agree then, that is the entirety of my argument. Getting a deep net especially one that is anywhere near even SLM size to be calibrated is tough, especially across domains. They claim calibration across a variety of datasets which is interesting.

_flux 13 hours ago|||
Seems like all normal english words could risk the same, so would using short but random strings be even better?

Actually to me it sounds it could be benchmarked if this kind of effect exists in the first place.

sigmoid10 13 hours ago||
Best option would be reasoning + clear system instructions + constrained output. That is, if you have to use a chat model. Which works well enough to be sure, but hey I haven't tried raising millions of dollars when I did that 3 years ago. But perhaps I was the stupid one.
ActivePattern 9 hours ago|||
"Reply with just the letter A, B, or C."

There, I fixed your problem.

xigoi 1 hour ago||
You’re still hoping that the model will respect your with to reply with a single letter. With Jev, the model doesn’t even have a concept of replying with something else.
dchftcs 12 hours ago|||
A fundamental benefit of LLMs over Jev is that you can use test-time compute to improve the accuracy. Jev might eventually evolve to use test-time compute, but the formulation seems to more elusive to me than for LLMs.
Onavo 4 hours ago|||
Isn't that effectively the same as the blog post? You are just pushing the token filter to the sampling step.
petesergeant 12 hours ago||
That's the approach that daseinlabs/open-jev takes, in contrast to the above, which is what TheoLeeCJ/openjev and ekzhang/openjev-sglang do

https://sgnt.ai/p/jev/

antirez 12 hours ago||
Because of masked attention in LLMs, if you put the options before the body (the email to analyze), the transformer already knows what it needs to look for, and can use more tokens to create state to address that specific task (BERT has no mask in the attention, so tokens attend also to next tokens). You could also do a few examples in the system prompt to improve calibration.

Another trick that works is to repeat the question two times: "I'm repeating the task and labels for clarity: ..."

__jf__ 6 hours ago||
Wow! TIL! I've been running a for loop around the two ordering variations to catch the winner of each turn and the difference is quite noticeable. In the options-after-body case in 47 of 100 attempts it classifies as phishing, whereas in the options-before-body case it classifies clearly as rickroll (94 out of 100 attempts)

Payroll sends you an email with a link to a Youtube video that plays a song.

Options after body:

    Average probabilities:
    Rickroll   0.5158 ( 51 wins)
    Phishing   0.4561 ( 47 wins)
    Spam       0.0281 (  2 wins)
    Joke       0.0000 (  0 wins)
    Legitimate 0.0000 (  0 wins)

Options before body:

    Average probabilities:
    Rickroll   0.9293 ( 94 wins)
    Joke       0.0549 (  5 wins)
    Phishing   0.0140 (  1 wins)
    Spam       0.0018 (  0 wins)
    Legitimate 0.0000 (  0 wins)
This was Gemma4-26B-A4B-NVFP4 by the way.

EDIT

Gemma4-12B-it-NVFP4 seems way less sensitive to option/body ordering:

Options after body:

    Average probabilities:
    Rickroll   0.9867 ( 99 wins)
    Phishing   0.0133 (  1 wins)
    Joke       0.0000 (  0 wins)
    Spam       0.0000 (  0 wins)
    Legitimate 0.0000 (  0 wins)
Options before body:

    Average probabilities:
    Rickroll   0.9401 ( 93 wins)
    Phishing   0.0336 (  3 wins)
    Spam       0.0250 (  4 wins)
    Joke       0.0010 (  0 wins)
    Legitimate 0.0002 (  0 wins)
Anyway, this for-looping stuff doing 100 calls to even a local VLLM API takes around 5 seconds in total, so this isn't anywhere close to sub-second Jev territory.
rcarmo 55 minutes ago||
Yah, that's what I use: https://rcarmo.github.io/projects/go-system-one uses Gemma, and that's partly why. Seems less prone to getting distracted with ordering.
jeff_ciesielski 22 minutes ago|||
This works very very well :).

https://github.com/Mushroom-Systems/lichen

ThePhysicist 11 hours ago|||
What a time to be alive, repeating questions to a model twice to increase accuracy.
SeriousM 11 hours ago|||
Repitation always helped make your point stronger. Repitation always helped make your point stronger.
lgas 8 hours ago|||
I guess repeating a mistake helps make it more obvious too.
peterleiser 8 hours ago||
With enough repitation you might get repitition.
rzzzt 1 hour ago|||
Use repetition to avoid trepidation if you have low reputation.
tanseydavid 7 hours ago|||
Or even repetition, repetition.
linuxrebe1 3 hours ago||
Mr Smith agrees.
0x20cowboy 2 hours ago||||
Repetition Legitimizes
mlmonkey 6 hours ago|||
You can say that again!
busfahrer 8 hours ago||||
I use ROT13 twice for extra security
starik36 5 hours ago||||
I had an issue with accuracy a bit ago. So I repeated a couple of things without understanding why and it solved the problem.

I am glad there is an actual reason.

techterrier 11 hours ago|||
fuck this timeline
xyzsparetimexyz 10 hours ago|||
I feel you
_superposition_ 10 hours ago|||
Bro this timeline makes no sense. Repeating instruction to a data center of geniuses.
UpsideDownRide 10 hours ago||
Djinniuses
stellalo 3 hours ago|||
Prompt Repetition Improves Non-Reasoning LLMs: https://arxiv.org/abs/2512.14982
iamflimflam1 30 minutes ago||
The number of - “I did/invented Jev last year”, or, “here’s a version of Jev I vibed up last night” is getting a bit ridiculous.

Especially ridiculous is how the hacker news crowd seems to be taking these at face value…

There was one the other day with a compelling demo. But when you looked closely at it, it was feeding in the options with the word “best” on the option to pick and a fine tuned model designed to recognise that word…

SylonZero 36 minutes ago||
Haha - I did enjoy this read! And there is a point to the whole marketing-dresses-up-stuff that is certainly true. I think it's worth pointing out the other HN story earlier https://news.ycombinator.com/item?id=49765348 about an open-weight model called Laya.

P.S. I am evaluating that model for a production use case where I would have used Jev

visarga 2 hours ago||
I also built one, but mine uses embeddings. It classifies concepts defined by a collection of positive and negative examples. The classifier model is trained in <1 second using ridge regression. The model itself is exactly the same shape as the embedding, so it works as a concept embedding. Since I already have a dataset, I can use it to do conformal prediction in order to calibrate confidence scores. Jev, on the other hand, has a generic model, not trained on in-domain examples, so its confidence scores are uncalibrated for any non-generic task.

So you might ask: how do I obtain the training examples? Just collect samples and use a coding agent to classify them as match or no match. From time to time you can add more examples to the dataset to have your concept adapt to changes in input distribution. It's all automated, but it only uses LLMs to train concept vectors, after that it works like a regular embedding model with a calibrated classifier on top. It's also 20-30x faster than Jev, free, and runs on CPU.

An illustration of how it defines a concept as opposed to simple cosine similarity: https://github.com/horiacristescu/semlabel/raw/main/images/c...

philipbk 8 hours ago||
> "25 lines of python" > "import Solution" ok
chpatrick 4 hours ago||
The 25 lines is the only thing that makes Jev different compared to Solution apparently.
jdiaz97 8 hours ago||
>we didn't call an api

>calls an api

ok

betenoire 5 hours ago||
not really fair to call downloading a model once to run locally the same thing as calling an api which happens for every question in jev
xigoi 1 hour ago|||
This assumes that you have a powerful computer that can run an LLM. Most people will have to call an LLM API every time, which is three orders of magnitude more expensive than Jev.
no-name-here 13 hours ago||
Beyond the missing latency and compute comparisons that Heaney commenter mentioned, also nothing about its error rate compared to Jev (nor if it even always outputs in a format the app can parse, not sure how solved that is).

But then at the end it says it’s parody. Maybe HN title should say it’s a joke.

est 13 hours ago||
latency and compute comparisons highly depends on your local setup.

you can swith to a better model for lower error rate.

ricardobeat 13 hours ago||
Which massively slows down the output. Doing this with Qwen 9B already takes you into seconds per answer territory, and Jev is supposedly frontier level intelligence.
baobabKoodaa 11 hours ago|||
Yeah it says it's a parody, but then in the same sentence it refers to the other "OpenJev" implementations, which are basically the same thing with marginally more effort. And it doesn't imply that those things are parodies too (and I don't think they are parodies).

Somehow the HN crowd has a bunch of "professionals" who don't care about error rates and think that a Qwen model running on a potato is frontier intelligence.

alxmths 10 hours ago||
1) get local model to run on the electrical output of a potato 2) accept Nobel price
TeMPOraL 10 hours ago||
You didn't specify time frames; 1) is doable for a very short time, with a lot of coulomb caching in between the computer and the potato :).

(For more realistic solution, surely someone must be working on optronics - these models just beg to have their weights cleverly etched into stacked sheets of plastic, so they can do inference for free on a beam of light.)

zer00eyz 8 hours ago||
> nothing about its...

Non deterministic systems have furthered the "brain rot" in our industry.

Lots of people were happy to ignore the code in their "supply chain" before LLM's - but suddenly not reading the LLM's output is a problem. I get they are different but we're in the same realm.

The lack of real data on performance of what ever application that one is trying to pitch is getting appalling. It's a lot of "trust me bro" this works better hand waving. And it's getting gross.

And how do we even measure nondeterministic systems? Because if I told you that Anthropic was spending millions of dollars having 1000's of agents "pre solve" benchmarks to build into their next version of the system you would scream they were cheating. Every one is focused on the "hacking" in the hugging face incident and no one is looking why they were even playing with those benchmarks in the first place.

"Trust me Bro"...

beamy 27 minutes ago||
> We didn't train a model with Reinforcement Learning for Calibrated Decisions (RLCD) to calibrate the decisions and probabilities

But aren’t calibrated predictions one of the defining features?

xigoi 41 minutes ago||
This is like saying that cars are useless because you can achieve the same thing by removing the cannon from a tank.
rfw300 12 minutes ago|
I think it's like saying Jev has been trumpeting the invention of a spinning transportation system when we've known such things as a "wheel" for thousands of years. Classification models have been with us far longer than autoregressive LLMs.
rcarmo 57 minutes ago|
Very nice as a conceptual thing, but there's a bit more to it. I've bolted Gemma 4 onto a custom pipeline for that (https://rcarmo.github.io/projects/go-system-one/) and it's OK-ish (a bit slow on my puny 3060, but I can use it to prototype a bunch of things locally until the Jev mania settles and we have better models).
More comments...