This document provides best practices for creating ground truth for an utterance. It can be viewed as a trajectory of the execution process of the utterance under an ideal execution process without hallucination or execution failure. The ground truth is the cornerstone to evaluate AI agent systems irresoective it domain or application. Ground truth represents the ideal trajectory - the expected sequence of planning decisions and execution steps that a system should follow to correctly answer a user’s natural language query, i.e. utterance.
Ground truth is a structured specification that defines:
It serves as the soft ground truth for automated evaluation, enabling systematic comparison of actual agent behavior against expert-defined expected behavior. “Soft” means the framework accommodates both types, providing exact answers for deterministic tasks and acceptance criteria for non-deterministic tasks. For example, in a deterministic task like “How many work orders in 2017?”, the ground truth would specify the exact number of work orders. In a non-deterministic task like “Recommend maintenance actions”, the ground truth would specify the criteria for a valid recommendation, such as “The recommended actions should address the top 3 failure modes with the highest risk scores.”
Enable rigorous, reproducible benchmarking of AI agent systems by providing:
While this document uses industrial asset management examples (from AssetOpsBench), the principles apply to any domain requiring agent-based automation, including energy systems, healthcare, finance, and customer service.
Ground truth supports evaluation of two complementary paradigms:
1. Multi-Agent Systems
2. Multi-MCP Systems
Key Insight: Both paradigms share the same ground truth structure. The difference lies in semantic interpretation:
type = agent type (e.g., “IoTAgent”), agent = agent nametype = MCP server type (e.g., “filesystem”), agent = server nameGround truth enables three critical benchmarking capabilities:
1. Architectural Comparison
2. Model Selection
3. Failure Mode Discovery
Ground truth serves as shared infrastructure for open source and research communities:
This document provides systematic workflow, structure definitions, best practices, and validation guidance for creating ground truth trajectories. Based on AssetOpsBench and industry best practices for agent evaluation.
This section provides a systematic, step-by-step process for creating ground truth trajectories. Follow this workflow to ensure completeness and consistency.
Phase 1: Understand the Utterance
↓
Phase 2: Define Expected Behavior
↓
Phase 3: Design the Ideal Trajectory
↓
Phase 4: Validate and Refine
↓
Phase 5: Document and Review
Objective: Fully comprehend what the user is asking and what constitutes success.
Key Questions:
Actions:
Example:
Utterance: "Get the work order of equipment CWC04013 for year 2017."
Analysis:
- Intent: Retrieve historical work order records
- Information needed: Work orders for specific equipment and time period
- Required agent: WOAgent (Work Order Agent)
- Data source: Work order database
- Constraints: Equipment ID = CWC04013, Year = 2017
- Group: retrospective (historical data retrieval)
- Category: Knowledge Query
- Type: Workorder
- Entity: Equipment
- Deterministic: true (33 records expected)
Objective: Specify what the correct output should be and how to validate it.
Key Decisions:
Decision 1: Is this deterministic or non-deterministic?
Ask: “Is there exactly one correct answer?”
Decision 2: What is the characteristic form?
For deterministic utterances:
"There will be 33 records. The expected response should retrieve
all work orders for equipment CWC04013 in the year 2017, ensuring
correct equipment ID and time filtering."
For non-deterministic utterances:
"The answer should contain one or more valid work order
recommendations with rationale. The recommendations should be
relevant to addressing anomalies in equipment CWC04009."
Decision 3: What is the expected output structure?
Define final_out:
Actions:
deterministic flag (true/false)characteristic_form descriptionfinal_out structurefinal_out_description explaining the outputObjective: Map out the step-by-step process the agent should follow.
Create planning_steps: Strategic decomposition of the problem
Template:
"planning_steps": [
{
"agent": "AgentName",
"instruction": "What this agent should accomplish (high-level)"
}
]
Guidelines:
Example:
"planning_steps": [
{
"agent": "WOAgent",
"instruction": "Create Equipment instance for CWC04013"
},
{
"agent": "WOAgent",
"instruction": "Create DateRange for year 2017"
},
{
"agent": "WOAgent",
"instruction": "Retrieve work orders for equipment and date range"
}
]
Create execution_steps: Specific tool calls and operations
For each step, define:
Template:
{
"name": "descriptive_step_name",
"action": "tool_or_function_name",
"agent": "AgentName",
"arguments": {
"param1": "value1",
"param2": "reference_to_previous_output"
},
"outputs": ["output_variable_name"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
}
Key Considerations:
Create execution_links: Connect steps to form DAG
Template:
"execution_links": [
{"source": "step1_name", "target": "step2_name"},
{"source": "step2_name", "target": "step3_name"}
]
Rules:
Validation:
Objective: Ensure ground truth is correct, complete, and consistent.
Structural Validation:
Semantic Validation:
Logical Validation:
Domain Validation:
Objective: Finalize documentation and prepare for use.
Required Documentation:
Recommended Note Content:
"note": "Source: [where this scenario came from];
Owner: [SME who created/validated it];
Context: [important background information];
Design rationale: [why this approach was chosen];
Implementation notes: [technical details];
Omitted: [what was intentionally left out]"
Review with Stakeholders:
Quality Gates:
START: New Utterance
↓
Q1: What is user's intent?
→ Identify: RETROSPECTIVE, PREDICTIVE, or PRESCRIPTIVE
↓
Q2: Is there exactly one correct answer?
→ YES: deterministic = true
→ NO: deterministic = false
↓
Q3: Which agents/servers are needed?
→ Single: type = "AgentName"
→ Multiple: type = "multiagent"
↓
Q4: What are the high-level steps?
→ Create planning_steps (strategic intent)
↓
Q5: What are the detailed operations?
→ Create execution_steps (tool calls)
↓
Q6: How do steps connect?
→ Create execution_links (DAG)
↓
Q7: What is the expected output?
→ Define final_out and characteristic_form
↓
Q8: Does it pass validation?
→ YES: Document and finalize
→ NO: Return to appropriate phase and refine
↓
DONE: Ground Truth Complete
Pitfall 1: Vague characteristic_form
Pitfall 2: Missing intermediate steps
Pitfall 3: Incorrect deterministic flag
Pitfall 4: Circular dependencies
Pitfall 5: Ambiguous variable references
Ground truth creation effort varies significantly based on scenario complexity:
Factors Affecting Creation Time:
Observed Patterns from AssetOpsBench:
Efficiency Strategies:
Note: Specific time estimates depend on team expertise, tooling, and domain complexity. Track your own metrics to establish baselines for your context.
Each ground truth scenario consists of the following key components:
{
"id": <integer>,
"uuid": "<optional-unique-identifier>",
"text": "<natural language utterance>",
"type": "<agent or MCP server type>",
"category": "<utterance category>",
"deterministic": <boolean>,
"characteristic_form": "<expected response description>",
"planning_steps": [...],
"execution_steps": [...],
"execution_links": [...],
"final_out": {...},
"final_out_description": [...]
}
IoT, FMSA, TSFM, Workorder, multiagentfilesystem, database, web-search, etc.multiagent when multiple agents must collaborateKnowledge Query, Data Query, Inference Query, Decision Support, Prediction, Complex Querytrue: Single verifiable correct answer (e.g., data retrieval, factual queries)false: Multiple valid responses possible (e.g., recommendations, predictions)agent and instructionStructure:
"planning_steps": [
{
"agent": "AgentName",
"instruction": "High-level description of what this agent should do"
}
]
Best Practices:
Structure:
"execution_steps": [
{
"name": "unique_step_identifier",
"action": "tool_or_function_name",
"agent": "AgentName",
"arguments": {
"param1": "value1",
"param2": "reference_to_previous_output"
},
"outputs": ["output_variable_name"],
"deterministic": {
"name": false,
"action": true/false,
"arguments": true/false,
"outputs": true/false
}
}
]
Field Details:
step1, create_equipment, get_sensor_data, filter_anomaliessensors, history, get_work_orders, pickle.load, FinishFinish, Self-Ask, Agent-Askagent: Which agent executes this step
@variable_name or just variable_name for references[] if no outputname: Is the step name deterministic? (usually false - can vary)action: Is the action/tool deterministic? (true for data retrieval, false for LLM calls)arguments: Are the arguments deterministic?outputs: Are the outputs deterministic?Structure:
"execution_links": [
{
"source": "step_name_1",
"target": "step_name_2"
}
]
Best Practices:
characteristic_formfinal_out instead{}The Finish step is a special terminal step that marks task completion and provides the final answer.
Characteristics:
"Finish"Usage Patterns:
Pattern 1: Direct Finish (IoT Agent)
{
"name": "finish",
"action": "Finish",
"agent": "IoTAgent",
"argument": "The assets at the MAIN site are: CQPA AHU 1, CQPA AHU 2B, Chiller 4, Chiller 6, Chiller 9, Chiller 3.",
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
}
Pattern 2: Finish with Structured Arguments (TSFM Agent)
{
"name": "return_final_answer",
"action": "Finish",
"agent": "TSFMAgent",
"arguments": {
"answer": true,
"evidence_models": ["ttm_96_28", "ttm_512_96"]
},
"outputs": ["final_answer"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
}
Pattern 3: Finish without Arguments (FMSA Agent)
{
"name": "finish",
"action": "Finish",
"arguments": "",
"outputs": ""
}
Best Practices:
Finish as an anchor/terminal stepFinish step (inconsistency noted in original data)Finish step’s output is used as the “final answer” for evaluationSelf-Ask: Agent asks itself a clarifying question
Agent-Ask: Agent requests information from another agent
IoTAgent, FMSRAgent, TSFMAgent, WOAgentsensors, history, get_work_orders, Equipment, DateRangeequipment, date_range, events, sensor_data, forecast_resultsresult, output, data unless context is clearcreate_equipment, filter_anomalies, calculate_statisticsstep1, step2, step3 (unless no better name exists)When to mark as deterministic:
truetruefalsefalsetruetruefalsetruetruefalsefalseExample:
{
"name": "load_work_orders",
"action": "pickle.load",
"deterministic": {
"name": false, // Step name can vary
"action": false, // pickle.load is not a standard action
"arguments": false, // File path may vary
"outputs": false // Content depends on file
}
}
For complex queries requiring multiple agents:
"type": "multiagent"
Example:
"planning_steps": [
{
"agent": "IoTAgent",
"instruction": "Retrieve sensor data for the equipment"
},
{
"agent": "TSFMAgent",
"instruction": "Analyze sensor data for anomalies"
},
{
"agent": "WOAgent",
"instruction": "Recommend work orders based on detected anomalies"
}
]
For utterances with multiple valid answers:
"deterministic": false
final_outcharacteristic_form, describe what makes an answer validpossible_alternatives to show other valid approachesExample:
"characteristic_form": "The answer should contain one or more valid work order recommendations with rationale. The recommendations should be relevant to addressing anomalies in equipment CWC04009.",
"deterministic": false,
"final_out": {
"recommendations": ["M005", "M006", "OP004"]
},
"final_out_description": [
"Recommended work orders based on anomaly analysis",
"Other valid recommendations may exist depending on prioritization criteria"
]
Before finalizing ground truth, validate:
final_out matches characteristic_form descriptionfinal_out_description is clear and completetype matches primary agent in planning/executioncategory aligns with utterance characteristicsdeterministic flag matches output predictabilityBefore submitting ground truth, verify:
Problem: Different agents use different Finish patterns
Solution: Standardize Finish usage
Problem: Unclear how outputs are referenced in arguments
Solution: Use consistent reference syntax
@variable or just variableProblem: Deterministic flags not set at all levels
Solution: Always include complete deterministic dict
"deterministic": {
"name": false,
"action": true/false,
"arguments": true/false,
"outputs": true/false
}
Problem: Execution links create cycles
Solution: Validate DAG structure
Problem: Jumping from data retrieval to final output without processing
Solution: Include all necessary transformations
Problem: Expected output not clearly described
Solution: Be specific and detailed
For complex ground truth scenarios:
For scenarios with conditional logic:
{
"name": "conditional_step",
"action": "if_then_else",
"agent": "Agent",
"arguments": {
"condition": "anomaly_detected == true",
"then_action": "recommend_maintenance",
"else_action": "continue_monitoring"
},
"outputs": ["action_taken"],
"deterministic": {
"name": false,
"action": false,
"arguments": false,
"outputs": false
}
}
For scenarios with parallel processing:
"execution_links": [
{"source": "get_data", "target": "analyze_path1"},
{"source": "get_data", "target": "analyze_path2"},
{"source": "analyze_path1", "target": "merge_results"},
{"source": "analyze_path2", "target": "merge_results"}
]
This section presents real-world patterns from AssetOpsBench ground truth scenarios, demonstrating practical implementations used in industrial asset management.
Use Case: Single-agent query for domain knowledge
Scenario: “List all failure modes of asset Wind Turbine.”
Pattern Characteristics:
{
"planning_steps": [
{
"agent": "FMSRAgent",
"instruction": "List all failure modes of asset Wind Turbine."
}
],
"execution_steps": [
{
"name": "get_failure_modes",
"action": "Get Failure Modes",
"agent": "FMSRAgent",
"arguments": "Wind Turbine",
"outputs": "The failure modes of asset Wind Turbine: ['Blade Failure', 'Gearbox Failure', 'Generator Failure', 'Bearing Failure', 'Electrical System Failure', 'Control System Failure', 'Foundation Failure', 'Tower Failure', 'Hub Failure', 'Pitch System Failure ', 'Yaw System Failure ', 'Hydraulic System Failure']",
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": false
}
},
{
"name": "finish",
"action": "Finish",
"arguments": "",
"outputs": ""
}
],
"execution_links": [
{"source": "get_failure_modes", "target": "finish"}
]
}
Use Case: Create objects, retrieve data, process, and generate output
Scenario: “Get the work order of equipment CWC04013 for year 2017.”
Pattern Characteristics:
{
"planning_steps": [
{
"agent": "WOAgent",
"instruction": "Create an Equipment instance using the provided equipment_id CWC04013."
},
{
"agent": "WOAgent",
"instruction": "Create a DateRange object spanning 2017-01-01 to 2017-12-31."
},
{
"agent": "WOAgent",
"instruction": "Retrieve the work orders file for the specified equipment and date range."
},
{
"agent": "WOAgent",
"instruction": "Load the work orders data from the retrieved file using pickle."
},
{
"agent": "WOAgent",
"instruction": "Generate a structured JSON file from the work orders using an LLM."
}
],
"execution_steps": [
{
"name": "create_equipment",
"action": "Equipment",
"agent": "WOAgent",
"arguments": {"equipment_id": "CWC04013"},
"outputs": ["equipment"],
"deterministic": {"name": false, "action": true, "arguments": true, "outputs": true}
},
{
"name": "create_date_range",
"action": "DateRange",
"agent": "WOAgent",
"arguments": {"start_date": "2017-01-01", "end_date": "2017-12-31"},
"outputs": ["date_range"],
"deterministic": {"name": false, "action": true, "arguments": true, "outputs": true}
},
{
"name": "get_work_orders_file",
"action": "get_work_orders",
"agent": "WOAgent",
"arguments": {"equipment": "equipment", "date_range": "date_range"},
"outputs": ["file"],
"deterministic": {"name": false, "action": true, "arguments": true, "outputs": true}
},
{
"name": "load_work_orders",
"action": "pickle.load",
"agent": "WOAgent",
"arguments": {"file": "file"},
"outputs": ["work_orders"],
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "print_work_orders",
"action": "print",
"agent": "WOAgent",
"arguments": {"obj": "work_orders"},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "generate_json",
"action": "LLM.generate_json",
"agent": "WOAgent",
"arguments": {"data": "work_orders"},
"outputs": ["json_file"],
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
}
],
"execution_links": [
{"source": "create_equipment", "target": "get_work_orders_file"},
{"source": "create_date_range", "target": "get_work_orders_file"},
{"source": "get_work_orders_file", "target": "load_work_orders"},
{"source": "load_work_orders", "target": "print_work_orders"},
{"source": "load_work_orders", "target": "generate_json"}
]
}
Use Case: Simple multi-agent coordination for knowledge retrieval
Scenario: “List all failure modes of asset Chiller 6 at MAIN site.”
Pattern Characteristics:
{
"planning_steps": [
{
"agent": "IoTAgent",
"instruction": "Get basic description/identifiers for Chiller 6 at MAIN site (asset verification)."
},
{
"agent": "FMSRAgent",
"instruction": "List all failure modes for the verified asset (Chiller 6 at MAIN)."
}
],
"execution_steps": [
{
"name": "fmsr_list",
"agent": "FMSRAgent",
"action": "get_failure_modes",
"arguments": {"asset_name": "Chiller 6", "site_name": "MAIN"},
"outputs": {
"status": "success",
"failure_modes": [
"Compressor Overheating: Failed due to Normal wear, overheating",
"Heat Exchangers: Fans: Degraded motor or worn bearing due to Normal use",
"Evaporator Water side fouling",
"Condenser Water side fouling",
"Condenser Improper water side flow rate",
"Purge Unit Excessive purge",
"Refrigerant Operated Control Valve Failed spring"
]
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "finalize",
"agent": "FMSRAgent",
"action": "Finish",
"arguments": {"validation_checks": ["len(failure_modes)==7"]},
"outputs": {"final_state": "completed"},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
}
],
"execution_links": [
{"source": "fmsr_list", "target": "finalize"}
],
"final_output": {
"asset": "Chiller 6",
"site": "MAIN",
"parameter": "Failure Modes",
"failure_modes": [
"Compressor Overheating: Failed due to Normal wear, overheating",
"Heat Exchangers: Fans: Degraded motor or worn bearing due to Normal use",
"Evaporator Water side fouling",
"Condenser Water side fouling",
"Condenser Improper water side flow rate",
"Purge Unit Excessive purge",
"Refrigerant Operated Control Valve Failed spring"
]
}
}
Use Case: Multi-agent workflow with retry logic and error handling
Scenario: “What is the forecast for ‘Chiller 9 Condenser Water Flow’ in the week of 2020-04-27 based on data from the MAIN site?”
Pattern Characteristics:
Key Pattern Elements:
{
"planning_steps": [
{
"agent": "IoTAgent",
"instruction": "Locate 'Condenser Water Flow' sensor for 'Chiller 9' at 'MAIN'."
},
{
"agent": "IoTAgent",
"instruction": "Retrieve windowed history (2020-04-27 → 2020-05-03) and save CSV."
},
{
"agent": "TSFMAgent",
"instruction": "List available pretrained checkpoints and select 'ttm_96_28'."
},
{
"agent": "TSFMAgent",
"instruction": "Run forecast on the CSV and save JSON to declared path."
},
{
"agent": "TSFMAgent",
"instruction": "Validate artifacts and finalize summary."
}
],
"execution_steps": [
{
"name": "sensors",
"agent": "IoTAgent",
"action": "LocateSensor",
"arguments": {
"site_name": "MAIN",
"assetnum": "Chiller 9",
"sensor_name_filter": "Condenser Water Flow"
},
"outputs": {
"status": "success",
"site_name": "MAIN",
"assetnum": "Chiller 9",
"sensor_id": "chiller9_condenser_water_flow",
"sensor_name": "Condenser Water Flow",
"file_path": "/tmp/cbmdir/chiller9_MAIN_sensors.json",
"message": "Located target sensor."
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "history",
"agent": "IoTAgent",
"action": "DownloadSeries_Attempt1",
"arguments": {
"site_name": "MAIN",
"assetnum": "9",
"metric": "Condenser Water Flow",
"start": "2020-04-27T00:00:00Z",
"final": "2020-05-03T23:59:59Z",
"save_series_csv": true,
"save_path": "data/raw/iot/main/chiller_9_condenser_water_flow_2020-04-27_to_2020-05-03.csv"
},
"outputs": {
"status": "failure",
"error": "assetnum '9' not found (expected 'Chiller 9').",
"csv_path": null,
"message": "History retrieval failed due to asset identifier mismatch."
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "history",
"agent": "IoTAgent",
"action": "DownloadSeries_ReattemptWithFixedAssetnum",
"arguments": {
"site_name": "MAIN",
"assetnum": "Chiller 9",
"metric": "Condenser Water Flow",
"start": "2020-04-27T00:00:00Z",
"final": "2020-05-03T23:59:59Z",
"save_series_csv": true,
"save_path": "data/raw/iot/main/chiller_9_condenser_water_flow_2020-04-27_to_2020-05-03.csv"
},
"outputs": {
"status": "success",
"rows": 581,
"sampling_hint": "irregular/partial (expected ~672 @ 15min)",
"csv_path": "data/raw/iot/main/chiller_9_condenser_water_flow_2020-04-27_to_2020-05-03.csv",
"message": "Series retrieved and saved to CSV."
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "jsonreader",
"agent": "IoTAgent",
"action": "DirectFileRead_Attempt",
"arguments": {
"file_name": "chiller9_condenser_water_flow_MAIN_2020-04-27.json"
},
"outputs": {
"status": "failure",
"error": "[Errno 2] No such file or directory: 'chiller9_condenser_water_flow_MAIN_2020-04-27.json'",
"message": "Direct JSON read failed; proceed with CSV path from history step."
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "tsfm_list_models",
"agent": "TSFMAgent",
"action": "EnumeratePretrainedCheckpoints",
"arguments": {},
"outputs": {
"status": "success",
"models": [
{"model_id": "ttm_96_28", "model_checkpoint": "ttm_96_28", "model_description": "Pretrained forecasting model with context length 96"},
{"model_id": "ttm_512_96", "model_checkpoint": "ttm_512_96", "model_description": "Pretrained forecasting model with context length 512"},
{"model_id": "ttm_energy_96_28", "model_checkpoint": "ttm_96_28", "model_description": "Energy-tuned model, context length 96"},
{"model_id": "ttm_energy_512_96", "model_checkpoint": "ttm_512_96", "model_description": "Energy-tuned model, context length 512"}
],
"selected": "ttm_96_28",
"message": "Selected checkpoint 'ttm_96_28' for forecasting."
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "tsfm_forecast",
"agent": "TSFMAgent",
"action": "RunForecast_ttm_96_28_WithCorrectArgs",
"arguments": {
"input_csv": "data/raw/iot/main/chiller_9_condenser_water_flow_2020-04-27_to_2020-05-03.csv",
"timestamp_col": "timestamp",
"value_col": "value",
"window_start": "2020-04-27T00:00:00Z",
"window_end": "2020-05-03T23:59:59Z",
"checkpoint": "ttm_96_28",
"save_path": "data/derived/forecast/chiller_9/condenser_water_flow/forecast_2020-04-27_to_2020-05-03_ttm_96_28.json"
},
"outputs": {
"status": "success",
"model_checkpoint": "ttm_96_28",
"input_read": true,
"input_rows": 581,
"forecast_span": {"start": "2020-04-27T00:00:00Z", "end": "2020-05-03T23:59:59Z"},
"forecast_file": "data/derived/forecast/chiller_9/condenser_water_flow/forecast_2020-04-27_to_2020-05-03_ttm_96_28.json",
"message": "Forecast generated and saved (arguments validated; prior unpacking/validation errors resolved)."
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
},
{
"name": "finalize",
"agent": "TSFMAgent",
"action": "Finish",
"arguments": {
"validation_checks": [
"exists:data/raw/iot/main/chiller_9_condenser_water_flow_2020-04-27_to_2020-05-03.csv",
"exists:data/derived/forecast/chiller_9/condenser_water_flow/forecast_2020-04-27_to_2020-05-03_ttm_96_28.json"
],
"summary_request": "Confirm variable binding, input read, forecast span, row counts, and artifact paths. Note prior failure remediation (assetnum correction; correct TSFM input schema)."
},
"outputs": {
"final_state": "completed",
"summary": "Forecast for Chiller 9 'Condenser Water Flow' (2020-04-27 → 2020-05-03) generated with checkpoint ttm_96_28. Input CSV (581 rows) read; forecast saved to declared path. Earlier issues (assetnum mismatch, missing JSON file, TSFM arg validation) were identified and resolved.",
"forecast_file": "data/derived/forecast/chiller_9/condenser_water_flow/forecast_2020-04-27_to_2020-05-03_ttm_96_28.json"
},
"deterministic": {"name": false, "action": false, "arguments": false, "outputs": false}
}
],
"execution_links": [
{"source": "sensors", "target": "history"},
{"source": "history", "target": "history"},
{"source": "history", "target": "jsonreader"},
{"source": "jsonreader", "target": "tsfm_list_models"},
{"source": "tsfm_list_models", "target": "tsfm_forecast"},
{"source": "tsfm_forecast", "target": "finalize"}
]
}
Key Lessons from ID 502:
Ground truth enables multiple evaluation dimensions:
DAG Comparison:
Output Comparison:
Planning Comparison:
When creating ground truth for multi-agent systems:
IoTAgent, FMSRAgent, TSFMAgent, WOAgentmultiagent type for scenarios requiring multiple agentsAgent-Ask for agent-to-agent queriesget_work_orders, get_sensor_data)Equipment, DateRange, Sensor)Example Multi-Agent Pattern:
{
"type": "multiagent",
"planning_steps": [
{
"agent": "IoTAgent",
"instruction": "Retrieve sensor data for equipment"
},
{
"agent": "TSFMAgent",
"instruction": "Analyze sensor data for anomalies"
},
{
"agent": "WOAgent",
"instruction": "Recommend work orders based on anomalies"
}
],
"execution_steps": [
{
"name": "get_sensor_data",
"action": "sensors",
"agent": "IoTAgent",
"arguments": {"site_name": "MAIN", "assetnum": "Chiller 6"}
},
{
"name": "detect_anomalies",
"action": "detect_anomalies",
"agent": "TSFMAgent",
"arguments": {"data": "sensor_data"}
},
{
"name": "recommend_wo",
"action": "recommend_work_order",
"agent": "WOAgent",
"arguments": {"anomalies": "detected_anomalies"}
}
]
}
When creating ground truth for MCP (Model Context Protocol) systems:
Use standard MCP server types:
filesystem: File operations (read, write, list, search)database: Database queries (SQL, NoSQL)web-search: Web search and scrapingapi-client: REST/GraphQL API callsgit: Version control operationsslack: Team communicationemail: Email operationscalendar: Calendar managementcomputation: Mathematical operationsmemory: Persistent storage for LLM contextUse MCP protocol tool naming conventions:
{
"action": "filesystem/read_file", // Server/tool format
"action": "database/query",
"action": "web-search/search",
"action": "api-client/post"
}
Or simplified format:
{
"action": "read_file", // Tool name only
"agent": "filesystem" // Server specified separately
}
Handle MCP resources with proper URIs:
{
"arguments": {
"resource_uri": "file:///path/to/data.csv",
"resource_type": "text/csv"
}
}
{
"arguments": {
"resource_uri": "db://localhost/sensors",
"query": "SELECT * FROM readings WHERE date > '2024-01-01'"
}
}
Reference MCP tool schemas in execution steps:
{
"name": "read_config",
"action": "read_file",
"agent": "filesystem",
"arguments": {
"path": "/config/app.json"
},
"outputs": ["file_content"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
}
For multi-MCP scenarios:
{
"type": "multiagent", // Or "multi-mcp"
"planning_steps": [
{
"agent": "filesystem",
"instruction": "Read data file"
},
{
"agent": "database",
"instruction": "Query reference data"
},
{
"agent": "api-client",
"instruction": "Send results to external API"
}
]
}
Example Multi-MCP Pattern:
{
"id": 600,
"text": "Read customer data from CSV, enrich with database info, and send to CRM API.",
"type": "multiagent",
"category": "Complex Query",
"deterministic": true,
"planning_steps": [
{
"agent": "filesystem",
"instruction": "Read customer CSV file"
},
{
"agent": "database",
"instruction": "Query customer details from database"
},
{
"agent": "api-client",
"instruction": "POST enriched data to CRM API"
}
],
"execution_steps": [
{
"name": "read_csv",
"action": "read_file",
"agent": "filesystem",
"arguments": {
"path": "/data/customers.csv"
},
"outputs": ["csv_content"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
},
{
"name": "parse_csv",
"action": "parse",
"agent": "filesystem",
"arguments": {
"content": "csv_content",
"format": "csv"
},
"outputs": ["customer_ids"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
},
{
"name": "query_details",
"action": "query",
"agent": "database",
"arguments": {
"sql": "SELECT * FROM customers WHERE id IN (@customer_ids)",
"params": {"customer_ids": "customer_ids"}
},
"outputs": ["customer_details"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": true
}
},
{
"name": "send_to_crm",
"action": "post",
"agent": "api-client",
"arguments": {
"url": "https://crm.example.com/api/customers",
"body": "customer_details",
"headers": {"Content-Type": "application/json"}
},
"outputs": ["api_response"],
"deterministic": {
"name": false,
"action": true,
"arguments": true,
"outputs": false
}
}
],
"execution_links": [
{"source": "read_csv", "target": "parse_csv"},
{"source": "parse_csv", "target": "query_details"},
{"source": "query_details", "target": "send_to_crm"}
]
}
When combining multi-agent and multi-MCP:
agent field for both agents and MCP serverstype to indicate primary system typeparadigm field if needed for clarity:
{
"type": "multiagent",
"paradigm": "hybrid",
"note": "IoTAgent uses filesystem MCP server"
}
{
"execution_steps": [
{
"name": "agent_decides",
"action": "analyze_requirements",
"agent": "PlannerAgent",
"outputs": ["required_files"]
},
{
"name": "mcp_retrieves",
"action": "read_file",
"agent": "filesystem",
"arguments": {"paths": "required_files"},
"outputs": ["file_contents"]
},
{
"name": "agent_processes",
"action": "process_data",
"agent": "ProcessorAgent",
"arguments": {"data": "file_contents"},
"outputs": ["results"]
}
]
}
Use Multi-Agent When:
Use Multi-MCP When:
Use Hybrid When:
Ground truth enables comprehensive evaluation at three levels:
| Level | Focus | Metrics | Weight |
|---|---|---|---|
| Outcome | Final result correctness | Task completeness (y₁), Data retrieval (y₂), Result verification (y₃) | 50% |
| Process | Execution trajectory | Action sequence, DAG structure, Step completeness | 30% |
| Planning | Strategic decomposition | ROUGE scores (planning alignment) | 20% |
Step 1: Collect Agent Trace → Step 2: Load Ground Truth → Step 3: Multi-Level Comparison
Three Core Metrics:
characteristic_form using LLM-as-Judge (0-1 score)final_outCombined Score: Rubric_Score = (y₁ + y₂ + y₃) / 3
Example (Scenario 421):
Comparison Methods:
Example:
load_events, dedupe)Use ROUGE metrics to compare planning strategies:
Example: GT planning vs Agent planning → ROUGE-L: 0.65
Final_Score = 0.5 × Rubric_Score + 0.3 × Execution_Score + 0.2 × Planning_Score
Complete Example (Scenario 421):
{
"final_score": 0.78,
"rubric_score": 0.87,
"execution_score": 0.68,
"planning_score": 0.65,
"failure_analysis": {
"missing_steps": ["load_events", "dedupe"],
"output_issues": "Missing 2 of 5 expected codes"
}
}
Aggregate Metrics Across Benchmark:
AssetOpsBench Example: GPT-4.1 achieved 0.72 avg score across 141 scenarios (70% completion rate)
Ground truth enables automatic identification of:
| Scenario Type | Approach |
|---|---|
| Deterministic | Exact matching, strict validation, focus on correctness |
| Non-Deterministic | Semantic similarity, allow trajectory variation, focus on outcome quality |
| Multi-Agent | Track coordination, evaluate inter-agent communication, verify specialization |
| Multi-MCP | Verify server selection, check tool parameters, validate resource URIs |
Utterance: “What assets can be found at the MAIN site?”
{
"id": 3,
"type": "IoT",
"text": "What assets can be found at the MAIN site?",
"category": "Knowledge Query",
"deterministic": true,
"characteristic_form": "The expected response should be the return value from querying the assets at the MAIN site. The response should be a reference to a file containing the list of assets",
"group": "retrospective",
"entity": "Site",
"note": "Source: IoT data operations; Deterministic query with single correct answer; Category: Knowledge Query",
"planning_steps": [
{"agent": "IoTAgent", "instruction": "list assets for site MAIN"}
],
"execution_steps": [
{
"name": "step1",
"action": "assets",
"agent": "IoTAgent",
"arguments": {"site_name": "MAIN"},
"outputs": []
},
{
"name": "finish",
"action": "Finish",
"agent": "IoTAgent",
"argument": "The assets at the MAIN site are: CQPA AHU 1, CQPA AHU 2B, Chiller 4, Chiller 6, Chiller 9, Chiller 3."
}
],
"execution_links": [{"source": "step1", "target": "finish"}]
}
Key Features: Linear DAG (2 steps), fully deterministic, single agent. Includes complete meta information: text, characteristic_form, group (retrospective), entity (Site), and note fields.
Utterance: “Review anomalies/alerts for Chiller 9 (CWC04009) in May-June 2020 and suggest work orders.”
{
"id": 421,
"type": "Workorder",
"deterministic": false,
"planning_steps": [
{"agent": "WOAgent", "instruction": "Create Equipment(CWC04009) and DateRange(2020-05-01 to 2020-06-30)"},
{"agent": "WOAgent", "instruction": "Retrieve and filter events to ALERT and ANOMALY"},
{"agent": "WOAgent", "instruction": "Get KPI-based and alert-based recommendations in parallel"},
{"agent": "WOAgent", "instruction": "Combine and deduplicate recommendations"}
],
"execution_steps": [
{"name": "create_equipment", "action": "Equipment", "arguments": {"equipment_id": "CWC04009"}, "outputs": ["equipment"]},
{"name": "create_date_range", "action": "DateRange", "arguments": {"start_date": "2020-05-01", "end_date": "2020-06-30"}, "outputs": ["date_range"]},
{"name": "get_events", "action": "get_events", "arguments": {"equipment": "equipment", "date_range": "date_range"}, "outputs": ["events_pickle_path"]},
{"name": "load_events", "action": "pickle_load", "arguments": {"file_path": "events_pickle_path"}, "outputs": ["events"]},
{"name": "filter_anomaly_alert", "action": "filter", "arguments": {"obj": "events", "condition": "event.event_category in {'ALERT','ANOMALY'}"}, "outputs": ["anomaly_alert_events"]},
{"name": "get_top_kpi_recommendations", "action": "recommend_from_top_kpi_anomalies", "arguments": {"events": "anomaly_alert_events", "top_k": 3}, "outputs": ["kpi_recommendations"]},
{"name": "alert_recommendation", "action": "recommend_work_order_from_alert", "arguments": {"rule_id": "RUL0018"}, "outputs": ["alert_rec"]},
{"name": "combine_and_dedupe", "action": "dedupe_by_key", "arguments": {"items": "[alert_rec] + kpi_recommendations", "key": "rec.primary_code"}, "outputs": ["final_result"]},
{"name": "print_final", "action": "print", "arguments": {"obj": "final_result"}}
],
"execution_links": [
{"source": "create_equipment", "target": "get_events"},
{"source": "create_date_range", "target": "get_events"},
{"source": "get_events", "target": "load_events"},
{"source": "load_events", "target": "filter_anomaly_alert"},
{"source": "filter_anomaly_alert", "target": "get_top_kpi_recommendations"},
{"source": "filter_anomaly_alert", "target": "alert_recommendation"},
{"source": "get_top_kpi_recommendations", "target": "combine_and_dedupe"},
{"source": "alert_recommendation", "target": "combine_and_dedupe"},
{"source": "combine_and_dedupe", "target": "print_final"}
],
"final_out": {"CWC04009": ["M005", "M006", "OP004", "M013", "OP002"]}
}
Key Features: Parallel branches (KPI + alert paths converge at dedupe), non-deterministic filtering/reasoning, 9 steps with 8 dependencies, ~3-4 hours to create.
DAG Pattern:
create_equipment ──┐
├─> get_events ─> load_events ─> filter ─┬─> kpi_rec ──┐
create_date_range ─┘ │ ├─> dedupe ─> print
└─> alert_rec ─┘
Comparison:
| Aspect | Example 1 | Example 2 |
|---|---|---|
| Steps | 2 | 9 |
| Dependencies | 1 | 8 |
| Deterministic | Fully | Partially |
| DAG Pattern | Linear | Parallel + Convergence |
| Creation Time | 30 min | 3-4 hours |
Key Insight: Both paradigms use the same ground truth structure. The only difference is semantic interpretation:
| Field | Multi-Agent Interpretation | Multi-MCP Interpretation |
|---|---|---|
type |
Agent type (IoTAgent, WOAgent) | MCP server type (filesystem, database) |
agent |
Agent name | MCP server name |
action |
Agent-specific function | MCP tool name |
planning_steps |
Agent orchestration plan | MCP server coordination plan |
execution_steps |
Agent function calls | MCP tool invocations |
Ground truth creation supports two distinct but structurally similar paradigms:
Concept: Multiple specialized AI agents, each with domain expertise, collaborate to solve complex tasks.
Characteristics:
Ground Truth Representation:
{
"type": "Workorder", // Primary agent type
"planning_steps": [
{
"agent": "WOAgent", // Specific agent name
"instruction": "Create Equipment instance"
}
],
"execution_steps": [
{
"name": "create_equipment",
"action": "Equipment", // Agent-specific action
"agent": "WOAgent", // Agent executing this step
"arguments": {...}
}
]
}
Concept: Multiple Model Context Protocol (MCP) servers provide standardized tools and resources that LLMs can use to accomplish tasks.
Characteristics:
Ground Truth Representation:
{
"type": "filesystem", // Primary MCP server type
"planning_steps": [
{
"agent": "filesystem", // MCP server name
"instruction": "Read configuration file"
}
],
"execution_steps": [
{
"name": "read_config",
"action": "read_file", // MCP tool name
"agent": "filesystem", // MCP server executing this step
"arguments": {
"path": "/config/app.json"
}
}
]
}
Use Multi-Agent Ground Truth When:
Use Multi-MCP Ground Truth When:
Use Hybrid Approach When:
Ground truth can be adapted between paradigms by reinterpreting fields:
Multi-Agent → Multi-MCP:
// Multi-Agent
{
"type": "IoTAgent",
"action": "get_sensor_data"
}
// Equivalent Multi-MCP
{
"type": "database",
"action": "query"
}
Multi-MCP → Multi-Agent:
// Multi-MCP
{
"type": "filesystem",
"action": "read_file"
}
// Equivalent Multi-Agent
{
"type": "FileAgent",
"action": "read"
}
Scenario: Retrieve work orders for equipment
{
"id": 400,
"text": "Get the work order of equipment CWC04013 for year 2017.",
"type": "Workorder",
"category": "Data Query",
"deterministic": true,
"planning_steps": [
{
"agent": "WOAgent",
"instruction": "Create Equipment instance for CWC04013"
},
{
"agent": "WOAgent",
"instruction": "Retrieve work orders for 2017"
}
],
"execution_steps": [
{
"name": "create_equipment",
"action": "Equipment",
"agent": "WOAgent",
"arguments": {"equipment_id": "CWC04013"}
},
{
"name": "get_work_orders",
"action": "get_work_orders",
"agent": "WOAgent",
"arguments": {
"equipment": "equipment",
"date_range": "date_range"
}
}
]
}
Scenario: Read and analyze configuration file
{
"id": 501,
"text": "Read the application configuration and validate required fields.",
"type": "filesystem",
"category": "Data Query",
"deterministic": true,
"planning_steps": [
{
"agent": "filesystem",
"instruction": "Read configuration file from disk"
},
{
"agent": "json-parser",
"instruction": "Parse JSON configuration"
},
{
"agent": "validator",
"instruction": "Validate required fields"
}
],
"execution_steps": [
{
"name": "read_config",
"action": "read_file",
"agent": "filesystem",
"arguments": {
"path": "/config/app.json"
},
"outputs": ["config_content"]
},
{
"name": "parse_json",
"action": "parse",
"agent": "json-parser",
"arguments": {
"content": "config_content"
},
"outputs": ["config_object"]
},
{
"name": "validate",
"action": "validate_schema",
"agent": "validator",
"arguments": {
"data": "config_object",
"required_fields": ["api_key", "endpoint", "timeout"]
},
"outputs": ["validation_result"]
}
]
}
Scenario: IoT agent uses filesystem MCP server
{
"id": 502,
"text": "Load sensor data from CSV file and detect anomalies.",
"type": "multiagent",
"category": "Complex Query",
"deterministic": false,
"planning_steps": [
{
"agent": "filesystem",
"instruction": "Read sensor data CSV file"
},
{
"agent": "IoTAgent",
"instruction": "Parse and validate sensor data"
},
{
"agent": "AnomalyDetectionAgent",
"instruction": "Detect anomalies in sensor readings"
}
],
"execution_steps": [
{
"name": "read_csv",
"action": "read_file",
"agent": "filesystem",
"arguments": {"path": "/data/sensors.csv"},
"outputs": ["csv_content"]
},
{
"name": "parse_data",
"action": "parse_sensor_data",
"agent": "IoTAgent",
"arguments": {"csv_data": "csv_content"},
"outputs": ["sensor_readings"]
},
{
"name": "detect_anomalies",
"action": "detect",
"agent": "AnomalyDetectionAgent",
"arguments": {"data": "sensor_readings"},
"outputs": ["anomalies"]
}
]
}
Decision Framework:
Recommendation: Start with the paradigm that matches your system architecture, then adapt as needed. The ground truth structure is flexible enough to support both.
planning_stepsexecution_stepsexecution_links form proper directed acyclic graphfinal_out or final_out_description with validation criteriaMain Sections (1-12): Core concepts, workflow, structure, best practices, examples, value proposition References (Section 13): Citations and related work Appendices (A-E): Detailed technical content
Ground truth trajectories enable:
ROI: 564 hours to create 141 scenarios → 1000+ hours saved in evaluation (AssetOpsBench experience)
By following this best practice, you can create ground truth data that enables systematic, reproducible evaluation of AI agent systems across diverse domains and use cases.
AssetOpsBenchGroundTruth/{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["id", "text", "type", "category", "deterministic", "characteristic_form", "planning_steps", "execution_steps", "execution_links"],
"properties": {
"id": {"type": "integer"},
"uuid": {"type": "string", "format": "uuid"},
"text": {"type": "string"},
"type": {"type": "string"},
"category": {"type": "string"},
"deterministic": {"type": "boolean"},
"characteristic_form": {"type": "string"},
"planning_steps": {
"type": "array",
"items": {
"type": "object",
"required": ["agent", "instruction"],
"properties": {
"agent": {"type": "string"},
"instruction": {"type": "string"}
}
}
},
"execution_steps": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "action", "agent"],
"properties": {
"name": {"type": "string"},
"action": {"type": "string"},
"agent": {"type": "string"},
"arguments": {"type": ["object", "string"]},
"outputs": {"type": "array"},
"deterministic": {
"type": "object",
"properties": {
"name": {"type": "boolean"},
"action": {"type": "boolean"},
"arguments": {"type": "boolean"},
"outputs": {"type": "boolean"}
}
}
}
}
},
"execution_links": {
"type": "array",
"items": {
"type": "object",
"required": ["source", "target"],
"properties": {
"source": {"type": "string"},
"target": {"type": "string"}
}
}
},
"final_out": {"type": ["object", "null"]},
"final_out_description": {
"type": "array",
"items": {"type": "string"}
}
}
}
Pattern: Agent uses wrong tool for the task
// Ground Truth
{"action": "get_work_orders"}
// Agent Execution
{"action": "get_events"} // Wrong tool
Detection: Compare execution_steps[].action fields
Fix: Improve tool descriptions, add examples
Pattern: Agent uses incorrect arguments
// Ground Truth
{"equipment_id": "CWC04013"}
// Agent Execution
{"equipment_id": "CWC04009"} // Wrong equipment
Detection: Compare execution_steps[].arguments fields
Fix: Validate parameter extraction, add constraints
Pattern: Agent skips required operations
// Ground Truth: 5 steps
create_equipment → create_date_range → get_events → load_events → process
// Agent: 3 steps (missing load_events, process)
create_equipment → create_date_range → get_events
Detection: Compare DAG node counts and structure Fix: Improve planning, add step-by-step guidance
Pattern: Agent executes steps in wrong order
// Ground Truth
A → B → C
// Agent Execution
A → C → B // Wrong order, may cause dependency errors
Detection: Compare execution_links topology
Fix: Enforce dependency constraints, validate prerequisites
Pattern: Agent stops before completing workflow
// Ground Truth
... → final_step → Finish
// Agent Execution
... → partial_step // Stops early, no Finish
Detection: Check for Finish action and final_out presence
Fix: Add completion criteria, validate output requirements
{
"id": 701,
"text": "Review patient symptoms and lab results to recommend diagnostic tests.",
"type": "Healthcare",
"category": "Diagnostic Recommendation",
"planning_steps": [
{"agent": "DiagnosticAgent", "instruction": "Retrieve patient symptoms and history"},
{"agent": "DiagnosticAgent", "instruction": "Analyze lab results"},
{"agent": "DiagnosticAgent", "instruction": "Recommend diagnostic tests based on findings"}
]
}
{
"id": 801,
"text": "Analyze Q4 revenue trends and forecast Q1 performance.",
"type": "Finance",
"category": "Forecasting",
"planning_steps": [
{"agent": "FinanceAgent", "instruction": "Retrieve Q4 revenue data"},
{"agent": "FinanceAgent", "instruction": "Calculate trends and growth rates"},
{"agent": "FinanceAgent", "instruction": "Generate Q1 forecast using time series model"}
]
}
{
"id": 901,
"text": "Resolve customer complaint about delayed shipment.",
"type": "CustomerService",
"category": "Issue Resolution",
"planning_steps": [
{"agent": "SupportAgent", "instruction": "Retrieve order and shipment details"},
{"agent": "SupportAgent", "instruction": "Identify delay cause"},
{"agent": "SupportAgent", "instruction": "Propose resolution and compensation"}
]
}