AI-Powered Equipment Maintenance Planning: Leveraging DeepSeek LLM and CrewAI for Smarter Decisions

Stuck behind a paywall? Read for free!
In the modern fast-evolving industrial world, data-driven decision-making is imperative. Modern utilities must juggle risk, expenditure, and resource constraints in optimizing asset performance. Traditional optimization methods provide rigid quantitative outputs but lack the provision of high-level strategy. By integrating a mixed-integer optimizer and a reasoning Large Language Model (LLM) — DeepSeek — and orchestrating the process using a platform like the agentic platform CrewAI, organizations can access high-level strategy and precise optimization.
Backstory:
I was in a meeting with a maintenance manager at a power generation company where we discussed strategies based on maintenance data. The gentleman presented a challenging example involving the use of equipment maintenance data to gain insights that could guide the strategic direction of the company’s maintenance division. The problem was quite complex back then. But about two years later, I revisit the scenario with agentic AI in mind. This shift in perspective led me to develop a system that merges traditional optimization with advanced reasoning — laying the foundation for the integrated system discussed here.
Background on Agentic AI
Agentic AI is an approach in Artificial Intelligence (AI) where autonomous agents collaborate to solve complex tasks. In this scenario, each agent focuses on a specific role — whether it’s financial analysis, risk assessment, or strategic communication. I used CrewAI to organize these agents into cohesive workflows, where tasks are broken into manageable units and crews are groups of agents and tasks following a predefined sequence. This framework enables:
- Modularity: Individual agents are easy to maintain and extend.
- Collaborative reasoning: Quantitative outputs from the optimization process are enhanced with qualitative insights from the LLM.
- Configurability: Dynamic adjustments are possible through configuration files and decorators.
This article and the accompanying code demonstrate how these principles can be applied to optimize equipment maintenance schedule and generate strategic insights for a department or company leaders using an LLM.
System Overview: A Modular Pipeline
The integrated system is built on three key components:
- Data Pipeline & Optimization Module:
Ingests equipment data, performs local analysis, and optimizes the maintenance schedule using a Mixed-Integer Programming approach (implemented with PuLP). - Agentic Reasoning with DeepSeek LLM:
Specialized agents — Financial Advisors, Risk & Compliance Specialists, and Strategic Communicators — leverage DeepSeek to turn raw optimization results into actionable recommendations. - Crew Orchestration:
Coordinates these agents and their tasks, ensuring the final output combines both quantitative optimization and qualitative strategic insights.
An architectural diagram illustrating the overall system flow is as follows:

