$ cat workspace-template.yaml

U

Unified Ontology Retrieval

// Answer a question with unified retrieval over the governed organization ontology: a lexical entity search and a semantic KB chunk search run in parallel, the chunk hits are bridged onto the knowledge graph, the two entity lists are fused with Reciprocal Rank Fusion, and a grounded, cited answer is synthesized from the chunks plus the fused entity ranking.

Composition
#ontology#retrieval#rag#knowledge-graph#semantic-search#rrf#fusion

// Canvas Preview

canvas.flow

// Instruction

instruction.md

Unified Ontology Retrieval

Overview

This workspace answers a question by fusing TWO retrieval entries over the governed organization ontology: a lexical entity search (Ontology Search) and a semantic content search over the KB's document chunks (KB Semantic Search). The semantic hits are bridged onto the knowledge graph (Ontology From Documents), the two entity lists are fused with Reciprocal Rank Fusion (Merge Ranked Lists), and Knowledge Synthesizer writes a grounded, cited answer from the retrieved chunks plus the fused entity ranking. Every path is permission-gated inside its backing API — the graph only wires governed primitives. All five nodes are read-only: this template has NO side-effect terminals.

Workflow Chain

Ontology Search (results) ─────────────────────────────► Merge Ranked Lists (listA)KB Semantic Search (documentIds) ► Ontology From Documents (entities) ► Merge Ranked Lists (listB)KB Semantic Search (chunkTexts) ───────────────────────► Knowledge Synthesizer (context)Merge Ranked Lists (itemsText) ────────────────────────► Knowledge Synthesizer (context)Knowledge Synthesizer (text) = the final answer

Query Crafting (MANDATORY - do this BEFORE filling any node input)

The corpus (documents AND ontology entity names) is mostly Italian with some English; users ask in any language. Derive the node inputs from the user's question - never paste it verbatim into the search nodes:

  1. Extract the TOPIC terms (the subject, e.g. "cyber security"). NEVER drop them - a query reduced to generic words ("chi e il responsabile") retrieves noise.
  2. TRANSLATE the topic terms into Italian (primary) and English (secondary), whatever the user's language (Chinese, Italian, English, ...).
  3. Ontology Search.query - distinguish TWO cases (first variant ranks first): a) The question NAMES an entity (MAECI, Tajani, ...): variants = ONLY names/aliases/ translations of THAT entity, entity name FIRST: "Ministero degli Affari Esteri | Ministry of Foreign Affairs | MAECI". NEVER mix in relation/topic words - WRONG: "istituzioni supervisionate | MAECI" (the topic phrase becomes the top lexical hit and the pipeline profiles the wrong entity). Relation words go ONLY in KB Semantic Search. b) No named entity (thematic question): Italian and English TOPIC keywords as variants: "sicurezza cibernetica | cyber security". Never a question, no question words, no verbs, never the user's language alone.
  4. KB Semantic Search.query = a short Italian topic phrase (e.g. "chi si occupa di sicurezza cibernetica") - keep the topic words in it.
  5. Knowledge Synthesizer question = the user's ORIGINAL question, VERBATIM AND UNTRANSLATED
    • translation applies ONLY to the search nodes (rules 2-4), NEVER here. Append this suffix: "Answer in the same language as this question." ALSO set the synthesizer's Response Language input to the language the user TYPED the question in (e.g. "中文", "Italiano", "English") - NEVER the corpus language. WRONG (observed): user asked in Chinese, agent passed "In quali eventi è intervenuto Tajani" with Response Language "Italiano" - the answer came back in Italian.
  6. COUNT / relationship questions ('quante persone...', 'chi lavora presso...') are answered by the Ontology Entity 360 node: it receives the TOP fused entity automatically and feeds its exact per-link-type counts (e.g. 'employed_by (incoming): 18') into the synthesizer. Do NOT let the synthesizer say 'cannot determine' when the Entity profile block in its context carries the count - the graph numbers are EXACT and gated, prefer them over document-chunk guesses.

