Azure AI/ML

Inside the Azure AI Language Service: PII Redaction, Sentiment, NER, and Conversational Language Understanding

A support ticket lands in your queue: “can we automatically strip credit-card numbers out of chat transcripts, flag the angry ones, and route the ‘cancel my account’ messages to retention?” Three different asks — redaction, sentiment, intent — and the instinct is three different machine-learning projects. It isn’t. All three are single REST calls to one Azure resource: the Azure AI Language service (formerly “Text Analytics” plus “LUIS”, now consolidated). It is the natural-language brain of Azure AI Services — a managed API that reads unstructured text and hands back structure: which spans are personal data, whether the tone is positive or negative, what real-world things (people, places, orgs, dates, quantities) are named, and — with a model you train — what the user is trying to do and the parameters they gave.

This article is the mental model, not a click-through of the portal. The Language service bundles roughly a dozen capabilities behind one endpoint and one key, and the single most useful thing you can learn is which capability answers which question — because once you can name the feature, the API call, the limits and the price are trivial. We split the dozen into two families that behave very differently: prebuilt features (PII, sentiment, key-phrase, language detection, NER, entity linking, summarization) that work out of the box with zero training, and custom features (Custom NER, Custom Text Classification, and Conversational Language Understanding / CLU) where you bring labelled data and train a model. Knowing that fork tells you the cost, the latency, the data-residency story and the maintenance burden before you write a line of code.

By the end you will reach for the Language service the way a senior engineer does: you will hear “redact”, “sentiment”, “extract the dates”, “what does the customer want”, “summarize this thread” and immediately map each to a feature, an API action, a sync-or-async decision, and a rough cost — and you will know the handful of gotchas (the 5,120-character document limit, opinion mining being off by default, PII categories you must allow-list, CLU versus the newer orchestration workflow) that separate a demo from production. It is squarely on the AI-900 and AI-102 exam paths, and it is the cheapest way to add language intelligence to an app without owning a model.

What problem this solves

Unstructured text is where business meaning hides and where code is blind. A chat transcript, a product review, an email, a contract clause, a voice-to-text snippet — to a database it is one opaque string. The questions you actually want answered (“is there a passport number in here?”, “is this customer about to churn?”, “what city is this address in?”, “is the user asking to book or to cancel?”) all require reading, and reading is exactly what traditional code cannot do. The historical answer was to hire data scientists, collect a corpus, train an NLP model, host it, and re-train it forever. For most teams that is months of work and a permanent operational tax for a feature that is not their core product.

The Language service collapses that. For the common questions, Microsoft has already trained the models and exposes them as prebuilt actions — you send text, you get structured JSON back, and you pay per character processed. There is no model to train, no GPU to rent, no corpus to label. For the questions that are specific to your domain — your product’s intents, your contract’s custom entity types — you still train, but on Microsoft’s platform with a labelling UI (Language Studio), managed training, and a one-line deploy, so you operate an application, not an ML stack.

Who hits this: any team with text and a question about it. Support and contact-centre teams (sentiment, intent routing, summarization), compliance and privacy teams (PII/PHI redaction before storage or logging), search and knowledge teams (entity extraction and linking to enrich an index), product teams building assistants and bots (CLU for intent + entities), and data teams cleaning or classifying document streams. What breaks without it is either a stalled feature (“we can’t ship redaction, we’d need an ML team”) or a fragile home-grown regex that misses the passport number formatted differently and leaks it into your logs.

To frame the whole service before the deep dive, here is every capability family, the one question it answers, and whether you train it:

Capability The question it answers Family You train it? Typical caller
Language detection “What language is this text?” Prebuilt No Any pipeline, as a pre-step
Sentiment analysis “Is the tone positive, negative or neutral?” Prebuilt No Reviews, support, social
Opinion mining What is the sentiment about (which aspect)?” Prebuilt (flag) No Product feedback
Key-phrase extraction “What are the main talking points?” Prebuilt No Tagging, search, digests
Named-entity recognition (NER) “What people/places/orgs/dates/quantities are named?” Prebuilt No Search enrichment, extraction
Entity linking “Which real-world entity (Wikipedia) is this?” Prebuilt No Disambiguation, knowledge
PII detection “Which spans are personal data, and redact them” Prebuilt No Compliance, logging, storage
Text summarization “Give me the gist (extractive or abstractive)” Prebuilt (LLM-backed) No Long threads, documents
Custom NER “Extract my entity types from my documents” Custom Yes Domain document extraction
Custom text classification “Classify docs into my categories” Custom Yes Routing, triage, taxonomy
Conversational Language Understanding (CLU) “What is the user’s intent and the entities in it?” Custom Yes Bots, voice assistants, IVR
Question answering “Answer from my knowledge base / FAQ” Custom Yes (curate) FAQ bots, support deflection

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should be comfortable calling a REST API (or using an SDK) with a bearer token or key, reading JSON, and running az in Cloud Shell. You should know what an Azure AI Services (Cognitive Services) resource is — a single Azure resource that exposes an AI capability behind an endpoint + key — and the basic idea of a managed identity for keyless auth. No machine-learning background is required; that is the point of the prebuilt features.

