ontology mapping R&D run Jev Disease Ontology Human Phenotype Ontology PubMed

…

Benchmarking the speed of mapping 10,000+ ontology concepts onto a document — and how it does it.
The setup
Twenty abstracts in. Every concept of the ontology comes out scored. One yes/no question at a time, a hundred per call.

The job: say which concepts each abstract touches — the Disease Ontology's … disease concepts, and the Human Phenotype Ontology's … phenotype terms. The usual route is a trained NER+linking stack. This run replaces it with one yes/no question per concept.

The instrument: Jev, a System One model. It generates no text. We give it the document and a prompt asking whether the abstract touches on each ontology concept. A calibrated probability comes back for each concept, and code branches on it.

Part 1

The task

No NER stack, no linking step, no graph store. Each term is one yes/no question against the text — … per document for DOID, … for HPO. Prompt used for TypeSafe's noul mapping:

# one Noul question per ontology term, ~100 per API call
state = { "document": abstract_text }

question("DOID_0014667"): noul
  instructions: Does `document` mention, describe, or clearly imply the
    concept 'disease of metabolism' — A disease that involves errors in
    metabolic processes? Synonymous wording counts; negation does not.
# HPO identical but for the term, e.g. HP_0002643 'Neonatal respiratory distress'

Jev has three question types:

These runs are all Noul, so outputs drop straight into a threshold.

The rule: not "what is this document about?" but one atomic gut-check per concept. Anything bigger gets split.

Part 2

How it did

Histogram of confidence levels
DOID · diseases
HPO · phenotypes

Second opinion. Jev mapped. A second pass re-read each abstract and judged every match yes / maybe / no — the colored cells in Part 3. It said "no" to … of the DOID matches and … of the HPO matches. The mapper is fast and broad (~800–1,000 questions/s); the checker is slow (~3 verdicts/s) and can say why.

The crosswalk, in code. Jev found a disease in the abstract (left, blue). The ontology files already carry that disease's curated symptom list. Side by side you see which known symptoms Jev rediscovered from 200 words and which findings the record lacks. Dashed rows are candidates to fill the record in. No model does the walking — it is a few lines of Python over the ontology files.

DOID → OMIM/Orphanet → curated HPO phenotypes
Middle: the crosswalk, from the files, not the model. Right: teal = Jev found the phenotype in the abstract (score shown) · grey = curated but absent from the text · dashed = found by Jev, missing from the record — a candidate to add. Hover for HP ids.
Part 3

MeSH vs. the result

Doesn't PubMed already do this? Its MeSH keywords are broad article-level topics assigned by humans, often months late. Each abstract below shows its real headings. MeSH has ~30,000 descriptors and almost none of HPO's ~20,000 phenotypes. That's the gap.

Pick an abstract. You see its text, its MeSH indexing, and both ontologies' decisions side by side. Cell colors are the second-opinion ("Kimi check") verdicts. Hover for the reason. Search filters to articles that have the term.

0.50
Part 4

Speed

One call, one hundred judgments
Watch one call. The document is read once. The questions stream in one by one. Each answer comes back as its own probability.
One document, every concept, one call
PMID 23666417, Update on cystinuria. Real DOID terms queued against the excerpt; real probabilities back. Chips are shortened from the actual instruction: "Does the document mention, describe, or clearly imply the concept…"
Latency of every API call in the DOID run

I ran ontology concept mapping on 20 PubMed sample abstracts (title + abstract text, 30k character limit).

Supplemental — batch-size scaling

Latency vs. questions per call
Same 1,360-character abstract throughout, three reps per batch size. Dots are individual runs; the line connects medians. Tokens per call (grey labels) grow linearly — latency does not.

Why doesn't the clock move? Not cluster MapReduce — the parallelism is inside the architecture. An LLM would emit each answer token by token; Jev's parallel sampler produces every answer in a single query, against a state read once. TypeSafe's launch post calls the intended use "map-reducing over big data" — the shape is theirs, the cluster isn't needed. (A request's ~32k-token budget, shared by state and questions, is why these runs batch at 100.)

Method. Noul questions, batch 100, concurrency 4; each (document, term) pair got exactly one judgment; a match is noul ≥ 0.5. Two ontologies over the same 20 abstracts. Second opinion: 20 parallel Kimi agents per ontology, one per abstract, judging each match yes / maybe / no against the text. Crosswalk: DOID xrefs (MIM/ORDO) → HPO phenotype.hpoa annotations, computed in Python. Code: ontology-jev — ontology.py, fetch_pubmed.py, run_experiment.py, batch_scaling.py, aggregate_results.py, crosswalk.py, fetch_mesh.py.
  1. TypeSafe AI. Jev & the System One API — documentation. docs.typesafe.ai (model jev-1.13.0; $0.042/Mtok input, output free).
  2. Schriml LM, et al. The Human Disease Ontology 2022 update. Nucleic Acids Res 2022. disease-ontology.org — doid.obo release 2026-08-31 (CC0); 12,284 non-obsolete terms. Köhler S, et al. The Human Phenotype Ontology in 2021. Nucleic Acids Res 2021. hpo.jax.org — hp.obo release 2026-09-01; 19,894 non-obsolete terms; phenotype.hpoa disease annotations.
  3. Sayers EW, et al. Database resources of the NCBI. Nucleic Acids Res 2025. E-utilities (esearch/efetch), query "rare genetic disease clinical phenotype", 20 abstracts.
  4. TypeSafe AI. Line-by-line search and Parallel questions cookbooks — the fan-out pattern this run scales up. docs.typesafe.ai/cookbooks
  5. Almeida D. Introducing System One Models & Jev. TypeSafe AI blog, Sep 2026. typesafe.ai/blog — the parallel sampler and the "map-reducing over big data" use case.
  6. LangChain. Building a harness with Jev. langchain.com/blog/building-a-harness-with-jev — the System One framing this intro borrows; TypeSafeClassifier, model routing, guardrail middleware.
  7. Corpus PMIDs: 38695103, 29555955, 38838312, 25351510, 29590070, 34008892, 25326635, 37516247, 32793115, 41411243, 39843740, 38060187, 34852371, 40759488, 23666417, 41024252, 40225925, 40653509, 39500555, 32409007.