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).
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 promptReturns
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 byrows : 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) |