This sits in the AI/ML track, at the applied services layer — above the raw model platforms (Azure Machine Learning, Azure OpenAI) and beside the other prebuilt AI services (Vision, Speech, Document Intelligence). It is the text-reading sibling of those. It pairs naturally with Azure Functions and Serverless Patterns: Event-Driven Compute when you wire it into an event pipeline (a blob lands, a function calls Language, the result is stored), with Azure Key Vault: Secrets, Keys and Certificates Done Right for the endpoint key if you must use keys, and with Azure Monitor and Application Insights: Full-Stack Observability for latency and error telemetry on the calls. If you are heading toward generative AI and retrieval, it is upstream of Azure AI Search for RAG: Vector Indexing, Hybrid Search, Semantic Ranking, and Indexer Pipelines (NER and key phrases enrich the index) and a sibling of the broader survey in AI-900: Azure AI Services — Vision, Language, Speech, Document Intelligence & Search.

Where each capability lives relative to the platforms around it, so you call the right tool:

Need Right Azure service Why not the Language service
Read text: PII, sentiment, NER, intent AI Language This is the right tool
Generate / rewrite / chat over text Azure OpenAI Language is analysis, not generation
Extract fields from invoices/forms (layout) Document Intelligence Language reads text, not document layout
Transcribe audio → text Azure AI Speech Feed Speech output into Language
Detect objects/text in images Azure AI Vision Different modality
Train your own from scratch, full control Azure Machine Learning Only if prebuilt/custom won’t fit
Semantic/vector search over a corpus Azure AI Search Language enriches the index, doesn’t host it

Core concepts

Five mental models make every later decision obvious.

One resource, one endpoint, one key, many features. You provision a single Azure AI Language resource (a kind: TextAnalytics Cognitive Services account, or a multi-service AI Services account). Every capability — PII, sentiment, NER, CLU — is reached at the same HTTPS endpoint (https://<name>.cognitiveservices.azure.com/) authenticated by the same key or Entra token. You do not deploy one resource per feature. The feature you want is selected by the API path and the request body, not by which resource you call. This is why “add sentiment” to an app that already does PII is zero new infrastructure.

Text goes in as documents; results come back per document. The API is batch-first. You send an array of documents, each with an id, the text, and optionally a language hint. The service processes each independently and returns results keyed by your id, plus a separate errors array for any document that failed (too long, unsupported language). The hard rule that bites everyone: a single document is capped at 5,120 characters for most synchronous text-analytics actions — longer text must be chunked by you before sending. Batch size and total payload are also bounded (commonly up to 25 documents and ~1 MB per sync request, with higher limits for async). You design around the document model, not around “send me the whole 50-page PDF”.

Prebuilt vs custom is the fork that decides everything. Prebuilt features (language detection, sentiment, key phrase, NER, entity linking, PII, summarization) ship Microsoft-trained models — call them immediately, pay per character, nothing to maintain. Custom features (Custom NER, Custom Text Classification, CLU, custom question answering) require you to create a project in Language Studio, label data, train a model, and deploy it to a named deployment, which you then call by project + deployment name. Custom buys you domain-specific accuracy at the cost of labelling effort, a training step, and per-model maintenance. Choosing prebuilt when “people, places, orgs, dates” is enough — and custom only when you need your entity types or your intents — is the most important design call.

Some actions are synchronous, some are long-running (async). Lightweight analyses (sentiment, key phrase, language, prebuilt NER/PII on a small batch) return in one synchronous call. Heavier or composite work — summarization, Text Analytics for health (extracting medical entities/relations, the PHI case), large multi-action batches, and custom-model analysis — runs as a Long-Running Operation (LRO): you POST to start a job, get back an operation URL, then poll until status: succeeded and read the results. Mixing these up (“why does summarize not return text immediately?”) is a classic first-call confusion. The async ones are async by design because they take longer.

CLU answers “what does the user want”, not “what does the text contain”. The prebuilt features describe text objectively (this span is an email; the tone is negative). Conversational Language Understanding (CLU) is purpose-built for utterances: you define intents (the goals: BookFlight, CancelAccount, CheckBalance) and entities (the parameters: a date, a destination, an amount), label example utterances, and train. At runtime CLU returns the top intent with a confidence score and the entities it pulled out. It is the engine behind bots and IVR. Its bigger sibling, the orchestration workflow, sits above multiple CLU/QnA/custom projects and routes an utterance to the right one — the pattern when a single assistant must “do many different things”.

The vocabulary in one table

Pin down every moving part before the deep sections; the glossary repeats these for lookup.

Term One-line definition Family Why it matters
Language resource The single Cognitive Services account you call One endpoint/key for all features
Document One {id, text, language?} unit you submit The 5,120-char limit is per document
Prebuilt feature Microsoft-trained, call-and-go Prebuilt No training, per-char billing
Custom feature You label + train + deploy Custom Domain accuracy, you maintain it
PII detection Finds + redacts personal-data spans Prebuilt Compliance before storage/logging
PHI / Text Analytics for health Medical entities + relations (async) Prebuilt Healthcare; runs as an LRO
Sentiment / opinion mining Polarity; opinion = aspect-level Prebuilt Opinion mining is off by default
NER Named-entity recognition (typed spans) Prebuilt Extraction/search enrichment
Entity linking Disambiguate to a Wikipedia entity Prebuilt “Apple” the company vs the fruit
Key-phrase extraction Main talking points Prebuilt Tagging, digests
Summarization Extractive (pick sentences) or abstractive (LLM) Prebuilt Long threads/docs; async
Intent (CLU) The user’s goal in an utterance Custom Routing in bots/IVR
Entity (CLU) A parameter in the utterance Custom Slot-filling
Orchestration workflow Routes utterances across CLU/QnA projects Custom One assistant, many skills
LRO Long-Running Operation (start → poll) How async actions return

The prebuilt features, one by one

These need no training. Send text, get structure. Here is the full prebuilt menu with what each returns and the one knob you must know.

Feature API action (analyze) What it returns Key knob / gotcha
Language detection LanguageDetection ISO code + confidence per doc Use as a pre-step; ambiguous short text is low-confidence
Sentiment analysis SentimentAnalysis doc + sentence polarity + scores Opinion mining is opt-in (opinionMining=true)
Key-phrase extraction KeyPhraseExtraction list of phrases per doc No scores; language-dependent quality
Named-entity recognition EntityRecognition typed entities + category + offset Categories are fixed; not your types
Entity linking EntityLinking entities linked to Wikipedia URLs English-centric; links can be absent
PII detection PiiEntityRecognition PII spans + redactedText Allow-list categories; default detects many
Summarization (extractive) ExtractiveSummarization top N original sentences Async (LRO); you set sentence count
Summarization (abstractive) AbstractiveSummarization newly-written summary Async (LRO); LLM-backed, longer latency

PII detection and redaction

The compliance workhorse. Send text, and PII detection returns the spans that are personal data — each with a category (Email, PhoneNumber, CreditCardNumber, Person, Address, government IDs such as USSocialSecurityNumber, and many country-specific types), a confidence score, and the character offset/length. Critically, it also returns a redactedText field with those spans masked (replaced by *), so you can store or log the redacted version directly. The mental model: PII is “NER specialised for personal data, plus a ready-made redacted string”.

Two knobs matter. First, the PII categories (piiCategories): by default the service detects a broad set, but you can pass an explicit allow-list so it only flags, say, CreditCardNumber and USSocialSecurityNumber and ignores Person (you may want names). Second, the domain: a phi domain narrows detection to protected health information for healthcare text. The classic mistake is assuming a regex is “good enough” and leaking a differently-formatted card number into logs — the trained model catches formats your regex won’t.

# PII detection over a small batch (synchronous) — returns redactedText per document
curl -s -X POST "$LANG_ENDPOINT/language/:analyze-text?api-version=2024-11-01" \
  -H "Ocp-Apim-Subscription-Key: $LANG_KEY" -H "Content-Type: application/json" \
  -d '{
    "kind": "PiiEntityRecognition",
    "parameters": { "piiCategories": ["CreditCardNumber","Email","PhoneNumber"] },
    "analysisInput": { "documents": [
      { "id": "1", "language": "en",
        "text": "Charge card 4111-1111-1111-1111, email me at jo@contoso.com." }
    ]}
  }'
