Structured Output for the TMS
The afternoon a medium-size carrier's operations director asked her lead dispatcher why the new AI dispatch tool was not saving anyone time, the answer she got was honest and instructive: "Because after the AI gives me a suggestion, I have to retype the whole thing into McLeod." The dispatcher was not complaining about the quality of the AI's suggestions. She was describing a workflow in which the AI produced a paragraph of prose, and the TMS (transportation management system, the platform that manages load tendering, driver assignment, billing, and the documentation trail from acceptance to proof of delivery) required discrete fields: a Load ID, an equipment code, a driver ID, an origin and destination with ZIP codes, a rate per mile and an all-in rate, a planned departure and arrival, and a status flag. Every time the AI answered in prose and the TMS accepted only structured data, a dispatcher had to translate between the two, and translation is where errors happen. This lesson is about eliminating that translation step: building the prompts, the output formats, and the field schemas that let an AI tool produce records the TMS can actually ingest, so that the value of the tool shows up in the TMS log rather than in a paragraph a dispatcher has to read, parse, and retype.
Why Prose Is the Wrong Output Format for Dispatch Work
A large language model's default output is natural language prose. It is what the model was trained to produce and what it does well in general-purpose contexts. A dispatcher asking "what's a good load for Johnson?" gets back a paragraph: "Driver Johnson, who has 7 hours of drive time remaining and is currently in Indianapolis, would be a strong candidate for the Columbus-to-Nashville load. The load pays approximately $1,820 all-in and fits within his HOS availability. I'd recommend confirming the pickup appointment before committing." That paragraph contains genuinely useful information. But the TMS cannot ingest a paragraph. The TMS needs: Driver ID = "Johnson, T" (employee ID 4422), Load ID = "CB-2024-0847," Equipment = "DV53," Origin = "Columbus OH 43215," Destination = "Nashville TN 37201," Rate = "$1,820.00," Planned pickup = "06/16/2026 14:00," Status = "PROPOSED."
When a tool produces prose and the system requires fields, a human translator sits between the tool and the system. That translator is the dispatcher, who is already juggling 10 drivers, 8 pending loads, 3 broker calls, and a driver on the shoulder of I-71 waiting for a tow. Adding a translation step to her workflow does not make her faster. It makes the AI tool a burden disguised as a benefit, and it explains why adoption stalls on dispatch floors where the integration was never completed past the chat window.
Structured output solves this by changing the question from "how do I get a useful answer from the AI?" to "how do I get a record the TMS can accept?" The two questions have different answers. The first is a question about AI quality; the second is a question about data engineering and prompt design. This lesson addresses the second question, which is the one that determines whether the AI tool changes the dispatcher's daily load or just adds a new window to open.
The core principle: the format of the AI's output should match the data model of the system that will receive it. When the prompt specifies the field names, the field types, the allowed values, and the JSON (JavaScript Object Notation, a lightweight data interchange format that most TMS platforms can parse programmatically) structure the TMS expects, the AI becomes a structured record generator rather than a prose generator. The dispatcher's job changes from "read and retype" to "review and confirm," which is faster, less error-prone, and easier to audit.
The goal of structured output is not to make the AI output look like data. It is to make the AI output be data: a record the TMS can accept without a human translator in the middle.
Mapping TMS Fields to AI Output: A Freight Data Schema
Before writing a structured-output prompt, the dispatcher or fleet manager needs to know what fields the TMS requires. Most TMS platforms (McLeod Software, Trimble Transportation, TMW Suite, Aljex, Axele, Rose Rocket, and others) expose their required fields through their load entry forms, their API documentation, or their EDI (electronic data interchange, the standard message formats used for machine-to-machine exchange of transportation documents including load tenders, shipment status updates, and freight bills) specifications. The structured-output prompt is built by taking those required fields and encoding them as the expected output schema for the AI tool.
A baseline field schema for a dry-van truckload dispatch record looks like this:
{
"load_id": "string (carrier-assigned, e.g. CB-2024-0847)",
"driver_id": "string (employee ID, e.g. 4422)",
"driver_name": "string (Last, First)",
"equipment_type": "string (code: DV53=53ft dry van, RF53=53ft reefer, FB48=48ft flatbed)",
"equipment_unit": "string (unit number, e.g. T-211)",
"origin": {
"city": "string",
"state": "string (2-letter code)",
"zip": "string (5-digit)",
"facility": "string (shipper name or DC name)",
"appointment": "string (ISO 8601 datetime, e.g. 2026-06-16T14:00:00-05:00)"
},
"destination": {
"city": "string",
"state": "string (2-letter code)",
"zip": "string (5-digit)",
"facility": "string (consignee name)",
"appointment": "string (ISO 8601 datetime)"
},
"rate": {
"all_in_usd": "number (e.g. 1820.00)",
"per_mile_usd": "number (e.g. 2.75)",
"rate_type": "string (SPOT | CONTRACT | BROKER)",
"rate_source": "string (cite: DAT, Truckstop, broker confirmation ID, or contract name)"
},
"miles": {
"loaded": "number (revenue miles)",
"deadhead": "number (empty miles to pickup)"
},
"hos_check": {
"driver_hours_available": "number (hours remaining per ELD)",
"estimated_drive_time": "number (hours, loaded miles at governed speed)",
"feasible": "boolean (true if drive time <= hours available with margin for loading)",
"eld_data_source": "string (cite: ELD timestamp or dispatcher-provided data)"
},
"commodity": "string (e.g. packaged food, automotive parts, general freight)",
"weight_lbs": "number",
"status": "string (PROPOSED | DISPATCHER_APPROVED | DISPATCHED | IN_TRANSIT | DELIVERED)",
"flags": [
"string (each unresolved compliance or data flag)"
],
"dispatcher_commit": {
"committed": "boolean (false until dispatcher explicitly confirms)",
"committed_by": "string (dispatcher name/ID, null until committed)",
"commit_timestamp": "string (ISO 8601, null until committed)"
}
}
This schema is a starting point, not a universal standard. Every TMS has its own field names and allowed value sets. The dispatcher or fleet manager building a structured-output workflow must map the schema above against their specific TMS's field requirements and adjust field names, types, and allowed values accordingly. The goal is a one-to-one correspondence between what the AI produces and what the TMS accepts, so that the import or copy-paste step requires no field-level editing.
The Prompt That Produces Structured Output
With the schema defined, the structured-output prompt tells the AI tool to produce its dispatch suggestions as JSON records matching that schema. Here is a working example of a system prompt that produces structured output:
You are a dispatch assistant for [Carrier Name]. For every load suggestion or
driver match you produce, output a single JSON record using the following schema
exactly. Do not include prose, explanations, or commentary outside the JSON
record. If a field cannot be populated from information provided in the request,
set its value to null and add a flag string in the "flags" array describing
exactly what data is needed to populate it.
Required output schema:
{
"load_id": null or string,
"driver_id": null or string,
"driver_name": null or string,
"equipment_type": null or string (DV53, RF53, FB48),
"equipment_unit": null or string,
"origin": {
"city": null or string,
"state": null or string,
"zip": null or string,
"facility": null or string,
"appointment": null or ISO8601 datetime string
},
"destination": {
"city": null or string,
"state": null or string,
"zip": null or string,
"facility": null or string,
"appointment": null or ISO8601 datetime string
},
"rate": {
"all_in_usd": null or number,
"per_mile_usd": null or number,
"rate_type": null or "SPOT" or "CONTRACT" or "BROKER",
"rate_source": null or string (cite source)
},
"miles": {
"loaded": null or number,
"deadhead": null or number
},
"hos_check": {
"driver_hours_available": null or number,
"estimated_drive_time": null or number,
"feasible": null or boolean,
"eld_data_source": null or string
},
"commodity": null or string,
"weight_lbs": null or number,
"status": "PROPOSED",
"flags": [],
"dispatcher_commit": {
"committed": false,
"committed_by": null,
"commit_timestamp": null
}
}
Rules:
1. Never set "feasible" to true unless "driver_hours_available" and
"estimated_drive_time" are both non-null and based on cited ELD data.
2. Never set "all_in_usd" or "per_mile_usd" to a number unless "rate_source"
is non-null and cites a real data source provided in this conversation.
3. Always set "status" to "PROPOSED" and "committed" to false.
Never set "status" to "DISPATCHED" or "committed" to true.
4. Add a flag string for every null field that requires dispatcher action
to resolve before committing the load.
This prompt produces machine-readable JSON, not a paragraph. Every field is either populated from data the dispatcher provided or set to null with a flag that explains what is missing. The dispatcher reviews the record, clears the flags, and confirms the commit -- then the record is ready for import into the TMS without retyping.
Turning TMS Prose Into Ingestible Records: The Extraction Workflow
Not all AI-generated content in a freight workflow starts from a prompt asking for a dispatch suggestion. A significant amount of useful freight data arrives as prose: broker emails with load details, shipper tender messages, driver check-in calls transcribed by voice-to-text, or rate confirmation documents that come as PDF text. All of these contain data that the TMS needs, buried in natural language that the TMS cannot parse directly. Structured-output prompts can also be used to extract that data into ingestible records.
The extraction workflow works like this: the dispatcher (or an automated trigger in the workflow) pastes the prose document into the AI tool with a prompt that says "extract the following fields from this document and produce a JSON record matching this schema." The AI tool reads the document, identifies the relevant field values, and outputs a structured record. The dispatcher reviews the record, verifies the extracted values against the source document, and imports the verified record into the TMS.
A working example of an extraction prompt for a broker tender email:
Extract the following fields from the broker tender email below and produce
a single JSON record. For any field not explicitly stated in the email,
set the value to null and add a flag describing what is missing.
Do not infer values not stated in the document. Do not calculate rates
from other fields if the rate is not explicitly stated.
Extract these fields:
- load_id (broker reference number, if stated)
- origin city, state, zip
- destination city, state, zip
- pickup appointment (date and time)
- delivery appointment (date and time)
- all_in_rate_usd (stated rate, if any; do not calculate)
- commodity
- weight_lbs
- equipment_type (as stated in the email)
- special_requirements (any temperature, hazmat, or delivery constraints)
- flags (one string per unstated or unclear field)
[BROKER TENDER EMAIL TEXT]
{paste email text here}
The output of this prompt is a structured record the dispatcher can verify in seconds against the source email and then import into the TMS. The extraction is not infallible: the AI can misread a field, conflate two pieces of data, or miss a detail buried in a footnote. The verification step is not optional. But "review a JSON record against a source email" is faster and more reliable than "read the email and manually enter every field into the TMS," which is the alternative the dispatcher currently performs on every tender.
The Verification Step Is Not Optional
A structured output record that has not been verified against the source data is not ready for the TMS. It is a draft. The distinction matters because the TMS record created from an unverified extraction becomes the operational record for the load: the load ID that the driver's ELD links to, the rate that the invoice is generated from, the delivery appointment that the shipper's dock books against. An error in the extraction that goes into the TMS without verification does not stay in the AI tool. It propagates through every downstream system and document that references that load.
The verification step for a structured output record consists of four checks: field presence (are there null fields that the dispatcher needs to resolve before the record is complete?), field accuracy (do the populated values match what appears in the source document?), constraint compliance (does the HOS feasibility field say "true" only if it is backed by real ELD data, and does the rate field cite a real source?), and status check (is the record set to PROPOSED and committed to false, confirming that a human commit step is still required?). These four checks take about 90 seconds on a typical record and are the difference between a TMS that trusts its AI-generated records and one that is quietly accumulating errors in the data behind every load.
For fleets tracking POD (proof of delivery, the signed or electronically confirmed record that freight was received at the destination) rates and on-time delivery performance, the accuracy of the appointment fields in structured output records matters directly. A TMS that shows a planned delivery of Thursday 14:00 but a shipper confirmation of Friday 09:00, because the extraction swapped the pickup and delivery appointments, will produce a false on-time flag that misleads the fleet manager's performance reporting. Catching that error at the 90-second verification step prevents a data-quality problem that could persist across weeks of reporting.
Structured Output for Specific Freight Document Types
Different freight document types require different extraction schemas. Here are the key document types and their core field requirements for structured output in a TMS context.
Rate confirmation (from broker or shipper). A rate confirmation is the document that specifies the agreed terms of a load: the load number, the equipment, the origin and destination, the rate, and any accessorial charges. The TMS needs to receive these fields to create an accurate load record and generate the correct invoice. The structured output schema for a rate confirmation should include: broker or shipper name and contact, load reference number, equipment type, origin (facility, city, state, ZIP, appointment), destination (same fields), all-in rate, accessorial breakdown (fuel surcharge, detention, stop-off pay if applicable), commodity, weight, and any special instructions. The rate_source field should cite the confirmation number and date.
Driver check-in report (from call or voice-to-text). Driver check-ins update the TMS with current position, ELD status, and any issues on the load. A structured extraction of a check-in produces a status update record with: driver ID, check-in timestamp, current location (city, state, highway or facility), miles to destination, ELD hours remaining, fuel level (if reported), load ID, and any issues flagged (breakdown, weather delay, detention at shipper, appointment change). The structured record feeds the TMS's shipment tracking module and the fleet manager's visibility dashboard without the dispatcher manually updating each field from their handwritten call notes.
DVIR (driver vehicle inspection report, the federally required pre-trip and post-trip inspection record under 49 CFR Part 396). A DVIR structured output record supports the maintenance workflow: unit number, driver ID, inspection date and time, inspection type (pre-trip or post-trip), each defect noted (component, description, severity), driver certification of defects, and repair status. When a DVIR shows defects, the structured record should include a flag that blocks dispatch of the unit until the defect is marked repaired and re-inspected. The TMS record created from a DVIR structured extraction connects the inspection event to the maintenance log, the dispatch system, and the CSA compliance file in one step instead of three separate manual entries.
Delivery receipt or POD (proof of delivery). A POD structured extraction produces the record that closes the load in the TMS, triggers invoicing, and satisfies the shipper's delivery confirmation requirement. Fields include: load ID, driver ID, consignee name and facility, actual delivery date and time, receiver signature (name and company), quantity and condition of freight received, any exceptions noted (short, damaged, refused), and the POD document reference number. The structured record closes the load, triggers the invoice generation step, and feeds the on-time delivery tracking that the fleet manager uses to monitor service performance.
Common Structured Output Failures and How to Prevent Them
Structured output from an AI tool fails in predictable ways. Understanding the failure modes before deployment prevents them from becoming TMS data problems.
Field hallucination: The tool populates a null field with a plausible-but-invented value rather than flagging it as missing. The most common version of this is a hallucinated rate: the tool sees that the rate field is required and fills it with an estimate drawn from its training data rather than from the rate confirmation the dispatcher provided. The prevention: the system prompt must explicitly instruct the tool to set null and add a flag when a field cannot be populated from provided data, and must explicitly prohibit estimating fields not stated in the source document. The verification step should specifically check every non-null rate field against the source document before the record goes into the TMS.
Field conflation: The tool populates the wrong field with data from the right neighborhood. A common example is origin and destination confusion in broker emails that describe the route in reverse order from the field layout. The prevention: the extraction prompt should specify not just the field names but the semantic definition of each field ("origin = point where driver picks up freight, NOT the broker's office or the shipper's headquarters"). The verification step should confirm that the origin ZIP is in the pickup location, not the delivery location or the broker's address.
Type mismatch: The tool produces a string where the TMS expects a number, or a date in a format the TMS does not parse. The most common version is date format: the tool produces "June 16, 2026 at 2 PM" where the TMS expects "2026-06-16T14:00:00-05:00." The prevention: the output schema in the system prompt must specify the exact type and format for every field, and the verification step should include a format check for date-time and numeric fields before import.
Status escalation: The tool sets the load status to "DISPATCHED" or sets "committed" to true without a dispatcher confirmation. This is a boundary violation: the tool has made an operational commitment that only the dispatcher is authorized to make. The prevention: the system prompt must explicitly prohibit setting status to anything other than "PROPOSED" and committed to anything other than false, and the verification step should check both fields before import. A TMS that accepts a DISPATCHED record from an AI tool without a dispatcher commit has no record of who authorized the load, which is a governance gap and a potential compliance problem if the load is later questioned.
Schema drift: The TMS updates its field names or accepted values, and the structured output prompt no longer matches the TMS's current schema. The prevention: assign ownership of the structured output schema to a specific person (typically the operations manager or TMS administrator), tie that ownership to the TMS's change management process, and test the structured output format against the TMS's current load entry form after any TMS update. A prompt that produces valid JSON but uses a field name the TMS no longer accepts is just as broken as a prompt that produces invalid JSON, but it is harder to catch without testing.
Key Takeaways
- Prose is the wrong output format for freight dispatch AI: the TMS accepts discrete fields, and a dispatcher who has to translate between AI prose and TMS fields is not faster, just differently burdened. Structured output eliminates the translation step.
- The goal of structured output is a one-to-one correspondence between what the AI produces and what the TMS accepts, so that the dispatcher's job changes from "read and retype" to "review and confirm."
- A baseline freight dispatch JSON schema must include: load ID, driver ID, equipment type and unit, origin and destination with appointments, rate with source citation, loaded and deadhead miles, HOS feasibility with ELD citation, commodity and weight, a flags array for unresolved data gaps, and a dispatcher commit block that starts as false and null.
- The cite-or-refuse rule applies to structured output: any numeric field (rate, miles, HOS hours) must be populated from data the dispatcher provided in the conversation or set to null with a flag. Hallucinated rates and estimated HOS that end up in TMS records propagate through invoicing, settlement, and compliance documentation.
- Structured output can also be used for extraction workflows: broker tenders, driver check-in calls, DVIRs, and POD documents all contain TMS data buried in prose that an extraction prompt can surface as ingestible records.
- The verification step is not optional: before any structured output record enters the TMS, the dispatcher must check field presence, field accuracy against the source document, constraint compliance (HOS feasibility based on real ELD data, rate based on cited source), and status (PROPOSED, committed=false).
- Common structured output failures are field hallucination, field conflation, type mismatch, status escalation, and schema drift. Each has a specific prevention: explicit null-and-flag rules, semantic field definitions, format specifications, hard status constraints, and schema ownership tied to TMS change management.
- Structured output from AI tools connects directly to the fleet's deadhead and revenue-per-truck metrics: when every load proposal contains a deadhead miles field populated from real data, the dispatcher's review step produces a consistent, analyzable record of the empty-mile cost that the program targets throughout L2 and L3.
Skill.re