Model Macro
⚠️ Warning
HelixQL is deprecated in HelixDB v2. Queries are now written with the Rust DSL and dispatched as JSON — see the Querying guide. This section is kept as a reference for legacy HelixQL projects.
For the complete documentation index optimized for AI agents, see llms.txt.
Usage
The #[model] macro specifies which embedding model to use for Embed() calls within a query. This allows you to optimize embeddings for different use cases—such as storing documents versus searching them.
#[model("provider:model-name:task-type")]
QUERY QueryName(param: Type) =>
result <- AddV<Type>(Embed(param), {properties})
RETURN result
ℹ️ Note
The
#[model]macro overrides the default embedding model configured in yourhelix.tomlfile for that specific query.
Syntax Reference
The model string follows the format "provider:model-name:task-type":
providerThe embedding service providermodel-nameThe specific model identifiertask-typeTask optimization hint
Supported models
| Provider | Model | Task Type | Notes |
|---|---|---|---|
gemini | gemini-embedding-001 | RETRIEVAL_DOCUMENT OR RETRIEVAL_QUERY | RETRIEVAL_DOCUMENT is the default if no task type is included |
openai | text-embedding-ada-002 | Not Supported | Not recommended |
openai | text-embedding-small | Not Supported | |
openai | text-embedding-large | Not Supported |
Why use different models for storage vs. search?
Many embedding providers offer task-specific optimizations. For example, Gemini’s embedding models support task types that hint whether the text being embedded is a document (to be stored and searched) or a query (used to search documents).
RETRIEVAL_DOCUMENT- Optimized for embedding documents that will be stored and retrieved laterRETRIEVAL_QUERY- Optimized for embedding search queries that find relevant documents
Using the appropriate task type can improve search relevance and retrieval quality.
⚠️ Warning
All vectors in a vector type must have the same dimensions. When using different task types, ensure both use the same model (e.g.,
gemini-embedding-001) so the dimensions match.
Example: Document Storage vs. Search
This example shows how to use different task types for storing clinical notes versus searching them.
#[model("gemini:gemini-embedding-001:RETRIEVAL_DOCUMENT")]
QUERY addClinicalNote (text: String) =>
note <- AddV<ClinicalNote>(Embed(text), {text: text})
RETURN note
#[model("gemini:gemini-embedding-001:RETRIEVAL_QUERY")]
QUERY searchClinicalNotes (query: String, k: I64) =>
notes <- SearchV<ClinicalNote>(Embed(query), k)
RETURN notes
V::ClinicalNote {
vector: [F64],
text: String
}
GEMINI_API_KEY=your_api_key
Here’s how to run the queries using the SDKs or curl:
from helix.client import Client
client = Client(local=True, port=6969)
# Store clinical notes with RETRIEVAL_DOCUMENT optimization
notes = [
"Patient presents with acute lower back pain radiating to left leg.",
"Follow-up visit: Blood pressure 120/80, heart rate normal.",
"MRI results show mild disc herniation at L4-L5 level."
]
for note in notes:
client.query("addClinicalNote", {"text": note})
# Search with RETRIEVAL_QUERY optimization
results = client.query("searchClinicalNotes", {
"query": "back pain symptoms",
"k": 5
})
print(results)
use helix_rs::{HelixDB, HelixDBClient};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = HelixDB::new(Some("http://localhost"), Some(6969), None);
// Store clinical notes with RETRIEVAL_DOCUMENT optimization
let notes = vec![
"Patient presents with acute lower back pain radiating to left leg.",
"Follow-up visit: Blood pressure 120/80, heart rate normal.",
"MRI results show mild disc herniation at L4-L5 level."
];
for note in ¬es {
let _inserted: serde_json::Value = client.query("addClinicalNote", &json!({
"text": note
})).await?;
}
// Search with RETRIEVAL_QUERY optimization
let results: serde_json::Value = client.query("searchClinicalNotes", &json!({
"query": "back pain symptoms",
"k": 5
})).await?;
println!("Search results: {results:#?}");
Ok(())
}
package main
import (
"fmt"
"log"
"github.com/HelixDB/helix-go"
)
func main() {
client := helix.NewClient("http://localhost:6969")
// Store clinical notes with RETRIEVAL_DOCUMENT optimization
notes := []string{
"Patient presents with acute lower back pain radiating to left leg.",
"Follow-up visit: Blood pressure 120/80, heart rate normal.",
"MRI results show mild disc herniation at L4-L5 level.",
}
for _, note := range notes {
payload := map[string]any{"text": note}
var inserted map[string]any
if err := client.Query("addClinicalNote", helix.WithData(payload)).Scan(&inserted); err != nil {
log.Fatalf("addClinicalNote failed: %s", err)
}
}
// Search with RETRIEVAL_QUERY optimization
searchPayload := map[string]any{
"query": "back pain symptoms",
"k": int64(5),
}
var results map[string]any
if err := client.Query("searchClinicalNotes", helix.WithData(searchPayload)).Scan(&results); err != nil {
log.Fatalf("searchClinicalNotes failed: %s", err)
}
fmt.Printf("Search results: %#v\n", results)
}
import HelixDB from "helix-ts";
async function main() {
const client = new HelixDB("http://localhost:6969");
// Store clinical notes with RETRIEVAL_DOCUMENT optimization
const notes = [
"Patient presents with acute lower back pain radiating to left leg.",
"Follow-up visit: Blood pressure 120/80, heart rate normal.",
"MRI results show mild disc herniation at L4-L5 level."
];
for (const note of notes) {
await client.query("addClinicalNote", { text: note });
}
// Search with RETRIEVAL_QUERY optimization
const results = await client.query("searchClinicalNotes", {
query: "back pain symptoms",
k: 5
});
console.log("Search results:", results);
}
main().catch((err) => {
console.error("Query failed:", err);
});
# Store clinical notes
curl -X POST \
http://localhost:6969/addClinicalNote \
-H 'Content-Type: application/json' \
-d '{"text":"Patient presents with acute lower back pain radiating to left leg."}'
curl -X POST \
http://localhost:6969/addClinicalNote \
-H 'Content-Type: application/json' \
-d '{"text":"Follow-up visit: Blood pressure 120/80, heart rate normal."}'
curl -X POST \
http://localhost:6969/addClinicalNote \
-H 'Content-Type: application/json' \
-d '{"text":"MRI results show mild disc herniation at L4-L5 level."}'
# Search clinical notes
curl -X POST \
http://localhost:6969/searchClinicalNotes \
-H 'Content-Type: application/json' \
-d '{"query":"back pain symptoms","k":5}'
⚠️ Warning
Make sure to set your
GEMINI_API_KEYenvironment variable (orOPENAI_API_KEYfor OpenAI models) in the same location as yourqueries.hx,schema.hx, andconfig.hx.jsonfiles.
Best Practices
Use consistent models for the same vector type
Always use the same embedding model for all queries that operate on the same vector type. Different models produce vectors with different dimensions, which will cause errors.
// Good - same model, different task types
#[model("gemini:gemini-embedding-001:RETRIEVAL_DOCUMENT")]
QUERY storeDoc (text: String) => ...
#[model("gemini:gemini-embedding-001:RETRIEVAL_QUERY")]
QUERY searchDocs (query: String, k: I64) => ...
// Bad - different models for same vector type
#[model("gemini:gemini-embedding-001:RETRIEVAL_DOCUMENT")]
QUERY storeDoc (text: String) => ...
#[model("openai:text-embedding-3-small")]
QUERY searchDocs (query: String, k: I64) => ...
Match task types to operations
Use RETRIEVAL_DOCUMENT for operations that store data and RETRIEVAL_QUERY for operations that search data.
// Storing documents
#[model("gemini:gemini-embedding-001:RETRIEVAL_DOCUMENT")]
QUERY addDocument (content: String) =>
doc <- AddV<Document>(Embed(content), {content: content})
RETURN doc
// Searching documents
#[model("gemini:gemini-embedding-001:RETRIEVAL_QUERY")]
QUERY findDocuments (query: String, limit: I64) =>
docs <- SearchV<Document>(Embed(query), limit)
RETURN docs
Consider using the default model for simple cases
If you don’t need task-specific optimization, you can skip the #[model] macro and use the default model from your config.hx.json.
// Uses default model from config.hx.json
QUERY simpleSearch (text: String, k: I64) =>
results <- SearchV<Document>(Embed(text), k)
RETURN results
Related Documentation
-
Embedding Vectors — Learn how to use the Embed function for automatic text embedding
-
Vector Search — Perform similarity search on vector data
-
MCP Macro — Expose queries as MCP endpoints for AI agents
-
AddV — Create new vector entries with embeddings