Documentation
¶
Overview ¶
Package gomlx provides an in-process sentence embedder for jess memory, backed by the pure-Go gomlx/compute/gobackend ML runtime.
Status: experimental. Tests download ~90MB of model weights and take a few seconds to warm up; CI skips them with -short.
Index ¶
Constants ¶
const ( DefaultModelID = "sentence-transformers/all-MiniLM-L6-v2" DefaultDim = 384 DefaultSeqLen = 128 )
Legacy defaults kept for callers that referenced them directly. New code should prefer DefaultModel (models.go) — it bundles the three together and matches the same MiniLM target.
Variables ¶
var ( ModelMiniLM_L6_V2 = Model{ ID: "sentence-transformers/all-MiniLM-L6-v2", Dim: 384, SeqLen: 128, } ModelMiniLM_L12_V2 = Model{ ID: "sentence-transformers/all-MiniLM-L12-v2", Dim: 384, SeqLen: 128, } ModelMpNetBase_V2 = Model{ ID: "sentence-transformers/all-mpnet-base-v2", Dim: 768, SeqLen: 384, } ModelBGESmall_EN_V1_5 = Model{ ID: "BAAI/bge-small-en-v1.5", Dim: 384, SeqLen: 512, } ModelBGEBase_EN_V1_5 = Model{ ID: "BAAI/bge-base-en-v1.5", Dim: 768, SeqLen: 512, } ModelBGELarge_EN_V1_5 = Model{ ID: "BAAI/bge-large-en-v1.5", Dim: 1024, SeqLen: 512, } ModelE5Small_V2 = Model{ ID: "intfloat/e5-small-v2", Dim: 384, SeqLen: 512, } ModelE5Base_V2 = Model{ ID: "intfloat/e5-base-v2", Dim: 768, SeqLen: 512, } ModelNomicEmbedText_V1_5 = Model{ ID: "nomic-ai/nomic-embed-text-v1.5", Dim: 768, SeqLen: 8192, } ModelMxbaiEmbedLarge_V1 = Model{ ID: "mixedbread-ai/mxbai-embed-large-v1", Dim: 1024, SeqLen: 512, } )
Known-good embedding models verified working against the GoMLX pure-Go (simplego) backend. All are sentence-transformer or sentence-transformer-compatible models with vocab.txt + onnx/model.onnx in their HF repo.
Performance ordering (fastest → highest quality) and size notes are approximate, measured on Apple M-series CPU:
MiniLM_L6_V2 — ~20ms/call, 90MB, 384-dim, baseline quality BGESmall_EN_V1_5 — ~25ms/call, 130MB, 384-dim, slightly better E5Small_V2 — ~30ms/call, 130MB, 384-dim, similar to BGE BGEBase_EN_V1_5 — ~80ms/call, 440MB, 768-dim, strong quality MpNetBase_V2 — ~80ms/call, 440MB, 768-dim, longstanding default NomicEmbedText — ~150ms/call, 550MB, 768-dim, long-context (8K) MxbaiEmbedLarge — ~250ms/call, 670MB, 1024-dim, best quality BGELarge_EN_V1_5 — ~250ms/call, 1.3GB, 1024-dim, comparable to mxbai
Memory write/read in jess is one embedding per call, so latency matters but not enormously. Quality vs disk footprint is the real choice axis. Default (MiniLM) is the right pick when in doubt — small, fast, well-understood, good enough for the retrieve-relevant-notes-from-a-personal-corpus use case.
var DefaultModel = ModelMiniLM_L6_V2
DefaultModel is what NewEmbedder uses when Options is left fully empty. Conservative pick: small, fast, well-understood, works for the common case.
Functions ¶
This section is empty.
Types ¶
type Embedder ¶
type Embedder struct {
// contains filtered or unexported fields
}
Embedder runs sentence-transformers BERT-style embedding models in-process via the pure-Go gomlx/compute/gobackend backend. No subprocess, no external runtime (no .so, no ONNX Runtime), no CGO — talon's single-binary cross-compile story stays intact.
Construction downloads the model + vocab from HuggingFace on first use (cached under HF's standard location: $HF_HOME or ~/.cache/huggingface). Subsequent constructions are warm.
Concurrency: Embed is safe to call from multiple goroutines. The internal exec is shared and protected by a mutex — running embeddings serially for now since gobackend's reentrancy isn't well-characterized and memory writes don't need parallelism.
func NewEmbedder ¶
NewEmbedder downloads + loads a sentence-transformers model and returns an in-process Embedder ready to call.
func (*Embedder) Embed ¶
Embed produces one vector per input text. Implements memory.Embedder.Embed for single-text calls; use EmbedBatch when you have multiple sentences to amortize the model call.
func (*Embedder) EmbedBatch ¶
EmbedBatch produces one vector per sentence. The model graph was built for a fixed batch dimension at construction time; mismatched batch sizes trigger a re-build (slow). For now batches are always 1 — talon's memory writes are one-at-a-time and recall queries one-at-a-time. Multi-batch support is a TODO.
type Model ¶
Model bundles the three things callers need to use an embedding model: the HuggingFace repo ID, the output dimensionality, and the model's positional-embedding limit. Bundling avoids the footgun of passing ModelID alone and forgetting to update Dim.
Pass to Options.Model to construct an Embedder against a known-good model:
emb, _ := gomlx.NewEmbedder(gomlx.Options{Model: gomlx.ModelNomicEmbedText})
Hosts that want a model not on the short list pass ModelID directly and let NewEmbedder auto-detect Dim/SeqLen from the repo's config.json. Pass Dim/SeqLen explicitly when you want to override the auto-detected values.
type Options ¶
type Options struct {
// Model bundles ID/Dim/SeqLen as one value. Highest-precedence
// way to specify the model. Use the canonical constants
// (gomlx.ModelMiniLM_L6_V2, gomlx.ModelNomicEmbedText_V1_5,
// etc.) for known-good targets, or build your own Model
// literal for a HF repo not on the list.
Model Model
// ModelID is the HuggingFace repo (e.g.
// "sentence-transformers/all-MiniLM-L6-v2"). Used when Model
// is the zero value. When Dim/SeqLen below are zero,
// NewEmbedder auto-detects them from the repo's config.json.
ModelID string
// Dim is the embedding dimensionality the model produces.
// When zero (and Model is unset), auto-detected from
// config.json's hidden_size.
Dim int
// SeqLen is the fixed token length the model graph is built
// for. When zero (and Model is unset), auto-detected from
// config.json's max_position_embeddings. Longer texts are
// truncated; shorter are padded.
SeqLen int
// AuthToken is the HuggingFace token (HF_TOKEN env). Required
// only for gated repos; public models load without it.
AuthToken string
}
Options configures NewEmbedder. Resolution order, highest precedence first:
- Model (a bundled ID/Dim/SeqLen triple) — use one of the known-good constants (ModelNomicEmbedText, etc.).
- ModelID + Dim + SeqLen all set — explicit override.
- ModelID set with Dim/SeqLen zero — auto-detect Dim/SeqLen from the model's HuggingFace config.json (one extra ~5KB download on first run; cached after).
- Everything empty — falls back to DefaultModel (MiniLM-L6-v2).
Resolution happens BEFORE the model download — invalid combinations surface as construction errors, not silent wrong-vector bugs.