Resonance Lattice on Microsoft Fabric
A team-shared knowledge model. One .rlat file in OneLake,
exposed as a Fabric User Data Function (UDF) — a small published
Python function anyone on the workspace can call. Query it from the CLI,
from Claude Code, or from a Fabric notebook, with no per-user encoder
install and no .rlat copies scattered across laptops.
What this gets you
A knowledge model is a single .rlat file:
your corpus (docs, code, a knowledge base) packaged for semantic search.
Hosted on Fabric, that file lives once in OneLake — Fabric's shared data
lake — and a UDF wraps it so every workspace member queries the same
copy.
Two example notebooks ship with the integration. The demo notebook
(fabric_demo_udf.ipynb) queries the UDF and writes telemetry
to two Delta tables. A second notebook
(fabric_analytics.ipynb) reads those tables and deploys a
Direct Lake semantic model you can point Power BI at.
The whole setup takes about fifteen minutes the first time.
For what this unlocks beyond search, read the write-up: a slicer that filters by meaning, not by value — type plain language, and a 96,000-row Power BI model recomputes over the listings that match.
What you'll need
- A Fabric workspace, with a Lakehouse you can write
Files/to. - About 500 MB of OneLake space — your
.rlatplus telemetry. - An Entra account on the workspace (signs you in once via a device code).
- Power BI Desktop — optional, only if you want to build visuals on the semantic model.
The end-to-end path:
Files/<SRC>/ --fabric_build.ipynb--> Files/rlat/<KM>.rlat --UDF.search--> results
|
v
fabric_demo_udf.ipynb --> udf_telemetry + udf_hits Delta
|
v
fabric_analytics.ipynb
|
v
rlat-analytics semantic model
Build a .rlat
You have three options.
A. Build inside Fabric (recommended for ongoing rebuilds)
Drop source files into Files/<SOURCE_DIR>/ in your
OneLake, then run the notebooks/examples/fabric_build.ipynb
notebook. The first run builds; every run after refreshes incrementally —
only changed files are re-encoded. Schedule it from a Fabric Pipeline if
you want it on a cron.
B. Build locally and upload
If you'd rather build from your own machine:
rlat build ./your-docs -o team-docs.rlat
rlat fabric publish-rlat ./team-docs.rlat \
--workspace <workspace-id> \
--lakehouse <lakehouse-id>
C. Build on a GPU for big seed corpora
For a first-time build over roughly 10,000 passages, Fabric's CPU is
slow. Build on Kaggle, Colab, or a local GPU machine, upload the seed
.rlat to Files/rlat/, and let
fabric_build.ipynb handle subsequent refreshes inside
Fabric.
Either way, the .rlat ends up at
Files/rlat/<KM_NAME>.rlat. Discovery is live: the UDF
lists the Files/rlat/ directory in OneLake each time, so any
upload — from a notebook, a helper, or a drag-drop — shows up on the next
discovery call. (The mechanism: Fabric's wrapped lakehouse client has no
directory-listing method, so the runtime calls the underlying OneLake
List Paths REST endpoint directly. No manifest file to maintain.)
If your workspace uses a different folder convention
(Files/knowledge/, Files/data/), set
RLAT_FABRIC_KM_DIR=<dirname> on the UDF item later. The
default is rlat.
Create a User Data Function item
In the Fabric portal: New → User Data Function. Pick a
name (for example rlat-search).
Open the item, then Manage Connections → add Lakehouse.
Pick the lakehouse from the previous step and set its alias to
kmLakehouse — that's the alias the UDF code references.
Add the rlat library and publish the code
Still on the UDF item: Library Management → Public libraries →
Add from PyPI, search for rlat, and install it at
workspace scope. Pin whatever version is current (for example
==2.1.0a13) so the UDF doesn't drift unexpectedly when a new
release lands.
Then publish the code from the repo's fabric/udf/ directory.
The simplest path: open fabric/udf/ in VS Code with the
Microsoft Fabric extension, sign in, map it to your UDF item, and
Publish. The directory holds:
fabric/udf/
function_app.py # search + list_kms entry points
requirements.txt # local-emulator fallback
Test the UDF
In the UDF item, select search, set
kmName=<your km>, fill in query, and hit
Run. You should get back JSON like
{band, cold, hits[]}. The first call may take a few seconds
(cold load); subsequent calls are sub-second.
could not stat Files/rlat/<km>.rlat means the upload
path or the kmLakehouse alias isn't matching. Check the
upload location and Manage Connections.
Query from your machine
pip install 'rlat[fabric]'
rlat fabric add team=https://<your-udf-endpoint-url>
The endpoint URL is on the UDF item under Properties → Endpoint
URL. The add command writes the alias to
~/.config/rlat/fabric.toml. If you're using Claude Code, it
also scaffolds a .claude/skills/rlat-fabric-search/ entry so
the agent sees the hosted knowledge model as a tool.
rlat search fabric://team # list available KMs
rlat search fabric://team/team-docs "how do I deploy?"
rlat search fabric://team/team-docs "..." --format=context
The first call prompts an Entra device-code sign-in — a URL and code printed to stderr. Sign in once; the token caches to your OS keyring and subsequent calls are silent.
Run the demo notebook
Upload notebooks/examples/fabric_demo_udf.ipynb into your
Fabric workspace and open it. Set:
UDF_BASE_URL— your UDF's endpoint URL (the part before/functions/<name>/invoke).KM_NAME— your knowledge model (for exampleteam-docs).DEMO_QUERIES— a list of queries you want logged.
Run it. You'll see retrieval results inline, plus two Delta tables appear in the bound lakehouse:
udf_telemetry— one row per query (latency, top-1 score, cold/warm flag, refusal flag).udf_hits— one row per retrieved passage (rank, source file, drift status).
Re-run any time you want a new batch of telemetry. Both tables are append-only.
Run the analytics notebook
Upload notebooks/examples/fabric_analytics.ipynb. Set
UDF_BASE_URL to the same endpoint, leave SM_NAME
as rlat-analytics, and run.
The notebook reads udf_telemetry, udf_hits, and
the per-build JSON files under Files/.rlat-builds/. It
materialises udf_builds, rebuilds four conformed dimension
tables (dim_query, dim_source_file,
dim_km, dim_date), and deploys a Direct Lake
semantic model named rlat-analytics to your workspace.
It is idempotent — re-run after every batch of demo runs or build invocations, or schedule it via a Fabric Pipeline. The dimension tables rebuild from the fact tables each time.
Connect Power BI
Open Power BI Desktop → Get Data → Power BI semantic models →
rlat-analytics. The semantic model ships with
measures grouped under 01 Activity, 02 Quality,
03 Drift, 04 Latency, 05 Coverage,
and 06 Maintenance, joined to dim_query,
dim_source_file, dim_km, and
dim_date. Drop the measures and dimensions on the canvas to
build whatever views your team cares about — top queries, refusal rate,
latency percentiles, build cadence.
That's the whole loop.
How it stays fresh
The UDF caches the triple (.rlat contents, store, encoder)
keyed by (kmName, OneLake last_modified). Every search call
stats the OneLake .rlat (cheap); when its
last_modified changes, the cache evicts and rebuilds from the
new bytes on the next call. Re-upload the .rlat after a
rlat build or rlat refresh — or after the build
notebook runs — and the next query sees fresh results, with no UDF
redeploy.
Up to eight distinct (kmName, mtime) tuples are cached at
once; older entries fall out, least-recently-used first.
Cold-start latency
The first call after a UDF container recycle pays for:
- The
.rlatdownload from OneLake (~100–300 MB). - The encoder ONNX cache from Hugging Face (~250 MB, revision-pinned).
- The ONNX runtime warm-up and first encode.
A few seconds cold, sub-second warm — the same figures you see when
testing the UDF in section 04. The UDF returns a
cold flag so callers can tell which they paid for.
Authentication
Two paths, in priority order:
-
Service-principal env vars. If
AZURE_CLIENT_ID,AZURE_CLIENT_SECRET, andAZURE_TENANT_IDare all set, aClientSecretCredentialis used silently. This is the right choice for CI or shared machines. -
Device-code flow (default).
rlat searchprints a URL and a code to stderr. Open the URL, paste the code. The token caches to your OS keyring (libsecret, Keychain, or Credential Manager). It works inside Claude Code: the prompt comes back through the Bash tool's stdout, you complete the browser flow, and the agent's tool call resolves with the search results.
The token cache name is rlat-fabric. The scope is
https://analysis.windows.net/powerbi/api/.default — the Power
BI scope, used to invoke UDFs, not the Fabric API scope (which is for item
CRUD).
Encoder distribution
Each .rlat records the encoder revision — a Hugging Face
commit SHA — it was built with. At UDF cold-start, the runtime reads that
revision from the .rlat metadata and downloads the matching
ONNX cache from tenfingers/rlat-gte-modernbert-base-onnx,
revision-pinned. No per-workspace encoder upload.
If your tenant blocks egress to huggingface.co, set
RLAT_FABRIC_ENCODER_SOURCE=onelake on the UDF environment and
stage the encoder cache to
Files/rlat-encoders/<revision>.tar.zst instead.
What's server-side vs client-side
| Task | Server (UDF) | Client (notebook / CLI) |
|---|---|---|
| Single-shot retrieval | yes | calls into UDF |
| Discovery (list KMs) | yes | calls into UDF |
| Build / incremental refresh | — | yes (fabric_build.ipynb in Fabric, or rlat build locally + rlat fabric publish-rlat) |
| Multi-hop deep-search | — | yes (drives the loop, calls the UDF for each hop) |
| Compare between hosted KMs | — | not yet — both KMs need to be local |
Troubleshooting
fabric alias 'team' not registered— runrlat fabric add team=<url>.rlat fabric listshows what's registered.- Device-code prompt never resolves — the token cache is stuck. Delete the
rlat-fabricentry in your OS keyring and retry, or switch to service-principal env vars for one-shot use. could not stat Files/rlat/<km>.rlat— either the.rlatis missing from OneLake at the expected path, or the lakehouse aliaskmLakehouseisn't bound on the UDF item.km has empty backbone.revision in metadata— the.rlatwas built with an older rlat that didn't pin the encoder revision. Rebuild it.- Hugging Face 404 or unfamiliar encoder errors — the revision pinned in the
.rlatdoesn't have a matching commit intenfingers/rlat-gte-modernbert-base-onnx. Either rebuild the.rlatagainst a published revision, or push the encoder cache to that repo at the right revision. - The new alpha won't show up in Library Management — Fabric's PyPI metadata cache lags. Either wait, or upload the wheel directly via Library Management → Private libraries.
See also
- Storage modes — where Fabric hosting fits among bundled, local, and remote.
- CLI reference — the
fabric://URL form and therlat fabric add / list / remove / publish-rlatsubcommands.
Three example notebooks ship in the repo's
notebooks/examples/ directory: fabric_build.ipynb
(runs the build/refresh against the OneLake filesystem mount, schedulable
from a Fabric Pipeline), fabric_demo_udf.ipynb (queries the
UDF and writes the two Delta tables), and
fabric_analytics.ipynb (deploys the Direct Lake semantic
model).