DEV Community

shashank ms
shashank ms

Posted on

LLM Applications in Transportation and Logistics

Freight operations still run on unstructured emails and spreadsheets. In this tutorial we will build a Logistics Request Parser that reads raw shipment descriptions and returns structured execution plans with cost estimates, carrier modes, and delivery timelines. The agent runs entirely on Oxlo.ai, so you pay a flat rate per request and never worry about token costs on long manifests.

What you'll need

Step 1: Configure the Oxlo.ai client

We instantiate the OpenAI-compatible client pointing at Oxlo.ai. Because Oxlo.ai uses flat per-request pricing, we can pass full manifest context without ballooning costs.

from openai import OpenAI
import json
import os

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

Step 2: Define the system prompt

The system prompt constrains the model to act as a logistics planner and emit only valid JSON. This keeps the output predictable and easy to integrate into a TMS.

SYSTEM_PROMPT = """You are a logistics planning engine.
A user will describe a shipment in plain language.
Extract the details and return a single JSON object with these keys:
- origin: string
- destination: string
- cargo_type: string
- weight_kg: number
- special_instructions: string or null
- recommended_mode: one of LTL, FTL, AIR, OCEAN, RAIL
- estimated_cost_usd: number
- transit_days: integer
- risks: array of strings

Rules:
1. If a dimension is missing, infer a reasonable default and note it in risks.
2. Return ONLY the JSON object, no markdown fences."""

Step 3: Build the planner function

This function sends the unstructured request to Oxlo.ai and parses the JSON response. We use Llama 3.3 70B for reliable instruction following.

def plan_shipment(user_message: str) -> dict:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )
    content = response.choices[0].message.content
    return json.loads(content)

Step 4: Harden output with retries

LLMs occasionally return markdown fences or extra text. We add a thin guard that strips fences and retries once on JSON failure. Because Oxlo.ai has no cold starts, the retry is fast.

def parse_json_safe(raw: str) -> dict:
    raw = raw.strip()
    if raw.startswith("

```"):
        raw = raw.split("\n", 1)[1].rsplit("```

", 1)[0].strip()
    return json.loads(raw)

def plan_shipment(user_message: str) -> dict:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )
    content = response.choices[0].message.content
    try:
        return parse_json_safe(content)
    except json.JSONDecodeError:
        retry_msg = f"Fix this so it is valid JSON only:\n\n{content}"
        response = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_message},
                {"role": "assistant", "content": content},
                {"role": "user", "content": retry_msg},
            ],
        )
        return parse_json_safe(response.choices[0].message.content)

Step 5: Batch process multiple requests

Logistics teams receive multiple requests at once. This loop processes a list of raw strings and returns a list of structured plans.

def batch_plan(shipments: list[str]) -> list[dict]:
    results = []
    for idx, req in enumerate(shipments, 1):
        print(f"Processing request {idx}/{len(shipments)}...")
        results.append(plan_shipment(req))
    return results

Run it

We feed the agent three real-world style requests and print the results. You can replace these with emails from your own inbox.

if __name__ == "__main__":
    requests = [
        "Need to move 12 pallets of refrigerated pharmaceuticals from Rotterdam to Chicago. Must stay under 5C. Weight around 3400 kg.",
        "Rush shipment: 200 kg of auto parts from Detroit to Toronto. Customer wants it tomorrow.",
        "Full truckload of furniture, 18,000 kg, Shanghai to Los Angeles. No special handling."
    ]

    plans = batch_plan(requests)
    for p in plans:
        print(json.dumps(p, indent=2))
        print("-" * 40)

Example output:

Processing request 1/3...
Processing request 2/3...
Processing request 3/3...
{
  "origin": "Rotterdam",
  "destination": "Chicago",
  "cargo_type": "refrigerated pharmaceuticals",
  "weight_kg": 3400,
  "special_instructions": "Must stay under 5C",
  "recommended_mode": "AIR",
  "estimated_cost_usd": 18500,
  "transit_days": 2,
  "risks": [
    "Temperature compliance required",
    "Customs clearance for pharmaceuticals"
  ]
}
----------------------------------------
{
  "origin": "Detroit",
  "destination": "Toronto",
  "cargo_type": "auto parts",
  "weight_kg": 200,
  "special_instructions": null,
  "recommended_mode": "FTL",
  "estimated_cost_usd": 850,
  "transit_days": 1,
  "risks": [
    "Next-day delivery may require expedited border clearance"
  ]
}
----------------------------------------
{
  "origin": "Shanghai",
  "destination": "Los Angeles",
  "cargo_type": "furniture",
  "weight_kg": 18000,
  "special_instructions": null,
  "recommended_mode": "OCEAN",
  "estimated_cost_usd": 4200,
  "transit_days": 18,
  "risks": [
    "Long transit time",
    "Port congestion possible"
  ]
}

Wrap-up and next steps

That is the core agent. From here, you can add function calling to pull live rate data from freight APIs, or switch to kimi-k2.6 on Oxlo.ai for multi-leg route reasoning with deeper chain-of-thought.

Top comments (0)