Smart Ticket Triage with Structured Output - Ship AI with Laravel EP2

Laravel News| 00:10:49|Apr 1, 2026
Chapters10
The goal is to have AI handle ticket categorization, priority, and routing in under a second, producing structured data rather than free-form notes. This builds on the previous episode where the agent responded to customers.

Structured, reliable ticket classification in Laravel using AI with a strict schema and low temperature for consistency.

Summary

Harris from Laravel News demonstrates how to replace free-form AI output with a structured, usable data payload for ticket triage. The episode emphasizes that plain AI replies are hard to route into dashboards or prioritize, so the team builds a dedicated ticket classifier that returns a fixed schema: category, priority, sentiment, and a concise summary. They enable this with the AI SDK’s structured output feature, scaffolding a new agent named ticket classifier and configuring a schema to enforce exact fields. Temperature is kept at 0.3 to ensure predictable results, and max tokens are capped at 300 to maintain consistency. The schema enumerates allowed values (e.g., categories like billing, shipping, product; priorities like low, medium, high, urgent; sentiments like happy, neutral, frustrated, angry) so the AI stays within bounds. Harris walks through wiring the classifier into a Laravel controller, proving a real workflow where incoming messages are classified and stored as structured tickets. The episode also highlights practical testing approaches, including a quick route, manual prompts, and Tinkerwell for live validation, all serving the goal of clean, actionable data rather than free text. Looking ahead, the plan is to extend this with real order data and customer history in the next episode, moving from talking to doing with customized agent tools. If you’re building a scalable support pipeline in Laravel, this episode shows how structured AI outputs unlock automatic routing, prioritization, and agent handoffs.

Key Takeaways

  • Enforce a strict output schema (category, priority, sentiment, summary) so AI results are immediately usable by downstream systems.
  • Use a structured flag in Laravel AI agents to gain an interface and schema that drive consistent responses.
  • Set max tokens to 300 and temperature to 0.3 for predictable, non-creative classifications.
  • Define explicit enums for category, priority, and sentiment to constrain AI output to known, actionable values.
  • Wire the classifier into a Laravel controller to automatically create tickets with the AI-derived fields.
  • Test the flow with routes, prompts, and Tinkerwell to verify the exact shape of the returned data.
  • Plan to enrich the classifier with real order data and customer history in future episodes for deeper automation.

Who Is This For?

Essential viewing for Laravel developers building AI-powered support workflows who need predictable data structures and automated routing. Great for teams wanting to move from free-form AI replies to structured, actionable ticket data.

Notable Quotes

"it's free text, right? It's free text, a paragraph."
The problem with using free-form AI output for ticket routing.
"The AI SDK has structure output that solves this exactly."
Introduction of structured output as the solution.
"This is an interface and a schema method."
Explanation of how the structured output is implemented in code.
"Everything works as expected. It has to do with returns. High priority frustrated customer report at the widget broke after one day."
Live validation showing a realistic classification result.
"Low temperature for consistency. Enums for valid values. A schema that enforces the exact safe we need."
Key configuration tips for reliable AI classification.

Questions This Video Answers

  • how can I implement structured AI outputs in Laravel for ticketing
  • what is a Laravel AI agent and how do you use the structured flag
  • how do enums and schemas improve AI reliability in support workflows
  • how can I test an AI ticket classifier in Laravel with Tinkerwell
  • what's the next step to integrate real order data into an AI-powered ticket system