# Response includes: "redactedText": "Charge card ********************, email me at *************."

The PII categories you will reach for most, and where each shows up:

Category (sample) Example match Common use
Email jo@contoso.com Logging hygiene, GDPR
PhoneNumber +91 98xxxxxxx Contact-centre transcripts
CreditCardNumber 4111 1111 1111 1111 PCI scope reduction
Person Priya Sharma Anonymising case notes
Address 12 MG Road, Bengaluru Shipping/KYC text
USSocialSecurityNumber / national IDs 123-45-6789 Compliance redaction
IPAddress 203.0.113.7 Security/log scrubbing
phi domain (health) diagnoses, medications HIPAA-adjacent workflows

Sentiment analysis and opinion mining

Sentiment returns a label — positive / negative / neutral / mixed — at both the document and sentence level, each with confidence scores for all three classes (they sum to ~1.0). “Mixed” appears at the document level when sentences disagree. That alone routes angry tickets and scores reviews.

The depth knob is opinion mining (aspect-based sentiment), which is off by default — you must pass opinionMining=true. With it on, the service links a sentiment to the target it is about: from “the battery is great but the screen is terrible” it returns two opinions — battery → positive, screen → negative — instead of a muddy “mixed”. For product feedback this is the difference between “customers are unhappy” and “customers love X but hate Y”. The trade-off is slightly higher latency and a richer payload to parse.

# Sentiment WITH opinion mining (aspect-level). Note opinionMining must be true.
curl -s -X POST "$LANG_ENDPOINT/language/:analyze-text?api-version=2024-11-01" \
  -H "Ocp-Apim-Subscription-Key: $LANG_KEY" -H "Content-Type: application/json" \
  -d '{
    "kind": "SentimentAnalysis",
    "parameters": { "opinionMining": true },
    "analysisInput": { "documents": [
      { "id": "1", "language": "en",
        "text": "The battery is great but the screen is terrible." }
    ]}
  }'

Reading the output has three layers, each with a trap: the document level gives one label plus three scores — and “mixed” is not neutral, it means the sentences disagree; the sentence level gives a label per sentence, which is how you find which sentence is negative; and the opinion level (target plus assessment) gives aspect-level polarity but is off by default until you set opinionMining=true.

Named-entity recognition and entity linking

