Skip to content
ONTO
Industry · Research

Research agents that build a knowledge graph — not a prompt soup.

A research copilot worth using extracts typed claims, attaches provenance, detects when papers contradict each other, and asks a human before resolving the conflict. ONTO does all four out of the box.

The pain.

RAG retrieves text, not facts.

"Pull the top-k chunks and stuff them in the prompt" is fine for QA. It does not build a graph. The researcher ends up with a long answer and no model of what the corpus knows.

No provenance, no audit.

Where did the claim come from? Which paper? Which page? Standard agent memory loses the chain. ONTO assertions carry provenance metadata by default.

Conflicts get averaged, not flagged.

When two papers disagree, the model picks a confident answer. The researcher never sees the disagreement. That is not a research tool — that is a hallucination machine with extra steps.

Domain scoping is manual.

A study from oncology shouldn't pollute the ML-systems knowledge graph. Most agent SDKs treat memory as one flat space.

The primitives that map to it.

Each piece of the pain above maps to a specific ONTO primitive — not a workaround layered on top.

Domain-scoped extraction

Four-level extraction includes "domain" scope — assertions partition by domain_id. Oncology claims and ML-systems claims live in separate sub-graphs.

Conflict detection

When two assertions disagree on a (subject, predicate) pair, the runtime creates a task for the researcher to resolve. No silent overwrite.

Plan Mode for synthesis

Synthesis runs in plan_only mode. Every conflict-resolution proposal becomes a reviewable task before the knowledge graph commits.

Background consolidation

Long ingestion runs spawn summarization and conflict detection on a cheaper model. Foreground time is spent reading; background time builds the graph.

A runnable example.

Ingest a corpus, extract typed claims per paper at domain scope, then plan a synthesis. Cross-paper conflicts surface as Plan Mode tasks for the researcher to resolve.

from onto import Onto, Models, BuiltinTools

onto = Onto(model=Models.GPT_OSS_20B, builtin_tools=BuiltinTools.STANDARD)

papers = load_paper_abstracts("./corpus/")  # 200 abstracts

# Extract typed claims at domain scope, in parallel.
for paper in papers:
    onto.run_sync(
        paper.text,
        user_id="research_session_2026Q2",
        consent_scopes=["memory:write", "domain:claims"],
        extract=True,
        extract_async=True,
        domain_id=paper.field,   # "oncology", "ml-systems", etc.
    )

# Plan a synthesis. Conflicts between papers surface as tasks.
plan = onto.run_sync(
    "Synthesize the corpus. Flag claims that disagree.",
    user_id="research_session_2026Q2",
    mode="plan_only",
    consent_scopes=["memory:read", "tasks:write"],
)

# Researcher approves resolutions task-by-task before they commit.
for conflict in plan.tasks:
    if researcher_approves(conflict):
        onto.execute_task(conflict, consent_scopes=["domain:claims:update"])

Considerations at scale.

Open-weight by default

For large corpora the bill matters. ONTO defaults to gpt-oss-20b-cloud (free open-weight); flip to a stronger model only where you need it.

Per-researcher cost rollup

onto.cost(user_id=...) gives per-researcher cost, useful for lab budgets and grant accounting.

Reproducibility

Every assertion stores the model_id and prompt fingerprint used to extract it. Re-runs against the same corpus are diffable.

Export

The UPO at domain scope serializes to RDF/Turtle and JSON-LD. Drop it into Neo4j or load it as a graph in your downstream tool.

Research

Build the research agent that adds to the knowledge graph — not noise.

Read the research-ingestion example or the article on mining typed facts from papers.