LaravelPHPLaravel NewsAIStructured OutputTicket ClassifierEnumsSchemaTinkerwellPrompt Engineering
Full Transcript
Right now, when a support dick comes in, someone rig it, picks a category, decides the priority, and routes it. What if AI did all of that in under a second? I'm Harris from Lava News, and today we're building a ticket classifier that returns clean structured data every single time. So, in the last episode, we built a support agent that respond to the customers. Let's look at what we got back. So let's go back to our browser and you'll see here that we got a JSON reply very generic some prompt tokens completion tokens provider and the model as well. So the main issue with this reply is that it's free form text, right? It's free text, a paragraph. If you want to route tickets, set priorities or build a dashboard, we need the structured data we can actually work with, not paragraphs in this case. So what we want is something like this, like down here. So we have the category which is billing priority which is set to high sentiment it's frustrated and the summary that the customer reports being charged twice and is upset that they have not received a response and this is actually the message that we got from the customer. I was charged twice and nobody is responding. So the AI SDK has structure output that solves this exactly. Let's get right to it. Let's scaffold a new agent. Now this time we use a structured flag. So PHP artisan make agent. We're going to name this ticket classifier and we're going to use structured flag in this case. So we got a new ticket classifier created successfully. So let's go ahead and open this up. So we have the ticket classifier as you can see it here. The structured flag adds the has structured output up here and this is very crucial. This is an interface and a schema method. So, let's begin with our attributes again like the last time. Let's go up here. Let's set max tokens. Let's import that. And let's set this to 300. And what we also need is the temperature like we had in the previous episode. Let's set this one to 0.3 in this case, which is much lower than our support agent. For classification, we want predictable results, not creative ones. So that's why we set it only to 0.3 in this case. Now let's go down to instructions. I'm going to copy and paste some basic instructions I already have and we're going to discuss them line by line. So let me paste it here. Going to save it and let's discuss that. We have a prompt that says you're a support ticket classifier for an online store. Analyze the customer message and classify it accurately. categories, billing, sipping, product, account, returns, and general. We have priority levels, low, medium, high, and urgent. And we also have the sentiment options, happy, neutral, frustrated, and angry. So that's what we give to our prompt. In this case, we list every allowed value. And this keeps the AI inside our expected option. Now, the key part, as we mentioned, is down here, the schema. So the schema tells the AI the exact shape of the response we want. So in our case as we mentioned earlier we have the category and what the category includes will be based on this enum billing shipping product account returns or general like we mentioned earlier like we gave to our prompt. Then we have the description the primary category of the support ticket and then we set that we really really need this category so we set it as required. We do similar things for priority, sentiment, and summary here at the end as well. So the SDK enforces this. You always get back exactly these four fields. Let's go ahead and test this with a few different messages. Now, first let's try an angry billing issue. So I'm going to go back to my web route here. Let's add a new route here. So we're going to name this classify test and then a closure here. And down here, what do we need in this case? We would like to have the result, which is going to be the new ticket classifier. And then we're going to have the prompt, the prompt that we get from the user. So, let's say that I was charged twice for my order and nobody is responding to my emails. This is unacceptable. Nice. So let's close this here. And let's return three things. We're going to return category. This will be based on the result of course, the priority again based on the results. Then we have the sentiment. And last but not least, we are going to have the summary. Save that. We access the response like an array. It's that simple. Each key matches our schema, the one we had inside our agent. Now let's go ahead and run it. classify test. Let's go back to our browser and let's run classify test. Oops, we got an error. Let's go back. Let's fix that. Let's close this. Go back again. Refresh. And now we should get an actual Yeah, we got it back. We got exactly the schema we needed. We got the category which is billing. The priority is set to high. the sentiment. I identify that it is angry, which makes sense because a customer reports being charged twice for an order and it's upset about the lack of female response. Let's go back and say that I'm going to try a different message now. And the message will be, hey, just wondering when my packets will arrive. Order 1055. No ras, just curious. Okay, let's refresh again. And now our AI identify that this has to do with shipping. Priority is low because it just asked for it to see how their order is going. It is neutral which is makes sense and customer is asking for the delivery status and expected arrival time of order 1055. It reads context and tone and not just keywords in this case. Now let's put this into a real workflow. Ticket comes in, we classify and then we store the results. Let's go back to our terminal and create a new controller. PHP make controller. We're going to name this ticket controller. Let's go back to editor and open this up. We're going to have a public function store. So let's do public function store. And then this will accept a request. We're going to have a validation of course. So we validate that the message will be obviously required. And we also want this to be a string as well. So now we have our classification. So classification equals new ticket classifier. Let's import that at the top. Of course, don't forget that. Then we have our prompt. And we get the message from our request. And now we're going to have the ticket which is going to be the user tickets. We're going to create those tickets and assign them to the user. Let's come down here. We need the message like we mentioned at the beginning. So request message. Then we do need the category which is going to be from the classification array of course. So classification category. Next one is priority sentiments. And last but not least summary. Let's don't forget to have a response back. So response change which one to be JSON the ticket. And this is a 2011 because we created perfect. So every ticket gets classified automatically in this case without the need of any human to read it to decide where it goes. So category picks the team priority picks the speed sentiment flags customers who need extra care. We haven't created the ticket model or migration yet. This controller is a preview of where we're headed. We'll wire up the database side in later episode. For now the important thing is the classifier itself. This is so cool. Let's go back to our routes file. Scroll down and we're going to add a new route which is going to be a post request of course because we want to create a new ticket. Going to have our ticket controller in this case. Let's import that again. And let's call the store method. And let's also add a middleware because we don't want from someone from the outside to call this endpoint without being authenticated first. Think about what you build on top of this. You could have high priority billing tickets go straight to finance. Angry customers get flagged for a senior agent. You could trigger different notification channels based on priority. Slack for urgent, email for low priority. You can do all sorts of things. All of that works because we have clean structured data instead of free text. Let's test this flow before we wrap up this episode. We're going to use Tinkerwell. I suggest you use something like that as well. It's a great tool. So go ahead and pull our user. So up until user first. See if we get the user. Okay, good. Now the classifier going to be new app AI agent ticket classifier and the results be classifier prompts my widgets broke after one day want my money back let's try to collect this only gets the necessary things we need and the necessary things N E R category. Let's add this in an array. Category priority sentiment summary. Yes, it's running. And we got exactly what we want. It has to do with returns. High priority frustrated customer report at the widget broke after one day. And it's requesting a refund. Everything works as expected. That's an intelligent ticket classifier that returns structured reliable data every time. Low temperature for consistency. Enums for valid values. A schema that enforces the exact safe we need. In the next episode, we're giving the support agent custom tools so it can look up real order data and customer history from the database. Goes from talking to doing. Subscribe if you want to catch that one. See you in the next

Get daily recaps from
Laravel News

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.