NER finds typed real-world spansPerson, Location, Organization, DateTime, Quantity, Email, URL, PhoneNumber and more — each with a category, optional subcategory, confidence, and offset. It is the extraction engine for search enrichment (“pull every organisation and date out of these filings”) and lightweight structuring of free text. The categories are fixed; if you need your domain’s entity types (a part number, a policy clause), that is Custom NER, not prebuilt.

Entity linking goes one step further: it disambiguates a recognised entity to a specific real-world identity, returning a Wikipedia URL and a unique data-source ID. From “Apple released a phone” it links Apple → en.wikipedia.org/wiki/Apple_Inc. (the company) rather than the fruit. It is English-centric and a link is not always available, but for knowledge-graph and disambiguation work it resolves the ambiguity NER leaves open.

NER vs entity linking vs Custom NER — pick the right one:

You need… Use Returns Train?
Generic typed entities (people, dates, orgs) Prebuilt NER Category + offset + score No
The specific real-world entity (disambiguated) Entity linking Wikipedia URL + ID No
Your own entity types from your docs Custom NER Your labels + offset Yes

Key-phrase extraction and summarization

Key-phrase extraction returns the main talking points of a document as a flat list of phrases — no scores, no categories. It is the cheap way to tag content, build digests, or generate search keywords. Quality is language-dependent and it will not invent structure; treat it as “the nouns that matter”.

Summarization comes in two flavours, both asynchronous (LRO). Extractive summarization selects the most important original sentences (you choose how many) — faithful to the source, no paraphrase. Abstractive summarization is LLM-backed and writes a new, condensed summary in its own words — more fluent, but it generates text, so it carries the usual generative caveats. There is also a conversation summarization mode tuned for chat transcripts (issue/resolution). The decision is fidelity vs fluency: extractive when you must not alter wording (legal, compliance), abstractive when you want a readable gist.

Key phrase vs the two summarizations:

Feature Output Sync/async Pick when
Key-phrase extraction List of phrases Sync Tagging, keywords, quick digest
Extractive summarization N original sentences Async (LRO) Must preserve exact wording
Abstractive summarization Newly-written summary Async (LRO) Want a fluent, condensed gist

The custom features and CLU

Custom features trade a labelling-and-training step for accuracy on your problem. All follow the same lifecycle: create project → label data in Language Studio → train → evaluate → deploy → call by project + deployment name.

Custom feature You define You label At runtime returns Replaces
Custom NER Your entity types Spans in your documents Your typed entities + offsets Generic NER (when it’s not enough)
Custom text classification Your categories (single/multi-label) Whole-document labels Predicted class(es) + scores Manual triage/routing
Conversational Language Understanding (CLU) Intents + entities Example utterances Top intent + entities + scores The retired LUIS
Custom question answering A knowledge base (Q/A pairs, from URLs/docs) Curate Q&A pairs Best answer + confidence FAQ bot logic

Conversational Language Understanding (CLU)

CLU is the headline custom feature and the modern replacement for LUIS (Language Understanding, retired). Its job is to read a short utterance — what a user typed or said — and return what they want and the details. You model two things:

At inference, CLU returns the top intent with a confidence score, a ranked list of the runners-up, and the entities it extracted with their types and spans. A bot reads the intent to choose a handler and the entities to fill the slots. The whole thing is trained and deployed in Language Studio and then called by project name + deployment name — the deployment name lets you run, say, a staging and a production model from the same project.

# Query a deployed CLU model: send the utterance, get top intent + entities
curl -s -X POST "$LANG_ENDPOINT/language/:analyze-conversations?api-version=2024-11-01" \
  -H "Ocp-Apim-Subscription-Key: $LANG_KEY" -H "Content-Type: application/json" \
  -d '{
    "kind": "Conversation",
    "analysisInput": { "conversationItem": {
      "id": "1", "participantId": "user",
      "text": "Book me a flight to Goa next Friday"
    }},
    "parameters": {
      "projectName": "travel-bot", "deploymentName": "production",
      "verbose": true
    }
  }'
# Returns: topIntent = "BookFlight", plus entities Destination=Goa, Date=next Friday

CLU concepts and the choice each forces:

CLU concept What it is Choice you make
Intent The user’s goal One per distinct action; keep them separable
Learned entity Taught by labelled examples When values vary freely (free text)
List entity Fixed vocabulary + synonyms When values are a known set (cities, plans)
Prebuilt entity Numbers, datetimes, etc. Free, reuse instead of teaching
Deployment A named, callable model version staging vs production slots
Confidence threshold Min score to accept the intent Below it → fall back / clarify

CLU vs the orchestration workflow

One CLU project handles one cohesive set of intents. When a single assistant must do fundamentally different jobs — answer FAQs and book travel and run a custom classifier — you do not cram them into one CLU project. You build an orchestration workflow: a top-level project whose “intents” are other projects (a CLU project, a custom question-answering knowledge base, another CLU). It reads the utterance and routes to the right child project, which then does the real work. The rule of thumb: one CLU project per skill; an orchestration workflow to choose the skill.

Aspect CLU project Orchestration workflow
Scope One coherent skill Many skills, one entry point
“Intents” point to Handlers in your app Other projects (CLU/QnA/custom)
Use when A bot does one job well An assistant juggles unrelated jobs
Returns Intent + entities Which project to call (then its result)

Architecture at a glance

