Integration
Jev with LlamaIndex
No package exists for this either — but unlike a chain framework, a retrieval framework has an obvious seam for a decision model. Retrieval returns candidates; something has to judge them. That judgement is exactly what Jev sells.
The seam is the postprocessor
A retrieval pipeline is retrieve, then rerank, then synthesise. The middle step is a filter over candidates you already have — a bounded set, one judgement each, no text to produce. That is a decision model's home ground, and it is the one place in a RAG stack where Jev is not a substitute for something but a better fit than what is usually there.
TypeSafe evidently agrees: its own documentation ships a cookbook on classifying RAG passages, and recommends a Noul as the relevance filter when you cannot narrow the state any other way.
Embeddings
Cheap, fast, and answers only one question: what looks similar to this?
Cross-encoder
Stronger ordering among near-duplicates. An opaque score, and another model to host.
Jev
Ask the actual question — does this passage answer it? — and get a calibrated probability you can threshold.
A node postprocessor
Two questions per node, asked in one call each: is it relevant at all, and how completely does it answer the question. The first is a filter, the second is the ordering.
from llama_index.core.postprocessor.types import BaseNodePostprocessor
from llama_index.core.schema import NodeWithScore, QueryBundle
from typesafe_sdk import Noul, Score, TypeSafeClient
class JevRerank(BaseNodePostprocessor):
"""Rerank retrieved nodes by asking about the query, not about distance."""
top_n: int = 5
min_relevance: float = 0.5
def _postprocess_nodes(self, nodes, query_bundle: QueryBundle | None = None):
if not query_bundle:
return nodes
client = TypeSafeClient()
question = query_bundle.query_str
rescored: list[NodeWithScore] = []
for node in nodes:
answers = client.system_one(
model="jev-latest",
# Only the passage and the question. Nothing else from the pipeline:
# unrelated state is a documented accuracy cost.
state={"question": question, "passage": node.node.get_content()},
questions={
"relevant": Noul(
instructions="Does this passage contain information that answers the question?",
),
"completeness": Score(
instructions="How completely does the passage answer the question?",
criteria=["Not at all", "A fragment", "Most of it", "Fully"],
),
},
).answers
if answers["relevant"].noul < self.min_relevance:
continue # dropped, not demoted — irrelevant context costs accuracy downstream
node.score = answers["completeness"].score
rescored.append(node)
rescored.sort(key=lambda n: n.score or 0.0, reverse=True)
return rescored[: self.top_n]Read the Score correctly
The single most common mistake with this pattern. A Score is not 0–1. It runs 0..n−1 across the rubric you wrote and it is literally the probability-weighted mean of the level indices — so the four levels above return something in 0..3, and a node scoring 2.68 sits between “Most of it” and “Fully”, leaning towards fully.
That makes it a good sort key and a bad percentage. If you need a 0–1 number for a UI, divide by len(criteria) - 1 and say so in the label. Probabilities come back keyed "0", "1", "2" — never by the label text.
What it costs, per query
Reranking is a per-candidate cost, so it is worth doing the arithmetic before you put it in a hot path. Twenty retrieved nodes of 500 tokens each:
20 nodes × 500 tokens = 10,000 tokens
10,000 / 1,000,000 × $0.042 = $0.00042 per query
≈ $0.42 per 1,000 queriesBoth questions ride in the same call per node, so asking about completeness as well as relevance is free — the state is ingested once and every question is evaluated against it in parallel. The cost is set by how much text you send, not by how much you ask about it. If you want it cheaper, truncate the passages; asking fewer questions saves nothing.
Common questions
Is there a LlamaIndex integration for Jev?
Not as of this page's last check — no first-party package from TypeSafe and none listed in awesome-jev. The integration surface you want is a node postprocessor, which is about thirty lines.
Can Jev replace my reranker?
For relevance filtering, often yes: you get a calibrated probability per node instead of an opaque similarity score, and you can ask about the actual question rather than about vector distance. For fine-grained ordering among near-identical passages, a purpose-built cross-encoder reranker is still stronger.
Is it cheaper than an LLM reranker?
Substantially. Input is $0.042 per million tokens with no output charge, so reranking a 500-token chunk costs about $0.000021. An LLM reranker pays for reasoning tokens on every chunk.