1 Punkte von GN⁺ 3 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • 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

 
GN⁺ 3 시간 전
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 habe ein Wörterbuch, das Wörter auf OpenStreetMap-Tags abbildet und ungefähr so aussieht: https://codeberg.org/cartes/web/src/branch/master/components...
      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.
    • Ich bin wirklich daran interessiert, eine einfache semantische Suche in eine native Desktop-App einzubauen.
      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.
    • Ich habe gerade die komplette Django-Dokumentation und unsere interne Wissensdatenbank eingebettet und kann nun beide Quellen sofort durchsuchen.
  • 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.

    • Zustimmung. Gleichzeitig war es auch schön, an die Zeit erinnert zu werden, als man allein am Geräusch des Computers vertraut erkennen konnte, was gerade passiert.
    • Ich war erschrocken, als der Lüfter anlief. Allerdings erschreckt mich auch mein Toaster gelegentlich.
    • CPU-Zyklen bis ans Limit ausnutzen – wer sagt denn, dass nur GPUs etwas Besonderes sind?
  • 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.

    • Für unseren Static Site Generator wollte ich sqlite-vec verwenden, aber als ich zuletzt nachgesehen habe, war HNSW entweder nicht implementiert oder die Unterstützung für Vektorsuche im Browser war nicht gut. Soweit ich mich erinnere, lief es wohl immer noch auf einen vollständigen Table Scan hinaus.
      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.

    • Eine ähnliche Idee: Es könnte auch interessant sein, eine SQLite-DB auf einem statischen Host per HTTP Range Requests und WASM zu verwenden.
      https://news.ycombinator.com/item?id=27016630
    • Tolle Idee. Ich mag Range Requests und Formate, die Clients auf statischem Hosting durchsuchen können, wirklich sehr.
  • 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.

    • Klingt gut. Wenn es Möglichkeiten gibt, das zu unterstützen, oder konkrete Use Cases, die in der Roadmap berücksichtigt werden sollten, lass es mich wissen.
  • 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.

    • Ja. Man kann den Index einmal serverseitig erstellen und nur die Embeddings ans Frontend senden.