DEV Community

shashank ms
shashank ms

Posted on

Using LLMs for Predictive Maintenance

We are going to build a lightweight predictive maintenance agent that reads machine sensor logs and recent work orders, then returns a structured risk assessment. It is aimed at plant engineers and ops teams who need to catch bearing degradation or thermal runaway before scheduled inspections. The whole pipeline runs against Oxlo.ai, so stuffing long telemetry histories into the prompt does not inflate your cost the way token-based providers do.

What you'll need

  • Python 3.10 or newer
  • The openai SDK. Install it with pip install openai
  • An Oxlo.ai API key from https://portal.oxlo.ai
  • A few minutes to copy, paste, and run the code

Step 1: Collect and normalize sensor data

In production this would pull from your SCADA or historian database. For this tutorial we will mock a helper that returns the last 24 hours of readings for a given asset tag.

import random
from datetime import datetime, timedelta

def get_recent_telemetry(machine_id: str):
    # Mock telemetry: vibration mm/s, temperature C, runtime hours
    base = {"machine_id": machine_id, "readings": []}
    now = datetime.utcnow()
    for i in range(6):
        base["readings"].append({
            "timestamp": (now - timedelta(hours=4 * i)).isoformat() + "Z",
            "vibration_ms": round(2.5 + random.random() * 3.0, 2),
            "temp_c": round(65 + random.random() * 25, 1),
            "runtime_hrs": 1200 + i * 4
        })
    return base

Step 2: Build the maintenance log context

LLMs reason better over plain text logs than raw CSV rows. We will render the telemetry into a concise text block, then append any free-text work orders.

def build_context(telemetry: dict, work_orders: list[str]) -> str:
    lines = [
        f"Machine: {telemetry['machine_id']}",
        "Recent telemetry (last 24 hours):",
    ]
    for r in telemetry["readings"]:
        lines.append(
            f"  {r['timestamp']} | vibration: {r['vibration_ms']} mm/s | "
            f"temp: {r['temp_c']} C | runtime: {r['runtime_hrs']} hrs"
        )
    if work_orders:
        lines.append("Recent work orders:")
        for wo in work_orders:
            lines.append(f"  - {wo}")
    return "\n".join(lines)

Step 3: Write the system prompt

The system prompt defines the agent as a reliability engineer and forces JSON output so downstream scripts can parse it without regex.

SYSTEM_PROMPT = """You are a reliability engineer specializing in rotating equipment.
Analyze the provided telemetry and maintenance history.
Respond with a single JSON object containing exactly these keys:
- risk_score: integer from 1 to 10
- likely_fault: one of [none, bearing_wear, misalignment, thermal_overload, lubrication_issue]
- recommended_action: one of [none, schedule_inspection, immediate_shutdown, order_parts]
- reasoning: a concise sentence explaining your decision

Use only the data provided. Do not invent measurements."""

Step 4: Wire the Oxlo.ai client

We use the OpenAI SDK as a drop-in client pointed at Oxlo.ai. Because Oxlo.ai uses flat per-request pricing, you can pass in long maintenance histories without watching input costs scale. See https://oxlo.ai/pricing for plan details.

from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

def assess_machine(machine_id: str, work_orders: list[str]):
    telemetry = get_recent_telemetry(machine_id)
    context = build_context(telemetry, work_orders)

    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": context},
        ],
        temperature=0.2,
    )

    return response.choices[0].message.content

Step 5: Parse the response and route the result

The model returns a JSON string. We will load it and print a human-readable maintenance ticket. If parsing fails, we fall back to raw text so the script never crashes silently.

import json

def run_maintenance_agent(machine_id: str, work_orders: list[str] = None):
    if work_orders is None:
        work_orders = []
    raw = assess_machine(machine_id, work_orders)
    try:
        result = json.loads(raw)
    except json.JSONDecodeError:
        result = {
            "risk_score": 0,
            "likely_fault": "unknown",
            "recommended_action": "manual_review",
            "reasoning": f"Unparseable response: {raw}"
        }

    print(f"Asset: {machine_id}")
    print(f"Risk Score: {result['risk_score']}/10")
    print(f"Likely Fault: {result['likely_fault']}")
    print(f"Action: {result['recommended_action']}")
    print(f"Reasoning: {result['reasoning']}")
    return result

Run it

Copy the snippets above into a single file named maintenance_agent.py, replace YOUR_OXLO_API_KEY, and execute it. Here is a sample invocation with a compressor that has recent thermal observations.

if __name__ == "__main__":
    work_orders = [
        "2024-05-10: Replaced discharge valve seal",
        "2024-05-14: Observed elevated casing temp during rounds"
    ]
    run_maintenance_agent("COMP-001-A", work_orders)

Example output:

Asset: COMP-001-A
Risk Score: 7/10
Likely Fault: thermal_overload
Action: schedule_inspection
Reasoning: Casing temperatures trending upward combined with recent thermal observation warrant inspection before next runtime milestone.

Next steps

Swap in kimi-k2.6 or deepseek-v3.2 if you want heavier reasoning over longer maintenance backlogs. Both are available on Oxlo.ai with the same request-based pricing.

For production, replace the mock telemetry with an MQTT or OPC-UA listener, and enable Oxlo.ai JSON mode or function calling to guarantee schema compliance instead of hand-rolling try/except blocks.

Top comments (0)