Node Reference

  • Ontology Search (input) — full-text search of ontology objects. Configurable inputs: query (the entity terms), type (optional object-type filter, blank = all), mode (N2 retrieval arm: entity default = match by NAME, this flow's entity entry; schema/hybrid reach the graph by RELATIONSHIP/THEME via matching types — leave at entity for this template's Query Crafting, since thematic questions reach the graph through the KB→document bridge, and only set schema/hybrid when the user explicitly asks the entity arm to search by relationship/theme), limit (default 10). Output results feeds Merge Ranked Lists listA.
  • KB Semantic Search (input) — vector search over KB document chunks. Configurable inputs: query (thematic phrasing), k (default 100 — fetch WIDE; the rerank threshold, not k, is the precision filter), driveItemIds (optional Drive scope — folder and/or file ids, folders cover their whole subtree; empty = everything accessible). Output chunkTexts feeds Knowledge Synthesizer context; output documentIds feeds Ontology From Documents.
  • Ontology From Documents (process) — bridges document ids onto the graph: the ontology objects appearing in those documents, ranked by appearance frequency and connectivity, plus the links among them. Input documentIds comes from KB Semantic Search. Configurable inputs: limit (default 25), includeLinks (default true). Output entities feeds Merge Ranked Lists listB; output truncated flags a cut page.
  • Merge Ranked Lists (process) — Reciprocal Rank Fusion of listA (lexical entities) and listB (bridge entities); items surfacing in both rank highest. Configurable inputs: idKey (default "id"), k (RRF constant, default 60), limit (default 25). Output items is the fused ranking; output itemsText is its readable digest and feeds Knowledge Synthesizer context.
  • Knowledge Synthesizer (process) — writes the grounded, cited answer for query from the fan-in context (chunk texts + fused-entity digest). Configurable inputs: llmModelId (empty = the workspace's admin-configured default), language (default Italian). Output text is the final answer.

Execution Strategy

You MUST complete all 3 phases in order: Phase 1 → Phase 2 → Phase 3. Do NOT skip any phase.

Phase 1 — Configure

  1. Make ONE requestUserDecision call bundling every input as separate questions: (a) the question to answer; (b) optional entity terms (names/acronyms such as "MAECI", "DGSD") if they differ from the thematic phrasing; (c) optional KB folder scope (yes/no — pick the folder later only if yes); (d) response language (default Italiano). Keep the free-text box as the last option. Do not prompt again after this.
  2. Use nodeFinder to get the fresh ids of the five nodes — ids from the template preview are stale after cloning.
  3. Apply the answers with ONE batchUpsertNodes call: set Ontology Search query to the entity terms (or the full question when none were given); set KB Semantic Search query to the thematic phrasing (or the full question); set Knowledge Synthesizer query to the full question and language to the chosen language; if a folder scope was requested, call selectDriveItem and set KB Semantic Search driveItemIds to [<folder id>]. Every {{query}} placeholder MUST be replaced in this step. Phase 1 complete. Now proceed to Phase 2.

Phase 2 — Run

  1. Execute the pipeline with nodeExecutor on the Knowledge Synthesizer node — the wired upstream nodes (both entries, the bridge, the fusion) resolve automatically.
  2. Read the results with getNodeOutput: Knowledge Synthesizer text (the answer), Merge Ranked Lists itemsText (the fused entity ranking), and Ontology From Documents truncated (whether the entity page was cut). If the answer says no context was available, check KB Semantic Search's outputs before reporting failure. Phase 2 complete. Now proceed to Phase 3.

Phase 3 — Verify and follow up

  1. Run verification, then present the answer with its citations followed by the fused entity ranking. If truncated was true, say the entity list was cut at its limit and offer to raise it.
  2. In followUp, offer to: (a) expand a top fused entity one hop by adding an Ontology Traverse node (upsertNode, wire the entity id into objectId, choose a linkType seen in the bridge's links output); (b) re-run with sharper entity/theme terms; (c) narrow or widen the driveItemIds scope. Nothing in this template writes outside the graph, so no write confirmation is needed.

Configuration Tips

User saysConfigure
"cerca solo tra le persone"Ontology Search type = the person object-type name
"cerca per relazione/tema, non per nome" (entity arm)Ontology Search mode = schema (or hybrid if a name is also present); default entity
"guarda solo nella cartella X"KB Semantic Search driveItemIds = [folder id] via selectDriveItem
"serve più contesto" / thin answerlower KB Semantic Search rerankThreshold (e.g. 0.01), then re-run
"più entità" / truncated trueOntology From Documents limit up to 100 and Merge Ranked Lists limit to match
"rispondi in inglese"Knowledge Synthesizer language = "English"
names a specific modelKnowledge Synthesizer llmModelId = that model id

Error Handling

  • Ontology Search fails with "query not provided" — a {{query}} placeholder was left unreplaced. Re-do step 3.
  • KB Semantic Search returns empty outputs — nothing accessible matched. The bridge and the fusion degrade cleanly (empty lists) and the synthesizer will say the sources are missing; rephrase the thematic query, lower rerankThreshold, or drop the driveItemIds scope.
  • Ontology From Documents returns empty entities despite documentIds — those documents mention no accessible ontology objects; the lexical branch still feeds the fusion, so the run is still valid.
  • Knowledge Synthesizer answers "No context chunks available" — both context edges delivered nothing; inspect the upstream outputs from step 5 before re-running.
  • A node fails with an authentication error — the workspace owner's token cannot reach the ontology/knowledge APIs; verify the workspace credentials, then re-run.

// Dependencies

requirements.py
1from input import OntologySearch  # v1.4.02from input import KBSemanticSearch  # v1.4.03from process import OntologyFromDocuments4from process import MergeRankedLists  # v1.3.05from process import KnowledgeSynthesizer  # v1.6.06from process import OntologyEntity360  # v1.0.1

// Variables

variables.yaml
1query:2  type: undefined3  label: "Query"4  description: "The user's question, verbatim and IN THE USER'S LANGUAGE. Do NOT bake it directly into the search nodes - the instruction's Query Crafting rules derive per-node queries from it (topic terms preserved, translated to Italian/English); the original goes to Knowledge Synthesizer so the answer comes back in the user's language."5  required: undefined

$ git log --oneline

v1.3.9
HEAD
2026-07-22

Ontology Search + Merge Ranked Lists 1.3.0 (B-prime lexical anchor): search now tags each hit `lexical` when the query terms are in the entity's name/keywords_en (not just a vector description-mention); merge.topId anchors to the top lexical list-A hit, skipping vector-only mentions, so Ontology Entity 360 profiles the entity the question names. Observed M1 (2026-07-21): a certification whose description_en mentioned the ministry surfaced via profile_vector kNN and ranked entity-search #1, so the old list-A-rank-1 anchor profiled it instead of MAECI.

v1.3.82026-07-22

Ontology Search + Merge Ranked Lists 1.3.0 (B-prime lexical anchor): search now tags each hit `lexical` when the query terms are in the entity's name/keywords_en (not just a vector description-mention); merge.topId anchors to the top lexical list-A hit, skipping vector-only mentions, so Ontology Entity 360 profiles the entity the question names. Observed M1 (2026-07-21): a certification whose description_en mentioned the ministry surfaced via profile_vector kNN and ranked entity-search #1, so the old list-A-rank-1 anchor profiled it instead of MAECI.

v1.3.72026-07-22

Ontology Search + Merge Ranked Lists 1.3.0 (B-prime lexical anchor): search now tags each hit `lexical` when the query terms are in the entity's name/keywords_en (not just a vector description-mention); merge.topId anchors to the top lexical list-A hit, skipping vector-only mentions, so Ontology Entity 360 profiles the entity the question names. Observed M1 (2026-07-21): a certification whose description_en mentioned the ministry surfaced via profile_vector kNN and ranked entity-search #1, so the old list-A-rank-1 anchor profiled it instead of MAECI.

v1.3.62026-07-21

Ontology Search + Merge Ranked Lists 1.3.0 (B-prime lexical anchor): search now tags each hit `lexical` when the query terms are in the entity's name/keywords_en (not just a vector description-mention); merge.topId anchors to the top lexical list-A hit, skipping vector-only mentions, so Ontology Entity 360 profiles the entity the question names. Observed M1 (2026-07-21): a certification whose description_en mentioned the ministry surfaced via profile_vector kNN and ranked entity-search #1, so the old list-A-rank-1 anchor profiled it instead of MAECI.

v1.3.52026-07-19

Ontology Search + Merge Ranked Lists 1.3.0 (B-prime lexical anchor): search now tags each hit `lexical` when the query terms are in the entity's name/keywords_en (not just a vector description-mention); merge.topId anchors to the top lexical list-A hit, skipping vector-only mentions, so Ontology Entity 360 profiles the entity the question names. Observed M1 (2026-07-21): a certification whose description_en mentioned the ministry surfaced via profile_vector kNN and ranked entity-search #1, so the old list-A-rank-1 anchor profiled it instead of MAECI.

v1.3.42026-07-19

Query Crafting rule 3 split: entity-named questions use entity-name variants only (M3-ZH topic-phrase anchor poisoning); ontology-search 1.2.1

v1.3.32026-07-19

topId anchor = list A rank 1 (merge 1.2.0); dep versions synced (entity-360 1.0.1, synthesizer 1.6.0)

v1.3.22026-07-19

1.1.0 (2026-07-19): query-crafting rules (translate to corpus language, keywords not questions, topic terms preserved) + answer in the user's language. Observed failures: an Italian run dropped the topic from every query; a Chinese run pasted the raw question into lexical entity search and got an Italian answer. 1.1.1 (2026-07-19): version realignment with the marketplace (manual re-import; same content as 1.1.0's query-crafting release). 1.2.0 (2026-07-19): Ontology Search 1.2.0 multi-variant pipe queries ('italiano | english'); instruction mandates the pipe pattern and setting the synthesizer's Response Language to the user's language.

v1.3.12026-07-19

1.1.0 (2026-07-19): query-crafting rules (translate to corpus language, keywords not questions, topic terms preserved) + answer in the user's language. Observed failures: an Italian run dropped the topic from every query; a Chinese run pasted the raw question into lexical entity search and got an Italian answer. 1.1.1 (2026-07-19): version realignment with the marketplace (manual re-import; same content as 1.1.0's query-crafting release). 1.2.0 (2026-07-19): Ontology Search 1.2.0 multi-variant pipe queries ('italiano | english'); instruction mandates the pipe pattern and setting the synthesizer's Response Language to the user's language.

