- Ternlight führt Text-Embeddings und Ähnlichkeitssuche direkt im Browser aus, ohne Serveraufrufe, und ermöglicht so den schnellen Aufbau kleiner clientseitiger semantischer Suchfunktionen
- Das Basispaket umfasst Engine und Gewichte zusammen in 7 MB, die Mini-Variante ist 5 MB groß und läuft ohne GPU auf der CPU
- Nach der Installation von
@ternlight/base lassen sich durch Import von embed und similar semantische Suchabläufe mit etwa 3 Zeilen erstellen
- Der Beispielaufruf sortiert die Top-3-Ergebnisse aus einer Rezeptliste; hervorgehoben werden rund 5 ms und keine Netzwerkaufrufe
- Die Demo zur Suche in der React-Dokumentation führt die Suche im Browser aus, sobald Nutzer eine Frage eingeben; betrieben wird sie vom 5-MB-Tier @ternlight/mini
Embeddings, die komplett im Browser bleiben
- Ternlight positioniert sich als „7-MB-Embedding-Modell“, das Texte in Millisekunden einbettet und keinen Server aufruft
-
Laufzeiteigenschaften
- Keine API-Aufrufe
- Engine + Gewichte: 7 MB
- Mini-Variante: 5 MB
- Schnelle Embeddings: etwa 5 ms
- Nur CPU, keine GPU
Installation und Nutzungsbeispiel
- Wird als einzelnes npm-Paket bereitgestellt und kann ohne separaten Modell-Download-Schritt oder Server genutzt werden
- Der Installationsbefehl lautet:
npm install @ternlight/base
- Aus
@ternlight/base werden embed und similar importiert, um semantische Suche auszuführen
import { embed, similar } from '@ternlight/base';
similar('easy weeknight dinner ideas', recipes, { topK: 3 });
// → ranked matches · ~5 ms · zero network
- Die Demo zur Suche in der React-Dokumentation führt die Suche im Browser aus, sobald Nutzer eine Frage eingeben, und läuft mit dem 5-MB-Tier @ternlight/mini
1 Kommentare
Hacker-News-Kommentare
Ich wollte als Hobbyprojekt ein nützliches Modell im Browser laufen lassen, habe daher aus MiniLM einen kleinen Satz-Encoder destilliert und ternary quantization-aware training angewendet.
Die Inferenz-Engine habe ich ebenfalls selbst geschrieben und als Rust → WASM SIMD ausgeliefert.
Es ist kein LLM, sondern ein Embedding-Modell: Gibt man Text hinein, erhält man einen 384-dimensionalen Vektor, und die Textrelevanz wird über die Kosinus-Ähnlichkeit zweier Vektoren bestimmt. Zum Beispiel kommen „reset my password“ und „I forgot my password“ auf etwa 0,88.
Es lässt sich für semantische Suche, FAQ-/Intent-Matching und Clustering nutzen; weil es on-device läuft, ist eine schnelle semantische Suche direkt bei der Eingabe möglich, ohne Abhängigkeit von APIs.
Die Demo durchsucht 2.000 React-Dokumente vollständig on-device: https://ternlight-demo.vercel.app
Auf npm gibt es zwei Stufen: @ternlight/base (7 MB, etwa 5 ms pro Embedding, bessere Embeddings) und @ternlight/mini (5 MB Transfergröße, etwa 2,5 ms pro Embedding), jeweils für Node und Browser gebündelt.
Das Repository enthält technische Details, MIT-Lizenz und die Trainings-Pipeline: https://github.com/soycaporal/ternlight
Mich interessiert, ob On-Device-Embeddings tatsächlich nützlich sind und welche Anwendungsfälle es dafür gibt.
Ich frage mich, ob es helfen könnte, dass ein Nutzer, der „pancake“ eingibt, crêpe findet, ohne dass ich explizit einen Wörterbucheintrag „pancake = crêpe“ anlegen muss.
Wenn ich es richtig verstanden habe, lädt die Library am Anfang einmal 5 MB herunter und lässt sich danach ähnlich nutzen wie derzeit Fuse.js?
Außerdem würde ich gern wissen, wie gut sie andere Sprachen als Englisch verarbeitet und ob man sie mit dem OpenStreetMap-Tag-Wiki trainieren könnte.
Mich würde interessieren, ob es Vergleiche mit anderen winzigen Embedding-Modellen gibt. Es ist schwer einzuschätzen, ob der Startpunkt MiniLM-L6 gewählt wurde, weil es in dieser Größenklasse besonders gut ist; als Metrik wird nur „Retrieval (SciFact NDCG@10)“ angegeben.
Allerdings sehe ich eine deutliche Abweichung von der behaupteten Performance: Auf einem i5-4570 in Firefox komme ich nicht auf 400, sondern nur auf 35 Embeddings pro Sekunde. Ich vermute, dass es auf einen Nicht-SIMD-Pfad zurückfällt, und werde auch das native Rust-Binary ausprobieren.
Cool, aber es wäre gut, auf der Landingpage einen Button zum Starten der Demo zu haben. Ich war ziemlich überrascht, als ich die Webseite geöffnet habe und sofort hörte, wie der Lüfter wie verrückt hochdrehte.
Es wäre schön, das als Astro- oder allgemeines Meta-Framework-Plugin zu bauen, das alle generierten HTML-Dateien automatisch parst und eine kleine Embedding-Datenbank erstellt.
Im Frontend könnte man diese lazy laden, und vielleicht ließe sich auch HNSW in Chunks speichern, sodass nur die für eine Suchanfrage benötigten Teile geladen werden müssen.
Also etwa wie https://pagefind.app/, aber mit vollständig statischer Vektorsuche.
Dass das nach Monaten oder Jahren immer noch so war, hat mich ziemlich enttäuscht, weil es wie ein Hinweis darauf wirkte, dass dem Projekt die Fähigkeit fehlt, es wirklich fertigzustellen. Zumal ich dieses Projekt bei einem Förderprogramm, auf das ich mich beworben hatte, als guten Kandidaten empfohlen hatte; sie wurden ausgewählt, ich nicht.
Falls jemand in diesem Bereich eine gute Lösung kennt oder ich bei SQLite-vec falschliege, würde ich mich über Hinweise freuen. Für unseren SSG haben wir uns im Grunde darauf festgelegt, erst noch ein paar Monate an anderer Infrastruktur zu arbeiten und es dann selbst zu bauen, falls es bis dahin nicht fertig ist.
Das könnte eine ziemlich coole Ergänzung zu einem DuckDB-HNSW-Suchprojekt sein, das ich früher hier gesehen habe: https://github.com/jasonjmcghee/portable-hnsw
Besonders spannend ist, dass die Suche über HTTP Range Requests auf statisch gehosteten Parquet-Dateien läuft.
Ich kann mir vorstellen, dass solche Dinge zu einem relativ offenen, verteilten Such-Ökosystem heranwachsen, das nicht von großen Konzernen kontrolliert wird.
https://news.ycombinator.com/item?id=27016630
Das ist wirklich cool und könnte das fehlende Puzzlestück für etwas sein, das ich früher einmal bauen wollte.
Mit https://github.com/npiesco/absurder-sql könnte man den gesamten Originalkorpus im Browser dauerhaft in IndexedDB/SQLite speichern.
Anschließend könnte man, statt alles vorab zu indexieren wie in https://weaviate.io/blog/chunking-strategies-for-rag, mit Ternlight bei Bedarf Embeddings erzeugen und cachen.
Damit würde auch Reciprocal Rank Fusion möglich, also hybride Suche, die natives SQLite-FTS5/BM25 mit der semantischen Suche von Ternlight kombiniert.
Gut gemacht.
Es wird mit 7 MB beworben, aber es gibt auch eine 5-MB-Mini-Version.
Mini nutzt intern offenbar 256-Element-Vektoren statt 384, um Platz zu sparen, und projiziert sie am Ende aus Kompatibilitätsgründen wieder auf 384.
Die Größe sinkt um ein Drittel, aber der Verlust ist nicht linear; selbst mit dem kleineren Datenpfad scheint der Informationsverlust geringer als ein Drittel zu sein.
Cooles Projekt.
Ich habe früher etwas Ähnliches versucht: http://sol.quipu-strands.com/
Ich wollte im Browser ein Embedding-Modell laden und Texte semantisch anordnen.
Ich habe ONNX-Gewichte (MPNet, MiniLM) von HuggingFace geholt, mit Transformers.js Embeddings erzeugt und dann einen Clusterer aus scikit-learn verwendet, der innerhalb der Seite über pyodide lief. Alles lief clientseitig, und ich war überrascht, dass es perfekt funktionierte.
Die Demo verhält sich ziemlich seltsam. Wenn man zum Beispiel nach „how to use typescript with createContext“ sucht, sind die Top-Ergebnisse nur Typescript-Einträge, sodass es wirkt, als würde die Ähnlichkeitssuche versagen.
Danke. Lokale Modelle werden eines Tages Privatsphäre bringen, und ich kenne bereits einen hervorragenden Anwendungsfall, der genau zu solchen kleinen Embedding-Modellen passt: günstige und schnelle Suche in Produktdatenbanken.
In meinem Fall ist auch die Abhängigkeit von der CPU ein Vorteil.
Kann man die Embedding-Erzeugung, die 30 Sekunden dauert, vorab durchführen und an den Browser schicken?
Die anschließende Inferenz ist dann schnell und gut.