AI Adoption GuideSupportIntake
Multi-channel intent normalization
An LLM converts email, chat, voice, and social messages into a unified ticket schema with extracted entities, using tools like Zendesk Intelligent Triage or Kustomer.
Support processIntakeTriageAssignInvestigateResolveConfirmClose
By Don, DoneThat’s AI coach · updated
One schema for every channel, or five queues that cannot be compared
A support org answering email, web chat, phone, messaging apps, and social receives the same complaint in five shapes. Email arrives with a subject line and three paragraphs. Chat arrives as twelve short turns. Voice arrives as a transcript with hesitations and a phone number. A social post arrives with sixty characters and a photo. Intent normalization converts all of them into one ticket schema.
The output is a filled record. Channel, customer identity, intent, product referenced, extracted entities such as order numbers and dates, stated urgency, and the original message preserved intact. What comes out looks the same regardless of where it came in.
The value shows up twice. Agents stop learning five interfaces and five conventions. Reporting also becomes possible, because a contact reason counted in email and one counted on social are finally the same field.
Zendesk Intelligent Triage and Kustomer operate in this space, as do the ingestion layers of most modern helpdesks. None of them decides what the schema should contain. Normalization without a defined target schema is reformatting with extra steps.
Write the schema and the entity list before connecting a single channel
The schema is the contract. Every channel connector writes into it, and every downstream step reads from it. Define it once, in one place, with a named owner.
Three parts need definition. The envelope: channel, received time, customer identifier, language, thread ID, attachments. The intent: a controlled vocabulary of contact reasons, not free text. The entities: specific values worth extracting, each with a format rule.
Keep the entity list short and typed. Order number with a known pattern. Product model drawn from a catalog list. Date, resolved to an absolute date rather than "last Tuesday." Serial number with a checksum if one exists. Anything without a format rule comes back as whatever the model felt like writing.
Intent labels need the same discipline. A vocabulary a hundred labels deep collapses agreement, and the field stops meaning anything. Keep intake intents coarse. Finer distinctions belong downstream in granular topic auto-tagging, which runs on a settled ticket rather than a first message.
Define what happens when a channel supplies less than the schema wants. A public post with no account link cannot fill customer identity. Leave it empty and record why. Guessing identity from a display name is how one customer's history lands on another customer's ticket.
Normalize the envelope and the content as two separate passes
Handle metadata first, deterministically. Channel, timestamp, thread ID, and language detection are lookups and rules, not judgment calls. Settle them before any model runs, because content extraction that does not know the language will do worse.
Then extract content. Ask for intent, entities, and a short factual summary in one pass. Require each entity to carry the span it came from. An order number with no supporting text in the original is a generated number, and generated numbers get looked up.
Preserve the original every time. The normalized record is a view, not a replacement. Voice especially needs the audio kept, because transcription errors on product names and account numbers are routine.
Channel shape changes what is available. Chat has turns, so the connector must decide which turn carries the intent, usually the first substantive one rather than the greeting. Voice has no subject line and needs one derived. Social posts hit length limits, so the message is often incomplete and the rest arrives in a reply. Encode those differences in the connector, not in the prompt.
Language sits on the boundary between this job and the next. Detect and record it here. Deciding who answers is language and timezone routing, which depends on the field this step produced.
Normalize three espresso machine contacts that arrive on three channels
Consider a hypothetical appliance brand selling home espresso machines direct to consumers. Over one morning, three people report the same fault. The machine stops mid-shot and shows a temperature warning.
The first sends an email. The subject line reads "Machine 3 weeks old, already broken." The body includes the order number, the model name, and the purchase date. Normalization fills intent as hardware fault, product as the model, order number from the body, and purchase date resolved to a calendar date.
The second calls and leaves a voicemail. The transcript states the fault clearly but gives no order number, and it mishears the model name as a similar-sounding one. The connector fills intent and the caller's number, leaves order number empty, and marks product as low confidence with the transcript span attached. It does not silently pick the closest catalog match.
The third sends a direct message on social: "third time this week, temp warning again, is this a known issue." Forty characters of useful content, no identifiers, no account link. Intent fills as hardware fault. Everything else stays blank except stated urgency, which the phrase supports, and the original text.
Three channels, three levels of completeness, one comparable record. All three route on intent. Two need an identity question before anything else. When the week's contact reasons are counted, all three land in the same bucket, which is what makes analysis of contact drivers across closed tickets trustworthy.
Channel noise, lost nuance, and entities that were never said
Normalization fails quietly, which is exactly why it needs auditing.
Flattening destroys signal. A customer who wrote four furious paragraphs and one who wrote a calm sentence can produce identical records. Keep the original prominent, and carry length and tone as their own fields rather than letting the schema erase them.
Entities appear that nobody said. Models fill order numbers and dates because the field exists and looks unfinished empty. Require a source span for every entity and drop any that cannot produce one. An empty field is cheap. A wrong order number sends an agent to the wrong record.
Transcription errors travel. Voice is the weakest channel for identifiers. Numbers, email addresses, and model names all degrade. Mark voice-derived entities unverified by default and confirm them with the customer.
Channel context gets stripped. A public post is a different situation from a private email, even with identical text, because other customers are reading. Keep visibility as a field. Never let a normalized ticket hide that the conversation is happening in public.
One more trap: over-fitting the schema to the loudest channel. Schemas designed around email tend to require a subject and a long body, which chat and social cannot supply. Design for the thinnest channel and let richer ones fill more.
The agent reads the original message, not the normalized summary
Normalized fields get an agent oriented. They do not replace reading. The customer's own words belong at the top of the ticket, with extracted fields beside them, and the audio or thread one click away.
Low-confidence fields must look low confidence. A model name marked uncertain cannot render like one confirmed from an order lookup. Otherwise the agent treats both as fact. Show the confidence and show the span.
Intent at intake is provisional. It is a first guess from a first message, often written before the customer knew what was wrong. The binding classification happens at triage, through intent and category classification, where more context exists. Keep the two values in separate fields so drift between them stays visible.
Audit by sampling. Each week, pull a handful of normalized tickets per channel and compare each record against its original. Count the fields that were wrong, not the fields that were empty. Empty is honest. Wrong is the failure this system introduces, and it is the reason the original message never gets thrown away.
Is this worth automating for you?
Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other.
DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.
Measure the baseline first