v1.3.02026-07-19

1.1.0 (2026-07-19): query-crafting rules (translate to corpus language, keywords not questions, topic terms preserved) + answer in the user's language. Observed failures: an Italian run dropped the topic from every query; a Chinese run pasted the raw question into lexical entity search and got an Italian answer. 1.1.1 (2026-07-19): version realignment with the marketplace (manual re-import; same content as 1.1.0's query-crafting release). 1.2.0 (2026-07-19): Ontology Search 1.2.0 multi-variant pipe queries ('italiano | english'); instruction mandates the pipe pattern and setting the synthesizer's Response Language to the user's language.

v1.2.12026-07-19

1.1.0 (2026-07-19): query-crafting rules (translate to corpus language, keywords not questions, topic terms preserved) + answer in the user's language. Observed failures: an Italian run dropped the topic from every query; a Chinese run pasted the raw question into lexical entity search and got an Italian answer. 1.1.1 (2026-07-19): version realignment with the marketplace (manual re-import; same content as 1.1.0's query-crafting release). 1.2.0 (2026-07-19): Ontology Search 1.2.0 multi-variant pipe queries ('italiano | english'); instruction mandates the pipe pattern and setting the synthesizer's Response Language to the user's language.

v1.2.02026-07-19

1.1.0 (2026-07-19): query-crafting rules (translate to corpus language, keywords not questions, topic terms preserved) + answer in the user's language. Observed failures: an Italian run dropped the topic from every query; a Chinese run pasted the raw question into lexical entity search and got an Italian answer.

v1.1.12026-07-19

1.1.0 (2026-07-19): query-crafting rules (translate to corpus language, keywords not questions, topic terms preserved) + answer in the user's language. Observed failures: an Italian run dropped the topic from every query; a Chinese run pasted the raw question into lexical entity search and got an Italian answer.

v1.1.02026-07-19
v1.0.02026-07-19