The diagram traces a single piece of text from the caller to the right Language capability and back, the way a production system actually wires it. Read it left to right. A client (web app, IVR, mobile) sends user text to your API tier — typically an App Service / Functions front controller behind Application Gateway — which authenticates the caller and then makes a server-side call to the Azure AI Language endpoint. The API tier holds a managed identity; it never ships a key to the browser. It fans the text to whichever capability the request needs: the prebuilt analyzer (PII redaction, sentiment, NER, key phrase, summarization) for objective analysis, or a deployed CLU model when the question is “what does the user want”. CLU, in turn, may sit behind an orchestration workflow that first decides which skill should handle the utterance.

Two cross-cutting paths complete the picture. On the trust side, the Language resource is reached over a private endpoint inside your VNet, authenticated by Entra ID (the API tier’s managed identity), with any fallback key kept in Key Vault — so text never traverses the public internet and no static secret lives in code. On the data and observability side, the redacted/structured result is written to storage (a blob or database, post-redaction so PII never lands raw) while latency, throughput and error telemetry stream to Azure Monitor / Application Insights. The numbered badges mark the four places this most often breaks: the 5,120-character document limit, the keyless-auth role grant, the private-endpoint DNS, and the async-poll contract for summarization/health.

Left-to-right Azure AI Language architecture: a client sends user text through Application Gateway to an App Service/Functions API tier holding a managed identity, which calls the Azure AI Language endpoint over a private endpoint authenticated by Entra ID with a fallback key in Key Vault; the service fans to a prebuilt analyzer for PII redaction, sentiment, NER, key-phrase and summarization, or to a deployed CLU model behind an orchestration workflow for intent and entity extraction; redacted results are written to storage and call telemetry flows to Azure Monitor and Application Insights, with numbered badges on the 5,120-character document limit, the keyless-auth role grant, private-endpoint DNS resolution, and the async long-running-operation poll for summarization and Text Analytics for health

Real-world scenario

Medanta Connect, a fictional mid-size health-insurance provider in Bengaluru, runs a customer-support contact centre handling ~30,000 chat and email contacts a month. Three problems landed on the platform team’s desk at once: agents were pasting customer messages (with Aadhaar numbers, policy IDs and phone numbers) into a logging tool, tripping a compliance review; the retention team had no way to spot “I want to cancel” early; and the new self-service bot was a brittle keyword matcher that failed the moment a customer phrased a request differently. The team of three had no data scientists and a tight budget (target under ₹12,000/month for the language layer).

They reached for the Language service deliberately, mapping each problem to a feature. Problem one (compliance)PII detection: a small Azure Function triggers whenever a transcript is finalised, calls PiiEntityRecognition with an allow-list of Aadhaar-style national IDs plus PhoneNumber and Email, and writes only the redactedText to the log store. Raw text never reaches the logging tool. Problem two (churn signal)sentiment analysis with opinion mining on: each inbound message is scored, and any document where sentiment is negative and the opinion target is “cancellation” or “refund” raises a flag that routes the contact to retention within seconds. Problem three (the bot)CLU: they modelled eight intents (CheckClaimStatus, CancelPolicy, UpdateContact, …) and entities for PolicyNumber and ClaimNumber, labelled ~40 utterances each in Language Studio, trained, and deployed a production model the bot calls.

The first cut had two stumbles, both instructive. The PII function intermittently returned InvalidDocumentBatch errors on long email threads — they had ignored the 5,120-character limit; the fix was to chunk each thread into ≤5,000-character documents (one API call, multiple documents) and stitch the redacted parts back. And the bot mis-routed “cancel my claim” to CancelPolicy because the two intents shared vocabulary; they fixed it by adding distinguishing utterances and raising the confidence threshold so low-confidence predictions fall back to “let me connect you to an agent” instead of guessing.

Cost came in comfortably under budget. At ~30,000 contacts averaging two text records each (~60,000 PII + 60,000 sentiment + ~25,000 CLU calls a month), they landed in the low ₹8,000–10,000/month range on the standard S tier, with the first chunk of monthly records covered by the free allowance during development. The wins were concrete: zero raw PII in logs (compliance signed off), retention engaged 4× more “cancel” intents before the customer churned, and bot containment rose from 22% to 48% because CLU understood paraphrase. The lesson on the wall: “We didn’t build NLP. We called it. The only ‘ML’ work was labelling forty sentences per intent and respecting the document limit.”

The build as a mapping, because the feature choice is the lesson:

Business problem Feature chosen Key setting Outcome
Aadhaar/phone in logs PII detection piiCategories allow-list; store redactedText Zero raw PII logged
Spot churn early Sentiment + opinion mining opinionMining=true; route on negative+target 4× earlier retention engagement
Brittle keyword bot CLU 8 intents, threshold fallback Containment 22% → 48%
Long email threads erroring (fix) chunking ≤5,000 chars/document InvalidDocumentBatch gone

Advantages and disadvantages

The managed-API model is what makes the Language service worth reaching for — and also where its limits live. Weigh it honestly.

