Official docs: Evaluate with the Azure AI Evaluation SDK
Built-in evaluators give you a consistent, reproducible way to measure quality and safety of your AI application outputs — from single examples during development to batch runs in CI/CD pipelines.
# Core evaluation SDK
pip install azure-ai-evaluation azure-identity
# For running against Azure OpenAI models
pip install openai
You also need:
"""Shared model configuration used across all examples in this lesson."""
model_config = {
"azure_deployment": "gpt-4o",
"azure_endpoint": "https://<your-endpoint>.openai.azure.com/",
"api_version": "2024-12-01-preview",
}
Tip: Store these values in environment variables rather than hardcoding them. Use
os.environ["AZURE_OPENAI_ENDPOINT"]in production code.
Start by evaluating one query-response pair to understand how each evaluator works.
"""Evaluate a single example with multiple quality evaluators."""
from azure.ai.evaluation import (
GroundednessEvaluator,
RelevanceEvaluator,
CoherenceEvaluator,
FluencyEvaluator,
)
# Initialize evaluators with the model config
groundedness = GroundednessEvaluator(model_config=model_config)
relevance = RelevanceEvaluator(model_config=model_config)
coherence = CoherenceEvaluator(model_config=model_config)
fluency = FluencyEvaluator(model_config=model_config)
# Test data
query = "How do I create an Azure AI Foundry project?"
context = (
"To create an Azure AI Foundry project, go to ai.azure.com, "
"click 'New project', select a hub (or create one), give your "
"project a name, and click Create. You need an Azure subscription "
"with Contributor access."
)
response = (
"To create a project, visit ai.azure.com and click 'New project'. "
"Select or create a hub, name your project, and click Create. "
"You'll need an Azure subscription with Contributor access."
)
# Run each evaluator
results = {
"groundedness": groundedness(query=query, context=context, response=response),
"relevance": relevance(query=query, context=context, response=response),
"coherence": coherence(query=query, response=response),
"fluency": fluency(query=query, response=response),
}
for name, result in results.items():
print(f"{name:>15}: {result}")
Expected output:
groundedness: {'groundedness': 5.0, 'groundedness_reason': '...'}
relevance: {'relevance': 5.0, 'relevance_reason': '...'}
coherence: {'coherence': 5.0, 'coherence_reason': '...'}
fluency: {'fluency': 5.0, 'fluency_reason': '...'}
Tip: Each evaluator returns a score (1–5) plus a human-readable reason explaining the rating. Use the reason for debugging low scores.
For realistic testing, evaluate against a dataset of many examples using the evaluate() function.
Create a JSONL file (eval_dataset.jsonl):
{"query": "What is Azure AI Foundry?", "context": "Azure AI Foundry is a unified platform for building AI apps.", "response": "Azure AI Foundry is a platform for building AI applications.", "ground_truth": "Azure AI Foundry is a unified platform for building, evaluating, and deploying AI applications."}
{"query": "How do I deploy a model?", "context": "In Azure AI Foundry, go to Model catalog, select a model, click Deploy, choose serverless or managed compute.", "response": "Navigate to Model catalog in Azure AI Foundry, pick your model, and click Deploy.", "ground_truth": "Go to the Model catalog in Azure AI Foundry, select a model, click Deploy, and choose serverless or managed compute."}
{"query": "What evaluators are available?", "context": "Azure AI Foundry offers quality evaluators like groundedness, relevance, coherence, and fluency. Safety evaluators detect violence, sexual content, self-harm, and hate.", "response": "Available evaluators include groundedness, relevance, coherence, fluency for quality, and violence, sexual, self-harm, hate detectors for safety.", "ground_truth": "Quality evaluators: groundedness, relevance, coherence, fluency. Safety evaluators: violence, sexual, self-harm, hate/unfairness."}
"""Run batch evaluation across a dataset with multiple evaluators."""
from azure.ai.evaluation import evaluate, F1ScoreEvaluator
from azure.ai.evaluation import (
GroundednessEvaluator,
RelevanceEvaluator,
CoherenceEvaluator,
FluencyEvaluator,
SimilarityEvaluator,
)
result = evaluate(
data="eval_dataset.jsonl",
evaluators={
"groundedness": GroundednessEvaluator(model_config=model_config),
"relevance": RelevanceEvaluator(model_config=model_config),
"coherence": CoherenceEvaluator(model_config=model_config),
"fluency": FluencyEvaluator(model_config=model_config),
"similarity": SimilarityEvaluator(model_config=model_config),
"f1_score": F1ScoreEvaluator(),
},
# Map dataset columns to evaluator parameters
evaluator_config={
"groundedness": {
"query": "${data.query}",
"context": "${data.context}",
"response": "${data.response}",
},
"relevance": {
"query": "${data.query}",
"context": "${data.context}",
"response": "${data.response}",
},
"coherence": {
"query": "${data.query}",
"response": "${data.response}",
},
"fluency": {
"query": "${data.query}",
"response": "${data.response}",
},
"similarity": {
"query": "${data.query}",
"response": "${data.response}",
"ground_truth": "${data.ground_truth}",
},
"f1_score": {
"response": "${data.response}",
"ground_truth": "${data.ground_truth}",
},
},
)
# Aggregate metrics
print("=== Aggregate Metrics ===")
for metric, value in result["metrics"].items():
print(f" {metric}: {value:.2f}")
# Per-row results
print("\n=== Per-Row Results ===")
for i, row in enumerate(result["rows"]):
print(f"\n Row {i}: query = {row['inputs.query'][:50]}...")
print(f" groundedness={row['outputs.groundedness.groundedness']}")
print(f" relevance={row['outputs.relevance.relevance']}")
print(f" f1_score={row['outputs.f1_score.f1_score']:.3f}")
Tip: The
evaluate()function runs evaluators in parallel for speed. Results include both per-row details and aggregate metrics (mean scores).
Safety evaluators detect harmful content categories. They use Azure AI Content Safety under the hood.
"""Run safety evaluations to detect harmful content."""
from azure.ai.evaluation import (
ViolenceEvaluator,
SexualEvaluator,
SelfHarmEvaluator,
HateUnfairnessEvaluator,
)
# Safety evaluators use the same model config
violence = ViolenceEvaluator(model_config=model_config)
sexual = SexualEvaluator(model_config=model_config)
self_harm = SelfHarmEvaluator(model_config=model_config)
hate = HateUnfairnessEvaluator(model_config=model_config)
# Test with a safe response
safe_response = (
"To reset your password, go to Settings > Security > Change Password. "
"Enter your current password and then your new password twice."
)
safety_results = {
"violence": violence(query="How do I reset my password?", response=safe_response),
"sexual": sexual(query="How do I reset my password?", response=safe_response),
"self_harm": self_harm(query="How do I reset my password?", response=safe_response),
"hate": hate(query="How do I reset my password?", response=safe_response),
}
for name, result in safety_results.items():
severity = result.get(f"{name}_score", result.get(f"{name}", "N/A"))
print(f" {name:>12}: severity={severity}")
Severity scale:
Tip: Set a threshold (e.g., severity ≤ 2) for automated quality gates. Any response above the threshold should trigger a review.
In practice, you run quality and safety evaluators together in one batch.
"""Combined quality and safety batch evaluation."""
from azure.ai.evaluation import (
evaluate,
GroundednessEvaluator,
RelevanceEvaluator,
CoherenceEvaluator,
FluencyEvaluator,
ViolenceEvaluator,
SelfHarmEvaluator,
HateUnfairnessEvaluator,
)
result = evaluate(
data="eval_dataset.jsonl",
evaluators={
# Quality
"groundedness": GroundednessEvaluator(model_config=model_config),
"relevance": RelevanceEvaluator(model_config=model_config),
"coherence": CoherenceEvaluator(model_config=model_config),
"fluency": FluencyEvaluator(model_config=model_config),
# Safety
"violence": ViolenceEvaluator(model_config=model_config),
"self_harm": SelfHarmEvaluator(model_config=model_config),
"hate": HateUnfairnessEvaluator(model_config=model_config),
},
evaluator_config={
"groundedness": {
"query": "${data.query}",
"context": "${data.context}",
"response": "${data.response}",
},
"relevance": {
"query": "${data.query}",
"context": "${data.context}",
"response": "${data.response}",
},
"coherence": {
"query": "${data.query}",
"response": "${data.response}",
},
"fluency": {
"query": "${data.query}",
"response": "${data.response}",
},
"violence": {
"query": "${data.query}",
"response": "${data.response}",
},
"self_harm": {
"query": "${data.query}",
"response": "${data.response}",
},
"hate": {
"query": "${data.query}",
"response": "${data.response}",
},
},
)
# Summary
metrics = result["metrics"]
print("Quality Scores (1-5):")
print(f" Groundedness: {metrics.get('groundedness.groundedness', 'N/A')}")
print(f" Relevance: {metrics.get('relevance.relevance', 'N/A')}")
print(f" Coherence: {metrics.get('coherence.coherence', 'N/A')}")
print(f" Fluency: {metrics.get('fluency.fluency', 'N/A')}")
print("\nSafety Scores (0=safe, 7=max severity):")
print(f" Violence: {metrics.get('violence.violence_score', 'N/A')}")
print(f" Self-harm: {metrics.get('self_harm.self_harm_score', 'N/A')}")
print(f" Hate: {metrics.get('hate.hate_unfairness_score', 'N/A')}")
Automate pass/fail decisions in your CI/CD pipeline:
"""Quality gate: fail the pipeline if evaluation scores are below thresholds."""
QUALITY_THRESHOLDS = {
"groundedness.groundedness": 4.0,
"relevance.relevance": 4.0,
"coherence.coherence": 4.0,
"fluency.fluency": 4.0,
}
SAFETY_MAX_SEVERITY = {
"violence.violence_score": 2,
"self_harm.self_harm_score": 2,
"hate.hate_unfairness_score": 2,
}
def check_quality_gate(eval_result: dict) -> bool:
"""Return True if all quality and safety gates pass."""
metrics = eval_result["metrics"]
passed = True
print("=== Quality Gate Results ===")
# Check quality minimums
for metric, threshold in QUALITY_THRESHOLDS.items():
value = metrics.get(metric, 0)
status = "✅ PASS" if value >= threshold else "❌ FAIL"
print(f" {metric}: {value:.2f} (min: {threshold}) {status}")
if value < threshold:
passed = False
# Check safety maximums
for metric, max_val in SAFETY_MAX_SEVERITY.items():
value = metrics.get(metric, 0)
status = "✅ PASS" if value <= max_val else "❌ FAIL"
print(f" {metric}: {value} (max: {max_val}) {status}")
if value > max_val:
passed = False
print(f"\nOverall: {'✅ ALL GATES PASSED' if passed else '❌ GATE FAILURE'}")
return passed
# Usage in CI/CD
gate_passed = check_quality_gate(result)
if not gate_passed:
raise SystemExit("Quality gate failed — blocking deployment.")
For teams that prefer a UI-driven workflow, the portal provides a guided evaluation wizard.
Tip: Use the portal wizard for exploratory evaluation and the SDK for automated CI/CD pipelines. Both produce compatible result formats.
Instead of evaluating pre-computed responses, you can point the evaluate() function at your live application:
"""Evaluate your application end-to-end by providing a target function."""
from azure.ai.evaluation import evaluate, RelevanceEvaluator, CoherenceEvaluator
from openai import AzureOpenAI
# Your application logic wrapped as a callable
client = AzureOpenAI(
azure_endpoint="https://<your-endpoint>.openai.azure.com/",
api_version="2024-12-01-preview",
)
def my_rag_app(query: str) -> dict:
"""Simulate a RAG app: retrieve context, then generate a response."""
# Step 1: Retrieve context (simplified — use real retrieval in production)
context = retrieve_documents(query)
# Step 2: Generate response
completion = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Answer using this context:\n{context}"},
{"role": "user", "content": query},
],
)
response = completion.choices[0].message.content
# Must return a dict with keys matching evaluator inputs
return {"response": response, "context": context}
def retrieve_documents(query: str) -> str:
"""Placeholder for your retrieval logic (e.g., Azure AI Search)."""
return "Azure AI Foundry supports GPT-4o, Llama, Mistral, and more."
# Evaluation dataset (only queries needed — the target function generates responses)
# eval_queries.jsonl:
# {"query": "What models does Azure AI Foundry support?"}
# {"query": "How do I evaluate my AI app?"}
result = evaluate(
data="eval_queries.jsonl",
target=my_rag_app,
evaluators={
"relevance": RelevanceEvaluator(model_config=model_config),
"coherence": CoherenceEvaluator(model_config=model_config),
},
evaluator_config={
"relevance": {
"query": "${data.query}",
"context": "${target.context}",
"response": "${target.response}",
},
"coherence": {
"query": "${data.query}",
"response": "${target.response}",
},
},
)
print("Target function evaluation complete!")
for metric, value in result["metrics"].items():
print(f" {metric}: {value:.2f}")
Tip: The
targetparameter calls your function for each row in the dataset. The function receives the dataset columns as keyword arguments and must return a dict. Use${target.<key>}in evaluator config to reference the returned values.
| Concept | Key Takeaway |
|---|---|
| Quality evaluators | Measure groundedness, relevance, coherence, fluency (1–5 scale) |
| Safety evaluators | Detect violence, sexual, self-harm, hate content (severity 0–7) |
evaluate() function |
Batch evaluation with parallel execution and aggregate metrics |
| Target function | Evaluate your live app end-to-end, not just cached responses |
| Quality gates | Automate pass/fail in CI/CD with threshold checks |
| Portal wizard | UI-driven evaluation for exploration and team collaboration |
| ← Overview | Next → Lesson 2: Custom Evaluators |