In this tutorial, you run continuous LLM-as-a-judge evaluations against the production GenAI traffic already flowing into Dynatrace, using the open-source dt-evals CLI. You score real interactions, detect quality drift over time, and pivot from any low score straight to the trace that produced it.
DevOps engineers and AI engineers who want to continuously score the quality of a GenAI service already sending traces to Dynatrace.
dt-evals against your Dynatrace environment and a judge providerNode.js 20 or later
A Dynatrace environment already receiving GenAI spans
A Dynatrace platform token with the following scopes. For how to create or update a token, see Platform tokens. You can let dtevals help you set up this token, see Set up credentials.
storage:spans:readstorage:buckets:readstorage:bizevents:readstorage:events:writestorage:metrics:writestorage:logs:readCredentials for one judge provider: OpenAI, Anthropic, Azure OpenAI, Google Gemini Enterprise Platform (Vertex AI), or Amazon Bedrock
The tutorial uses GenAI spans that already exist in your environment, so any service that sends them to Dynatrace will work.
If you don't have one yet, you can start with the pydantic-ai/opentelemetry sample application from dynatrace-oss/dynatrace-ai-agent-instrumentation-examples. It is a music history agent that uses pydantic-ai's native OpenTelemetry support to emit GenAI spans to Dynatrace.
Ensure your application is already running and its spans are visible in
AI Observability before continuing.
Follow these steps to run evaluations with dt-evals.
This example uses OpenAI as the judge provider. To configure a different provider, such as Anthropic, Azure OpenAI, Google Gemini Enterprise Platform (Vertex AI), or Amazon Bedrock, see Supported providers.
Install dt-evals globally, or run it on demand with npx.
npm install -g @dynatrace-oss/dt-evals
Verify the installation:
dt-evals --version
dt-evals needs a Dynatrace platform token (to read spans and write results) and a key for your judge provider. The CLI reads both from the environment and never stores them in the config file; it picks them up automatically, regardless of how you supply them.
The easiest way is to let the CLI walk you through it.
dt-evals doctor
When you do this, dt-evals doctor:
.env file.The dt-evals configure wizard in the next step also prompts for these credentials.
If you prefer to set the variables yourself, export them directly and the CLI will use them. For information about how to create a token, see Platform tokens; grant the scopes listed in Prerequisites.
export DT_API_TOKEN=dt0s16.<your-token>export OPENAI_API_KEY=<your-key>
For CI, set the same variables as pipeline secrets instead of exporting them locally.
Run the interactive wizard. The wizard connects to your Dynatrace environment, selects your judge provider, and writes a .dt-eval.yaml file to the current directory.
dt-evals configure
The wizard produces a config similar to what's shown in the following code block. Set scope.service to the service that emits your GenAI spans, and choose which evaluators to run under metrics.enabled.
schemaVersion: 2name: music-agent-evalsdynatrace:environmentUrl: https://<your-env-id>.live.dynatrace.com# apiToken loaded from the DT_API_TOKEN environment variablejudge:provider: openaimodel: gpt-4.1scope:service: pydantic-ai-music-agentsince: 1hsampling:strategy: randompercent: 10metrics:enabled:- faithfulness- relevance- hallucination- toxicity- driftalerts:thresholds:faithfulness: 0.7relevance: 0.7storeEvaluatedPrompt: false
By default, dt-evals reads OpenTelemetry GenAI semantic convention fields. If your spans expose LLM input and output under different attribute names, map them to the canonical fields with scope.spanFields. For more information, see the dt-evals README.
The wizard writes .dt-eval.yaml to the current directory. Continue to the next step to validate your config and connectivity.
Before the first run, confirm that your config, Dynatrace connectivity, and judge provider are all reachable.
dt-evals validate
Run all enabled evaluators against a sample of recent traces.
The CLI writes results back to Dynatrace as bizevents with event.type == "gen_ai.evaluation.result", linked to their source traces.
Here are some example runs that you could do:
To evaluate only a certain percentage of traces, use --sample.
dt-evals run --since 1h --sample 10
--since sets the trace lookback window, for example 1h or 24h.--sample is the percentage of traces to evaluate.To run a single evaluator, use --metric.
dt-evals run --since 6h --metric faithfulness
To preview the work without calling the judge or writing results, use --dry-run.
dt-evals run --since 1h --sample 5 --dry-run
Built-in evaluators cover common safety, grounding, and quality checks. When you need a project-specific rubric, create your own LLM-as-a-judge evaluator with the interactive wizard.
For example, suppose you want to score whether the chatbot answers in a concise, on-brand style.
Run the wizard and define an answer-style evaluator with your own judge prompt, scoring range, and pass threshold.
dt-evals evaluators add
The wizard stores the evaluator locally. Enable it in .dt-eval.yaml like any built-in evaluator.
metrics:enabled:- faithfulness- answer-style
Inspect and test it before a full run.
dt-evals evaluators show answer-styledt-evals evaluators test answer-style
To gate a deployment on quality, add the --ci flag to your run. The command exits with a non-zero code when a score falls below its configured threshold, which fails the pipeline step.
dt-evals run --ci
To repeat a run on a schedule, invoke it from your own scheduler, such as a cron job or a CI pipeline trigger.
After the scheduled run completes, open the Evaluations tab in
AI Observability to confirm new scores appear.
When you run dt-evals, it samples the GenAI spans in your configured timeframe, masks personally identifiable information in memory, scores each interaction with your judge model, and writes the results back to Dynatrace as bizevents.
bizevents entry linked to its source trace, so a low score is never a dead end.For gradual regressions rather than single-run breaches, enable the drift evaluator. The drift evaluator compares recent scores against a seven-day baseline of prior evaluation results.
With your evaluations in place, you can explore scores, drift, and threshold breaches in Dynatrace.
In
AI Observability, open the Evaluations tab to see pass and fail rates, average score per evaluator, score distribution, and drift over time. Select any failing score to open the originating trace and inspect the prompt, retrieval context, model call, and tool usage behind it.
For more information about the tabs, see AI Observability app.
The Evaluations tab is currently part of our Preview program and is governed by our preview terms. The features offered in the preview are not complete and may undergo significant changes prior to general availability.
Evaluation results are queryable as bizevents. To see the average score per evaluator, run the following query:
fetch bizevents| filter event.type == "gen_ai.evaluation.result"| summarize avg_score = avg(gen_ai.evaluation.score.value), by: { gen_ai.evaluation.name }| sort avg_score asc
Each result carries the score (gen_ai.evaluation.score.value), the pass or fail label (gen_ai.evaluation.score.label), the judge's explanation, and the source trace_id.
Because results are bizevents, you can alert on quality as you would any other signal. Create a custom alert on a rising fail rate or a dropping average score, and route notifications to your team.