Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.
Managed agents are only available on Enterprise plans.
A project with thousands of traces holds patterns no single trace shows you. Some are what users keep asking for, some are the ways your agent keeps failing, and neither shows up in a latency chart. A managed agent can read the whole project, summarize each trace, group the summaries into named patterns, and write those patterns back onto the traces as annotations so you can filter by them.Arize AX offers three other ways to turn traces into named patterns: Arize Skills in your coding agent, Alyx in the product, or manual annotation. A managed agent works through traces in one unattended run.
You will start a managed agent session against a tracing project, hand it a prompt that describes a summarize-and-cluster pipeline, and read the patterns it finds. The agent runs four stages: it summarizes each trace in a sentence using its own model, turns those summaries into vectors, reduces the vectors to a few dimensions, and clusters the result. It names each cluster and annotates the traces in it with that name, so you can then filter your traces by pattern.This guide is for builders who already have tracing projects in Arize AX and have managed agents enabled on their account. No prior experience with managed agents is required.You should be comfortable with:
Tracing projects in Arize AX, and reading traces in the UI
Each run happens in a sandbox, an isolated container that Arize AX tears down afterward. What the agent can reach is fixed before the run starts, and the prompts below are written to fit those limits:
Capability
Detail
Your traces
The agent reads spans through the Arize AX API, over a time window you choose rather than a whole project at once.
Project scope
The agent’s credentials cover your entire space, so name the project you want analyzed in the prompt.
Python
A plain interpreter with nothing extra installed.
More packages
The agent can install libraries only when a GitHub repo is attached to the run.
Summarization
The agent’s own model calls. No embedding model is reachable, so the vectors have to come from the text of the summaries.
Writing back
The agent can create an annotation config and label spans for you, but it cannot change a config once one exists.
Deliverables
Files the agent saves as deliverables outlive the sandbox.
Which pipeline you can ask for comes down to one thing: whether a GitHub repo is attached to the run, because that is what opens PyPI.With a repo attached, the agent installs scikit-learn and UMAP and clusters with the libraries built for the job, which produces tighter clusters and handles more traces per run.Without a repo, every step has to be computable with the standard library, and requires no repo setup. It is recommended for batches of up to a few thousand traces. Past a few thousand, narrow the time window or attach a repo.Both routes produce the same summaries, the same annotation config, and the same filters. Only vectorizing and clustering differ.
Three methods carry the pipeline, all computable with the standard library:
TF-IDF weighs each word by how often it appears in one summary against how rare it is across all of them, turning short summaries into vectors with nothing downloaded.
Spectral reduction takes the top eigenvectors of the trace-by-trace similarity matrix, which is classical multidimensional scaling on the cosine kernel. Sparse text vectors cluster poorly at full width, and this is the part UMAP would do if you could install it.
Average-link agglomerative clustering merges the closest pair of clusters until nothing is similar enough to join, so you set a similarity threshold rather than a cluster count.
1
Start a session in Agent Studio
Open Observe → Signal & Agents → + New Agent and choose Start from scratch. Then:
Select the tracing project you want analyzed. This is the project the agent reads and annotates.
Leave the agent config as None.
Configuring a run in Agent Studio: selecting a project, and the agent config, skill, and repo options this pipeline leaves alone
2
Give it the pipeline as a prompt
Paste this as the task prompt. It describes the pipeline in stages, and each stage names its own output so the agent cannot quietly skip one. Replace <project> with your project’s name first; $ARIZE_SPACE_ID is already set inside the sandbox, so leave it as written.
Find the recurring patterns in this project's traces, then label the traces with them.Sandbox constraints: PyPI is not reachable, so do not try to install anything.Use only the Python standard library; /usr/bin/python3 is 3.13 with nothird-party packages. There is no embedding API reachable from here either. Ifsomething you need is genuinely unavailable, stop and tell me rather thansubstituting a different method.1. Export spans with `ax spans export <project> --days 30 --limit 5000 --stdout`. Do not use `--all`: bulk export needs Arrow Flight, which this sandbox blocks. `--limit` defaults to 100, so always set it high enough to cover the window, and if the result comes back exactly at the limit, narrow `--days` and export in several passes rather than accepting a truncated set. Group the spans by `context.trace_id`. For each trace keep the root span's `context.span_id`, `attributes.input.value`, `attributes.output.value`, its `start_time`, the `attributes.tool.name` of any child tool spans, and `status_message` for any span whose `status_code` is ERROR. Report how many spans you exported and how many distinct traces they cover, and work through all of them rather than a sample.2. Summarize each trace in under 25 words: what the user wanted, what the agent did, and how it ended. Give intent and outcome equal weight, and state a success as plainly as a failure. No order IDs, emails, or other incidental detail, and no boilerplate tail such as "no errors occurred".3. Turn the summaries into vectors with tf-idf: - lowercase, split on non-letters, drop tokens under 3 characters - drop tokens appearing in only one summary, and tokens appearing in more than half of them - weight each token as (1 + log(count in summary)) * log(total summaries / summaries containing it) - L2-normalize every vector4. Reduce before clustering. Compute the trace-by-trace cosine similarity matrix, double-center it, then take its top 10 eigenvectors by power iteration with deflation, each scaled by the square root of its eigenvalue. Re-normalize the resulting 10-dimensional rows.5. Cluster in that reduced space with average-link agglomerative merging on cosine similarity: merge the two closest clusters while their average-link similarity is at least 0.30. Break ties by lowest trace index so repeat runs are identical.6. Any cluster holding fewer than 3 traces is not a pattern. Give those traces the slug `unclustered`, and report how many there are.7. Name each cluster in under 10 words. Give each one a slug to use as a label: lowercase, hyphenated, 30 characters or less.8. Write /workspace/.artifacts/patterns.json with one object per cluster: slug, name, trace count, earliest and latest trace timestamp, and three example trace summaries. Then report in your reply: total traces, cluster count, unclustered count, and the largest and smallest cluster size.9. Set up the annotation config. Check first with `ax annotation-configs get pattern --space $ARIZE_SPACE_ID`. - If it does not exist, create it with `ax annotation-configs create --name pattern --space $ARIZE_SPACE_ID --type CATEGORICAL` and one `--value <slug>` per cluster, plus `--value unclustered`. - If it already exists, use the slugs it already lists. Match each cluster to the closest existing slug and reuse it, and label any cluster with no good match `unclustered`. Do not create a second config under another name, and do not try to amend this one: config names are unique per space, and the `ax` build here cannot update a config's values. Report any cluster you had to leave unlabelled so I can widen the config myself. The type must be uppercase, labels are capped at 30 characters, and a categorical config needs between 2 and 100 values.10. Annotate the traces. Build a JSON array of records, one per root span: {"record_id": "<root span id>", "values": [{"name": "pattern", "label": "<slug>", "text": "<that trace's summary>"}]} then run `ax spans annotate <project> --space $ARIZE_SPACE_ID --file <path> --days 31`. Send at most 1000 records per request. Every span id has to fall inside the day window or the whole request is rejected, and the window cannot exceed 31 days, so keep the export window inside that limit too.Finally, tell me which clusters are ordinary demand, which are failures, andwhich are requests the agent has no way to satisfy.
The diagnostics in steps 6 and 8 are what let you audit the result. Compare the reported trace count against your project’s actual volume, because an agent that quietly worked on a subset produces labels that look complete and undercount every pattern. A cluster confined to a single hour is an incident rather than a pattern, which is why each one carries a time range.Click Run session.
Attaching a repo opens PyPI, which lets the agent install the clustering libraries. The repo’s contents are never used: attaching one is only what changes the sandbox’s egress rules, so any repo you can access works.Three methods carry the pipeline, each from a library the agent installs:
TF-IDF weighs each word by how often it appears in one summary against how rare it is across all of them, turning short summaries into vectors. scikit-learn also drops common English words, which sharpens the contrast between summaries.
UMAP reduces those vectors to a handful of dimensions, keeping summaries that share vocabulary near each other. Sparse text vectors cluster poorly at their full width.
HDBSCAN groups the reduced vectors by density. You never say how many patterns to expect, and it labels traces that fit no cluster as noise rather than forcing them into one. min_cluster_size sets the smallest group it will call a cluster.
1
Connect GitHub and set the repo
Open Observe → Signal & Agents → + New Agent, and choose Start from scratch, then:
Select the tracing project you want analyzed. This is the project the agent reads and annotates.
Leave the agent config as None, or choose an agent config with a repo attached.
Authorize GitHub next to the Repo field. If an Install GitHub App button is offered, use it and then pick your repository from the list, which attaches the integration for you. Otherwise click + Add skill, choose GitHub, and paste a personal access token as GH_TOKEN with repo read scope.
If you went the token route, set Repo to org/repo.
The repo field is ignored unless a GitHub skill is attached.
Already have an agent config with a GitHub skill and repo? Pick it from the agent config menu instead and skip this step. Binding one hides the ad-hoc skills picker, because the run inherits its skills and repo.
2
Give it the pipeline as a prompt
Paste this as the task prompt. Replace <project> with your project’s name first; $ARIZE_SPACE_ID is already set inside the sandbox, so leave it as written.
Find the recurring patterns in this project's traces, then label the traces with them.A repo is attached to this run, so PyPI is reachable. Create a virtualenv with`uv venv` and install scikit-learn and umap-learn into it, and use thatvirtualenv for every script below. Use scikit-learn's own HDBSCAN(sklearn.cluster.HDBSCAN) rather than the standalone hdbscan package, whichneeds a compiler. If an install fails, stop and tell me rather than falling backto a different method.1. Export spans with `ax spans export <project> --days 30 --limit 5000 --stdout`. Do not use `--all`: bulk export needs Arrow Flight, which this sandbox blocks. `--limit` defaults to 100, so always set it high enough to cover the window, and if the result comes back exactly at the limit, narrow `--days` and export in several passes rather than accepting a truncated set. Group the spans by `context.trace_id`. For each trace keep the root span's `context.span_id`, `attributes.input.value`, `attributes.output.value`, its `start_time`, the `attributes.tool.name` of any child tool spans, and `status_message` for any span whose `status_code` is ERROR. Report how many spans you exported and how many distinct traces they cover, and work through all of them rather than a sample.2. Summarize each trace in under 25 words: what the user wanted, what the agent did, and how it ended. Give intent and outcome equal weight, and state a success as plainly as a failure. No order IDs, emails, or other incidental detail, and no boilerplate tail such as "no errors occurred".3. Vectorize the summaries with TfidfVectorizer, sublinear_tf=True, min_df=2, max_df=0.5, and stop_words="english".4. Reduce with UMAP: metric="cosine", n_components=5, n_neighbors of roughly the square root of the trace count, and a fixed random_state so repeat runs match.5. Cluster the reduced vectors with HDBSCAN, min_cluster_size=5 and min_samples=1.6. Traces HDBSCAN labels -1 are noise. Give them the slug `unclustered`, and report how many there are.7. Name each cluster in under 10 words. Give each one a slug to use as a label: lowercase, hyphenated, 30 characters or less.8. Write /workspace/.artifacts/patterns.json with one object per cluster: slug, name, trace count, earliest and latest trace timestamp, and three example trace summaries. Then report in your reply: total traces, cluster count, unclustered count, and the largest and smallest cluster size.9. Set up the annotation config. Check first with `ax annotation-configs get pattern --space $ARIZE_SPACE_ID`. - If it does not exist, create it with `ax annotation-configs create --name pattern --space $ARIZE_SPACE_ID --type CATEGORICAL` and one `--value <slug>` per cluster, plus `--value unclustered`. - If it already exists, use the slugs it already lists. Match each cluster to the closest existing slug and reuse it, and label any cluster with no good match `unclustered`. Do not create a second config under another name, and do not try to amend this one: config names are unique per space, and the `ax` build here cannot update a config's values. Report any cluster you had to leave unlabelled so I can widen the config myself. The type must be uppercase, labels are capped at 30 characters, and a categorical config needs between 2 and 100 values.10. Annotate the traces. Build a JSON array of records, one per root span: {"record_id": "<root span id>", "values": [{"name": "pattern", "label": "<slug>", "text": "<that trace's summary>"}]} then run `ax spans annotate <project> --space $ARIZE_SPACE_ID --file <path> --days 31`. Send at most 1000 records per request. Every span id has to fall inside the day window or the whole request is rejected, and the window cannot exceed 31 days, so keep the export window inside that limit too.Finally, tell me which clusters are ordinary demand, which are failures, andwhich are requests the agent has no way to satisfy.
min_cluster_size is the number to scale with volume. Leaving it low on a large project fragments patterns that belong together.Click Run session.
If your account restricts annotation config creation, create the config yourself before the run and paste its allowed values into step 9 in place of the create instruction:
Follow the transcript from the session detail slide-over, opened from the Agent List tab under Signal & Agents. The run exports spans, writes summaries, reduces and clusters them, then reports a named pattern for every cluster with the number of traces in it. The example below comes from a customer support agent:
Pattern
Traces
billing-escalation-failed
32
order-billing-limited-access
30
damaged-gear-needs-info
16
order-not-found
14
legacy-pwd-reset-failure
12
defective-item-no-tools
11
item-resolved-with-tools
9
cancel-modify-order-failed
6
unclustered
1
Read past the labels to the counts and examples. In this example the largest patterns are the ones the agent exists to handle, and the interesting ones are smaller: a dependency that fails for one class of input, and requests the agent has no tool to satisfy. That last kind never shows up in an error rate, because from the agent’s side those runs succeeded. It just quietly could not help.Notice that these labels lean on outcome rather than intent: one kind of request split into separate patterns according to whether it succeeded. That is the pipeline working as intended, and it is worth knowing before you read your own result, because patterns divide on whatever the summaries make salient.
2
Filter traces by pattern
Open any trace in the project and check the Annotations panel on its root span. The pattern label and the trace summary appear there, which confirms the write landed.Patterns are now a filter:
Because the agent annotates root spans, this returns one span per matching trace rather than every span in those traces.From there a pattern behaves like any other slice: curate it into a dataset for an experiment, put it in a dashboard to watch its volume, or send it to a labeling queue for review.
3
Run it again as traffic changes
Patterns drift, so a single run describes the window it read and nothing later. Re-run the same prompt against a newer window whenever you want a current picture.Step 9 is what makes a second run safe. Each run clusters from scratch and would otherwise invent fresh slug names, which silently breaks saved filters, so the prompt tells the agent to read the existing config and reuse the slugs already in it. Config names are unique per space, so a run that tries to create pattern again fails outright, and an agent left to improvise may route around that error by creating a differently named config.Because a run inside the sandbox cannot amend a config’s values, genuinely new patterns come back reported rather than labelled. Widen the config yourself when that happens:
--value replaces the whole list rather than adding to it, so pass every value you want to keep, or existing annotations will point at labels the config no longer allows.
The numbers in either prompt are starting points, not settled values. The two knobs pull in opposite directions: a higher similarity threshold splits clusters apart, while a higher min_cluster_size merges them by discarding the small ones. On the no-repo route the threshold is the lever; on the repo route it is min_cluster_size.Clusters that mix unrelated patterns. Raise the threshold above 0.30, or on the repo route lower min_cluster_size. A threshold set too low produces one large cluster that has swallowed several unrelated intents. Ask for more clusters than feels natural and merge them yourself, since over-merged clusters hide exactly the small patterns worth finding.Too many traces landing in unclustered. Lower the threshold. The unclustered share climbs steeply once the threshold is too high, so move it in small steps. On the repo route, lower min_cluster_size instead.One pattern split across several clusters. Expect some of this and merge by hand. TF-IDF matches shared words rather than shared meaning, so “asking for a refund” and “want my money back” need not meet, and a single intent can end up spread across two or three clusters however you tune it. On the no-repo route, the number of eigenvectors is a secondary lever: more of them tends to fragment, fewer tends to merge.Everything in one cluster. The summaries are the problem rather than the parameters. Incidental detail like order IDs gives TF-IDF spurious signal, and a shared boilerplate phrase in every summary flattens the contrast between them. Tighten the summary instruction.
Do not read a low unclustered count as proof the clustering was good. Reduction pulls outliers toward the mass, so genuinely one-off traces are more likely to be absorbed into a cluster than set aside. The count is useful for spotting a threshold set too high; it is not outlier detection.
Fewer traces annotated than you expected. The most common cause is the export, not the clustering: --limit defaults to 100, and --all cannot be used in the sandbox. Check the span and trace counts the agent reported, and if the span count sits exactly on the limit it truncated the window. Partial labels look complete and undercount every pattern.
The agent tries to install packages and then improvises. PyPI is unreachable without a repo attached, and a blocked install rarely stops a run: the agent invents its own method instead, which no longer matches any guidance here. The no-repo prompt’s opening constraint exists to prevent this, so keep it.
The install fails on the repo route. Check that GitHub is authorized and not only that a repo is named, since the repo field is ignored without it. If umap-learn pulls in a numba that will not build, pin umap-learn and numba to recent versions with prebuilt wheels for Python 3.13.
ax spans export fails with a proxy or connection error on --all. Bulk export uses Arrow Flight, which the sandbox blocks. Use --days and --limit instead.
ax spans annotate rejects the whole batch. Every span ID has to fall inside the lookup window, and the window cannot exceed 31 days, so keep the export window inside that limit rather than widening --days past it. Spans older than 31 days cannot be annotated this way at all. Batches are also capped at 1000 records.
Annotations are rejected with label '<x>' is not one of the allowed values. The agent invented a slug that the annotation config does not list. Have it create the config from its own slugs, or paste the allowed values into the prompt.
no annotation config with name 'pattern' exists. The config must exist before any span is annotated. Confirm the name in the prompt matches it exactly.
Labels cannot exceed 30 characters while creating the config. The agent used a cluster summary as a value. Ask for a separate short slug and keep the summary in the annotation’s text field.
Everything lands in one cluster or all in noise. See Tuning the clusters. Check the summaries first: if they all end in the same phrase, or all name the same tool, they will cluster into a single blob no matter what the parameters say.
You now have a repeatable pipeline: one prompt that summarizes, clusters, and labels a whole project, and a filter that turns any pattern into a slice you can act on.Clustering is one job you can hand a managed agent, not the limit of what they do. The same agent reads your traces, runs code, and reports back, so the pattern generalizes:
Evaluating agents
Point a run at a slice of traces and have it draft labels and an evaluator prompt from what it finds.
Skills and permissions
With a GitHub skill attached, a session can trace a failure to its source, write a test, and open a PR.
Signal & Agents
Run any of the above on a cron schedule or a metric threshold instead of by hand.
Signal
Signal scans a project continuously and surfaces ranked issues, with no prompt required.
What these share is the shape of the request: a goal, a bound project, and permission to use tools. Anything you could work out by reading traces and running code, you can hand to an agent instead, once as a session or on a schedule.
Sandboxes, data access, credentials, and the boundaries of a run.
Agent Studio
Start sessions and automations, and bind a project to a run.
Agent Configs
Save the runtime, sandbox, and skills a run should use, instead of configuring each one.
Human review
Annotation configs, labeling traces, and review workflows.
Managed Agents CLI
Start sessions, follow transcripts, and trigger automations with ag instead of the UI.
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Arize AX Docs","colors":{"primary":"#7A0047","light":"#FF8AC8","dark":"#FF74BF"},"logo":{"light":"https://mintcdn.com/arize-ax/V-uvingrGLOCK4VD/logo/light.svg?fit=max\u0026auto=format\u0026n=V-uvingrGLOCK4VD\u0026q=85\u0026s=cc58ee9388d5b5253d39b65cc662908f","dark":"https://mintcdn.com/arize-ax/V-uvingrGLOCK4VD/logo/dark.svg?fit=max\u0026auto=format\u0026n=V-uvingrGLOCK4VD\u0026q=85\u0026s=b16a0266f5913934131301a1b60af51e","href":"https://arize.com"},"favicon":"https://mintcdn.com/arize-ax/1gcABHkqP5TIGbru/favicon.ico?fit=max\u0026auto=format\u0026n=1gcABHkqP5TIGbru\u0026q=85\u0026s=aef538e87b54a3c819583bc40acfc2f8","appearance":{"default":"dark"},"background":{"color":{"light":"#FFFFFF","dark":"#0A0A12"}},"navbar":{"links":[],"primary":{"type":"button","label":"Get started","href":"https://app.arize.com/auth/join"}},"footer":{"socials":{"x":"https://x.com/arizeai","bluesky":"https://bsky.app/profile/arize.bsky.social","threads":"https://www.threads.com/@arize.ai","instagram":"https://www.instagram.com/arize_ai","linkedin":"https://www.linkedin.com/company/arizeai","youtube":"https://youtube.com/@arizeai","slack":"https://arize-ai.slack.com/ssb/redirect","website":"https://fosstodon.org/@arizeai"},"links":[{"header":"Support","items":[{"label":"Chat Us On Slack","href":"https://arize-ai.slack.com/ssb/redirect"},{"label":"support@arize.com","href":"mailto:support@arize.com"},{"label":"System Status","href":"https://status.arize.com"}]},{"header":"Get Started","items":[{"label":"Signup For Free","href":"https://arize.com/join"},{"label":"Book A Demo","href":"https://arize.com/request-a-demo"}]},{"header":"Resources","items":[{"label":"Blog","href":"https://arize.com/blog"}]}]},"seo":{"metatags":{"canonical":"https://arize.com/docs"},"indexing":"all"},"fonts":{"heading":{"family":"Geist","weight":600},"body":{"family":"Geist"}},"styling":{"codeblocks":{"theme":{"light":"github-light-default","dark":"github-dark-default"}},"latex":true},"integrations":{"gtm":{"tagId":"GTM-W96XM35"}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"interaction":{"drilldown":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"arize-ax","hasAudioNarration":false,"actualSubdomain":"arize-ax","customDomains":[],"gitSource":{"type":"github","owner":"arize-ai","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae380784e7ff22194787ded","collectionId":"a65f120b-b255-4fa1-b354-0058e05ffbd3","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae380784e7ff22194787ded"},"feedback":{"thumbs":true,"contextualFeedback":{"allowEmail":true,"emailDisclaimer":"We will only use your email to follow up with you about this feedback."}},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"REMOVE_BRANDING":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae41841e58218f8aa350b51","clientVersion":"0.0.4021","searchFilterCounts":[{"language":"default","tag":"APIs, SDKs, \u0026 Skills","count":354},{"language":"default","tag":"Get Started","count":243},{"language":"default","tag":"API reference","count":200},{"language":"default","tag":"REST","count":167},{"language":"default","tag":"Endpoints","count":164},{"language":"default","tag":"API clients","count":142},{"language":"default","tag":"Machine Learning","count":139},{"language":"default","tag":"ML observability","count":139},{"language":"default","tag":"Integrations","count":129},{"language":"default","tag":"Guides","count":69}]},"assistantConfig":{"enableAskAiButton":true,"enableStarterQuestions":true,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"email":"support@arize.com"}},"basePath":"/docs","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"starterQuestions":[{"_id":"6944513fe59e82150b5700b3","deploymentId":"6894ef048eafbd2a7c20796e","questionText":"Need more help? Ask our team in #arize-ax-platform-support on community Slack.","status":"active","generatedBy":"manual","createdAt":"2025-12-18T19:08:47.802Z","updatedAt":"2025-12-18T19:15:01.436Z","__v":0}],"googleFontsInlined":true},"customCss":[{"filePath":"style.css","content":"/* cyrillic-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 300;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrodmgPn.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 300;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrMdmgPn.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* symbols2 */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 300;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFg08vz7ehw.woff2) format('woff2');\n unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 300;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrgdmgPn.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 300;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrkdmgPn.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 300;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrcdmg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrodmgPn.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrMdmgPn.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* symbols2 */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFg08vz7ehw.woff2) format('woff2');\n unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrgdmgPn.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrkdmgPn.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrcdmg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrodmgPn.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrMdmgPn.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* symbols2 */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFg08vz7ehw.woff2) format('woff2');\n unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrgdmgPn.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrkdmgPn.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrcdmg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrodmgPn.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrMdmgPn.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* symbols2 */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFg08vz7ehw.woff2) format('woff2');\n unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrgdmgPn.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrkdmgPn.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Geist Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/geistmono/v6/or3nQ6H-1_WfwkMZI_qYFrcdmg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\nhtml:root{--font-family-mono-custom:'Geist Mono';--gray-50:248 248 246;--gray-100:242 242 237;--gray-200:230 230 223;--gray-300:205 205 200;--gray-400:179 179 191;--gray-500:138 138 150;--gray-600:91 91 105;--gray-700:62 62 78;--gray-800:46 46 61;--gray-900:21 21 31;--gray-950:10 10 18;--ax-radius-sm:2px;--ax-radius-md:6px;--ax-radius-lg:8px;--ax-accent-bg:#FF74BF;--ax-panel:#CDBEF7;--ax-panel-2:#E3DBFC;--ax-panel-code:#FFFFFF;--ax-panel-border:rgba(19, 22, 64, 0.22);--ax-panel-icon:#4827C1;--ax-panel-t1:#121221;--ax-panel-t2:#2A2A38;--ax-panel-accent:#6E1046;--ax-panel-code-kw:#3F4110;--ax-panel-code-flag:#5A3200;--ax-panel-code-url:#004A70;--ax-panel-selection:#FFE9F4}html:not(.dark){--ax-bg:#FFFFFF;--ax-surface:#F8F8F4;--ax-code-bg:#F5F5ED;--ax-chip:#EDEDE2;--ax-line:rgba(19, 22, 64, 0.20);--ax-t1:#121221;--ax-t2:#2E2E3D;--ax-t3:#3E3E4E;--ax-accent:#7A0047;--ax-accent-line:rgba(255, 98, 182, 0.55);--ax-accent-soft:#FFE9F4;--ax-on-accent:#121221;--ax-note:#E8F3EC;--ax-note-line:rgba(30, 70, 50, 0.24);--ax-note-t:#1B4230;--ax-warn:#FBEEE0;--ax-warn-line:rgba(90, 50, 0, 0.24);--ax-warn-t:#54300A;--ax-blue:#E7F3FD;--ax-blue-line:rgba(0, 82, 125, 0.24);--ax-blue-t:#00527D;--ax-danger:#FFEBE9;--ax-danger-line:rgba(207, 34, 46, 0.28);--ax-danger-t:#A40E26}html.dark{--ax-bg:#0A0A12;--ax-surface:#15151F;--ax-code-bg:#05050B;--ax-chip:#221B3A;--ax-line:rgba(247, 247, 252, 0.16);--ax-t1:#F5F5FA;--ax-t2:#DCDCE6;--ax-t3:#B3B3C4;--ax-accent:#FF8AC8;--ax-accent-line:rgba(255, 138, 200, 0.45);--ax-accent-soft:#2A1425;--ax-on-accent:#0A0A12;--ax-note:#10241A;--ax-note-line:rgba(159, 224, 188, 0.30);--ax-note-t:#9FE0BC;--ax-warn:#2A1B0A;--ax-warn-line:rgba(255, 201, 138, 0.30);--ax-warn-t:#FFC98A;--ax-blue:#0A1A24;--ax-blue-line:rgba(57, 195, 255, 0.30);--ax-blue-t:#97D8FF;--ax-danger:#2A0F12;--ax-danger-line:rgba(255, 138, 148, 0.30);--ax-danger-t:#FFB3B8}#content{line-height:1.75}#content h1,#page-title{font-size:clamp(2rem,1.4rem + 2.1vw,2.875rem);line-height:1.12;letter-spacing:-.02em;font-weight:600}#content h2,#content h3,#content h4{letter-spacing:-.01em;font-weight:600}#content code,#content kbd,#content samp{font-feature-settings:'tnum' 1}#content a:not(.card){color:var(--ax-accent);text-decoration-thickness:1px;text-underline-offset:3px}:focus-visible{outline:2px solid var(--ax-accent-line);outline-offset:2px}html.dark :focus-visible{outline-color:var(--ax-accent-line)}::selection{background:var(--ax-accent-soft)}#navbar{background:var(--ax-bg);border-bottom:1px solid var(--ax-line)}#navbar div:has(>.nav-tabs){position:relative}#navbar div:has(>.nav-tabs)::before{content:'';position:absolute;top:0;left:50%;width:100vw;margin-left:-50vw;border-top:1px solid var(--ax-line);pointer-events:none}.nav-tabs-item[data-active]{box-shadow:inset 0 -2px 0 var(--ax-accent)}.ax-product-selector{position:relative;display:inline-flex;align-items:stretch;flex:0 0 auto}.ax-product-selector--desktop{margin-left:.75rem;align-self:center}.page-context-dropdown__label{font-family:inherit;font-weight:400}.page-context-dropdown__chevron>span{display:inline-block;transition:transform 150ms ease}.page-context-dropdown__chevron svg{display:block;width:1rem;height:1rem}.page-context-dropdown__chevron[aria-expanded=true]>span{transform:rotate(180deg)}.page-context-dropdown__menu{position:absolute;z-index:60;top:calc(100% + .55rem);right:0;min-width:12.5rem;padding:.4rem;background:var(--ax-bg);border:1px solid var(--ax-line);border-radius:var(--ax-radius-md);box-shadow:0 .75rem 1.5rem rgb(10 10 18/.18)}.ax-product-selector--desktop .page-context-dropdown__menu{right:auto;left:0}.page-context-dropdown__menu[hidden]{display:none}.page-context-dropdown__item{display:flex;align-items:center;justify-content:space-between;min-height:2.5rem;padding:.55rem .65rem;color:var(--ax-t1);border-radius:var(--ax-radius-sm);font-size:.9375rem;font-weight:400;text-decoration:none;transition:background-color 150ms ease,color 150ms ease}.page-context-dropdown__item:focus-visible,.page-context-dropdown__item:hover{color:var(--ax-accent);background:var(--ax-accent-soft)}#sidebar-content li[data-active]>a,.page-context-dropdown__item[data-selected=true]{color:var(--ax-accent);font-weight:500}.page-context-dropdown__item[data-selected=true]::after{content:'✓';margin-left:1.5rem;color:var(--ax-accent);font-size:.875rem}@media (prefers-reduced-motion:reduce){.page-context-dropdown__chevron>span,.page-context-dropdown__item{transition:none}}@media (max-width:767px){#navbar .ax-product-selector--desktop{display:none}#mobile-nav-content .ax-product-selector--mobile{margin:.5rem 0 1rem}#mobile-nav-content .page-context-dropdown__label{flex:1 1 auto}#mobile-nav-content .page-context-dropdown__chevron{flex:0 0 auto}#mobile-nav-content .page-context-dropdown__menu{position:static;margin-top:.4rem}}#topbar-cta-button{background:var(--ax-accent-bg);color:var(--ax-on-accent);border-radius:var(--ax-radius-md);border:0}#topbar-cta-button span,#topbar-cta-button svg{color:var(--ax-on-accent)!important}#assistant-entry,#search-bar-entry{background:var(--ax-surface);border:1px solid var(--ax-line);border-radius:var(--ax-radius-md)}#assistant-entry{border:1px solid var(--ax-accent-line)}#assistant-entry svg{color:var(--ax-accent)}#page-context-menu,.page-context-dropdown{font-size:.9375rem;align-items:stretch}#page-context-menu-button,.page-context-dropdown__label{display:inline-flex;align-items:center;padding:10px 14px;border-radius:var(--ax-radius-md) 0 0 var(--ax-radius-md);background:var(--ax-surface);color:var(--ax-t1);border:1px solid var(--ax-line);text-decoration:none}#page-context-menu-button>div{font-size:.9375rem;gap:9px}#page-context-menu>button[aria-haspopup],.page-context-dropdown__chevron{height:auto;align-self:stretch;aspect-ratio:auto;padding:10px 11px;border-radius:0 var(--ax-radius-md) var(--ax-radius-md) 0;background:var(--ax-surface);color:var(--ax-t3);border:1px solid var(--ax-line);border-left:0;cursor:pointer}#sidebar-content li[data-active]>a{background:var(--ax-accent-soft);border-radius:var(--ax-radius-md)}.sidebar-group-header{font-weight:600;color:var(--ax-t1)}.toc-item[data-active],.toc-item[data-active] a{color:var(--ax-accent);font-weight:400}.card.card,.frame.frame{background:var(--ax-surface);border-radius:var(--ax-radius-lg)}.card.card{border-color:var(--ax-line);box-shadow:none}.frame.frame{border:1px solid var(--ax-line)}.accordion-group.accordion-group,.accordion.accordion{border-radius:var(--ax-radius-md);border-color:var(--ax-line)}.accordion.accordion{background:var(--ax-surface)}.code-block.code-block,.code-group.code-group{background:var(--ax-code-bg);border-color:var(--ax-line);border-radius:var(--ax-radius-md)}.code-block-background,html.dark .code-block-background{background:var(--ax-code-bg)!important}#content :not(pre)>code{background:var(--ax-chip);border-radius:var(--ax-radius-sm)}.code-block:has([data-floating-buttons]) [data-fade-overlay]{background-image:none}[data-floating-buttons] button{background:var(--ax-chip)}.callout .code-block-background,.callout .code-block.code-block,.callout .code-group.code-group,html.dark .callout .code-block-background{background:var(--ax-bg)!important}.callout{border-radius:var(--ax-radius-lg)}.callout[data-callout-type=callout],.callout[data-callout-type=info]{background:var(--ax-surface);border-color:var(--ax-line)}.callout[data-callout-type=callout] [data-component-part=callout-content],.callout[data-callout-type=info] [data-component-part=callout-content]{color:var(--ax-t2)!important}.callout[data-callout-type=check],.callout[data-callout-type=tip]{background:var(--ax-note);border-color:var(--ax-note-line)}.callout[data-callout-type=check] [data-component-part=callout-content],.callout[data-callout-type=tip] [data-component-part=callout-content]{color:var(--ax-note-t)!important}.callout[data-callout-type=warning]{background:var(--ax-warn);border-color:var(--ax-warn-line)}.callout[data-callout-type=warning] [data-component-part=callout-content]{color:var(--ax-warn-t)!important}.callout[data-callout-type=note]{background:var(--ax-blue);border-color:var(--ax-blue-line)}.callout[data-callout-type=note] [data-component-part=callout-content]{color:var(--ax-blue-t)!important}.callout[data-callout-type=danger]{background:var(--ax-danger);border-color:var(--ax-danger-line)}.callout[data-callout-type=danger] [data-component-part=callout-content]{color:var(--ax-danger-t)!important}[data-component-part=step-number]>div{background:var(--ax-accent-soft);border:1px solid var(--ax-accent-line);color:var(--ax-accent);font-weight:500}.update.update-container{flex-direction:column;gap:.5rem;border-top:1px solid var(--ax-line)}.update.update-container:first-of-type{border-top:none}.update.update-container>div:first-child{width:100%;position:static}.update.update-container>div:last-child{width:100%;max-width:none}#content th{color:var(--ax-t1);font-weight:600}#content td,#content th{border-bottom:1px solid var(--ax-line)}footer{border-top:1px solid var(--ax-line)}.ax-hero .callout{background:var(--ax-panel);border-color:var(--ax-panel-border);border-radius:var(--ax-radius-lg)}.ax-hero .callout [data-component-part=callout-content],.ax-hero .callout li,.ax-hero .callout p,.ax-hero .code-group [role=tab]{color:var(--ax-panel-t2)!important}.ax-hero .callout h2,.ax-hero .callout h3,.ax-hero .callout strong{color:var(--ax-panel-t1)!important}.ax-hero .callout [data-component-part=callout-icon] svg{background:var(--ax-panel-icon)!important}.ax-hero .code-block,.ax-hero .code-block-background,.ax-hero .code-group{background:var(--ax-panel-code)!important;border-color:var(--ax-panel-border)}.ax-hero .code-block,.ax-hero .code-group{padding:0;overflow:hidden}html.dark .ax-hero .code-block,html.dark .ax-hero .code-block-background,html.dark .ax-hero .code-group,html.dark .ax-hero .shiki,html:not(.dark) .ax-hero .code-block,html:not(.dark) .ax-hero .code-block-background,html:not(.dark) .ax-hero .code-group{background:var(--ax-panel-code)!important}html.dark .ax-hero .shiki,html.dark .ax-hero .shiki span{color:var(--ax-panel-t1)!important}html.dark .ax-hero .shiki span[style*='#FFA657']{color:var(--ax-panel-code-kw)!important}html.dark .ax-hero .shiki span[style*='#79C0FF']{color:var(--ax-panel-code-flag)!important}html.dark .ax-hero .shiki span[style*='#A5D6FF']{color:var(--ax-panel-code-url)!important}.ax-hero .code-group>div:first-child,html.dark .ax-hero .code-group>div:first-child{background:var(--ax-panel-2)!important;border-bottom:1px solid var(--ax-panel-border)}.ax-hero .callout a,.ax-hero .code-group [role=tab][aria-selected=true]{color:var(--ax-panel-accent)!important}.ax-hero .code-group [role=tab][aria-selected=true]>div:last-child{background:var(--ax-panel-accent)!important}.ax-hero .code-block svg,.ax-hero .code-group svg{color:var(--ax-panel-t2)}html.dark .ax-hero [data-fade-overlay]{background-image:linear-gradient(to right,rgb(255 255 255/0) 0,rgb(255 255 255/.2) 10px,rgb(255 255 255/.5) 25px,rgb(255 255 255/.8) 35px,rgb(255 255 255) 45px)}.ax-hero ::selection,.ax-hero::selection{background:var(--ax-panel-selection)}.card-group .card img{max-height:197px!important}.card-group[class$=\"-2\"] .card img{height:160px!important}.card-group[class$=\"-3\"] .card img{height:150px!important}table{display:table!important}.step-title{font-size:1.5rem!important}"}],"page":{"pagePath":"ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents","slug":"/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents","pageMetadata":{"title":"Cluster trace patterns with managed agents","description":"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.","keywords":["managed agents","patterns","error modes","clustering","umap","hdbscan","trace summaries","annotations","agent studio","arize ax"],"href":"/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{Card,CardGroup,CodeBlock,Frame,Heading,Info,Note,Step,Steps,Tab,Table,Tabs}=_components;if(!Card)_missingMdxReference(`Card`,true);if(!CardGroup)_missingMdxReference(`CardGroup`,true);if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Frame)_missingMdxReference(`Frame`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Info)_missingMdxReference(`Info`,true);if(!Note)_missingMdxReference(`Note`,true);if(!Step)_missingMdxReference(`Step`,true);if(!Steps)_missingMdxReference(`Steps`,true);if(!Tab)_missingMdxReference(`Tab`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Tabs)_missingMdxReference(`Tabs`,true);return _jsxs(_Fragment,{children:[_jsx(Info,{children:_jsx(_components.p,{children:`Managed agents are only available on Enterprise plans.`})}),`\n`,_jsxs(_components.p,{children:[`A project with thousands of traces holds patterns no single trace shows you. Some are what users keep asking for, some are the ways your agent keeps failing, and neither shows up in a latency chart. A `,_jsx(_components.a,{href:`/ax/agents/connect-your-harness`,children:`managed agent`}),` can read the whole project, summarize each trace, group the summaries into named patterns, and write those patterns back onto the traces as annotations so you can filter by them.`]}),`\n`,_jsxs(_components.p,{children:[`Arize AX offers `,_jsx(_components.a,{href:`/ax/observe/tracing/view-and-manage-traces#analyze-traces-for-error-modes`,children:`three other ways to turn traces into named patterns`}),`: Arize Skills in your coding agent, Alyx in the product, or manual annotation. A managed agent works through traces in one unattended run.`]}),`\n`,_jsx(Heading,{level:`2`,id:`overview`,children:`Overview`}),`\n`,_jsx(_components.p,{children:`You will start a managed agent session against a tracing project, hand it a prompt that describes a summarize-and-cluster pipeline, and read the patterns it finds. The agent runs four stages: it summarizes each trace in a sentence using its own model, turns those summaries into vectors, reduces the vectors to a few dimensions, and clusters the result. It names each cluster and annotates the traces in it with that name, so you can then filter your traces by pattern.`}),`\n`,_jsx(_components.p,{children:`This guide is for builders who already have tracing projects in Arize AX and have managed agents enabled on their account. No prior experience with managed agents is required.`}),`\n`,_jsx(_components.p,{children:`You should be comfortable with:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Tracing projects in Arize AX, and reading traces in the UI`}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/ax/evaluate/human-review`,children:`Annotations`}),` as a way to label spans`]}),`\n`,_jsx(_components.li,{children:`Basic clustering vocabulary: vector representations, dimensionality reduction, clusters, and outliers`}),`\n`]}),`\n`,_jsx(_components.p,{children:`By the end, you will be able to:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Write a prompt that turns an open-ended “find the patterns” request into a repeatable pipeline`}),`\n`,_jsx(_components.li,{children:`Judge whether the clusters an agent reports are real`}),`\n`,_jsx(_components.li,{children:`Filter traces by pattern, and build datasets from them`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`before-you-start`,children:`Before you start`}),`\n`,_jsx(_components.p,{children:`You need:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`A tracing project with at least `,_jsx(_components.strong,{children:`one hundred traces`}),`. The patterns surfaced in smaller projects may already be obvious.`]}),`\n`,_jsxs(_components.li,{children:[`Managed agents enabled on your account, and `,_jsx(_components.strong,{children:`write access`}),` to the space. See `,_jsx(_components.a,{href:`/ax/agents/connect-your-harness#permissions`,children:`Skills and permissions`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`The `,_jsxs(_components.a,{href:`/api-clients/cli/auth`,children:[_jsx(_components.code,{children:`ax`}),` CLI`]}),` installed and authenticated locally, for the filter and export commands at the end. The agent’s own copy comes preinstalled in its sandbox.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`what-managed-agents-can-access`,children:`What managed agents can access`}),`\n`,_jsx(_components.p,{children:`Each run happens in a sandbox, an isolated container that Arize AX tears down afterward. What the agent can reach is fixed before the run starts, and the prompts below are written to fit those limits:`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Capability`}),_jsx(_components.th,{children:`Detail`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Your traces`})}),_jsx(_components.td,{children:`The agent reads spans through the Arize AX API, over a time window you choose rather than a whole project at once.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Project scope`})}),_jsx(_components.td,{children:`The agent’s credentials cover your entire space, so name the project you want analyzed in the prompt.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Python`})}),_jsx(_components.td,{children:`A plain interpreter with nothing extra installed.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`More packages`})}),_jsx(_components.td,{children:`The agent can install libraries only when a GitHub repo is attached to the run.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Summarization`})}),_jsx(_components.td,{children:`The agent’s own model calls. No embedding model is reachable, so the vectors have to come from the text of the summaries.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Writing back`})}),_jsx(_components.td,{children:`The agent can create an annotation config and label spans for you, but it cannot change a config once one exists.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Deliverables`})}),_jsx(_components.td,{children:`Files the agent saves as deliverables outlive the sandbox.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`two-routes`,children:`Two routes`}),`\n`,_jsx(_components.p,{children:`Which pipeline you can ask for comes down to one thing: whether a GitHub repo is attached to the run, because that is what opens PyPI.`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`With a repo attached`}),`, the agent installs scikit-learn and UMAP and clusters with the libraries built for the job, which produces tighter clusters and handles more traces per run.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Without a repo`}),`, every step has to be computable with the standard library, and requires no repo setup. It is recommended for batches of `,_jsx(_components.strong,{children:`up to a few thousand traces`}),`. Past a few thousand, narrow the time window or attach a repo.`]}),`\n`,_jsx(_components.p,{children:`Both routes produce the same summaries, the same annotation config, and the same filters. Only vectorizing and clustering differ.`}),`\n`,_jsx(Heading,{level:`2`,id:`cluster-the-patterns`,children:`Cluster the patterns`}),`\n`,_jsxs(Tabs,{children:[_jsxs(Tab,{title:`No repo`,id:`no-repo`,children:[_jsx(_components.p,{children:`Three methods carry the pipeline, all computable with the standard library:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://en.wikipedia.org/wiki/Tf%E2%80%93idf`,children:`TF-IDF`}),` weighs each word by how often it appears in one summary against how rare it is across all of them, turning short summaries into vectors with nothing downloaded.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Spectral reduction`}),` takes the top eigenvectors of the trace-by-trace similarity matrix, which is classical multidimensional scaling on the cosine kernel. Sparse text vectors cluster poorly at full width, and this is the part `,_jsx(_components.a,{href:`https://umap-learn.readthedocs.io/en/latest/how_umap_works.html`,children:`UMAP`}),` would do if you could install it.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Average-link agglomerative clustering`}),` merges the closest pair of clusters until nothing is similar enough to join, so you set a similarity threshold rather than a cluster count.`]}),`\n`]}),_jsxs(Steps,{children:[_jsxs(Step,{title:`Start a session in Agent Studio`,children:[_jsxs(_components.p,{children:[`Open `,_jsx(_components.strong,{children:`Observe → Signal \u0026 Agents → + New Agent`}),` and choose `,_jsx(_components.strong,{children:`Start from scratch`}),`. Then:`]}),_jsxs(_components.ol,{children:[`\n`,_jsx(_components.li,{children:`Select the tracing project you want analyzed. This is the project the agent reads and annotates.`}),`\n`,_jsxs(_components.li,{children:[`Leave the agent config as `,_jsx(_components.strong,{children:`None`}),`.`]}),`\n`]}),_jsx(Frame,{caption:`Configuring a run in Agent Studio: selecting a project, and the agent config, skill, and repo options this pipeline leaves alone`,children:_jsx(`video`,{src:`https://storage.googleapis.com/arize-assets/doc-images/managed%20agents/managed-agents-configure-run.mp4`,alt:`Configuring a run in Agent Studio: selecting a tracing project, with agent config, skill, and repo options available`,width:`100%`,height:`100%`,style:{display:`block`,objectFit:`fill`,backgroundColor:`transparent`},controls:true,autoPlay:true,muted:true,loop:true,playsInline:`true`})})]}),_jsxs(Step,{title:`Give it the pipeline as a prompt`,children:[_jsxs(_components.p,{children:[`Paste this as the task prompt. It describes the pipeline in stages, and each stage names its own output so the agent cannot quietly skip one. Replace `,_jsx(_components.code,{children:`\u003cproject>`}),` with your project’s name first; `,_jsx(_components.code,{children:`$ARIZE_SPACE_ID`}),` is already set inside the sandbox, so leave it as written.`]}),_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`71`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default github-dark-default`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0d1117`,color:`#1f2328`,\"--shiki-dark\":`#e6edf3`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`71`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`Find the recurring patterns in this project's traces, then label the traces with them.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`Sandbox constraints: PyPI is not reachable, so do not try to install anything.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`Use only the Python standard library; /usr/bin/python3 is 3.13 with no`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`third-party packages. There is no embedding API reachable from here either. If`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`something you need is genuinely unavailable, stop and tell me rather than`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`substituting a different method.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\"1. Export spans with `ax spans export \u003cproject> --days 30 --limit 5000\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" --stdout`. Do not use `--all`: bulk export needs Arrow Flight, which this\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" sandbox blocks. `--limit` defaults to 100, so always set it high enough to\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` cover the window, and if the result comes back exactly at the limit, narrow`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `--days` and export in several passes rather than accepting a truncated set.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" Group the spans by `context.trace_id`. For each trace keep the root span's\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `context.span_id`, `attributes.input.value`, `attributes.output.value`, its\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `start_time`, the `attributes.tool.name` of any child tool spans, and\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `status_message` for any span whose `status_code` is ERROR. Report how many\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` spans you exported and how many distinct traces they cover, and work through`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` all of them rather than a sample.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`2. Summarize each trace in under 25 words: what the user wanted, what the agent`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` did, and how it ended. Give intent and outcome equal weight, and state a`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` success as plainly as a failure. No order IDs, emails, or other incidental`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` detail, and no boilerplate tail such as \"no errors occurred\".`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`3. Turn the summaries into vectors with tf-idf:`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - lowercase, split on non-letters, drop tokens under 3 characters`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - drop tokens appearing in only one summary, and tokens appearing in more`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` than half of them`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - weight each token as (1 + log(count in summary)) * log(total summaries /`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` summaries containing it)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - L2-normalize every vector`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`4. Reduce before clustering. Compute the trace-by-trace cosine similarity`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` matrix, double-center it, then take its top 10 eigenvectors by power`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` iteration with deflation, each scaled by the square root of its eigenvalue.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` Re-normalize the resulting 10-dimensional rows.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`5. Cluster in that reduced space with average-link agglomerative merging on`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` cosine similarity: merge the two closest clusters while their average-link`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` similarity is at least 0.30. Break ties by lowest trace index so repeat runs`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` are identical.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`6. Any cluster holding fewer than 3 traces is not a pattern. Give those traces`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" the slug `unclustered`, and report how many there are.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`7. Name each cluster in under 10 words. Give each one a slug to use as a label:`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` lowercase, hyphenated, 30 characters or less.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`8. Write /workspace/.artifacts/patterns.json with one object per cluster: slug,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` name, trace count, earliest and latest trace timestamp, and three example`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` trace summaries. Then report in your reply: total traces, cluster count,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` unclustered count, and the largest and smallest cluster size.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`9. Set up the annotation config. Check first with`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `ax annotation-configs get pattern --space $ARIZE_SPACE_ID`.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - If it does not exist, create it with`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `ax annotation-configs create --name pattern --space $ARIZE_SPACE_ID\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" --type CATEGORICAL` and one `--value \u003cslug>` per cluster, plus\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `--value unclustered`.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - If it already exists, use the slugs it already lists. Match each cluster to`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` the closest existing slug and reuse it, and label any cluster with no good`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" match `unclustered`. Do not create a second config under another name, and\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` do not try to amend this one: config names are unique per space, and the`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `ax` build here cannot update a config's values. Report any cluster you had\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` to leave unlabelled so I can widen the config myself.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` The type must be uppercase, labels are capped at 30 characters, and a`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` categorical config needs between 2 and 100 values.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`10. Annotate the traces. Build a JSON array of records, one per root span:`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` {\"record_id\": \"\u003croot span id>\", \"values\": [{\"name\": \"pattern\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` \"label\": \"\u003cslug>\", \"text\": \"\u003cthat trace's summary>\"}]}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" then run `ax spans annotate \u003cproject> --space $ARIZE_SPACE_ID --file \u003cpath>\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" --days 31`. Send at most 1000 records per request. Every span id has to fall\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` inside the day window or the whole request is rejected, and the window`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` cannot exceed 31 days, so keep the export window inside that limit too.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`Finally, tell me which clusters are ordinary demand, which are failures, and`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`which are requests the agent has no way to satisfy.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),_jsx(_components.p,{children:`The diagnostics in steps 6 and 8 are what let you audit the result. Compare the reported trace count against your project’s actual volume, because an agent that quietly worked on a subset produces labels that look complete and undercount every pattern. A cluster confined to a single hour is an incident rather than a pattern, which is why each one carries a time range.`}),_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Run session`}),`.`]})]})]})]}),_jsxs(Tab,{title:`With a repo`,id:`with-a-repo`,children:[_jsxs(_components.p,{children:[`Attaching a repo opens PyPI, which lets the agent install the clustering libraries. The repo’s contents are never used: attaching one is only what changes the sandbox’s egress rules, so `,_jsx(_components.strong,{children:`any repo you can access works`}),`.`]}),_jsx(_components.p,{children:`Three methods carry the pipeline, each from a library the agent installs:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://en.wikipedia.org/wiki/Tf%E2%80%93idf`,children:`TF-IDF`}),` weighs each word by how often it appears in one summary against how rare it is across all of them, turning short summaries into vectors. scikit-learn also drops common English words, which sharpens the contrast between summaries.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://umap-learn.readthedocs.io/en/latest/how_umap_works.html`,children:`UMAP`}),` reduces those vectors to a handful of dimensions, keeping summaries that share vocabulary near each other. Sparse text vectors cluster poorly at their full width.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://scikit-learn.org/stable/modules/clustering.html#hdbscan`,children:`HDBSCAN`}),` groups the reduced vectors by density. You never say how many patterns to expect, and it labels traces that fit no cluster as noise rather than forcing them into one. `,_jsx(_components.code,{children:`min_cluster_size`}),` sets the smallest group it will call a cluster.`]}),`\n`]}),_jsxs(Steps,{children:[_jsxs(Step,{title:`Connect GitHub and set the repo`,children:[_jsxs(_components.p,{children:[`Open `,_jsx(_components.strong,{children:`Observe → Signal \u0026 Agents → + New Agent`}),`, and choose `,_jsx(_components.strong,{children:`Start from scratch`}),`, then:`]}),_jsxs(_components.ol,{children:[`\n`,_jsx(_components.li,{children:`Select the tracing project you want analyzed. This is the project the agent reads and annotates.`}),`\n`,_jsxs(_components.li,{children:[`Leave the agent config as `,_jsx(_components.strong,{children:`None`}),`, or choose an agent config with a repo attached.`]}),`\n`,_jsxs(_components.li,{children:[`Authorize GitHub next to the `,_jsx(_components.strong,{children:`Repo`}),` field. If an `,_jsx(_components.strong,{children:`Install GitHub App`}),` button is offered, use it and then pick your repository from the list, which attaches the integration for you. Otherwise click `,_jsx(_components.strong,{children:`+ Add skill`}),`, choose `,_jsx(_components.strong,{children:`GitHub`}),`, and paste a personal access token as `,_jsx(_components.code,{children:`GH_TOKEN`}),` with repo read scope.`]}),`\n`,_jsxs(_components.li,{children:[`If you went the token route, set `,_jsx(_components.strong,{children:`Repo`}),` to `,_jsx(_components.code,{children:`org/repo`}),`.`]}),`\n`]}),_jsx(_components.p,{children:`The repo field is ignored unless a GitHub skill is attached.`}),_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Already have an agent config with a GitHub skill and repo?`}),` Pick it from the agent config menu instead and skip this step. Binding one hides the ad-hoc skills picker, because the run inherits its skills and repo.`]})})]}),_jsxs(Step,{title:`Give it the pipeline as a prompt`,children:[_jsxs(_components.p,{children:[`Paste this as the task prompt. Replace `,_jsx(_components.code,{children:`\u003cproject>`}),` with your project’s name first; `,_jsx(_components.code,{children:`$ARIZE_SPACE_ID`}),` is already set inside the sandbox, so leave it as written.`]}),_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`63`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default github-dark-default`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0d1117`,color:`#1f2328`,\"--shiki-dark\":`#e6edf3`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`63`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`Find the recurring patterns in this project's traces, then label the traces with them.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`A repo is attached to this run, so PyPI is reachable. Create a virtualenv with`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\"`uv venv` and install scikit-learn and umap-learn into it, and use that\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`virtualenv for every script below. Use scikit-learn's own HDBSCAN`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`(sklearn.cluster.HDBSCAN) rather than the standalone hdbscan package, which`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`needs a compiler. If an install fails, stop and tell me rather than falling back`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`to a different method.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\"1. Export spans with `ax spans export \u003cproject> --days 30 --limit 5000\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" --stdout`. Do not use `--all`: bulk export needs Arrow Flight, which this\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" sandbox blocks. `--limit` defaults to 100, so always set it high enough to\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` cover the window, and if the result comes back exactly at the limit, narrow`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `--days` and export in several passes rather than accepting a truncated set.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" Group the spans by `context.trace_id`. For each trace keep the root span's\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `context.span_id`, `attributes.input.value`, `attributes.output.value`, its\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `start_time`, the `attributes.tool.name` of any child tool spans, and\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `status_message` for any span whose `status_code` is ERROR. Report how many\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` spans you exported and how many distinct traces they cover, and work through`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` all of them rather than a sample.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`2. Summarize each trace in under 25 words: what the user wanted, what the agent`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` did, and how it ended. Give intent and outcome equal weight, and state a`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` success as plainly as a failure. No order IDs, emails, or other incidental`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` detail, and no boilerplate tail such as \"no errors occurred\".`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`3. Vectorize the summaries with TfidfVectorizer, sublinear_tf=True, min_df=2,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` max_df=0.5, and stop_words=\"english\".`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`4. Reduce with UMAP: metric=\"cosine\", n_components=5, n_neighbors of roughly the`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` square root of the trace count, and a fixed random_state so repeat runs match.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`5. Cluster the reduced vectors with HDBSCAN, min_cluster_size=5 and`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` min_samples=1.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\"6. Traces HDBSCAN labels -1 are noise. Give them the slug `unclustered`, and\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` report how many there are.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`7. Name each cluster in under 10 words. Give each one a slug to use as a label:`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` lowercase, hyphenated, 30 characters or less.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`8. Write /workspace/.artifacts/patterns.json with one object per cluster: slug,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` name, trace count, earliest and latest trace timestamp, and three example`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` trace summaries. Then report in your reply: total traces, cluster count,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` unclustered count, and the largest and smallest cluster size.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`9. Set up the annotation config. Check first with`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `ax annotation-configs get pattern --space $ARIZE_SPACE_ID`.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - If it does not exist, create it with`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `ax annotation-configs create --name pattern --space $ARIZE_SPACE_ID\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" --type CATEGORICAL` and one `--value \u003cslug>` per cluster, plus\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `--value unclustered`.\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` - If it already exists, use the slugs it already lists. Match each cluster to`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` the closest existing slug and reuse it, and label any cluster with no good`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" match `unclustered`. Do not create a second config under another name, and\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` do not try to amend this one: config names are unique per space, and the`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" `ax` build here cannot update a config's values. Report any cluster you had\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` to leave unlabelled so I can widen the config myself.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` The type must be uppercase, labels are capped at 30 characters, and a`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` categorical config needs between 2 and 100 values.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`10. Annotate the traces. Build a JSON array of records, one per root span:`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` {\"record_id\": \"\u003croot span id>\", \"values\": [{\"name\": \"pattern\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` \"label\": \"\u003cslug>\", \"text\": \"\u003cthat trace's summary>\"}]}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" then run `ax spans annotate \u003cproject> --space $ARIZE_SPACE_ID --file \u003cpath>\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:\" --days 31`. Send at most 1000 records per request. Every span id has to fall\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` inside the day window or the whole request is rejected, and the window`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` cannot exceed 31 days, so keep the export window inside that limit too.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`Finally, tell me which clusters are ordinary demand, which are failures, and`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`which are requests the agent has no way to satisfy.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),_jsxs(_components.p,{children:[_jsx(_components.code,{children:`min_cluster_size`}),` is the number to scale with volume. Leaving it low on a large project fragments patterns that belong together.`]}),_jsxs(_components.p,{children:[`Click `,_jsx(_components.strong,{children:`Run session`}),`.`]})]})]})]})]}),`\n`,_jsxs(Note,{children:[_jsx(_components.p,{children:`If your account restricts annotation config creation, create the config yourself before the run and paste its allowed values into step 9 in place of the create instruction:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default github-dark-default`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0d1117`,color:`#1f2328`,\"--shiki-dark\":`#e6edf3`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#FFA657`},children:`ax`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` annotation-configs`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` create`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --name`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` pattern`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --space`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`space-i`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`d`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --type`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` CATEGORICAL`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` order-status`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` refund-eligibility`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` password-reset`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` unclustered`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Values are capped at `,_jsx(_components.strong,{children:`30 characters`}),` each, and a categorical config needs `,_jsx(_components.strong,{children:`between 2 and 100`}),` of them. Short slugs, not sentences.`]})]}),`\n`,_jsx(Heading,{level:`2`,id:`read-and-use-the-patterns`,children:`Read and use the patterns`}),`\n`,_jsx(_components.p,{children:`Everything from here is the same for both routes.`}),`\n`,_jsxs(Steps,{children:[_jsxs(Step,{title:`Read the clusters`,children:[_jsxs(_components.p,{children:[`Follow the transcript from the session detail slide-over, opened from the `,_jsx(_components.strong,{children:`Agent List`}),` tab under `,_jsx(_components.a,{href:`/ax/agents/build-your-own-agent`,children:`Signal \u0026 Agents`}),`. The run exports spans, writes summaries, reduces and clusters them, then reports a named pattern for every cluster with the number of traces in it. The example below comes from a customer support agent:`]}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Pattern`}),_jsx(_components.th,{children:`Traces`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`billing-escalation-failed`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`32`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`order-billing-limited-access`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`30`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`damaged-gear-needs-info`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`16`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`order-not-found`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`14`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`legacy-pwd-reset-failure`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`12`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`defective-item-no-tools`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`11`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`item-resolved-with-tools`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`9`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`cancel-modify-order-failed`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`6`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`unclustered`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:`1`})]})]})]}),_jsx(_components.p,{children:`Read past the labels to the counts and examples. In this example the largest patterns are the ones the agent exists to handle, and the interesting ones are smaller: a dependency that fails for one class of input, and requests the agent has no tool to satisfy. That last kind never shows up in an error rate, because from the agent’s side those runs succeeded. It just quietly could not help.`}),_jsx(_components.p,{children:`Notice that these labels lean on outcome rather than intent: one kind of request split into separate patterns according to whether it succeeded. That is the pipeline working as intended, and it is worth knowing before you read your own result, because patterns divide on whatever the summaries make salient.`})]}),_jsxs(Step,{title:`Filter traces by pattern`,children:[_jsxs(_components.p,{children:[`Open any trace in the project and check the `,_jsx(_components.strong,{children:`Annotations`}),` panel on its root span. The `,_jsx(_components.code,{children:`pattern`}),` label and the trace summary appear there, which confirms the write landed.`]}),_jsx(_components.p,{children:`Patterns are now a filter:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default github-dark-default`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0d1117`,color:`#1f2328`,\"--shiki-dark\":`#e6edf3`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`2`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`annotation.pattern.label = 'legacy-pwd-reset-failure'`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),_jsxs(_components.p,{children:[`Use it in the trace view, in a `,_jsx(_components.a,{href:`/ax/observe/tracing/saved-views`,children:`saved view`}),`, or from the CLI:`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default github-dark-default`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0d1117`,color:`#1f2328`,\"--shiki-dark\":`#e6edf3`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#FFA657`},children:`ax`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` spans`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` export`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`projec`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`t`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --filter`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` \"annotation.pattern.label = 'legacy-pwd-reset-failure'\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --all`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --space`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`space-i`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`d`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`})]}),`\n`]})})}),_jsx(_components.p,{children:`Because the agent annotates root spans, this returns one span per matching trace rather than every span in those traces.`}),_jsxs(_components.p,{children:[`From there a pattern behaves like any other slice: `,_jsx(_components.a,{href:`/ax/observe/take-action/curate-dataset`,children:`curate it into a dataset`}),` for an experiment, put it in a `,_jsx(_components.a,{href:`/ax/observe/dashboards`,children:`dashboard`}),` to watch its volume, or send it to a `,_jsx(_components.a,{href:`/ax/evaluate/human-review#labeling-queues`,children:`labeling queue`}),` for review.`]})]}),_jsxs(Step,{title:`Run it again as traffic changes`,children:[_jsx(_components.p,{children:`Patterns drift, so a single run describes the window it read and nothing later. Re-run the same prompt against a newer window whenever you want a current picture.`}),_jsxs(_components.p,{children:[`Step 9 is what makes a second run safe. Each run clusters from scratch and would otherwise invent fresh slug names, which silently breaks saved filters, so the prompt tells the agent to read the existing config and reuse the slugs already in it. Config names are unique per space, so a run that tries to create `,_jsx(_components.code,{children:`pattern`}),` again fails outright, and an agent left to improvise may route around that error by creating a differently named config.`]}),_jsx(_components.p,{children:`Because a run inside the sandbox cannot amend a config’s values, genuinely new patterns come back reported rather than labelled. Widen the config yourself when that happens:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default github-dark-default`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0d1117`,color:`#1f2328`,\"--shiki-dark\":`#e6edf3`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#FFA657`},children:`ax`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` annotation-configs`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` update`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` categorical`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` pattern`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --space`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`space-i`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`d`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`existing-slu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`g`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`existing-slu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`g`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`new-slu`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:`g`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:`>`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#FF7B72`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#79C0FF`},children:` --value`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#A5D6FF`},children:` unclustered`})]}),`\n`]})})}),_jsxs(_components.p,{children:[_jsx(_components.code,{children:`--value`}),` replaces the whole list rather than adding to it, so pass every value you want to keep, or existing annotations will point at labels the config no longer allows.`]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`tuning-the-clusters`,children:`Tuning the clusters`}),`\n`,_jsxs(_components.p,{children:[`The numbers in either prompt are starting points, not settled values. The two knobs pull in opposite directions: a higher similarity threshold splits clusters apart, while a higher `,_jsx(_components.code,{children:`min_cluster_size`}),` merges them by discarding the small ones. On the no-repo route the threshold is the lever; on the repo route it is `,_jsx(_components.code,{children:`min_cluster_size`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Clusters that mix unrelated patterns.`}),` Raise the threshold above 0.30, or on the repo route lower `,_jsx(_components.code,{children:`min_cluster_size`}),`. A threshold set too low produces one large cluster that has swallowed several unrelated intents. Ask for more clusters than feels natural and merge them yourself, since over-merged clusters hide exactly the small patterns worth finding.`]}),`\n`,_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[`Too many traces landing in `,_jsx(_components.code,{children:`unclustered`}),`.`]}),` Lower the threshold. The unclustered share climbs steeply once the threshold is too high, so move it in small steps. On the repo route, lower `,_jsx(_components.code,{children:`min_cluster_size`}),` instead.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`One pattern split across several clusters.`}),` Expect some of this and merge by hand. TF-IDF matches shared words rather than shared meaning, so “asking for a refund” and “want my money back” need not meet, and a single intent can end up spread across two or three clusters however you tune it. On the no-repo route, the number of eigenvectors is a secondary lever: more of them tends to fragment, fewer tends to merge.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Everything in one cluster.`}),` The summaries are the problem rather than the parameters. Incidental detail like order IDs gives TF-IDF spurious signal, and a shared boilerplate phrase in every summary flattens the contrast between them. Tighten the summary instruction.`]}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[`Do not read a low `,_jsx(_components.code,{children:`unclustered`}),` count as proof the clustering was good. Reduction pulls outliers toward the mass, so genuinely one-off traces are more likely to be absorbed into a cluster than set aside. The count is useful for spotting a threshold set too high; it is not outlier detection.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`troubleshooting`,children:`Troubleshooting`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Fewer traces annotated than you expected.`}),` The most common cause is the export, not the clustering: `,_jsx(_components.code,{children:`--limit`}),` defaults to 100, and `,_jsx(_components.code,{children:`--all`}),` cannot be used in the sandbox. Check the span and trace counts the agent reported, and if the span count sits exactly on the limit it truncated the window. Partial labels look complete and undercount every pattern.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`The agent tries to install packages and then improvises.`}),` PyPI is unreachable without a repo attached, and a blocked install rarely stops a run: the agent invents its own method instead, which no longer matches any guidance here. The no-repo prompt’s opening constraint exists to prevent this, so keep it.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`The install fails on the repo route.`}),` Check that GitHub is authorized and not only that a repo is named, since the repo field is ignored without it. If `,_jsx(_components.code,{children:`umap-learn`}),` pulls in a `,_jsx(_components.code,{children:`numba`}),` that will not build, pin `,_jsx(_components.code,{children:`umap-learn`}),` and `,_jsx(_components.code,{children:`numba`}),` to recent versions with prebuilt wheels for Python 3.13.`]}),`\n`,_jsxs(_components.li,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`ax spans export`}),` fails with a proxy or connection error on `,_jsx(_components.code,{children:`--all`}),`.`]}),` Bulk export uses Arrow Flight, which the sandbox blocks. Use `,_jsx(_components.code,{children:`--days`}),` and `,_jsx(_components.code,{children:`--limit`}),` instead.`]}),`\n`,_jsxs(_components.li,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`ax spans annotate`}),` rejects the whole batch.`]}),` Every span ID has to fall inside the lookup window, and the window cannot exceed 31 days, so keep the export window inside that limit rather than widening `,_jsx(_components.code,{children:`--days`}),` past it. Spans older than 31 days cannot be annotated this way at all. Batches are also capped at 1000 records.`]}),`\n`,_jsxs(_components.li,{children:[_jsxs(_components.strong,{children:[`Annotations are rejected with `,_jsx(_components.code,{children:`label '\u003cx>' is not one of the allowed values`}),`.`]}),` The agent invented a slug that the annotation config does not list. Have it create the config from its own slugs, or paste the allowed values into the prompt.`]}),`\n`,_jsxs(_components.li,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`no annotation config with name 'pattern' exists`}),`.`]}),` The config must exist before any span is annotated. Confirm the name in the prompt matches it exactly.`]}),`\n`,_jsxs(_components.li,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`Labels cannot exceed 30 characters`}),` while creating the config.`]}),` The agent used a cluster summary as a value. Ask for a separate short slug and keep the summary in the annotation’s text field.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Everything lands in one cluster or all in noise.`}),` See `,_jsx(_components.a,{href:`#tuning-the-clusters`,children:`Tuning the clusters`}),`. Check the summaries first: if they all end in the same phrase, or all name the same tool, they will cluster into a single blob no matter what the parameters say.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`beyond-patterns`,children:`Beyond patterns`}),`\n`,_jsx(_components.p,{children:`You now have a repeatable pipeline: one prompt that summarizes, clusters, and labels a whole project, and a filter that turns any pattern into a slice you can act on.`}),`\n`,_jsx(_components.p,{children:`Clustering is one job you can hand a managed agent, not the limit of what they do. The same agent reads your traces, runs code, and reports back, so the pattern generalizes:`}),`\n`,_jsxs(CardGroup,{cols:2,children:[_jsx(Card,{title:`Evaluating agents`,icon:`clipboard-check`,href:`/ax/concepts/evaluators/evaluating-agents`,children:_jsx(_components.p,{children:`Point a run at a slice of traces and have it draft labels and an evaluator prompt from what it finds.`})}),_jsx(Card,{title:`Skills and permissions`,icon:`code-branch`,href:`/ax/agents/connect-your-harness`,children:_jsx(_components.p,{children:`With a GitHub skill attached, a session can trace a failure to its source, write a test, and open a PR.`})}),_jsx(Card,{title:`Signal \u0026 Agents`,icon:`clock`,href:`/ax/agents/build-your-own-agent`,children:_jsx(_components.p,{children:`Run any of the above on a cron schedule or a metric threshold instead of by hand.`})}),_jsx(Card,{title:`Signal`,icon:`magnifying-glass`,href:`/ax/observe/signal`,children:_jsx(_components.p,{children:`Signal scans a project continuously and surfaces ranked issues, with no prompt required.`})})]}),`\n`,_jsx(_components.p,{children:`What these share is the shape of the request: a goal, a bound project, and permission to use tools. Anything you could work out by reading traces and running code, you can hand to an agent instead, once as a session or on a schedule.`}),`\n`,_jsx(Heading,{level:`2`,id:`next-steps`,children:`Next steps`}),`\n`,_jsxs(CardGroup,{cols:2,children:[_jsx(Card,{title:`How agents work`,icon:`diagram-project`,href:`/ax/agents/connect-your-harness`,children:_jsx(_components.p,{children:`Sandboxes, data access, credentials, and the boundaries of a run.`})}),_jsx(Card,{title:`Agent Studio`,icon:`wand-magic-sparkles`,href:`/ax/agents/build-your-own-agent`,children:_jsx(_components.p,{children:`Start sessions and automations, and bind a project to a run.`})}),_jsx(Card,{title:`Agent Configs`,icon:`layer-group`,href:`/ax/agents/build-your-own-agent`,children:_jsx(_components.p,{children:`Save the runtime, sandbox, and skills a run should use, instead of configuring each one.`})}),_jsx(Card,{title:`Human review`,icon:`tags`,href:`/ax/evaluate/human-review`,children:_jsx(_components.p,{children:`Annotation configs, labeling traces, and review workflows.`})}),_jsx(Card,{title:`Managed Agents CLI`,icon:`terminal`,href:`/api-clients/ag/overview`,children:_jsxs(_components.p,{children:[`Start sessions, follow transcripts, and trigger automations with `,_jsx(_components.code,{children:`ag`}),` instead of the UI.`]})})]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":{"theme":{"light":"github-light-default","dark":"github-dark-default"}},"config":{},"pageMetadata":{"title":"Cluster trace patterns with managed agents","description":"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.","keywords":["managed agents","patterns","error modes","clustering","umap","hdbscan","trace summaries","annotations","agent studio","arize ax"],"href":"/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Overview","slug":"overview","depth":2,"children":[]},{"title":"Before you start","slug":"before-you-start","depth":2,"children":[]},{"title":"What managed agents can access","slug":"what-managed-agents-can-access","depth":2,"children":[]},{"title":"Two routes","slug":"two-routes","depth":2,"children":[]},{"title":"Cluster the patterns","slug":"cluster-the-patterns","depth":2,"children":[]},{"title":"Read and use the patterns","slug":"read-and-use-the-patterns","depth":2,"children":[]},{"title":"Tuning the clusters","slug":"tuning-the-clusters","depth":2,"children":[]},{"title":"Troubleshooting","slug":"troubleshooting","depth":2,"children":[]},{"title":"Beyond patterns","slug":"beyond-patterns","depth":2,"children":[]},{"title":"Next steps","slug":"next-steps","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/docs/_mintlify/custom/arize-ax/6a30b7a67da02161/analytics.js","/docs/_mintlify/custom/arize-ax/67a4d27b62fababa/product-selector.js"],"subdomain":"arize-ax","siteName":"Arize AX Docs","title":"Cluster trace patterns with managed agents - Arize AX Docs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-20T17:03:43.669Z","originalFileLocation":"ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Arize AX Docs\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Cluster trace patterns with managed agents - Arize AX Docs\">\u003cmeta data-mint-head property=\"og:description\" content=\"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Arize AX Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://arize-ax.mintlify.app/_mintlify/api/og/v2?division=Observe\u0026amp;title=Cluster+trace+patterns+with+managed+agents\u0026amp;description=Use+a+managed+agent+to+summarize+every+trace+in+a+project%2C+cluster+the+summaries+into+named+patterns%2C+and+label+your+traces+so+patterns+become+filterable.\u0026amp;theme=95c8f62533e1d113476c56a7\u0026amp;signature=24734a143018f1f894247292950f20fd452ec05fb58498e68c740ad6e2e2eb11\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Cluster trace patterns with managed agents - Arize AX Docs\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://arize-ax.mintlify.app/_mintlify/api/og/v2?division=Observe\u0026amp;title=Cluster+trace+patterns+with+managed+agents\u0026amp;description=Use+a+managed+agent+to+summarize+every+trace+in+a+project%2C+cluster+the+summaries+into+named+patterns%2C+and+label+your+traces+so+patterns+become+filterable.\u0026amp;theme=95c8f62533e1d113476c56a7\u0026amp;signature=24734a143018f1f894247292950f20fd452ec05fb58498e68c740ad6e2e2eb11\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/arize-ax/vxzD83QsbAzzm43O/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Arize AX Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#7A0047\">\u003clink data-mint-head rel=\"canonical\" href=\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://arize.com/#organization\",\"name\":\"Arize AX Docs\",\"url\":\"https://arize.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/arize-ax/V-uvingrGLOCK4VD/logo/light.svg?fit=max\u0026auto=format\u0026n=V-uvingrGLOCK4VD\u0026q=85\u0026s=cc58ee9388d5b5253d39b65cc662908f\"}},{\"@type\":\"WebSite\",\"@id\":\"https://arize.com/docs#website\",\"name\":\"Arize AX Docs\",\"url\":\"https://arize.com/docs\",\"publisher\":{\"@id\":\"https://arize.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents#webpage\",\"url\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents\",\"name\":\"Cluster trace patterns with managed agents\",\"description\":\"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.\",\"dateModified\":\"2026-10-20T17:03:43.669Z\",\"isPartOf\":{\"@id\":\"https://arize.com/docs#website\"},\"breadcrumb\":{\"@id\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Observe\",\"item\":\"https://arize.com/docs/ax/cookbooks/observe/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cluster trace patterns with managed agents\",\"item\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents#article\",\"headline\":\"Cluster trace patterns with managed agents\",\"name\":\"Cluster trace patterns with managed agents\",\"description\":\"Use a managed agent to summarize every trace in a project, cluster the summaries into named patterns, and label your traces so patterns become filterable.\",\"url\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents\",\"mainEntityOfPage\":{\"@id\":\"https://arize.com/docs/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents#webpage\"},\"dateModified\":\"2026-10-20T17:03:43.669Z\",\"keywords\":\"managed agents, patterns, error modes, clustering, umap, hdbscan, trace summaries, annotations, agent studio, arize ax\",\"publisher\":{\"@id\":\"https://arize.com/#organization\"},\"isPartOf\":{\"@id\":\"https://arize.com/docs#website\"}}]}\u003c/script>","siteName":"Arize AX Docs","nav":{"global":null,"tabs":[{"tab":"Get Started","pages":[{"title":"Get Started","href":"/ax"}]},{"tab":"Guides","pages":[{"title":"Overview","sidebarTitle":"Overview","href":"/ax/cookbooks"},{"group":"Instrument","pages":[{"title":"Instrument","sidebarTitle":"Overview","href":"/ax/cookbooks/instrument/overview"},{"group":"Instrument Agents Built with Anthropic","pages":[{"title":"Agents Built with the Claude Agent SDK","href":"/ax/cookbooks/instrument/claude-agent-sdk-guide"},{"title":"Trace and Evaluate Claude Managed Agents","href":"/ax/cookbooks/instrument/claude-managed-agents-guide"},{"title":"Agents Built with the Anthropic SDK","href":"/ax/cookbooks/instrument/anthropic-sdk-guide"}]},{"group":"Instrument agents built with OpenAI","pages":[{"title":"Trace and Evaluate an Agent Built with the OpenAI Agents SDK","sidebarTitle":"Agents built with the OpenAI Agents SDK","href":"/ax/cookbooks/instrument/openai-agents-cookbook"},{"title":"Trace an Agent Built with the OpenAI SDK","sidebarTitle":"Agents built with the OpenAI SDK","href":"/ax/cookbooks/instrument/openai-sdk-guide"}]},{"title":"Instrument LangChain agents","href":"/ax/cookbooks/instrument/langchain-guide"},{"title":"Instrument AI Coding Agents","href":"/ax/cookbooks/instrument/tracing-coding-agents"},{"title":"Instrument Vercel Eve Agents","href":"/ax/cookbooks/instrument/tracing-a-vercel-eve-agent"},{"title":"Instrument Mastra agents","href":"/ax/cookbooks/instrument/mastra-guide"},{"title":"Instrument Groq agents","href":"/ax/cookbooks/instrument/groq-sdk-guide"},{"title":"Instrument LiteLLM agents","href":"/ax/cookbooks/instrument/litellm-guide"},{"title":"Instrument Google ADK agents","href":"/ax/cookbooks/instrument/google-adk-guide"},{"title":"Instrument \u0026 Evaluate a Customer Support Agent","href":"/ax/cookbooks/instrument/tracing-and-evaluating-agents"},{"title":"OpenInference Best Practices","href":"/ax/cookbooks/instrument/openinference-best-practice"},{"title":"Tracing Integrations","href":"/ax/cookbooks/tracing-integrations"}]},{"group":"Observe","pages":[{"title":"Observe","description":"Guides for observing and monitoring your LLM and agent applications in production with Arize AX.","sidebarTitle":"Overview","href":"/ax/cookbooks/observe/overview"},{"title":"Cluster trace patterns with managed agents","href":"/ax/cookbooks/observe/cluster-trace-patterns-with-managed-agents"},{"title":"Online Evals \u0026 Monitoring for Agents in Production (Mosaic AI)","description":"This notebook is adapted from Databricks's '[Mosaic AI Agent Framework: Author and deploy a tool-calling LangGraph agent](https://docs.databricks.com/aws/en/notebooks/source/generative-ai/langgraph-tool-calling-agent.html)'","href":"/ax/cookbooks/observe/arize-+-mosaic-ai-agent-framework"},{"title":"Designing Realtime Guardrails: Input, Output, and the Cost of Blocking","href":"/ax/cookbooks/observe/designing-realtime-guardrails"}]},{"group":"Evaluate","pages":[{"title":"Evaluate","sidebarTitle":"Overview","href":"/ax/cookbooks/evaluate/overview"},{"title":"Evaluations Quickstart","href":"/ax/cookbooks/evaluate/evaluations-quickstart"},{"title":"Align LLM Evals with Human Judgment","href":"/ax/cookbooks/evaluate/align-llm-evals-with-human-judgment"},{"title":"Why Public Benchmarks Lie: Building Your Own Eval Harness","href":"/ax/cookbooks/evaluate/model-comparison-for-an-email-text-extraction-service"},{"title":"Trace-Level Evaluation: Beyond Input/Output Checks","href":"/ax/cookbooks/evaluate/trace-level-evaluations-for-a-recommendation-agent"},{"title":"Session-Level Evaluation: Scoring the Whole Conversation","href":"/ax/cookbooks/evaluate/session-level-evaluations-for-an-ai-tutor"},{"title":"Evaluating RAG Retrieval Quality and Correctness","href":"/ax/cookbooks/evaluate/evaluating-rag"},{"title":"Evaluate a Math Problem-Solving Agent Using Ragas","href":"/ax/cookbooks/evaluate/ragas-agents-cookbook"},{"title":"Pydantic Evals","href":"/ax/cookbooks/evaluate/pydantic-evals"},{"title":"Tracing and Evaluating Voice Applications","href":"/ax/cookbooks/evaluate/tracing-and-evaluating-audio"},{"title":"Audio Transcription And Evaluation With Gemini Flash","href":"/ax/cookbooks/evaluate/gemini-audio-evals"},{"title":"Evaluate Receipt Agents with an Image Judge","href":"/ax/cookbooks/evaluate/evaluate-receipt-agents-with-image-judge"},{"title":"Use Jev as a Remote Evaluator","href":"/ax/cookbooks/evaluate/jev-remote-evaluator"}]},{"group":"Improve","pages":[{"title":"Improve","sidebarTitle":"Overview","href":"/ax/cookbooks/improve/overview"},{"title":"Build, Test, and Optimize a Trip-Planner Prompt","href":"/ax/cookbooks/improve/trip-planner-build-test-optimize"},{"title":"Prompt Experimentation For Summarization Task","href":"/ax/cookbooks/improve/summarization"},{"title":"Text2SQL Application for Database Querying","href":"/ax/cookbooks/improve/text2sql"},{"title":"Improving Structured Output Generation with Prompt Learning","href":"/ax/cookbooks/improve/improving-structured-output-generation-with-prompt-learning"},{"title":"Optimizing Coding Agent Prompts for Planning","href":"/ax/cookbooks/improve/optimizing-coding-agent-prompts-for-planning"},{"title":"Optimizing Coding Agent Prompts for Execution","href":"/ax/cookbooks/improve/optimizing-coding-agent-prompts-for-execution"},{"title":"Observe and Optimize Coding Agent Workflows","sidebarTitle":"Observe and Optimize Coding Agent Workflows","href":"/ax/cookbooks/improve/observe-and-optimize-coding-agent-workflows"},{"title":"Find and Fix Issues in Your AI App with a Coding Agent","sidebarTitle":"Find and Fix Issues with a Coding Agent","href":"/ax/cookbooks/improve/find-and-fix-issues-with-a-coding-agent"},{"title":"Optimizing Your Eval Prompts","href":"/ax/cookbooks/improve/optimizing-your-eval-prompts"}]},{"group":"Advanced Workflows","pages":[{"title":"Advanced Workflows","sidebarTitle":"Overview","href":"/ax/cookbooks/advanced-workflows/overview"},{"title":"Evaluating Agentic RAG Using Arize AX And Couchbase","href":"/ax/cookbooks/advanced-workflows/evaluating-agentic-rag-using-arize-and-couchbase"},{"title":"Product Recommendation Agent: Google Agent Engine \u0026 LangGraph","href":"/ax/cookbooks/advanced-workflows/tracing-a-langgraph-application-with-agent-engine-in-vertex-ai"},{"title":"A2A Financial Trading Agents - Google ADK / MCP / Llama","href":"/ax/cookbooks/advanced-workflows/tracing-a2a-agent"},{"title":"Multi-modal Autonomous Browser Agent with LLama Models ","href":"/ax/cookbooks/advanced-workflows/trace-evaluate-browser-use-agent-with-l-lama4"},{"title":"Trace LangChain Agent \u0026 Microsoft Risk+Safety Evaluators (Microsoft Foundry)","href":"/ax/cookbooks/advanced-workflows/evaluating-and-improving-ai-agents-at-scale-with-microsoft-foundry"},{"title":"Trace Red Teaming Agent (Microsoft Foundry)","href":"/ax/cookbooks/advanced-workflows/foundry-red-team"},{"title":"Jailbreak and Prompt Injection Defense","href":"/ax/cookbooks/advanced-workflows/jailbreak-and-prompt-injection-defense"},{"title":"Dual Tracing into Databricks Unity Catalog and Arize AX","href":"/ax/cookbooks/instrument/dual-o-tel-ingest-into-unity-catalog-and-arize-ax"},{"title":"AI Research","href":"/ax/cookbooks/ai-research"}]},{"group":"Migrate","pages":[{"title":"Migrate","sidebarTitle":"Overview","href":"/ax/cookbooks/migrate/overview"},{"title":"Migrate from Phoenix to Arize AX","sidebarTitle":"Migrate from Phoenix","href":"/ax/cookbooks/migrate/migrate-from-phoenix"},{"title":"Migrate from Braintrust to Arize AX","sidebarTitle":"Migrate from Braintrust","href":"/ax/cookbooks/migrate/migrate-from-braintrust"},{"title":"Migrate from Langfuse to Arize AX","sidebarTitle":"Migrate from Langfuse","href":"/ax/cookbooks/migrate/migrate-from-langfuse"},{"title":"Migrate from LangSmith to Arize AX","sidebarTitle":"Migrate from LangSmith","href":"/ax/cookbooks/migrate/migrate-from-langsmith"}]}]},{"tab":"Integrations","pages":[{"title":"Integrations","href":"/ax/integrations"}]},{"tab":"APIs, SDKs, \u0026 Skills","pages":[{"title":"APIs, SDKs, \u0026 Skills","href":"/api-reference/overview"}]},{"tab":"Learn","pages":[{"title":"Learn","href":"/ax/learn"}]},{"tab":"Concepts","pages":[{"title":"Concepts","href":"/ax/concepts/otel-openinference/overview"}]},{"tab":"Self-Hosting","pages":[{"title":"Self-Hosting","href":"/ax/selfhosting"}]},{"tab":"Changelog","pages":[{"title":"Changelog","href":"/ax/release-notes"}]}]},"title":"Cluster trace patterns with managed agents - Arize AX Docs","buildId":"dpl_DGmhKsAzJdVqypJzon18vViniWRY","deploymentId":"dpl_DGmhKsAzJdVqypJzon18vViniWRY","dynamics":["07c022d89b"],"chunks":["Frame-Bb6zlep0.js","DynamicMarkdown-34OtG_BH.js"]}