Semantic Embeddings
Embedding vectors are used by three services in the CRISalid AI stack:
- IKG stores embedding vectors directly on graph nodes, enabling vector similarity search in Neo4j. Vectors are computed offline, in batch, after each write that produces embeddable nodes (document titles, abstracts, etc.).
- CRISalid Agents computes embeddings on demand at query time to power semantic tools such as
publications-by-theme, which searches the graph by semantic similarity rather than exact keyword matching. - CRISalid Taxi embeds the OpenAlex taxonomy once at startup and the documents it is asked to classify, to assign topics by semantic similarity (see Topics classification).
All three services use the same embedding endpoint and model — configured once in the shared .env.
For IKG, embedding computation is opt-in. Eligible nodes are labelled in the graph regardless of whether computation is enabled, so you can populate the graph first and add embeddings later — no rebuild required.
IKG-specific configuration
The following variables are specific to IKG and are set in docker/ikg/.env:
# Enable batch embedding computation in the IKG service (default: false)
EMBEDDING_ENABLED=true
# Must match the model's actual output size; used to configure the Neo4j vector index.
# Common values: 384 (multilingual-e5-small), 768 (e5-base), 1024 (bge-m3), 1536 (OpenAI ada-002)
EMBEDDING_DIMENSIONS=1024
# Number of texts sent per request. Must not exceed the server's max-client-batch-size.
EMBEDDING_BATCH_SIZE=32
CRISalid Taxi-specific configuration
Set in docker/crisalid-taxi/.env:
# Number of texts sent per request. Must not exceed the server's max-client-batch-size.
TAXI_EMBEDDING_BATCH_SIZE=32
The default similarity threshold (TAXI_SIMILARITY_THRESHOLD) is calibrated for bge-m3; recalibrate it when changing the embedding model.
Computing embeddings (IKG)
Once enabled, embeddings are updated automatically after each write that produces embeddable nodes. For an existing graph, or to reprocess failed nodes, run the CLI inside the running container:
# Process all pending and failed nodes (default)
docker compose exec crisalid-ikg python -m app.cli literals compute-embeddings
# Restrict to specific literal types (e.g. titles and abstracts only)
docker compose exec crisalid-ikg python -m app.cli literals compute-embeddings \
--types document_title,document_abstractThe command prints status counts before and after:
Embedding status counts: {'pending': 42831, 'success': 0}
...
Done. Embedding status counts after: {'success': 42831}
Changing the embedding model
If you switch to a model with a different output dimension, update EMBEDDING_API_MODEL in the common .env and EMBEDDING_DIMENSIONS in docker/ikg/.env, restart the stack, then rebuild the vector index:
docker compose exec crisalid-ikg python -m app.cli literals compute-embeddings \
--recreate-vector-indexes--recreate-vector-indexes resets all embeddings and recomputes them from scratch. The graph remains usable during reprocessing; vector search results will be partial until all nodes are processed.