DEV Community

shashank ms
shashank ms

Posted on

Introduction to LLMs for Energy and Manufacturing

We are going to build a maintenance log parser that reads unstructured shift notes from factory technicians and outputs structured incident reports. It helps plant engineers triage equipment issues without digging through pages of noisy text. We will wire it directly to Oxlo.ai and run it against realistic shop-floor examples.

What you'll need

  • Python 3.10 or newer
  • The OpenAI SDK: pip install openai
  • An Oxlo.ai API key from https://portal.oxlo.ai. Oxlo.ai uses request-based pricing, so long log entries do not inflate your cost the way token-based billing would. See https://oxlo.ai/pricing for details.

Step 1: Configure the Oxlo.ai client

I always start by verifying the connection with a simple health-check prompt. This confirms my API key and base URL are correct before I build logic around it.

from openai import OpenAI

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

response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Say 'Connection OK' and nothing else."},
    ],
)

print(response.choices[0].message.content)

Step 2: Define the system prompt

The system prompt is the contract. It tells the model exactly what to extract from raw maintenance notes and how to format the result. I keep it strict and give it a concrete JSON schema.

SYSTEM_PROMPT = """You are a manufacturing maintenance parser.
Read the technician's log entry and emit a single JSON object with these keys:
- equipment_tag: the machine or line identifier (e.g., PUMP-101, HVAC-A)
- fault_code: a short hyphenated code for the issue, or "UNKNOWN"
- severity: one of LOW, MEDIUM, HIGH, CRITICAL
- summary: one sentence describing the problem
- recommended_action: one sentence describing the immediate next step
Rules:
- Output ONLY valid JSON.
- Do not wrap the JSON in markdown code fences.
- If the log is ambiguous, set severity to MEDIUM and fault_code to UNKNOWN."""

Step 3: Parse a single log entry

Now I feed the prompt a realistic log entry. I use JSON mode to enforce valid output, then load the string with Python's json module.

import json

user_message = """
Shift: Night-2
Tech: Maria
Log: Boiler-7 pressure reading spiked to 220 PSI at 02:15. Safety valve opened and vented steam for ~3 min. Reset controller and manually locked out fuel feed. Recovered to 180 PSI by 02:40. Recommend inspection of PID loop before restart.
"""

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

result = json.loads(response.choices[0].message.content)
print(json.dumps(result, indent=2))

Step 4: Batch process a full shift report

Plant supervisors usually paste multiple notes into one file. I split the file on blank lines and run each chunk through the parser, collecting results in a list. Because Oxlo.ai charges per request, not per token, a long shift report costs the same as a short one.

raw_shift_report = """
Conveyor-B belt squeaking since mid-shift. Lubricated tensioner but noise persists. Might need new bearing.

Motor-M3 tripped thermal overload twice. Ambient temp in electrical room is 38 C. Checked ventilation fan, seems clogged.

Tank-12 level sensor giving erratic 4-20 mA signal. Calibrated transmitter, still drifting. Ordered replacement probe.
"""

entries = [entry.strip() for entry in raw_shift_report.strip().split("\n\n") if entry.strip()]
reports = []

for entry in entries:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": entry},
        ],
        response_format={"type": "json_object"},
    )
    reports.append(json.loads(response.choices[0].message.content))

print(json.dumps(reports, indent=2))

Step 5: Filter and escalate critical items

Finally, I add a small Python filter so the morning supervisor sees only HIGH and CRITICAL items. This keeps the signal-to-noise ratio tight.

critical_items = [r for r in reports if r.get("severity") in ("HIGH", "CRITICAL")]

print(f"Total entries: {len(reports)}")
print(f"Require immediate attention: {len(critical_items)}")

for item in critical_items:
    print(f"- {item['equipment_tag']}: {item['summary']}")
    print(f"  Action: {item['recommended_action']}")

Run it

Save the script as maintenance_parser.py, replace YOUR_OXLO_API_KEY, and run python maintenance_parser.py. You should see output similar to this.

$ python maintenance_parser.py
Connection OK
{
  "equipment_tag": "Boiler-7",
  "fault_code": "PRESSURE-SPIKE",
  "severity": "HIGH",
  "summary": "Boiler pressure spiked to 220 PSI causing safety valve to vent steam.",
  "recommended_action": "Inspect PID control loop before restarting boiler."
}
[
  {
    "equipment_tag": "Conveyor-B",
    "fault_code": "BEARING-WEAR",
    "severity": "MEDIUM",
    "summary": "Conveyor belt squeaking persists after lubrication, likely bearing failure.",
    "recommended_action": "Replace tensioner bearing during next scheduled downtime."
  },
  {
    "equipment_tag": "Motor-M3",
    "fault_code": "THERMAL-TRIP",
    "severity": "HIGH",
    "summary": "Motor tripped thermal overload twice due to high ambient temperature.",
    "recommended_action": "Clean clogged ventilation fan and monitor thermal load."
  },
  {
    "equipment_tag": "Tank-12",
    "fault_code": "SENSOR-DRIFT",
    "severity": "MEDIUM",
    "summary": "Level sensor signal drifting after calibration.",
    "recommended_action": "Install replacement probe when it arrives."
  }
]
Total entries: 3
Require immediate attention: 1
- Motor-M3: Motor tripped thermal overload twice due to high ambient temperature.
  Action: Clean clogged ventilation fan and monitor thermal load.

Next steps

Connect the parser to your CMMS by POSTing the JSON reports to a webhook after each batch run. If your plant still uses paper logbooks, swap the text input for kimi-k2.6 vision and feed it scanned pages so the agent reads handwriting directly through Oxlo.ai's image input support.

Top comments (0)