Skip to main content

Embeddings and clustering

Use dataset clustering to explore unscored data, or attach an embedding config to a hosted evaluation to explore scored rows. Both workflows use the transform.embed_project operation, which preserves row identity and adds a nested embed column containing 2D coordinates, cluster labels and pipeline provenance. High-dimensional vectors are not persisted in run output.

Supported data​

SchemaEmbedding taskInput
gdi_text_v1single_turn_llmPrompt and expected output when present
gdi_text_v1single_turn_ragPrompt and retrieved context
gdi_image_v1classificationWhole image
gdi_image_v1detectionObject appearance, box layout or both

The task identifiers in the table determine the embedding method. Multi-turn text and segmentation embeddings are unsupported. Detection pools objects into one vector per image, so one plotted point represents an image, not an individual box.

Dataset clustering accepts 25 to 10,000 rows. Project configs may impose a lower maximum. Availability also depends on access and the computation operation being registered and ready in your environment.

Cluster a dataset version​

Before you begin, configure SDK authentication and select an existing dataset version that you have permission to edit. This example sends requests to a running AIP deployment.

import aip_sdk as aip

aip.init()
dataset = aip.load_dataset(id="DATASET_ID")
clusters = dataset.clusters("VERSION_ID")
availability = clusters.availability()
if not availability.available:
raise SystemExit(availability.reason)

try:
run = clusters.run()
print(run.id) # Retain this ID to resume polling.
result = clusters.wait(run.id, timeout=600)
print(result.pipeline_id, result.pipeline, result.noise_rows)
except aip.DatasetClustersTimeoutError:
raise SystemExit("Polling timed out. Resume with clusters.wait(run.id).")
except aip.AipError as exc:
raise SystemExit(str(exc)) from exc

If the project has an embedding configuration, omit min_cluster_size to use its configured value. Pass min_cluster_size explicitly to override the minimum number of rows in each group. This setting does not determine how many clusters the operation creates. If the project has no embedding configuration, AIP uses its default unsupervised configuration.

Dataset clustering runs one unsupervised pipeline. It ignores supervised pipelines and selects the first unsupervised pipeline when sorted by derived pipeline ID. If a legacy configuration contains no unsupervised pipeline, AIP uses the default configuration.

AIP saves the resolved configuration with the clustering run. Later changes to the project configuration do not alter existing results.

The dataset dashboard displays saved points, including noise. Inspect result.pipeline for the stored model, projection, clustering and diagnostics; older results may omit provenance fields. A successful computation may contain only noise. Reading saved results does not require the operation to be available.

A workspace permits one active clustering job. Repeating its version and settings returns that job; a conflicting request raises ConflictError. Polling timeout does not cancel computation. Call clusters.get_run(run.id) to inspect status or resume clusters.wait(run.id). After an uncertain start response, check clusters.latest_run() before submitting again. Unsupported data or unavailable computation raises UnprocessableEntityError; a failed job raises RunFailedError.

Project a scored run​

Pass a config dictionary as embeddings= to aip.run. This requires a hosted SUT, connection and compatible metrics. The following live-only example uses an existing text project, dataset and connection.

import aip_sdk as aip

aip.init()
hosted_config = {
"embeddings": {"qa": {"modality": "text", "task_type": "single_turn_llm"}},
"projections": {"unsup": {}},
"clusterings": {"default": {"min_cluster_size": 5}},
"pipelines": [
{"embedding": "qa", "projection": "unsup", "clustering": "default"}
],
}

with aip.run(
project="PROJECT_ID",
dataset="DATASET_ID@v1",
sut_id="SUT_ID",
connection_id="CONNECTION_ID",
metrics=["llm.bleu"],
embeddings=hosted_config,
) as run:
run.poll_status(interval=5, timeout=600)

print(run.embeddings.pipeline_ids)
coordinates = run.embeddings.coordinates

An embedding configuration combines three steps: embedding, projection and clustering. AIP derives each pipeline ID from its selected steps, producing IDs such as umap.qa.unsupervised.

Within one computation, pipelines that use the same embedding reuse the cached embedding chunks instead of computing them again. Every configuration must include at least one unsupervised pipeline as a baseline. Supervised projections can use an available per-row metric to guide the layout. Compare a supervised layout with the unsupervised baseline to understand how the selected metric affected the projection.

The platform snapshots the config when creating the run. Omitting embeddings= or passing None inherits a project default when one exists. Clear that default with project.set_embedding_config(None) to stop inheriting it.

Reading hosted coordinates requires no embeddings extra. Dictionary configs such as hosted_config work with aip.run(embeddings=...) without importing the local embedding library.

Optional local preview requires the SDK's [embeddings] extra, the relevant modality dependencies and a typed EmbedProjectConfig. compute() does not accept a dictionary. Convert the hosted config before passing it to local preview:

# Local-only: install the embedding dependencies and provide a compatible df.
from aip_embeddings_core import EmbedProjectConfig

local_config = EmbedProjectConfig.model_validate(hosted_config)
result = aip.embeddings.compute(df, local_config)

Inspect failures and save categories​

A configuration can request several projections. If one pipeline fails, AIP keeps the coordinates from the pipelines that succeeded. For a hosted run, run.embeddings.pipelines lists every configured pipeline — a failed one carries status="failed" and its error, so you no longer need to compare IDs to spot a missing projection. run.embeddings.pipeline_ids remains the succeeded subset. For local preview, inspect result.failed for pipeline errors.

If no pipeline produces coordinates, the embedding operation fails. Evaluation scoring is separate: a hosted run can finish scoring successfully but have no saved embedding coordinates. In that case, run.embeddings.coordinates raises EmbeddingsError. Check that the expected pipeline IDs and coordinates are present before using the embedding plot; a completed evaluation status alone is insufficient.

Use Clusters to inspect the saved projection, filter categories through the legend or draw a lasso. The run explorer also offers numeric colouring and CSV export. Performance by category is on Explore, with Table and Chart views over the same grouped results. Preview filtering shows full dataset rows.

To persist clustered categories from a completed run:

# Live-only: run must contain a successful pipeline with non-noise labels.
saved = run.embeddings.save_clusters("semantic_groups", "umap.qa.unsupervised")
print(saved.id, saved.assigned_rows, saved.unassigned_rows)

Noise and null cluster labels are omitted. Saving an all-noise pipeline raises EmbeddingsError. Saving a name again replaces its assignments. See Assigned dimensions for scope, authorship and coverage on later versions.