Advantages (why this model helps you) Disadvantages (why it bites)
Prebuilt models, zero training — call PII/sentiment/NER today, no ML team, no GPUs Prebuilt categories are fixed; your entity types need Custom NER (labelling + training)
One endpoint/key for a dozen features — add a capability with zero new infra Everything routes through one resource — its quota/throttle is a shared ceiling
Per-character pricing, generous free tier — cheap to start, predictable to scale At very high volume, per-record cost adds up; needs commitment-tier planning
Ready-made redactedText — PII redaction is a field, not a project Redaction is span-replacement; semantic anonymisation (consistent pseudonyms) is on you
Custom features on a managed platform — label in a UI, train and deploy in clicks Custom models are yours to maintain — drift, re-labelling, re-training over time
Data-residency + private endpoint + Entra auth — enterprise-grade controls Defaults are public-endpoint + key auth; you must turn the security knobs on
Exam-relevant, well-documented — AI-900/AI-102, stable SDKs The async (LRO) actions trip first-timers expecting a synchronous reply

The model is right when your text questions are common (the prebuilt set covers them) or domain-specific but bounded (a handful of intents/entity types you can label). It bites when you need generation (that is Azure OpenAI), full model control (Azure Machine Learning), or document-layout extraction (Document Intelligence) — using Language for those is the wrong tool. The disadvantages are all manageable, but only if you know the prebuilt/custom fork, the document limit, and the sync/async split before you design.

Hands-on lab

Provision a Language resource, then run PII redaction and sentiment from the shell — free-tier-friendly (use the F0 free SKU; delete at the end). Run in Cloud Shell (Bash).

Step 1 — Variables and resource group.

RG=rg-lang-lab
LOC=eastus
LANG=lang-lab-$RANDOM   # globally-unique account name
az group create -n $RG -l $LOC -o table

Step 2 — Create the Language resource (free F0 SKU). It is a Cognitive Services account of kind TextAnalytics:

az cognitiveservices account create -n $LANG -g $RG -l $LOC \
  --kind TextAnalytics --sku F0 --yes -o table

Expected: an account row; kind = TextAnalytics, sku.name = F0. (One F0 per subscription per region.)

Step 3 — Grab the endpoint and a key into env vars.

LANG_ENDPOINT=$(az cognitiveservices account show -n $LANG -g $RG --query properties.endpoint -o tsv)
LANG_KEY=$(az cognitiveservices account keys list -n $LANG -g $RG --query key1 -o tsv)
echo "$LANG_ENDPOINT"

Step 4 — Redact PII (synchronous). Send one document; read redactedText:

curl -s -X POST "$LANG_ENDPOINT/language/:analyze-text?api-version=2024-11-01" \
  -H "Ocp-Apim-Subscription-Key: $LANG_KEY" -H "Content-Type: application/json" \
  -d '{ "kind":"PiiEntityRecognition",
        "analysisInput": { "documents": [
          { "id":"1","language":"en",
            "text":"Call me on +91 9876543210 or mail jo@contoso.com." } ]}}' | jq '.results.documents[0].redactedText'

Expected: the phone number and email replaced with *.

Step 5 — Score sentiment with opinion mining.

curl -s -X POST "$LANG_ENDPOINT/language/:analyze-text?api-version=2024-11-01" \
  -H "Ocp-Apim-Subscription-Key: $LANG_KEY" -H "Content-Type: application/json" \
  -d '{ "kind":"SentimentAnalysis",
        "parameters": { "opinionMining": true },
        "analysisInput": { "documents": [
          { "id":"1","language":"en",
            "text":"Delivery was fast but the packaging was damaged." } ]}}' \
  | jq '.results.documents[0] | {sentiment, confidenceScores}'

Expected: a document-level mixed (fast = positive, damaged = negative), with per-sentence and opinion detail in the full payload.

Step 6 — Detect language (the cheap pre-step).

curl -s -X POST "$LANG_ENDPOINT/language/:analyze-text?api-version=2024-11-01" \
  -H "Ocp-Apim-Subscription-Key: $LANG_KEY" -H "Content-Type: application/json" \
  -d '{ "kind":"LanguageDetection",
        "analysisInput": { "documents": [ { "id":"1","text":"Bonjour, comment ça va?" } ]}}' \
  | jq '.results.documents[0].detectedLanguage'

Expected: name: French, iso6391Name: fr, with a confidence score.

Step 7 — Teardown. Delete the whole resource group:

az group delete -n $RG --yes --no-wait

End to end, the lab proves four things with zero training and one resource: the account creates on the free F0 SKU (step 2), the endpoint and key drop into env vars (step 3), PII detection returns a masked redactedText (step 4), sentiment returns a document-level mixed with opinions when opinionMining is on (step 5), and language detection identifies fr (step 6) — then the resource group teardown leaves no lingering cost (step 7).

Common mistakes & troubleshooting

The Language API is forgiving until a handful of contract details bite. Each below is symptom → root cause → confirm → fix.

