We are going to build a supply chain disruption analyzer that ingests live shipment data, scores risk factors, and returns structured mitigation steps. It is designed for logistics teams who need immediate visibility into delays without maintaining a custom rules engine.
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
I start by importing the OpenAI SDK and pointing it at Oxlo.ai. Because Oxlo.ai is fully OpenAI-compatible, this is the only client I need throughout the project.
from openai import OpenAI
import json
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
Step 2: Prepare sample supply chain data
Next I create a realistic payload representing two inbound shipments, a weather alert, and a supplier delay notice. In production this would come from your TMS or EDI feed.
SHIPMENTS = [
{
"shipment_id": "SH-28491",
"origin": "Port of Shanghai",
"destination": "Los Angeles",
"eta": "2024-06-14T08:00:00Z",
"status": "at_sea",
"cargo": ["electronics", "batteries"],
"value_usd": 450000
},
{
"shipment_id": "SH-28492",
"origin": "Rotterdam",
"destination": "New York",
"eta": "2024-06-12T14:00:00Z",
"status": "customs_hold",
"cargo": ["pharma", "cold_chain"],
"value_usd": 890000
}
]
ALERTS = [
{"type": "weather", "severity": "high", "region": "North Atlantic", "detail": "Hurricane warnings for June 13-15"},
{"type": "supplier", "severity": "medium", "supplier_id": "SUP-112", "detail": "Battery plant shutdown extended 48 hours"}
]
Step 3: Write the analyst system prompt
The system prompt defines the agent's role and forces JSON output with specific fields. I keep it strict so downstream code can rely on the schema.
SYSTEM_PROMPT = """You are a supply chain risk analyst. Your job is to evaluate active shipments and alerts, then produce a structured risk assessment.
Rules:
- Output valid JSON only. No markdown, no explanation outside the JSON.
- Risk level must be one of: low, medium, high, critical.
- For each high or critical risk, provide a recommended_action with a concrete step.
- affected_shipments must list shipment_ids.
JSON schema:
{
"overall_risk": "low|medium|high|critical",
"assessments": [
{
"shipment_id": "string",
"risk_level": "string",
"root_cause": "string",
"recommended_action": "string",
"financial_exposure_usd": 0
}
],
"summary": "string"
}
"""
Step 4: Build the assessment agent
This function formats the data into a user message and calls Oxlo.ai. I use llama-3.3-70b because it handles structured JSON reliably, and I enable JSON mode via response_format. Because Oxlo.ai uses request-based pricing, passing a large payload with extra supplier context does not inflate the cost. See https://oxlo.ai/pricing for plan details.
def analyze_supply_chain(shipments, alerts):
user_message = f"""Active shipments:
{json.dumps(shipments, indent=2)}
Active alerts:
{json.dumps(alerts, indent=2)}
Produce the risk assessment JSON now.
"""
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"},
temperature=0.2,
)
raw = response.choices[0].message.content
return json.loads(raw)
Step 5: Add deep reasoning for critical risks
For any assessment flagged critical, I send a second request to a reasoning model to generate a detailed mitigation plan. This two-stage pattern keeps routine scoring fast while giving complex cases deeper analysis.
def deep_mitigation_plan(assessment):
prompt = f"""Shipment {assessment['shipment_id']} is critical due to: {assessment['root_cause']}.
Recommended action so far: {assessment['recommended_action']}.
Provide a detailed, step-by-step mitigation plan for the logistics team."""
response = client.chat.completions.create(
model="deepseek-v3.2",
messages=[
{"role": "system", "content": "You are a senior supply chain operations lead. Be concise and actionable."},
{"role": "user", "content": prompt},
],
temperature=0.3,
)
return response.choices[0].message.content
Run it
The script below ties everything together. It runs the analyzer, prints the structured report, and triggers the deep reasoning pass for any critical items.
if __name__ == "__main__":
result = analyze_supply_chain(SHIPMENTS, ALERTS)
print(json.dumps(result, indent=2))
for item in result.get("assessments", []):
if item.get("risk_level") == "critical":
plan = deep_mitigation_plan(item)
print(f"\n--- Deep plan for {item['shipment_id']} ---")
print(plan)
Example output:
{
"overall_risk": "high",
"assessments": [
{
"shipment_id": "SH-28492",
"risk_level": "critical",
"root_cause": "Customs hold on cold chain pharma with approaching weather delays",
"recommended_action": "Expedite customs broker engagement and prepare contingency routing via air freight",
"financial_exposure_usd": 890000
},
{
"shipment_id": "SH-28491",
"risk_level": "medium",
"root_cause": "Battery supplier extended shutdown may delay last-mile fulfillment",
"recommended_action": "Confirm alternative supplier SUP-113 inventory and update ETA",
"financial_exposure_usd": 450000
}
],
"summary": "Two shipments require attention. SH-28492 is critical due to compounded customs and weather risk."
}
--- Deep plan for SH-28492 ---
1. Contact customs broker immediately to identify hold reason and documentation gaps.
2. Prepare air freight booking from alternative EU hub to New York to bypass Atlantic weather.
3. Notify cold chain facility in New York to extend receiving hours.
4. Update customer success team with revised delivery window and backup plan.
Wrap-up
This agent gives you a working foundation. Two concrete next steps: integrate it with your TMS webhook so it evaluates real shipment events as they arrive, and add a scheduled cron job that feeds daily supplier EDI files into the analyzer to catch delays before they hit the port. Oxlo.ai's flat per-request pricing means you can increase alert volume or attach lengthy Bills of Lading without token costs scaling alongside context length.
Top comments (0)