1️⃣ Synthetic Data Generation and Ingestion
Before any optimization can happen, we need data. Since I didn’t have access to real production-level equipment data, I generated synthetic maintenance data that mirrors real-world records.
The data included the following :-
- Equipment ID: Unique identifier for each asset.
- Equipment Type: Categories like transformers, circuit breakers, etc.
- Age: Randomly sampled from a skewed beta distribution to represent both older and newer equipment.
- Maintenance Count: Number of past maintenance events, generated using a Poisson distribution.
- Cost: Estimated maintenance cost, adjusted for age and equipment type.
- Risk Impact: Severity score that varies with equipment type and age.
- Labor Hours: Estimated labor hours required for maintenance.
- Failure Probability: Likelihood of failure if maintenance isn’t performed.
Here’s the code used to generate this synthetic dataset that is then saved to a CSV file.
import numpy as np
import pandas as pd
def generate_equipment_data(
num_records: int = 1000,
output_file: str = "synthetic_equipment_data.csv",
random_seed: int = 42
):
"""
Generates a synthetic dataset of electrical equipment maintenance records.
Each row includes:
- equipment_id (unique)
- equipment_type (categorical)
- age (years)
- maintenance_count (# of maintenance tasks done so far)
- cost (estimated cost to maintain this piece of equipment)
- risk_impact (severity factor of failure)
- labor_hours (labor hours needed if maintained)
- failure_probability (prob. of failure if NOT maintained soon)
Distributions / relationships:
- 'age' is between 1 and 40, skewed so there's a reasonable mix of younger/older equipment.
- 'cost' correlates somewhat with 'age' and 'equipment_type' (older or heavy equipment → higher cost).
- 'failure_probability' is correlated with age and equipment_type (transformers, etc. might have higher base risk).
- 'maintenance_count' is Poisson-distributed, roughly correlated with age.
- 'risk_impact' is higher for certain critical types (transformer, circuit_breaker) vs. standard ones.
- 'labor_hours' also varies by equipment type.
The final result is saved as a CSV file.
"""
np.random.seed(random_seed)
equipment_types = [
"transformer",
"circuit_breaker",
"switchgear",
"electric_pole",
"insulator",
"capacitor_bank",
"fuse_cutout",
]
base_cost_map = {
"transformer": 8000,
"circuit_breaker": 6000,
"switchgear": 5000,
"electric_pole": 2000,
"insulator": 1000,
"capacitor_bank": 3000,
"fuse_cutout": 1500
}
base_risk_map = {
"transformer": 3.0,
"circuit_breaker": 2.5,
"switchgear": 2.0,
"electric_pole": 1.2,
"insulator": 1.0,
"capacitor_bank": 1.5,
"fuse_cutout": 1.0
}
base_labor_map = {
"transformer": 16,
"circuit_breaker": 12,
"switchgear": 10,
"electric_pole": 6,
"insulator": 2,
"capacitor_bank": 5,
"fuse_cutout": 3
}
equipment_ids = []
types = []
ages = []
maintenance_counts = []
costs = []
risk_impacts = []
labor_hours_list = []
failure_probs = []
for i in range(num_records):
equip_id = f"EQUIP_{i+1:04d}"
e_type = np.random.choice(equipment_types)
raw_age = np.random.beta(a=2, b=5) * 40
age = int(max(1, raw_age))
maintenance_count = np.random.poisson(lam=age / 5.0)
base_cost = base_cost_map[e_type]
cost_variation = np.random.uniform(0.8, 1.2)
cost = int(base_cost * (1 + age / 50.0) * cost_variation)
base_risk = base_risk_map[e_type]
risk_var = np.random.uniform(-0.4, 0.4)
risk_impact = round(max(0.5, base_risk + (age / 40.0) + risk_var), 2)
base_labor = base_labor_map[e_type]
labor_factor = np.random.uniform(0.7, 1.3)
labor_hours = int(base_labor * labor_factor)
type_risk_factor = base_risk / 5.0
age_factor = age / 50.0
noise = np.random.normal(0, 0.05)
p_fail = max(0, min(1, type_risk_factor + age_factor + noise))
equipment_ids.append(equip_id)
types.append(e_type)
ages.append(age)
maintenance_counts.append(maintenance_count)
costs.append(cost)
risk_impacts.append(risk_impact)
labor_hours_list.append(labor_hours)
failure_probs.append(round(p_fail, 3))
df = pd.DataFrame({
"equipment_id": equipment_ids,
"equipment_type": types,
"age": ages,
"maintenance_count": maintenance_counts,
"cost": costs,
"risk_impact": risk_impacts,
"labor_hours": labor_hours_list,
"failure_probability": failure_probs
})
df["cost"] = df["cost"].clip(lower=500)
df.to_csv(output_file, index=False)
print(f"[INFO] Generated {num_records} records and saved to '{output_file}'.")
if __name__ == "__main__":
generate_equipment_data(
num_records=1000,
output_file="synthetic_equipment_data.csv", #inpt for local anaysis
)
With the synthetic data in place, let’s dive into how I analysed it to uncover key insights.
2️⃣ Local Analysis: Understanding the Data
With the synthetic dataset in place, I had to run a local analysis to explore key metrics, such as failure probabilities, maintenance costs, and risk levels.
Here’s how the local analysis works:
# local_summarizer.py
import pandas as pd
def summarize_maintenance_plan(schedule_df: pd.DataFrame, top_n: int = 10) -> dict:
"""
Summarizes the maintenance schedule, providing high-level and equipment-type specific insights.
Args:
schedule_df (pd.DataFrame): The maintenance schedule dataframe.
top_n (int): Number of top costly items to include in the summary.
Returns:
dict: A dictionary containing overall stats, grouped summaries, and top costly items.
"""
# Overall stats
total_items = len(schedule_df)
total_maintained = schedule_df["maintain"].sum()
total_cost_maintained = (schedule_df["cost"] * schedule_df["maintain"]).sum()
avg_risk = schedule_df["failure_probability"].mean() if "failure_probability" in schedule_df.columns else 0
# Group stats by equipment type
group_stats = schedule_df.groupby("equipment_type").agg(
total_items_by_type=("equipment_id", "count"),
maintained_by_type=("maintain", "sum"),
avg_cost_by_type=("cost", "mean"),
avg_failure_prob_by_type=("failure_probability", "mean")
).reset_index()
# Top N costly items
top_n_costly = schedule_df.nlargest(top_n, "cost")
# Prepare the summary dictionary
summary_dict = {
"overall_stats": {
"total_equipment": int(total_items),
"items_maintained": int(total_maintained),
"total_cost_for_maintained": float(total_cost_maintained),
"average_failure_probability": float(avg_risk),
},
"group_by_equipment_type": group_stats.to_dict(orient="records"),
"top_n_costly_items": top_n_costly[[
"equipment_id", "equipment_type", "cost", "maintain", "failure_probability"
]].to_dict(orient="records")
}
return summary_dict
def generate_text_summary(summary_dict: dict) -> str:
"""
Converts the summary dictionary into a human-readable text format.
Args:
summary_dict (dict): The summary dictionary generated by summarize_maintenance_plan.
Returns:
str: A formatted text summary.
"""
overall = summary_dict["overall_stats"]
group_list = summary_dict["group_by_equipment_type"]
top_n_list = summary_dict["top_n_costly_items"]
# Build the text summary
text_parts = []
text_parts.append("**High-Level Maintenance Plan Stats:**")
text_parts.append(f"- Total equipment: {overall['total_equipment']}")
text_parts.append(f"- Maintained items: {overall['items_maintained']}")
text_parts.append(f"- Total cost for maintained: ${overall['total_cost_for_maintained']:.2f}")
text_parts.append(f"- Average failure probability: {overall['average_failure_probability']:.3f}")
text_parts.append("\n**By Equipment Type:**")
for row in group_list:
text_parts.append(
f"- {row['equipment_type']}: {row['total_items_by_type']} items, "
f"{row['maintained_by_type']} maintained, avg cost=${row['avg_cost_by_type']:.1f}, "
f"avg fail prob={row['avg_failure_prob_by_type']:.3f}"
)
text_parts.append("\n**Top-Cost Items (sample):**")
for item in top_n_list:
text_parts.append(
f"- ID {item['equipment_id']}, type={item['equipment_type']}, "
f"cost=${item['cost']}, maintain={item['maintain']}, "
f"fail_prob={item['failure_probability']:.3f}"
)
text_parts.append("\n(Truncated schedule. Full data is stored locally.)")
return "\n".join(text_parts)
Insights Derived:
- Total Equipment Analyzed: 1,000 units
- Average Failure Probability: ~0.57
- Top High-Cost Equipment: Predominantly transformers with high failure probabilities.
The full output is below:
**High-Level Maintenance Plan Stats:**
- Total equipment: 1000
- Maintained items: 249
- Total cost for maintained: $749993.00
- Average failure probability: 0.570
**By Equipment Type:**
- capacitor_bank: 134 items, 24 maintained, avg cost=$3600.2, avg fail prob=0.513
- circuit_breaker: 143 items, 17 maintained, avg cost=$7441.9, avg fail prob=0.713
- electric_pole: 128 items, 33 maintained, avg cost=$2452.9, avg fail prob=0.461
- fuse_cutout: 141 items, 45 maintained, avg cost=$1791.8, avg fail prob=0.409
- insulator: 151 items, 103 maintained, avg cost=$1222.1, avg fail prob=0.431
- switchgear: 157 items, 10 maintained, avg cost=$6155.6, avg fail prob=0.611
- transformer: 146 items, 17 maintained, avg cost=$9911.1, avg fail prob=0.835
**Top-Cost Items (sample):**
- ID EQUIP_0072, type=transformer, cost=$15313, maintain=0, fail_prob=1.000
- ID EQUIP_0594, type=transformer, cost=$14622, maintain=0, fail_prob=1.000
- ID EQUIP_0046, type=transformer, cost=$14086, maintain=0, fail_prob=1.000
- ID EQUIP_0877, type=transformer, cost=$14051, maintain=0, fail_prob=1.000
- ID EQUIP_0908, type=transformer, cost=$13100, maintain=0, fail_prob=1.000
- ID EQUIP_0103, type=transformer, cost=$12885, maintain=0, fail_prob=0.922
- ID EQUIP_0774, type=transformer, cost=$12752, maintain=0, fail_prob=0.876
- ID EQUIP_0336, type=transformer, cost=$12712, maintain=0, fail_prob=0.954
- ID EQUIP_0165, type=transformer, cost=$12602, maintain=0, fail_prob=0.872
- ID EQUIP_0748, type=transformer, cost=$12326, maintain=0, fail_prob=1.000
3️⃣ Mathematical Optimization: The Ideal Maintenance Plan
While local analysis offers valuable insights, it doesn’t answer the key question: Which equipment should be maintained within budgetary constraints?
For this, we use mathematical optimization through PuLP, a Python linear programming library.
Objective:
- Minimize total risk by deciding which assets to maintain.
- Apply a reduced risk factor (α) to maintained assets.
Constraints:
- Budget Constraint: Total maintenance costs must not exceed the allocated budget.
- Labor Constraint: Total labor hours must stay within limits (if applied).
Here’s the core optimization logic:
# maintenance_pipeline.py
import pandas as pd
from pulp import LpProblem, LpMinimize, LpVariable, lpSum, LpBinary, LpStatus
class MaintenanceOptimizer:
def __init__(self, alpha=0.0, include_manpower_constraint=False, manpower_limit=None):
self.alpha = alpha
self.include_manpower_constraint = include_manpower_constraint
self.manpower_limit = manpower_limit
def optimize_schedule(self, risk_df: pd.DataFrame, budget: float, cost_col: str = "cost", fail_prob_col: str = "failure_probability", risk_impact_col: str = "risk_impact", labor_col: str = "labor_hours"):
if cost_col not in risk_df.columns or fail_prob_col not in risk_df.columns:
raise ValueError(f"Missing required columns: {cost_col}, {fail_prob_col}.")
if risk_impact_col not in risk_df.columns:
risk_df[risk_impact_col] = 1.0
df = risk_df.copy()
problem = LpProblem("MaintenanceOptimization", LpMinimize)
df["var"] = [LpVariable(f"x_{eid}", cat=LpBinary) for eid in df["equipment_id"]]
objective_terms = []
for i, row in df.iterrows():
x_var = row["var"]
p_fail = row[fail_prob_col]
imp = row[risk_impact_col]
risk_if_not = p_fail * imp
risk_if_maint = self.alpha * p_fail * imp
expression = risk_if_not * (1 - x_var) + risk_if_maint * (x_var)
objective_terms.append(expression)
problem += lpSum(objective_terms), "TotalRisk"
cost_expr = lpSum(row[cost_col] * row["var"] for _, row in df.iterrows())
problem += cost_expr <= budget, "BudgetConstraint"
if self.include_manpower_constraint and labor_col in df.columns and self.manpower_limit is not None:
labor_expr = lpSum(row[labor_col] * row["var"] for _, row in df.iterrows())
problem += labor_expr <= self.manpower_limit, "ManpowerConstraint"
problem.solve()
df["maintain"] = [int(var.varValue) for var in df["var"]]
sol_status = LpStatus[problem.status]
total_risk_value = 0.0
for _, row in df.iterrows():
if row["maintain"] == 1:
total_risk_value += self.alpha * row[fail_prob_col] * row[risk_impact_col]
else:
total_risk_value += row[fail_prob_col] * row[risk_impact_col]
df.drop(columns=["var"], inplace=True)
df["solution_status"] = sol_status
df["optimized_risk"] = total_risk_value
return df
def ingest_data(file_path: str) -> pd.DataFrame:
df = pd.read_csv(file_path)
return df
def local_analysis(df: pd.DataFrame) -> dict:
total_equipment = len(df)
avg_failure = df["failure_probability"].mean() if "failure_probability" in df.columns else 0
high_risk_count = (df["failure_probability"] > 0.7).sum() if "failure_probability" in df.columns else 0
summary = {
"total_equipment": total_equipment,
"avg_failure_probability": float(avg_failure),
"high_risk_count": int(high_risk_count),
}
print(summary)
return summary
def local_optimization(df: pd.DataFrame, budget: float) -> pd.DataFrame:
optimizer = MaintenanceOptimizer(alpha=0.0, include_manpower_constraint=True, manpower_limit=5000)
schedule_df = optimizer.optimize_schedule(
risk_df=df,
budget=budget,
cost_col="cost",
fail_prob_col="failure_probability",
risk_impact_col="risk_impact",
labor_col="labor_hours"
)
return schedule_df
def run_pipeline(file_path: str, budget: float) -> dict:
df = ingest_data(file_path)
analysis = local_analysis(df)
schedule_df = local_optimization(df, budget)
plan_summary = {
"maintenance_schedule": schedule_df.to_dict(orient="records"),
"optimized_risk": float(schedule_df["optimized_risk"].iloc[0]) if len(schedule_df) else 0.0,
"solution_status": schedule_df["solution_status"].iloc[0] if len(schedule_df) else "Unknown",
}
return {
"analysis_summary": analysis,
"plan_summary": plan_summary
}
Results of the above process are:
- An optimized schedule indicating which equipment should be maintained.
- A minimized total risk within budget constraints.
Sample output for EQUIP_0999 is as follows.
{'equipment_id': 'EQUIP_0999', 'equipment_type': 'circuit_breaker', 'age': 15, 'maintenance_count': 4,
'cost': 8513, 'risk_impact': 3.07, 'labor_hours': 11, 'failure_probability': 0.805, 'maintain': 0, 'solution_status': 'Optimal',
'optimized_risk': 971.6045199999995}, {'equipment_id': 'EQUIP_1000', 'equipment_type': 'electric_pole', 'age': 1, 'maintenance_count': 0,
'cost': 1817, 'risk_impact': 1.61, 'labor_hours': 6, 'failure_probability': 0.293, 'maintain': 0, 'solution_status': 'Optimal',
'optimized_risk': 971.6045199999995}], 'optimized_risk': 971.6045199999995, 'solution_status': 'Optimal'}
4️⃣ Agentic Reasoning with DeepSeek
Even after optimization, decision-makers often need contextual insights. This is where Agentic AI and DeepSeek came into play. I ran DeepSeek locally via Ollama.
deepseek_llm = LLM(
model="ollama/deepseek-r1:7b",
base_url="http://localhost:11434",
api_key="" # Empty because as we are using ollama locally
)
Specialized Agents:
- Financial Advisor: Provided cost breakdowns and ROI analysis.
- Risk & Compliance Specialist: Highlighted safety and regulatory concerns.
- Strategic Communicator: Synthesized findings of the previous agents into an executive summary.
Each agent uses DeepSeek to reason over the optimized data, translating raw numbers into actionable business insights. They are defined as follows:
from crewai import Agent, Task, LLM
from yaml import safe_load
def load_prompt(file_path: str, prompt_key: str) -> dict:
with open(file_path) as f:
prompts = safe_load(f)
return prompts[prompt_key]
# Create a single LLM instance for all agents using the Deepseek model
deepseek_llm = LLM(
model="ollama/deepseek-r1:7b",
base_url="http://localhost:11434",
api_key="" # Empty because of using a local model
)
def create_financial_agent():
financial_prompt = load_prompt('prompts/financial_agent.yaml', 'financial_analysis')
financial_agent = Agent(
role='Financial Advisor',
goal='Maximize ROI within the allocated budget',
backstory='Expert in utility sector economics with CPA certification',
llm=deepseek_llm, # Use the unified Deepseek LLM instance
verbose=True
)
return financial_agent
def create_risk_agent():
risk_prompt = load_prompt('prompts/risk_agent.yaml', 'risk_assessment')
risk_agent = Agent(
role='Risk and Compliance Specialist',
goal='Focus on safety, regulatory requirements, and potential legal issues',
backstory='Former utility regulator with safety compliance expertise',
llm=deepseek_llm, # Use the unified Deepseek LLM instance
verbose=True
)
return risk_agent
def create_communicator_agent():
comm_prompt = load_prompt('prompts/communicator_agent.yaml', 'executive_summary')
communicator_agent = Agent(
role='Strategic Communicator',
goal='Merge various advisors\' insights into a coherent, executive-level summary',
backstory='Former management consultant with technical translation expertise',
llm=deepseek_llm, # Use the unified Deepseek LLM instance
verbose=True
)
return communicator_agent
def get_financial_advice(agent, plan_summary: dict) -> str:
prompt_config = load_prompt('prompts/financial_agent.yaml', 'financial_analysis')
prompt = prompt_config['prompt'].format(content=plan_summary['summary'])
task = Task(
description=prompt_config['description'],
agent=agent,
expected_output=prompt_config['expected_output'],
context=[{
"description": "Maintenance Plan Summary",
"content": plan_summary['summary'],
"expected_output": "Markdown report with cost breakdowns and 3-year ROI projections"
}],
config={'llm': 'ollama_config.yaml'}
)
output = task.execute_sync(context=prompt)
return output.raw if output and output.raw is not None else ""
def get_risk_advice(agent, analysis_summary: dict, plan_summary: dict) -> str:
prompt_config = load_prompt('prompts/risk_agent.yaml', 'risk_assessment')
prompt = prompt_config['prompt'].format(
analysis_content=analysis_summary,
plan_content=plan_summary['summary']
)
task = Task(
description=prompt_config['description'],
agent=agent,
expected_output=prompt_config['expected_output'],
context=[
{
"description": "Analysis Summary",
"content": analysis_summary,
"expected_output": "Risk matrix with probability/impact scores and mitigation strategies"
},
{
"description": "Maintenance Plan Summary",
"content": plan_summary['summary'],
"expected_output": "Risk matrix with probability/impact scores and mitigation strategies"
}
],
config={'llm': 'ollama_config.yaml'}
)
output = task.execute_sync(context=prompt)
return output.raw if output and output.raw is not None else ""
def get_communicator_report(agent, financial_advice: str, risk_advice: str) -> str:
prompt_config = load_prompt('prompts/communicator_agent.yaml', 'executive_summary')
prompt = prompt_config['prompt'].format(
financial_content=financial_advice,
risk_content=risk_advice
)
task = Task(
description=prompt_config['description'],
agent=agent,
expected_output=prompt_config['expected_output'],
context=[
{
"description": "Financial Advice",
"content": financial_advice,
"expected_output": "Executive memo with prioritized action items and risk tradeoffs"
},
{
"description": "Risk Advice",
"content": risk_advice,
"expected_output": "Executive memo with prioritized action items and risk tradeoffs"
}
],
config={'llm': 'ollama_config.yaml'}
)
output = task.execute_sync(context=prompt)
return output.raw if output and output.raw is not None else ""
5️⃣ Full Pipeline Execution
The entire process—from data ingestion to strategic reporting—is managed by a main orchestration script.
The workflow overview is as follows :-
- Generate synthetic data.
- Perform local analysis.
- Run mathematical optimization.
- Leverage Agentic AI for reasoning.
- Produce an executive-level summary.
This modular approach ensures that each component can be developed and improved independently while contributing to the larger goal. Below is the code for the the main.py file that puts together every piece.
#main.py
import sys
import json
import pandas as pd
import os
# Import your pipeline and agent functions
from maintenance_pipeline import run_pipeline
from strategy_agents import (
create_financial_agent,
create_risk_agent,
create_communicator_agent,
get_financial_advice,
get_risk_advice,
get_communicator_report
)
# Import local summarizer
from local_summarizer import summarize_maintenance_plan, generate_text_summary
def main(file_path: str, budget: float):
"""
1) Run the local pipeline to get analysis and plan.
2) Summarize the large 'maintenance_schedule' so we don't exceed token limits.
3) Pass the summary to Financial and Risk agents.
4) Combine their advice using the Communicator agent.
"""
# 1) Run the local pipeline
pipeline_results = run_pipeline(file_path, budget)
analysis_summary = pipeline_results["analysis_summary"]
plan_summary = pipeline_results["plan_summary"]
# Convert maintenance_schedule to a DataFrame and summarize it
schedule_list = plan_summary["maintenance_schedule"]
schedule_df = pd.DataFrame(schedule_list)
summary_dict = summarize_maintenance_plan(schedule_df, top_n=10)
summary_text = generate_text_summary(summary_dict)
# 3) Create the agents
financial_agent = create_financial_agent()
risk_agent = create_risk_agent()
communicator_agent = create_communicator_agent()
# 4) Gather advice
print("=== FINANCIAL ADVICE ===")
fin_advice = get_financial_advice(financial_agent, {"summary": summary_text})
print(fin_advice)
print("\n=== RISK & COMPLIANCE ADVICE ===")
risk_advice = get_risk_advice(risk_agent, analysis_summary, {"summary": summary_text})
print(risk_advice)
print("\n=== COMMUNICATOR SUMMARY ===")
final_summary = get_communicator_report(communicator_agent, fin_advice, risk_advice)
print(final_summary)
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python main.py <csv_file_path> <budget>")
sys.exit(1)
csv_file = sys.argv[1]
budget_value = float(sys.argv[2])
main(csv_file, budget_value)
The Financial Advisor dives deep into the maintenance plan summary, producing a detailed financial analysis report. This agent focuses on:
- Breaking down projected maintenance costs to understand where the budget is allocated.
- Providing budget recommendations based on cost analyses.
- Calculating potential Return on Investment (ROI) by evaluating cost-saving opportunities and identifying areas for efficiency improvements.
The result is a clear, actionable report highlighting key financial metrics and offering strategies to optimize spending. This ensures that the utility company uses its budget efficiently, maximizing financial performance while maintaining service quality. Its output is below:
# Agent: Financial Advisor
## Final Answer:
### Financial Analysis Report: Maintenance Plan for Utility Sector Equipment
---
#### 1. Cost Breakdown by Equipment Type
| **Equipment Type** | **Total Items** | **Maintained Items** | **Average Cost per Maintained Item** | **Total Maintenance Cost** |
|---------------------|-----------------|-----------------------|---------------------------------------|----------------------------|
| capacitor_bank | 134 | 24 | $3,600.20 | $864.05 |
| circuit_breaker | 143 | 17 | $7,441.90 | $126,512.30 |
| electric_pole | 128 | 33 | $2,452.90 | $8,1,943.70 |
| transformer | 146 | 24 | $9,911.00 | $237,864.00 |
| **Total** | **545** | **98** | **-** | **$749,993.00** |
---
#### 2. ROI Projection Over 3 Years
Assuming that maintenance costs are $749,993 over 3 years for the maintained items, and considering the failure probabilities (Fp) provided, we can estimate the potential savings by maintaining vs. not maintaining each item.
For example, let's consider an item with a cost of maintenance ($C_m$) and a failure probability ($F_p$). The annual maintenance cost per item is $C_m / \text{number of items}$, while the expected failure-related cost without maintenance can be estimated as:
\[
\text{Expected Savings} = F_p \times (\text{Cost of Failure} - C_m)
\]
However, since we do not have exact breakdown costs for failures ($C_f$), we cannot calculate precise ROI values. Instead, we can outline the potential savings based on failure probabilities and maintenance costs.
---
#### 3. Cost-Saving Strategies
1. **Prioritize High-Failure Items**: Focus on maintaining items with higher failure probabilities (Fp) to prevent significant future costs.
- Items like transformer (Fp = ~0.835) should be a top priority for maintenance due to high risk.
2. **Invest in Predictive Maintenance**: Replace traditional maintenance methods with predictive monitoring systems to reduce unplanned failures and save on long-term replacement costs.
3. **Optimize Maintenance Workforce**: Streamline maintenance operations by cross-training technicians or using automation where possible, reducing labor costs per item.
---
#### 4. Risk-Adjusted Impact
The risk associated with each equipment type is directly related to its failure probability:
- High-Failure Items (e.g., transformer): Must be maintained to avoid catastrophic failures.
- Medium-High Failure Items: Prioritize maintenance to mitigate significant but manageable costs.
- Low-Failure Items: These can be managed with less intensive maintenance protocols, freeing up resources for higher-priority tasks.
---
#### 5. Conclusion
The total maintenance cost of $749,993 over 3 years is reasonable given the scale of equipment and operations. However, by focusing on high-risk items (e.g., transformers) and optimizing maintenance strategies, the utility sector can further reduce costs while ensuring operational reliability.
---
This report provides a detailed financial assessment of the maintenance plan, highlighting areas for optimization to enhance efficiency and reduce risk.
⚖️ Risk & Compliance Advice
The Risk & Compliance agent takes a critical look at the maintenance plan, evaluating it from a safety and regulatory perspective. This involves:
- Identifying safety compliance gaps that could expose the company to risks.
- Highlighting regulatory issues and potential areas of non-compliance.
- Pinpointing failure cascade risks that could result in widespread system failures.
- Assessing workforce safety concerns to ensure the maintenance plan protects personnel.
Such an evaluation helps ensure that the maintenance plan not only makes financial sense but also adheres to safety regulations and minimizes operational risks. The output from the run is shown below:
=== RISK & COMPLIANCE ADVICE ===
# Agent: Risk and Compliance Specialist
## Task: Evaluate operational and compliance risks
# Agent: Risk and Compliance Specialist
## Final Answer:
Evaluation of Operational and Compliance Risks
#### 1. Safety Compliance Gaps:
- **High-Risk Equipment**: The presence of high-risk equipment (262 items) suggests potential gaps in compliance with safety standards, particularly for transformers which may not meet updated regulations on maintenance intervals and fault management.
- **Training Deficiencies**: Inadequate training among the workforce regarding high-risk equipment could lead to non-compliance, increasing legal risks.
#### 2. Regulatory Exposure Points:
- **Non-Maintenance of High-Risk Items**: Transformers with zero maintenance (as seen in Top-Cost Items) may violate regulatory requirements, exposing the system to regulatory scrutiny and potential penalties.
- **Failure Probability Compliance**: Equipment must adhere to specified failure probabilities; failing to meet these could result in regulatory issues.
#### 3. Failure Cascade Risks:
- **Transformer Failures**: High failure probability (0.835) for transformers poses a significant risk of cascading failures, potentially leading to widespread power outages and operational disruptions.
- **Cascading Impact**: Without proper maintenance or mitigation strategies, transformer failures could propagate through the grid, causing severe infrastructure impacts.
#### 4. Workforce Safety Factors:
- **Insufficient Maintenance Knowledge**: The low maintenance rate (249/1000) indicates inadequate training on identifying high-risk equipment and appropriate maintenance procedures.
- **Incident Rates**: Inadequate workforce knowledge increases the risk of incidents, potentially leading to injuries.
#### Mitigation Strategies:
1. **Comprehensive Maintenance Programs**:
- Develop a standardized maintenance plan for each equipment type (transformers, circuit breakers, etc.), adhering strictly to regulatory guidelines.
- Ensure transformers are maintained at specified intervals and meet updated safety standards.
2. **Workforce Training**:
- Provide extensive training programs focusing on identifying high-risk equipment and proper maintenance practices.
- Regularly audit worker knowledge to ensure compliance with maintenance protocols.
3. **Predictive Maintenance Implementation**:
- Invest in technologies for predictive maintenance to optimize transformer and circuit breaker management, reducing the likelihood of cascading failures.
4. **Regulatory Compliance Audits**:
- Conduct regular audits to check adherence to safety standards and maintenance schedules.
- Address any regulatory non-compliance promptly to avoid penalties and maintain trust with regulators.
By addressing these gaps and implementing mitigation strategies, the system can significantly reduce operational and compliance risks associated with high-risk equipment.
📋Executive Summary — Strategic Communicator Agent
The Strategic Communicator acts as the bridge between technical insights and high-level strategy. This agent:
- Synthesizes outputs from both the Financial Advisor and the Risk & Compliance Specialist.
- Crafts a concise, executive-level summary that highlights the most critical insights.
- Translates technical jargon into clear, strategic recommendations tailored for decision-makers.
The final output is a polished, easy-to-understand executive summary that presents key takeaways, helping stakeholders make informed strategic decisions quickly and confidently. Sample output is as follows:
=== COMMUNICATOR SUMMARY ===
# Agent: Strategic Communicator
## Task: Create board-level summary
# Agent: Strategic Communicator
## Final Answer:
Executive Summary for Utility Sector Maintenance Plan**
---
**Executive Summary**
This maintenance plan outlines a strategic approach to address high-risk equipment in the utility sector, focusing on operational efficiency, safety, and compliance. Key findings include:
- **Total Cost**: The system incurs $10 million annually over three years.
- **High-Risk Equipment**: Transformers dominate with 83% Fp, necessitating priority maintenance.
- **Cost-Saving Strategies**: Predictive maintenance reduces unplanned failures, while workforce training enhances compliance.
**Priority Action Items**
1. **Transformer Maintenance Prioritization**
- Develop a standardized maintenance plan for transformers adhering to updated standards.
2. **Comprehensive Maintenance Program**
- Implement regular audits and training on transformer maintenance.
3. **Workforce Development**
- Train technicians on high-risk equipment identification and maintenance.
4. **Predictive Maintenance Implementation**
- Explore technologies to optimize transformer management, reducing cascading failures.
5. **Regulatory Compliance**
- Address gaps in compliance with new regulations and maintain operational standards.
**Financial vs Risk Tradeoffs**
Investing in predictive maintenance and workforce training may incur higher costs initially but will save significantly by preventing cascading failures and operational disruptions over the long term.
**90-Day Action Plan**
- Month 1: Assess current protocols, develop a training program outline, explore predictive maintenance options.
- Month 2: Implement initial audits, schedule retraining sessions for key personnel.
- Month 3: Finalize training modules, begin regular audit scheduling.
**Long-Term Strategic Implications**
Implementing these actions will enhance operational resilience, ensure regulatory compliance, and improve public trust. By addressing risks proactively, the system maintains efficiency and safety, preventing future penalties and disruptions.
---
This structured approach ensures a clear, actionable plan to mitigate risks and optimize costs in the utility sector's maintenance operations.
Executive Summary for Utility Sector Maintenance Plan**
💡 Discussion and Future Work
This hybrid approach — blending mathematical optimization with qualitative reasoning through DeepSeek and CrewAI — showcases how quantitative models and agentic reasoning can seamlessly complement one another. The result is a system that not only crunches numbers efficiently but also offers contextual, strategic insights to guide high-level decision-making.
The integration of these two worlds brings several key advantages:
- Enhanced Decision-Making: Combining raw data analysis with human-like reasoning helps deliver richer, more actionable insights.
- Modularity: Each component — whether it’s data ingestion, optimization, or reasoning — operates independently yet cohesively, making the system flexible and easy to scale.
- Scalability: The architecture supports the addition of new agents or data sources, allowing it to adapt to evolving business needs.
What’s Next?
While this framework already offers powerful capabilities, there are exciting opportunities for future improvements:
- Dynamic Task Execution:
Implementing real-time, dynamic task allocation where agents can adapt based on live data and changing scenarios. - Advanced Memory Utilization:
Enhancing agentic reasoning with memory features that allow agents to retain context over multiple iterations, enabling deeper, more nuanced insights. - Integration of Additional Data Sources:
Expanding the system to pull in real-time sensor data, historical maintenance logs, and even strategic documents, further enriching the insights generated.
✅ Conclusion
In this article, I explored a comprehensive framework for equipment maintenance planning that combines Mixed-Integer Programming (MIP) optimization with DeepSeek-based reasoning, all orchestrated through CrewAI.
Here’s a quick recap of what we achieved:
- ✅ Generated synthetic data that simulates real-world maintenance scenarios.
- ✅ Built a robust maintenance pipeline that optimizes schedules using MIP techniques.
- ✅ Leveraged Agentic AI and specialized agents to transform raw optimization results into actionable strategic insights.
- ✅ Delivered a cohesive, executive-level summary — balancing financial, risk, and operational considerations.
This hybrid approach effectively bridges the gap between mathematical rigor and human-centric strategic planning.
📂 Want to dive into the code? 👉 Click here to access the repo with all the code.
🤝 Let’s Connect!
If you’re working on maintenance planning or AI-driven decision support systems and want to brainstorm ideas, I’d love to connect!
- 💬 Have questions? Let’s discuss your AI and optimization challenges.
- 📖 Enjoyed this guide? Follow me for more deep dives into AI, industrial optimization, and strategic decision-making.
- 🔥 Stay tuned! More practical guides on implementing AI in complex environments are on the way.
Thanks for reading! 🙏 🚀
📚 References
- 🔗 DeepSeek — Reasoning Large Language Model
- 🔗 CrewAI — Agentic AI Orchestration Framework
- 🔗 Agentic AI: What Is It and How Will It Change Work? — Harvard Business Review
- 🔗 PuLP — Python Linear Programming Modeler