# Symptom Root cause Confirm Fix
1 InvalidDocument / InvalidDocumentBatch, some docs error A document exceeds 5,120 chars (or batch too big) Check the per-doc errors[] in the response Chunk to ≤5,000 chars; ≤25 docs/sync request
2 Summarize “returns nothing”/202 only It is async (LRO), not synchronous Response is 202 with an operation-location header Poll the operation URL until succeeded
3 401/403 Unauthorized Wrong key, wrong region endpoint, or missing RBAC for Entra auth Re-check key + endpoint; for token auth check role Use matching key+endpoint; grant Cognitive Services Language Reader/User
4 Opinion mining “doesn’t work” opinionMining left at its default false Inspect the request parameters Set opinionMining: true
5 PII misses a category you expected An allow-list (piiCategories) excluded it, or wrong domain Diff the piiCategories you sent Omit the allow-list (detect all) or add the category
6 429 Too Many Requests Throttled past the tier’s rate (TPS) Response code 429 + Retry-After Back off/retry; raise tier or use commitment tier
7 CLU 404/empty result Wrong projectName/deploymentName, or model not deployed Confirm the deployment name in Language Studio Deploy the model; pass the exact deployment name
8 CLU mis-routes similar intents Overlapping training utterances; threshold too low Inspect topIntent confidence vs runners-up Add distinguishing utterances; raise the confidence threshold + fallback
9 Private-endpoint calls time out Public network disabled but DNS still resolves public IP nslookup <name>.cognitiveservices.azure.com returns public IP Wire the privatelink Private DNS zone to the VNet
10 Wrong language results No language hint and auto-detect guessed wrong Check detectedLanguage on the doc Pass the language field explicitly per document
11 Health/PHI call “slow or missing” Text Analytics for health is async by design It is an LRO job, not sync Start the job, poll, then read entities/relations
12 Custom model accuracy poor Too few / imbalanced labelled examples Review the evaluation metrics in Language Studio Add balanced examples per label; re-train

Two distinctions waste the most time. Sync vs async: some analyze calls return data immediately while others return 202 with an operation-location header — a 202 means poll the operation URL, a 200 means read the body now. Prebuilt vs custom call shape: prebuilt actions select the feature with a kind, but custom actions (CLU and friends) also need a projectName and deploymentName — omit those and the custom call fails outright.

Best practices

Security notes

The Language service reads your text, so the security posture is about who can call it, how the call is authenticated, where the text travels, and what you keep afterwards.

Identity and access. Prefer Microsoft Entra ID authentication over keys: assign the calling identity (a managed identity on your App Service/Function) a least-privilege role — Cognitive Services Language Reader for read/analyze, or Cognitive Services User/Contributor only where management is needed — scoped to the resource. This removes a static secret from your code path entirely. If you must use keys, store them in Key Vault (referenced via the app’s managed identity), rotate the two keys on a schedule (regenerate key2, swap, regenerate key1), and never embed a key in client-side code — all calls are server-side.

Network isolation. By default the endpoint is public. For sensitive data, disable public network access and place a private endpoint in your VNet so traffic stays on the Azure backbone; pair it with the privatelink.cognitiveservices.azure.com Private DNS zone so the hostname resolves to the private IP. This is the same pattern as Azure Private Link and Private DNS: Keeping PaaS Off the Public Internet.

Data handling. Redact PII before persistence and before logging — the redactedText field exists precisely so raw personal data never lands at rest. Encryption at rest is on by default with Microsoft-managed keys; bring customer-managed keys (CMK) in Key Vault for regulated workloads. Choose a region that meets your data-residency obligations, and review the service’s data-retention behaviour for your features (prebuilt text analysis does not retain your input to train Microsoft’s models, but always confirm against current terms for the specific feature and region).

The security knobs at a glance:

Control Default Hardened setting Why
Auth method Key Entra ID / managed identity No static secret in code
RBAC role Cognitive Services Language Reader (least priv) Read/analyze only
Key storage In app config Key Vault reference Centralised, rotatable
Network Public endpoint Private endpoint + DNS zone Text off the public internet
Encryption at rest Microsoft-managed Customer-managed key (CMK) Regulated workloads
Data at rest you create Raw output Store redactedText only No raw PII persisted

Cost & sizing

Billing is per text record — a unit of up to 1,000 characters of processed text — and you are charged per feature applied. A 2,500-character document run through sentiment counts as 3 text records for that feature; running it through both PII and sentiment counts the records twice (once per feature). That model makes cost easy to estimate from volume and the number of features you apply.

What drives the bill, and how to control each:

Cost driver Effect How to control
Characters processed More text → more records Trim/strip boilerplate before sending
Features per document Each feature bills separately Apply only the features you need
Tier (S vs commitment) Per-record vs reserved capacity High volume → commitment tier for a flat rate
Custom model usage Custom features bill per record too Cache/avoid re-analysing unchanged text
Summarization (abstractive) LLM-backed → priced higher Use extractive when fluency isn’t required
Async health/PHI Specialised, distinct meter Batch and dedupe before submitting

Sizing guidance: the free F0 tier gives a monthly allowance (commonly several thousand text records) — enough for development and small workloads, one F0 per subscription per region. The standard S tier is pay-as-you-go per record with a per-second throughput ceiling that you raise by tier; if you process millions of records a month, a commitment tier (a reserved monthly capacity at a discounted flat rate) beats per-record pricing. Right-sizing is mostly “stop paying for features and characters you don’t need”: detect language once, strip signatures and quoted history from emails before sending, and don’t run abstractive summarization where extractive (cheaper, faster) suffices.

A rough order-of-magnitude monthly picture (illustrative — confirm current rates and your region):

