Skip to content

Semantic Templates and Vocabularies

These two pages control the optional LLM extraction pass that infers relations your parser cannot see. They are the deepest customization the console offers, and the two most useful when your content is not code.

  • Semantic Templates (/app/semantic-templates) — how the model is asked: which files a prompt claims, what it says, which relations it may return.
  • Vocabularies (/app/ontologies) — what things are: your own classes and relations, with the extraction checked against them.

First, what extraction actually is

The engine builds its knowledge graph in three passes:

  1. Deterministic AST/metadata — nodes and Contains / Defines edges. No LLM.
  2. Tree-sitter relationsImports, Calls, Implements, References. No LLM.
  3. Semantic extraction — an LLM proposes the relations the first two cannot infer. Edges only; it never invents nodes.

Only pass 3 uses a model, and only pass 3 is what these pages configure. If you turn extraction off in Settings, passes 1 and 2 keep working and the graph still exists — it just stops gaining inferred edges.

Source code is never sent to the LLM. Pass 3 runs on text-like content (documents, tables, prose) and receives the deterministic nodes from pass 1.

Semantic templates

A template is an extraction profile: a selector that decides which files it claims, a prompt, and the list of relations it is allowed to return.

They layer on the built-ins

The engine ships built-in profiles. Yours are added on top: a template whose id matches a built-in replaces it, and a new id adds to the set. You cannot lose the built-ins by adding your own, which is why the list shows yours and the defaults together.

Selection is by evidence, not by priority

This is the single thing people get wrong. A template claims a file because the file's own content matches its declared markers — priority only breaks ties between templates that made an equally strong case.

So to target content, describe it:

  • language_markers — distinctive words that appear in the content.
  • required_headers — for tables: column names that must all be present.
  • optional_headers — column names that strengthen the match without being required.

A template that declares markers and matches none of them does not claim the file at all; extraction falls back to the engine's generic prompt. Raising priority will not win you files.

Writing the prompt

These placeholders are substituted for you. Anything else in braces is sent to the model as literal text.

PlaceholderFilled with
{source_text}The file, or table chunk, being extracted from.
{file_path}Path of the file — useful for asking the model to scope ids.
{allowed_relations_json}Your allowed_relations, as a JSON array.
{response_schema}The schema name the model must answer in.
{profile_id}This template's id.
{headers_json}Column headers, for CSV/TSV/PSV and Markdown tables.

allowed_relations is a filter, not a suggestion

A relation the model returns that is not on your list is discarded. If your prompt asks for relations you did not allow, you get zero edges from a template that otherwise looks correct. Keep the prompt and the list in agreement — the easy way is to interpolate {allowed_relations_json} into the prompt itself.

Reading extraction health

The health card reports two numbers that are deliberately not combined, because they fail for different reasons:

  • Attempts completed — did extraction run at all. Low values point at the provider or credentials, not your template.
  • LLM output kept — how much of what the model proposed survived filtering. Low values point at your template or the confidence threshold.

High completion with low kept is the classic broken template. When you see it, read Why relations were dropped:

ReasonFix
relation_not_allowedYour prompt and allowed_relations disagree.
low_confidenceThe confidence threshold is above what this model produces here.

Vocabularies

A vocabulary declares the classes and relations your content actually has — crm:Contact, code:Module — so extraction can be checked against something real instead of a generic relation set.

A vocabulary does nothing on its own

Saving one has no effect until a semantic template names it. Open the template, pick the vocabulary in its Ontology field, and apply. Until then extraction runs exactly as it did before.

A template naming a vocabulary must leave its relation list empty

The two are alternative ways of saying which relations are permitted. Setting both is refused rather than resolved by precedence — whichever the engine honoured would silently ignore the other.

Classes: your term, and how it is stored

A class is your term (crm:Contact). The stored kind beside it is the engine's own fixed vocabulary, and several of your classes may share one: crm:Contact and crm:Deal can both be stored as block and stay distinct, because the class id carries the meaning.

The description is prompt material, not documentation. The model reads it to decide what to classify as what, so a vague description is a quality problem, not a cosmetic one.

Empty endpoints mean any class

Selecting no source or target classes for a relation leaves it unconstrained — it may connect anything. It does not mean the relation connects nothing.

Constrain a relation only where the constraint is real. Ranging documented_by to a document class is useful, because a model emitting "module documented by module" has misread its input. Constraining everything just to be tidy costs you edges.

An endpoint the model leaves unclassified is kept by default, even for a constrained relation: a domain says which classes may participate, not that every endpoint must carry one. So adding a constraint never silently requires you to classify everything.

Check the evidence rate before requiring evidence

Every built-in prompt asks the model to cite the span it inferred a relation from, and the extraction health card reports how often it actually does.

Turning on Require evidence for a relation drops every assertion without a citation. Against a template whose model rarely cites, that removes nearly the whole yield. Read the evidence rate first, then decide.

Editing a vocabulary re-extracts what used it

The vocabulary is part of the extraction cache key, so changing it invalidates the cached results of every file extracted under it. Those files are extracted again — with the LLM cost that implies. Batch your vocabulary edits rather than making them one at a time.

Both pages: apply, don't just save

Templates and vocabularies are read when your runtime is rebuilt. A saved edit is stored but not live, and a Changes pending banner appears until you click Apply changes. Until then, extraction keeps using the previous set and the health numbers will not move — which reads exactly like a template that does not work.

Where to use them

  • Bind a vocabulary to a database source to give its rows ontology classes — see Connecting a Database.
  • Write a template for a document type your corpus is full of and the built-ins do not recognise: RFCs, runbooks, meeting notes, a bespoke CSV export.

Released under the Private Beta License.