ESC
Type to search...
S
Soli Docs

AI Functions

Embedding generation and LLM text completion against OpenAI-compatible endpoints. Endpoints and API keys are read from the environment, so credentials stay out of app code — one place to review where text is sent (a single point for GDPR / data-residency review).

Works with OpenAI or a self-hosted vLLM / Ollama / llama.cpp (often keyless)

embed(text)

embed(text)

Generate an embedding vector for a string — the write-side counterpart to Model.similar, which embeds the query but not the documents you store.

Parameters

text : String - text to embed

Returns

Array<Float> - the embedding vector. Raises if SOLI_EMBEDDING_API_KEY is unset or the call fails.
class Article < Model
  vector_index "embedding", dimension: 1536, metric: "cosine"

  before_save fn() {
    this.embedding = embed(this.title + "\n" + this.body)
  }
end

embed_batch(texts)

embed_batch(texts)

Embed many texts in a single request, returned in input order. Use it to back-fill embeddings over an existing collection instead of one call per row.

Parameters

texts : Array<String> - texts to embed

Returns

Array<Array<Float>> - one vector per input, in input order
articles = Article.where({ "embedding": null }).all
vectors  = embed_batch(articles.map(fn(a) a.title))
articles.each_with_index(fn(article, i) {
  article.embedding = vectors[i]
  article.save()
})

llm_generate(system, user)

llm_generate(system, user)

Chat completion via an OpenAI-compatible chat/completions endpoint.

Parameters

system : String - system prompt (role / instructions)
user : String - user prompt

Returns

String - the model's completion text. Raises if the call fails.
summary = llm_generate(
  "You summarize support tickets in one sentence.",
  ticket.body
)

Streaming: inside an sse block, out.llm_stream(system, user) streams the completion token-by-token to the browser and returns the full answer. For an answer grounded in your own data, retrieve context first with Model.rag (embed → ANN → generate, returning { answer, sources }).

rerank(query, rows)

rerank(query, rows[, { field:, limit: }])

Reorder an array of already-retrieved records by how many query tokens each one's text contains — most relevant first. Pure and offline (no LLM, no server round-trip), so it's a cheap second pass after similar / hybrid / graph_rag to bias the order toward a phrase.

Parameters

query : String - the phrase to rank by
rows : Array - records to reorder (model instances or hashes)
field : String - text field to rank on (optional; defaults to the first non-empty of content / text / summary / body / title)
limit : Int - keep only the top N after reordering (optional)

Returns

Array - the same records, reordered most-relevant first (ties keep input order)
rows = Article.similar("vector databases", "embedding", 20)
top5 = rerank("hnsw index tuning", rows, { "field": "content", "limit": 5 })

For LLM-based reranking or a stored retrieve→rerank pipeline, drop to raw SDBQL: RERANK(query, docs, { mode: "llm" }) and RAG_PIPELINE(name, @vec) via db.query.

Configuration

All AI functions read their endpoint and credentials from environment variables. The SOLI_LLM_API_KEY is optional — it is omitted from the request when unset, so keyless local servers work out of the box.

Variable Default
SOLI_EMBEDDING_API_KEY required for embed / embed_batch
SOLI_EMBEDDING_URL https://api.openai.com/v1/embeddings
SOLI_EMBEDDING_MODEL text-embedding-3-small
SOLI_LLM_URL https://api.openai.com/v1/chat/completions
SOLI_LLM_API_KEY optional (omitted when unset)
SOLI_LLM_MODEL gpt-4o-mini
SOLI_LLM_TEMPERATURE optional (only sent when set)
SOLI_LLM_MAX_TOKENS optional (only sent when set)