your knowledge, accessible
Knowledge Graphs for AECO — a course for domain experts
A shared, organization-wide catalog that says, once, what kinds of things exist in the business
Every system, every document, every AI pipeline then maps into this same catalog instead of inventing its own.
BOT gave us about ten ideas for a building
An Object Type Library does the same job for everything else the organization knows
Each layer builds on the previous.
Reasoning then stitches them together with inferred
relationships.
Separating what a file contains from where it lives
So how would we represent this?
Same input = same output
Provider + file path
file content
qcy:FileContent carries metadata and
category assignments
Same content — three locations on different systems
qcy:FileContent
qcy:md5Hash — content fingerprintqcy:mime — MIME type stringqcy:sizeBytes — file sizeqcy:openFormat — readable without proprietary
tools?
qcy:language — detected languageqcy:textSummary — LLM-generated summaryqcy:FileLocation
qcy:filePath — relative path on the providerqcy:suffix — file extensionqcy:remoteRelativePath — provider-specific pathqcy:remoteProvider → qcy:ProviderTypeEvery subset of a document is a first-class citizen
Any subset of a document is referred to as a Fragment and each Fragment can have sub-fragments in any arbitrary depth
Information such as the page number or the fragment position relative to its parent can be expressed using Selectors
qcy:DocumentPageFragment — a page in a paginated
document
qcy:TextFragment — a passage of textqcy:ImageFragment — an image or figureqcy:TableFragment — a table with rows and columns
Document → Pages → sub-fragments at any depth
qcy:PageSelector — page number (integer)qcy:XYWHSelector — bounding box on a pageqcy:TextIndexSelector — character range
"start,end"
qcy:TextDirectiveSelector — text fragment syntax
#::text=…
qcy:IFCExpressIDSelector — IFC line numberqcy:IFCGlobalIDSelector — IFC GlobalIdqcy:IDSelector — generic identifier (XML, JSON, …)
qcy:TimeRangeSelector — time range in media files
qcy:PageSelector locates the page,
qcy:XYWHSelector locates the image within
it
Reasoning derives qcy:containsFragment
implicitly from selectors — you never need to assert it manually.
INSERT {
GRAPH <implicit> {
?sub qcy:containsFragment ?obj
}
}
WHERE {
?sel a qcy:Selector ;
qcy:selectorSubject ?sub ;
qcy:selectorObject ?obj .
?obj a qcy:Fragment .
FILTER NOT EXISTS { ?sub qcy:containsFragment ?obj }
}
Every occurrence of a named thing in a document is unique
One process in the
pipelines is
finding mentionings of Entity References in the
content of any document
Default entities: Company, Person, Address, Material ...
Other: custom entities defined per project
Selectors can further specify where in the parent fragment it is found. For example specified as a bounding box or with an index range in a text.
All Entity Mentions are unique, so Albert Einstein in one document is not directly considered the same as Albert Einstein or A. Einstein in another document.
A follow-up process in the pipelines, is the entity resolution step, where we link similar entities
the standardized representations of Named Entities
For Canonical Entities there will be only ONE Albert Einstein that refers to all individual occurrences
IfcUnitaryEquipment
Asset #88213
"Rooftop AC #4"
Three unrelated records that happen to describe the same physical object — and nobody notices until a warranty dispute forces someone to prove it.
With canonical entities, all three Entity Mentions resolve to one Canonical Entity.
Multiple mentions of the same location resolve to one
qcy:CanonicalEntity
qcy:CanonicalEntity
qcy:label — preferred English labelqcy:explicit — user-confirmed entity?qcy:hasFoundingMention → the mention that
established this entity
qcy:hasEntityCategory → category (Person, Wall,
Space, …)
qcy:similarTo → linked open data (Wikidata,
OpenStreetMap, …)
qcy:hasProperty → additional key-value facts
qcy:confidence — resolution confidenceCanonical entities also inherit the relations found between their entity mentions:
INSERT {
GRAPH <implicit> {
?c1 ?rel ?c2
}
}
WHERE {
?m1 a qcy:EntityMention ;
?rel ?m2 ;
qcy:resolvesTo ?c1 .
?m2 a qcy:EntityMention ;
qcy:resolvesTo ?c2 .
FILTER(?m1 != ?m2)
FILTER NOT EXISTS { ?c1 ?rel ?c2 }
}
Relations like qcy:elementHasMaterial,
qcy:contractInvolvesParty, or
qcy:associatedWith automatically propagate from
mentions to canonical entities.
Wall (mention) -[elementHasMaterial]-> Concrete (mention)
∴ Wall (canonical)
-[elementHasMaterial]-> Concrete (canonical)
Reasoning does the tedious work for you
Nobody has to manually tag a contract as "related to Building 4". It falls out of the links that are already there.
Most Canonical Entities in our pipelines are created by AI but it is also possible to define Explicit Canonical Entities in a project.
These are entities that are well defined in the project.
For example from a room programme or a project member list.
The approach can be:
Here is the list of people - only resolve to those
Show me what you found and I will flag the relevant ones as explicit
All entity mentions are processed by the pipeline. Similar mentions are clustered and resolved to a canonical entity.
qcy:explicit = false
A project practitioner defines a list of canonical entities — e.g. from a room programme or member directory. Only mentions matching this list are resolved.
qcy:explicit = true
"List all unique windows in Building A and every property assigned to them" — impossible across five model files, trivial once they're canonical entities.
Define the zoning categories once, top-down, so every future document resolves to the same official taxonomy.
The asset register becomes the authoritative list every AI-discovered mention must resolve against.
Built to work at project scale
+1 million documents
in a single knowledge graph
Entity resolution, cross-document linking, provenance tracking and graph traversal — all working reliably at that volume
That is not a trivial engineering problem. We have solved it.
qcy:about
qcy:elementHasMaterial on canonical entities
qcy:about on the qcy:FileContent
qcy:hasFoundingMention →
qcy:selectorObject → fragment → document
The knowledge foundation — built from all your project documents
Shape the index to your business — connect your data, define your rules
Not covered in this course
An AI agent that reasons across your entire project knowledge
Shape the index to your business
Before you start a project, the Tuner lets you define exactly what you care about
Tell the Tuner what your classification codes mean
AEC projects use coding systems to name documents — discipline codes, floor numbers, project stages, revision labels
Once the Tuner knows the mapping, you can search in plain English:
“Mechanical plan for the third floor in project stage 3”
No need to know the code — the index resolves it for you
Connect your existing data to the graph
Define mappings once — your structured data becomes part of the knowledge graph
Then validate what you've built
Run automated QA against the knowledge representation — checking for missing data, inconsistencies and rule violations
Precise rule-based checks and fuzzy matching to catch near-misses your team would never find manually
Always run this first. No computers.
In groups, 20 minutes.
Careful — some cards are decoys.
You just did entity resolution by hand
Each pile is a Canonical Entity. Each card in it is an Entity Mention. Your justification is the confidence.
Did any group leave a card unsorted? Good — so does the pipeline.
"From spreadsheet to Canonical Entities"
Requires a Cue sandbox project
In groups, 45 minutes. No code at any point.
Space — or do you need a custom one?
Use the built-in catalog — Person, Organization, Space, Asset,
and so on. A room list maps straight to
Space.
Define your own in the Tuner's category app, for something specific to your organization: "Lease Clause", "Valve Type", "Inspection Zone".
Choosing between these is the act of designing an Object Type Library.
Fill in the blanks with the object types your organization actually deals with. Keep this sheet — you finish it tomorrow.
Note what did not happen
Nothing was migrated. Nothing was deleted. The spreadsheet still sits exactly where it was — its rows just have a permanent, connected identity now.
"I don't need one system to rule them all — I need one shared vocabulary of object types so that everything I already have can point to the same thing."
You put your own data into the graph. Tomorrow you ask it questions in plain English — and see the answer come back sourced to the rows you loaded today.
Day 6 — The knowledge graph as integration layer