Workload Volume (records/mo) Tier Rough monthly order
Dev / spike a few thousand F0 (free) ₹0
Small app (PII + sentiment) ~120,000 S (PAYG) low thousands of ₹
Contact centre (multi-feature) ~1–2 million S → commitment tens of thousands of ₹
High-volume platform 10M+ Commitment tier flat reserved rate, best unit cost

Interview & exam questions

Q1. What is the Azure AI Language service and how does it relate to the old Text Analytics and LUIS? It is the consolidated natural-language API in Azure AI Services, exposing prebuilt features (PII, sentiment, key phrase, NER, entity linking, language detection, summarization) and custom features (Custom NER, custom text classification, CLU, custom question answering) behind one endpoint and key. It absorbed the former Text Analytics service and replaced LUIS with CLU. (AI-900/AI-102.)

Q2. Difference between prebuilt and custom features? Prebuilt features use Microsoft-trained models you call immediately and pay per record — no training. Custom features require you to create a project, label data in Language Studio, train, evaluate and deploy your own model, then call it by project + deployment name. Choose prebuilt for generic needs, custom for domain-specific entities, classes or intents.

Q3. A team must strip personal data from chat logs. Which feature, and what does it return? PII detection (PiiEntityRecognition). It returns each PII span with a category, confidence and offset, plus a redactedText field with those spans masked — store the redacted text so raw PII never persists. Optionally pass piiCategories to allow-list, or the phi domain for health data.

Q4. What is opinion mining and how do you enable it? Aspect-based sentiment: instead of one document polarity, it ties sentiment to the specific target (“battery → positive, screen → negative”). It is off by default; you enable it by setting opinionMining: true in the sentiment request parameters.

Q5. NER vs entity linking — when each? NER returns generic typed spans (Person, Location, Organization, DateTime, Quantity…) with categories and offsets. Entity linking goes further and disambiguates a recognised entity to a specific real-world identity (a Wikipedia URL), e.g. “Apple” the company vs the fruit. Use NER for extraction, linking for disambiguation/knowledge.

Q6. What is CLU and what does it return at runtime? Conversational Language Understanding reads a user utterance and returns the top intent (the user’s goal) with a confidence score plus a ranked list, and the entities (parameters like dates, destinations) extracted from it. You model intents and entities, label utterances, train and deploy. It is the modern replacement for LUIS and powers bots/IVR.

Q7. When do you use an orchestration workflow instead of a single CLU project? When one assistant must handle fundamentally different jobs (FAQ answering and booking and a custom classifier). The orchestration workflow’s “intents” point to other projects and route the utterance to the right one. Rule: one CLU project per skill, an orchestration workflow to choose the skill.

Q8. Which features are asynchronous and why does it matter? Summarization (extractive and abstractive), Text Analytics for health (PHI), and large/custom analyses run as Long-Running Operations — you POST to start, receive 202 with an operation URL, and poll until succeeded. Treating them as synchronous (“it returned nothing”) is a common first-call error.

Q9. What is the per-document character limit and how do you handle longer text? A single document is capped at 5,120 characters for most synchronous text-analytics actions (with batch and payload limits too). For longer text you chunk it into multiple ≤5,000-character documents in one (or more) batched request and reassemble the results client-side.

Q10. How should you authenticate to the Language service in production? Prefer Microsoft Entra ID with a managed identity on the calling service, granted a least-privilege role (e.g. Cognitive Services Language Reader) — no static secret in code. If keys are unavoidable, keep them in Key Vault, rotate the two keys, and call only server-side. Lock the endpoint behind a private endpoint for sensitive data.

Q11. How is the service priced and how do you control cost? Per text record (up to 1,000 characters), billed per feature applied. Control it by trimming boilerplate, applying only needed features, using extractive over abstractive summarization, and moving high volume from pay-as-you-go S to a commitment tier. The F0 free tier covers development.

Q12. Customer says CLU mis-routes “cancel my claim” to a “cancel policy” intent — how do you fix it? The intents share vocabulary and training is ambiguous. Add distinguishing example utterances to each intent, retrain, and raise the confidence threshold so low-confidence predictions fall back to a clarifying question or a human handoff instead of guessing.

Quick check

  1. Which prebuilt feature returns a ready-to-store redactedText field, and what must you set to restrict which categories it flags?
  2. Opinion mining is enabled by which parameter, and what does it add over plain sentiment?
  3. Name two features that run as asynchronous Long-Running Operations.
  4. What does CLU return at runtime, and how do you call a specific trained model?
  5. What is the per-document character limit for most synchronous text-analytics actions, and how do you process longer text?

Answers

  1. PII detection (PiiEntityRecognition) returns redactedText. Set the piiCategories allow-list to restrict which categories it flags (e.g. only CreditCardNumber, Email).
  2. The opinionMining: true parameter. It adds aspect-level sentiment — tying polarity to the specific target (“battery → positive, screen → negative”) rather than one document-level label.
  3. Any two of: extractive summarization, abstractive summarization, Text Analytics for health (PHI), and large/custom-model analyses.
  4. CLU returns the top intent (with confidence + ranked runners-up) and the entities extracted from the utterance. You call a specific model by passing its projectName and deploymentName.
  5. 5,120 characters per document. For longer text, chunk it into multiple ≤5,000-character documents in batched requests and reassemble the results client-side.

Glossary

Next steps

AzureAI LanguageCognitive ServicesPIISentiment AnalysisNERCLUAI-102
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading