We are going to build a shipment exception analyzer that reads raw logistics alerts and returns structured triage data. Logistics teams deal with hundreds of unstructured delay notifications, port congestion updates, and carrier exceptions daily. This agent turns those walls of text into structured JSON with severity scores and recommended next steps.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK:
pip install openai
Step 1: Configure the Oxlo.ai client
Set up the OpenAI SDK to point at Oxlo.ai. I keep my key in an environment variable, but you can paste it directly for a quick test.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY", "YOUR_OXLO_API_KEY")
)
Step 2: Write the system prompt
The system prompt is the only part you need to edit to change the agent's behavior. It defines the output schema and tone.
SYSTEM_PROMPT = """You are a logistics exception analyzer. Read the user's raw alert and return a JSON object with exactly these fields:
- shipment_id: string or null
- exception_type: string, e.g., "delay", "damage", "misroute", "customs_hold"
- location: string or null
- severity: one of "low", "medium", "high", "critical"
- root_cause_summary: string, max 12 words
- recommended_action: string, max 12 words
- confidence: float between 0.0 and 1.0
Rules:
- Use null when information is missing.
- Severity "critical" means the shipment will miss a hard deadline or incurs demurrage.
- Be concise. No prose outside the JSON."""
Step 3: Extract structured data with JSON mode
Test the agent against a single alert. I use Llama 3.3 70B because it follows instructions reliably, and I enable JSON mode so the output is machine readable.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a logistics exception analyzer. Read the user's raw alert and return a JSON object with exactly these fields:
- shipment_id: string or null
- exception_type: string, e.g., "delay", "damage", "misroute", "customs_hold"
- location: string or null
- severity: one of "low", "medium", "high", "critical"
- root_cause_summary: string, max 12 words
- recommended_action: string, max 12 words
- confidence: float between 0.0 and 1.0
Rules:
- Use null when information is missing.
- Severity "critical" means the shipment will miss a hard deadline or incurs demurrage.
- Be concise. No prose outside the JSON."""
user_message = (
"ALERT: Container MSCU1234567 delayed at Port of Long Beach due to customs examination. "
"Expected dwell 48-72 hours. Consignee: Acme Logistics. Vessel: Ever Given. "
"Original ETA: 2024-05-15."
)
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 daily alert feed
In production, you receive dozens of alerts at once. This loop sends each one to Oxlo.ai and collects the results. Because Oxlo.ai uses request-based pricing, the cost is predictable even when the alerts are long EDI messages with thousands of tokens.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a logistics exception analyzer. Read the user's raw alert and return a JSON object with exactly these fields:
- shipment_id: string or null
- exception_type: string, e.g., "delay", "damage", "misroute", "customs_hold"
- location: string or null
- severity: one of "low", "medium", "high", "critical"
- root_cause_summary: string, max 12 words
- recommended_action: string, max 12 words
- confidence: float between 0.0 and 1.0
Rules:
- Use null when information is missing.
- Severity "critical" means the shipment will miss a hard deadline or incurs demurrage.
- Be concise. No prose outside the JSON."""
alerts = [
"ALERT: Container MSCU1234567 delayed at Port of Long Beach due to customs examination. Expected dwell 48-72 hours.",
"NOTICE: Trailer T-889 flipped on I-95 near Richmond. Cargo: electronics. Driver status: uninjured. Tow en route.",
"UPDATE: Flight CX881 departs HKG 6 hours late. AWB 160-12345678. Perishable pharma shipment. Reroute to ORD suggested.",
]
triage_list = []
for alert in alerts:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": alert},
],
response_format={"type": "json_object"},
)
triage_list.append(json.loads(response.choices[0].message.content))
critical = [item for item in triage_list if item.get("severity") == "critical"]
print(f"Processed {len(triage_list)} alerts. Critical count: {len(critical)}")
for item in critical:
print(item.get("shipment_id"), item.get("recommended_action"))
Run it
Save the script as exception_agent.py, export your OXLO_API_KEY, and run python exception_agent.py. The first alert should return JSON similar to this:
{
"shipment_id": "MSCU1234567",
"exception_type": "customs_hold",
"location": "Port of Long Beach",
"severity": "high",
"root_cause_summary": "Customs examination causing 48 to 72 hour dwell",
"recommended_action": "Notify consignee and customs broker",
"confidence": 0.91
}
Next steps
Two concrete ways to extend this agent. First, wire the output into a Slack webhook so critical alerts ping the operations channel automatically. Second, swap in Qwen 3 32B on Oxlo.ai to handle multilingual alerts from international carriers without changing any code, since the platform is fully OpenAI SDK compatible.
Top comments (0)