Two Python scripts for automated validation of voice agent evaluation datasets in JSONL format.
Available as:
- ✅ Command-line tools (CLI)
- ✅ Python modules (programmatic import)
- ✅ Agent Skills (dynamic discovery)
Purpose: Validates basic dataset consistency and completeness
Checks:
- ✅ JSONL syntax correctness (valid JSON per line)
- ✅ Required field completeness (WavPath, Question, Answer, conversationID, system_prompt)
- ✅ Audio file presence (all referenced WAV files exist)
- ✅ Conversation structure (turn counts, system_prompt consistency)
Purpose: Validates content quality and appropriateness
Checks:
- ✅ System prompt relevance to conversation content
- ✅ Tool definition appropriateness (action requests vs. conversational)
- ✅ Question intent classification (action/instructional/general)
- ✅ Content quality metrics (length, diversity, depth)
No additional dependencies required beyond Python 3.7+. Uses only standard library modules.
# Validate a JSONL file directly
python validate_dataset_consistency.py path/to/dataset.jsonl
python validate_dataset_quality.py path/to/dataset.jsonl
# Validate by folder (auto-detects JSONL file)
python validate_dataset_consistency.py path/to/dataset_folder/
python validate_dataset_quality.py path/to/dataset_folder/# Strict mode - conservative keyword-only alignment matching
python validate_dataset_quality.py dataset.jsonl --strict
# Verbose mode - detailed per-conversation breakdown
python validate_dataset_quality.py dataset.jsonl --verbose
# JSON export - save results for programmatic access
python validate_dataset_quality.py dataset.jsonl --json results.json
# Ignore comment lines - handle // or # comments (non-standard)
python validate_dataset_quality.py dataset.jsonl --ignore-comments
# Combine multiple flags
python validate_dataset_quality.py dataset.jsonl --strict --verbose --json output.jsonConsistency Validator Options:
# Ignore comment lines in JSONL
python validate_dataset_consistency.py dataset.jsonl --ignore-comments
# Validate specific turn count (e.g., all conversations must have 3 turns)
python validate_dataset_consistency.py dataset.jsonl --expected-turns 3
# Combine flags
python validate_dataset_consistency.py dataset.jsonl --ignore-comments --expected-turns 3Flag Details:
-
--strict: Uses keyword-only domain matching (more conservative, ~50% vs default ~88%)- Removes generic support pattern detection
- Requires domain-specific vocabulary in conversations
- Useful for validating domain expertise
-
--verbose/-v: Shows detailed per-conversation analysis- Lists each conversation with alignment status
- Shows question previews for unaligned conversations
- Helps identify specific conversations needing review
-
--json <file>: Exports results to JSON file- Structured data for integration with other tools
- Includes all metrics and domain breakdowns
- Enables automated processing in CI/CD pipelines
-
--ignore-comments: Skips lines starting with//or#- Non-standard JSONL extension (use with caution)
- Useful for test datasets with inline documentation
- Comment lines are silently skipped during processing
- Validator reports number of skipped lines
-
--expected-turns N: Validates all conversations have exactly N turns- Default behavior (no flag): Analyzes and reports turn count distribution
- With flag: Validates all conversations match the specified turn count
- Use when dataset requires uniform conversation length
- Provides warnings for conversations that don't match expected count
- Example:
--expected-turns 3ensures all conversations are 3-turn dialogs
# Consistency validation
python validate_dataset_consistency.py "local_datasets/DataOcean/20260122-wave1-50"
# Quality validation (default mode - permissive)
python validate_dataset_quality.py "local_datasets/DataOcean/20260122-wave1-50"
# Quality validation with strict mode
python validate_dataset_quality.py "local_datasets/DataOcean/20260122-wave1-50" --strict
# Detailed analysis with verbose output
python validate_dataset_quality.py "local_datasets/DataOcean/20260122-wave1-50" --verbose
# Export results for reporting
python validate_dataset_quality.py "local_datasets/DataOcean/20260122-wave1-50" --json report.json# Windows PowerShell
python validate_dataset_consistency.py dataset.jsonl && python validate_dataset_quality.py dataset.jsonl
# Linux/Mac
python validate_dataset_consistency.py dataset.jsonl && python validate_dataset_quality.py dataset.jsonlThese validators can be integrated into your workflow in three different ways, depending on your use case.
Best for: Manual validation, ad-hoc checks, scripting
# Run from command line
python validate_dataset_consistency.py dataset.jsonl
python validate_dataset_quality.py dataset.jsonl --strictWhen to use:
- ✅ Manual dataset validation
- ✅ Quick checks during development
- ✅ Shell scripts and automation
- ✅ CI/CD pipelines (via shell commands)
Best for: Hard-coded workflows, guaranteed validation, fixed pipelines
from dataset_validator.validate_dataset_consistency import DatasetConsistencyValidator
from dataset_validator.validate_dataset_quality import DatasetQualityValidator
def prepare_dataset_for_evaluation(dataset_path):
# Step 1: Consistency (MANDATORY - must pass)
consistency = DatasetConsistencyValidator(dataset_path)
if not consistency.validate():
raise ValueError(f"Dataset invalid: {consistency.errors}")
# Step 2: Quality (ADVISORY - guides improvements)
quality = DatasetQualityValidator(dataset_path, strict=True)
results = quality.validate()
# Step 3: Make decision based on quality
if results['prompt_alignment'] >= 70:
return {'status': 'ready', 'quality': 'good'}
else:
return {'status': 'ready', 'quality': 'needs_review', 'results': results}When to use:
- ✅ Validation is always required (mandatory gate)
- ✅ Fixed CI/CD pipelines
- ✅ Automated testing frameworks
- ✅ Single-purpose scripts
- ✅ Need direct access to result attributes
Advantages:
- Direct function calls (fast)
- Full control over execution
- Rich return values accessible
- Easy debugging
- No additional abstractions
Best for: Autonomous agents, flexible workflows, context-aware validation
Skill Definitions Location: ../.github/skills/
validate-dataset-consistency-py/validate-dataset-quality-py/
How agents use skills:
Agent Workflow:
1. User: "Run evaluation on my dataset"
2. Agent discovers available skills
3. Agent reads skill definitions:
- when_to_use: "BEFORE running voice agent evaluations"
- description: What the skill does
- parameters: Available options
4. Agent decides: "I should validate first"
5. Agent calls skill with appropriate parameters
6. Based on results, agent decides next actionExample: Foundry Agent Integration
# Agent discovers skills dynamically
skills = agent.discover_skills()
# Agent reads skill metadata
consistency_skill = skills['validate-dataset-consistency']
when_to_use = consistency_skill.when_to_use # "BEFORE running evaluations"
# Agent decides to use skill
if 'dataset' in user_request and 'evaluation' in user_request:
# Call skill
result = agent.call_skill('validate-dataset-consistency', {
'dataset_path': extracted_path,
'expected_turns': 3
})
if result.exit_code == 0:
# Proceed to quality check
quality_result = agent.call_skill('validate-dataset-quality', {
'dataset_path': extracted_path,
'strict': True
})Example: GitHub Copilot CLI
# Natural language - ask Copilot to validate
gh copilot suggest "validate the dataset at sample_data.jsonl for consistency"
# Copilot discovers skills, suggests command, and can execute:
# python dataset_validator/validate_dataset_consistency.py sample_data.jsonl
# Ask for complete validation workflow
gh copilot suggest "fully validate my voice dataset with strict quality checking"
# Copilot can chain commands:
# 1. Run consistency check
# 2. If passed, run quality check with --strict
# 3. Report results and suggest next steps
# Context-aware parameter selection
gh copilot suggest "validate MultiConversationSample dataset, it has variable turn counts"
# Copilot recognizes context and suggests appropriate flags:
# python validate_dataset_consistency.py MultiConversationSample
# (without --expected-turns, since user mentioned variable turns)
# Troubleshooting with Copilot
gh copilot suggest "my dataset validation failed, help me understand the errors"
# Copilot can:
# - Re-run validation with verbose output
# - Explain error messages
# - Suggest specific fixesWhen to use:
- ✅ Agent needs to decide IF validation is needed
- ✅ Agent chooses WHICH mode to use (strict/default)
- ✅ Multiple agents share validation service
- ✅ Workflow is dynamic and context-dependent
- ✅ Agent discovers tools without hard-coding
- ✅ Natural language interface preferred (Copilot CLI)
- ✅ Want guided workflow with suggestions (Copilot CLI)
Advantages:
- Agent discovers automatically
- No hard-coding in agent logic
- Reusable across agents
- Version control per skill
- Context-aware decision making
- Natural language commands (Copilot CLI)
- Guided workflows with suggestions (Copilot CLI)
- Automated error interpretation (Copilot CLI)
- Running manual checks
- Shell scripting
- Simple automation
- Validation always required (mandatory)
- Fixed CI/CD pipeline
- Direct programmatic control needed
- Single-purpose workflow
- Agent decides when to validate
- Multiple agents using validators
- Dynamic, context-aware workflows
- Foundry Agents or similar platforms
You can mix and match! For example:
- Use Skills for Foundry Agent (dynamic)
- Use Python Modules in CI/CD (fixed)
- Use CLI for manual testing
Each line should be a valid JSON object with these fields:
{
"WavPath": "conversation1-turn1.wav",
"Question": "User question text",
"Answer": "Expected answer or ground truth",
"conversationID": "conversation1",
"system_prompt": "System prompt defining agent behavior",
"tool_definitions": null
}- WavPath: Filename of audio file (relative to JSONL location)
- Question: User's question/input text
- Answer: Expected answer for evaluation
- conversationID: Identifier grouping multi-turn conversations
- system_prompt: Agent instructions (must be consistent within a conversation)
- tool_definitions: Tool/function definitions (optional, can be null)
Datasets using the Foundry media format are also supported. Instead of WavPath, audio is provided inline via input_audio:
{
"messages": [
{"role": "system", "content": "Agent instructions"},
{"role": "user", "content": [
{"type": "text", "text": "User query"},
{"type": "input_audio", "input_audio": {"data": "data:audio/wav;base64,UklGR...", "format": "wav"}}
]}
],
"expected_output": "Expected response",
"conversationID": "conv1"
}Audio can be a base64 data-URI (data:audio/wav;base64,...) or an Azure Blob Storage URL. The consistency validator detects both formats automatically.
dataset_folder/
├── dataset.jsonl # Dataset metadata
├── conversation1-turn1.wav # Input audio files
├── conversation1-turn2.wav
├── conversation1-turn3.wav
├── conversation1-turn1-response.wav # Response audio (optional)
└── ...
================================================================================
DATASET CONSISTENCY VALIDATION
Dataset: 20260122-wave1-50.jsonl
================================================================================
✓ 1. JSONL SYNTAX VALIDATION
✅ PASSED: All 150 lines are valid JSON
✓ 2. REQUIRED FIELDS VALIDATION
✅ WavPath: 150/150 valid
✅ Question: 150/150 valid
✅ Answer: 150/150 valid
✅ conversationID: 150/150 valid
✅ system_prompt: 150/150 valid
✓ 3. AUDIO FILES VALIDATION
✅ PASSED: All 150 referenced files exist
✓ 4. CONVERSATION STRUCTURE VALIDATION
Total conversations: 50
Total entries: 150
Turn Count Distribution:
• 3 turns: 50 conversations (100.0%)
✅ CONSISTENT: All conversations have 3 turns
✅ PASSED: All conversations have consistent system_prompts
🎯 STATUS: ✅ ALL CHECKS PASSED
With --expected-turns flag:
✓ 4. CONVERSATION STRUCTURE VALIDATION
Total conversations: 50
Total entries: 150
✅ PASSED: All conversations have exactly 3 turns
✅ PASSED: All conversations have consistent system_prompts
🎯 STATUS: ✅ ALL CHECKS PASSED
Variable turn counts (no flag):
✓ 4. CONVERSATION STRUCTURE VALIDATION
Total conversations: 2
Total entries: 9
Turn Count Distribution:
• 3 turns: 1 conversations (50.0%)
• 6 turns: 1 conversations (50.0%)
ℹ INFO: Dataset has variable turn counts across 2 different patterns
(Use --expected-turns flag to validate specific turn count)
✅ PASSED: All conversations have consistent system_prompts
================================================================================
DATASET QUALITY VALIDATION
Dataset: 20260122-wave1-50.jsonl
================================================================================
✓ 1. SYSTEM PROMPT RELEVANCE
✅ Aligned: 44/50 (88.0%)
✅ GOOD: 88.0% alignment indicates strong prompt-content matching
✓ 2. TOOL DEFINITION APPROPRIATENESS
✅ CORRECT: No action requests detected.
Dataset is conversational/instructional support.
✓ 3. CONTENT QUALITY METRICS
Average Question length: 90 characters
Average Answer length: 542 characters
✅ GOOD: Content has good depth and diversity
📊 Key Metrics:
✅ System Prompt Alignment: 88.0%
✅ Tool Definitions: correct
✅ Content Quality: 3/3
- 0: Validation passed
- 1: Validation failed or error occurred
Use exit codes in CI/CD pipelines:
python validate_dataset_consistency.py dataset.jsonl
if [ $? -eq 0 ]; then
echo "Validation passed"
python validate_dataset_quality.py dataset.jsonl
fiDefault Mode (Permissive):
- ≥70%: Good alignment - quality support responses detected
- 50-70%: Moderate - review recommended
- <50%: Low - prompts may not match conversations
Strict Mode (Conservative):
- ≥60%: Good alignment - domain keywords present
- 40-60%: Moderate - mixed domain expertise
- <40%: Low - domain vocabulary missing
Note: Default mode is recommended for general validation. Use --strict when validating domain-specific expertise.
- correct: No action requests, NULL tools appropriate
- needs_review: Action requests present, consider adding tools
- good: Action requests have tool definitions
- mixed: Mixed dataset with both types
- 3: Excellent - good length, depth, and diversity
- 2: Good - meets quality standards
- 1: Moderate - some concerns
- 0: Needs improvement - quality issues detected
Solution: Specify the exact JSONL file path instead of folder
Solution: Ensure WAV files are in the same folder as JSONL, with exact filename matches
Solution: Each conversation should use the same system_prompt across all turns
Solution: Review system prompts - may be too generic or mismatched to conversation topics
Use these scripts before running evaluations:
# 1. Validate consistency
python validate_dataset_consistency.py dataset.jsonl || exit 1
# 2. Validate quality
python validate_dataset_quality.py dataset.jsonl || exit 1
# 3. Run evaluation
python voice_agent_audio_input_evaluation.py --input dataset.jsonlBoth scripts can be imported as modules for custom validation workflows:
from validate_dataset_consistency import DatasetConsistencyValidator
from validate_dataset_quality import DatasetQualityValidator
# Custom validation pipeline
consistency = DatasetConsistencyValidator("dataset.jsonl")
if consistency.validate():
# Use strict mode for domain-specific datasets
quality = DatasetQualityValidator("dataset.jsonl", strict=True, verbose=True)
results = quality.validate()
# Access detailed results
alignment = results['prompt_alignment']['alignment_percentage']
print(f"Alignment: {alignment:.1f}%")
# Check specific metrics
domains = results['prompt_alignment']['domains']
for domain, stats in domains.items():
print(f"{domain}: {stats['aligned']}/{stats['total']}"){
"status": "success",
"prompt_alignment": {
"total_conversations": 50,
"aligned": 44,
"unaligned": 6,
"alignment_percentage": 88.0,
"domains": {
"Smart Home Tech Support": {"total": 10, "aligned": 9},
...
}
},
"tool_appropriateness": {
"with_tools": 0,
"without_tools": 150,
"action_requests": 0,
"instructional": 49,
"general": 101,
"assessment": "correct"
},
"content_quality": {
"avg_question_length": 89.6,
"avg_answer_length": 541.6,
"unique_prompts": 32,
"total_conversations": 50,
"total_entries": 150,
"quality_score": 3
}
}For issues or questions about these validation scripts, refer to the main project documentation or create an issue in the repository.
Last Updated: 2026-01-30