Skip to content

Verification

Jev is cheap and fast enough to check the work of other systems, including LLMs, extraction pipelines and agents, on every request. Keep the deterministic checks in code, ask narrow questions about the rest, and escalate only what fails.

Citation checks

A quote that doesn't appear in the source is fabricated, and code can tell that without a model. But a verbatim quote can still fail to support the claim, so judge the quote in its context:

enum class Verdict { VERIFIED, CONTRADICTED, UNSUPPORTED, FABRICATED }

data class CitationCheck(
    val verdict: Verdict,
    val needsReview: Boolean,
)

suspend fun checkCitation(
    jev: JevApi,
    claim: String,
    quote: String,
    sections: List<String>,
): CitationCheck {
    // Deterministic first: a quote that isn't in the source is fabricated, no model needed.
    val section =
        sections.firstOrNull { it.contains(quote) }
            ?: return CitationCheck(Verdict.FABRICATED, needsReview = false)

    // Then judge the quote in context: a verbatim quote can still fail to support the claim.
    val state =
        buildJsonObject {
            put("claim", claim)
            put("section", section)
        }
    val relation =
        jev
            .query(state = state) {
                choice("relation", "How does the section relate to the claim?") {
                    "supports" means "The section states the claim or directly implies that it is true"
                    "contradicts" means "The section states the opposite of the claim or implies it is false"
                    "says_nothing" means "The section does not address what the claim asserts, either way"
                }
            }.choice("relation")

    val verdict =
        when (relation.choice) {
            "supports" -> Verdict.VERIFIED
            "contradicts" -> Verdict.CONTRADICTED
            else -> Verdict.UNSUPPORTED
        }
    return CitationCheck(verdict, needsReview = relation.confidence < 0.8)
}

In TypeSafe's RFC 7519 example, all four accurate citations were verified at 0.93 confidence or higher, and all four planted failures were caught. The two with low confidence were exactly the "says nothing" cases, and the confidence gate sent them to review.

Extraction checks

A cheap model extracts the fields; Jev checks each field, and only the flagged records go to an expensive reasoning model:

// Verify a cheap model's extraction field by field; escalate only when a check fires.
suspend fun needsEscalation(
    jev: JevApi,
    sourceText: String,
    extracted: Map<String, String>,
): Boolean {
    val checks =
        mapOf(
            "hallucinated" to "Is the `extracted_field` unsupported by, or absent from, the source text?",
            "off_target" to "Was the `extracted_field` pulled from incidental text, not a real mention of the field?",
            "format_violation" to "Does the `extracted_field` violate the format implied by the field's name?",
        )
    val result =
        jev.query(state = sourceText) {
            for ((field, value) in extracted) {
                for ((check, question) in checks) {
                    // Phrase every check so TRUE means "something is wrong".
                    noul("$field::$check", entry("field" to field, "extracted_field" to value, "question" to question))
                }
            }
        }
    // Max, not mean: one confident red flag is enough to escalate.
    return result.nouls.values.maxOf { it.noul } > 0.7
}

What makes these checks work:

  • Narrow and grounded. Each check asks one yes/no question about one field against the source. Vague "is this record good?" questions give mushy scores.
  • Bad = TRUE. Phrase every check so that "yes" means "something is wrong", with explicit criteria.
  • Max, not mean. One confident red flag should escalate, not be averaged away.

Tool-call traces

Verify an agent's tool calls with one question per property rather than one question about the whole trace:

// Check an agent's tool calls with narrow questions rather than one "is this trace correct?".
suspend fun toolCallProblems(
    jev: JevApi,
    traceJson: JsonObject,
): List<String> {
    val result =
        jev.query(state = traceJson) {
            noul("wrong_tool", "Is `trace.tool_calls[0].name` an inappropriate tool for `request.text`?")
            noul("schema_violation", "Do `trace.tool_calls[0].arguments` violate the tool's `parameters` schema?")
            noul("unit_mismatch", "Does `trace.tool_calls[0].arguments.unit` differ from `request.unit`?")
            noul("date_mismatch", "Does `trace.tool_calls[0].arguments.date` differ from `request.date`?")
        }
    return result.nouls.filterValues { it.isTrue(0.7) }.keys.toList()
}

Each failing check names the specific problem, which is easier to act on than a single low score.