Document Intelligence: Custom Models, Classification and RAG Ingestion

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

This page targets Azure CLI 2.90.0, the Document Intelligence REST API v4.0 2024-11-30, and the client libraries azure-ai-documentintelligence 1.0.2 (Python), Azure.AI.DocumentIntelligence 1.0.0 (.NET), com.azure:azure-ai-documentintelligence 1.0.10 (Java) and azure-search-documents 12.0.0 (Python), checked on 2026-10-06.

The prebuilt models on Document Intelligence: Read, Layout and Prebuilt Models cover common documents. This page covers documents that are specific to your business (custom models), packets that mix several document types (classifiers), and preparing documents for retrieval-augmented generation (layout to Markdown).

Custom models

Model type How it works Choose it when

Custom template

Learns fixed positions of fields from a few labeled samples (5 or more).

Every document uses the same layout, such as your own order form.

Custom neural

A deep-learning model fine-tuned on your labeled samples; tolerates layout variation.

The same document type comes in different layouts, such as supplier statements.

Composed model

Groups up to 200 custom models behind one model ID, with a classifier choosing which model analyzes each document.

One endpoint for many forms.

Training limits: up to 50,000 pages per training set for template, neural training measured in compute time (a monthly free allowance, then billed), and a limit on the number of custom models per resource (check the service limits page). Labeling happens in Document Intelligence Studio: upload samples to a Blob container, draw boxes around fields, then train. Models can be copied between resources (copy-to) for promotion from test to production.

Custom classifiers

A custom classifier (documentClassifiers) recognizes the type of each document, and with splitMode=auto splits a multi-document file into its parts. Typical flow: classify, split, then send each part to the right extraction model.

flowchart LR inbox[Mailroom PDF with several documents] --> clf[Custom classifier, splitMode auto] clf -->|invoice pages| inv[prebuilt-invoice] clf -->|delivery note pages| dn[Custom neural model delivery-note] clf -->|contract pages| ct[prebuilt-contract] clf -->|unknown| review[Manual review queue] inv --> out[orders-api] dn --> out ct --> legal[Contracts store]

Training and calling a custom model

TOKEN=$(az account get-access-token --resource https://cognitiveservices.azure.com --query accessToken -o tsv)

curl -s -i -X POST \
  "https://$FOUNDRY.cognitiveservices.azure.com/documentintelligence/documentModels:build?api-version=2024-11-30" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "modelId": "delivery-note-v1",
    "buildMode": "neural",
    "azureBlobSource": {"containerUrl": "https://stbookshelf.blob.core.windows.net/training-delivery-notes"}
  }'
from azure.ai.documentintelligence import DocumentIntelligenceAdministrationClient, DocumentIntelligenceClient
from azure.ai.documentintelligence.models import (
    AzureBlobContentSource, BuildDocumentModelRequest, DocumentBuildMode,
)
from azure.identity import DefaultAzureCredential

endpoint = "https://foundry-bookshelf.cognitiveservices.azure.com/"
admin = DocumentIntelligenceAdministrationClient(endpoint, DefaultAzureCredential())
model = admin.begin_build_document_model(BuildDocumentModelRequest(
    model_id="delivery-note-v1",
    build_mode=DocumentBuildMode.NEURAL,
    azure_blob_source=AzureBlobContentSource(
        container_url="https://stbookshelf.blob.core.windows.net/training-delivery-notes"),
)).result()
print(model.model_id, list(model.doc_types))

client = DocumentIntelligenceClient(endpoint, DefaultAzureCredential())
with open("delivery-note.pdf", "rb") as f:
    result = client.begin_analyze_document("delivery-note-v1", body=f).result()
print(result.documents[0].fields["ShipmentId"].content)
using Azure;
using Azure.AI.DocumentIntelligence;
using Azure.Identity;

var admin = new DocumentIntelligenceAdministrationClient(
    new Uri("https://foundry-bookshelf.cognitiveservices.azure.com/"), new DefaultAzureCredential());

var source = new AzureBlobContentSource(new Uri("https://stbookshelf.blob.core.windows.net/training-delivery-notes"));
var options = new BuildDocumentModelOptions("delivery-note-v1", DocumentBuildMode.Neural) { AzureBlobSource = source };

Operation<DocumentModelDetails> build = await admin.BuildDocumentModelAsync(WaitUntil.Completed, options);
Console.WriteLine(build.Value.ModelId);
import com.azure.ai.documentintelligence.DocumentIntelligenceClient;
import com.azure.ai.documentintelligence.DocumentIntelligenceClientBuilder;
import com.azure.ai.documentintelligence.models.*;
import com.azure.identity.DefaultAzureCredentialBuilder;

DocumentIntelligenceClient client = new DocumentIntelligenceClientBuilder()
    .endpoint("https://foundry-bookshelf.cognitiveservices.azure.com/")
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildClient();

AnalyzeResult result = client.beginClassifyDocument("mailroom-classifier",
        new ClassifyDocumentOptions("https://stbookshelf.blob.core.windows.net/mailroom/batch-0917.pdf")
            .setSplit(SplitMode.AUTO))
    .getFinalResult();
result.getDocuments().forEach(d -> System.out.println(d.getDocumentType() + " pages " + d.getBoundingRegions()));

Layout to Markdown for RAG

prebuilt-layout with outputContentFormat=markdown returns the document as Markdown: headings from paragraph roles, tables as HTML <table> elements (which keep merged cells), figures with captions, and page-break markers. Chunking by heading keeps each chunk on one topic, which improves retrieval.

The job below parses a publisher’s catalog PDF, splits it at ## headings, and uploads the chunks to the catalog-docs index on search-bookshelf:

import re
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import AnalyzeDocumentRequest, DocumentContentFormat
from azure.identity import DefaultAzureCredential
from azure.search.documents import SearchClient

cred = DefaultAzureCredential()
di = DocumentIntelligenceClient("https://foundry-bookshelf.cognitiveservices.azure.com/", cred)
search = SearchClient("https://search-bookshelf.search.windows.net", "catalog-docs", cred)

source = "https://stbookshelf.blob.core.windows.net/media/publisher-catalog-2026.pdf"
result = di.begin_analyze_document(
    "prebuilt-layout",
    AnalyzeDocumentRequest(url_source=source),
    output_content_format=DocumentContentFormat.MARKDOWN,
).result()

def chunk_by_heading(markdown, max_chars=4000):
    sections = re.split(r"(?m)^(?=#{1,2} )", markdown)
    for section in sections:
        title = section.splitlines()[0].lstrip("# ").strip() if section.strip() else ""
        for start in range(0, len(section), max_chars):
            yield title, section[start:start + max_chars]

docs = [
    {"id": f"catalog-2026-{i}", "title": title, "content": text, "source": source}
    for i, (title, text) in enumerate(chunk_by_heading(result.content))
    if text.strip()
]
search.upload_documents(docs)
print(f"uploaded {len(docs)} chunks")

Vector fields are left to the index’s integrated vectorization, covered on Azure AI Search with Foundry Tools. The general parsing and freshness concerns are on Document Parsing and Ingestion Pipelines & Freshness.

Containers, batch API and the legacy package

  • Containers: v4.0 Read and Layout run as containers for on-premises processing, billed against a FormRecognizer resource (see Pricing, Quotas, Containers and Monitoring).

  • Batch API: documentModels/{modelId}:analyzeBatch analyzes every file in a Blob container and writes results to another container. Use it for backlogs instead of thousands of single calls.

  • Legacy package: azure-ai-formrecognizer (3.3.x) targets v3.0 and v2.1. v3.0 reaches end of support on 2029-03-30 and v2.1 on 2027-09-15. Move to azure-ai-documentintelligence, whose client and model names differ (DocumentAnalysisClient becomes DocumentIntelligenceClient).

Provisioning

In the Azure portal

  1. In Document Intelligence Studio (https://documentintelligence.ai.azure.com/studio), choose Custom extraction model or Custom classification model, create a project and connect it to foundry-bookshelf and a Blob container of samples.

  2. Label at least 5 samples per document type, then Train.

  3. Grant the resource’s managed identity Storage Blob Data Reader on the training container.

With the Azure CLI

az storage container create --account-name stbookshelf --name training-delivery-notes --auth-mode login
az storage blob upload-batch --account-name stbookshelf --destination training-delivery-notes \
  --source ./samples/delivery-notes --auth-mode login

Use cases

Scenario Feature Why this feature Example input → output

Bookshelf: publisher catalogs into the support knowledge base

Layout to Markdown + heading chunker

Headings and tables survive; chunks stay on topic.

publisher-catalog-2026.pdf → 180 chunks in catalog-docs

Bookshelf: delivery notes from small distributors

Custom neural model

No prebuilt model; layouts vary by distributor.

Delivery note → shipment ID, ISBNs, quantities

Mixed-document mailrooms

Custom classifier with splitMode=auto, then per-type models

One scanned batch contains many document types.

60-page scan → 9 documents routed to 3 models

Company-specific forms

Custom template

Fixed layout; very few samples needed.

Internal returns form → fields

Knowledge-base ingestion

Layout Markdown + AI Search

RAG over manuals with tables.

Manual PDF → searchable chunks

When not to use it

Clean up

curl -s -X DELETE \
  "https://$FOUNDRY.cognitiveservices.azure.com/documentintelligence/documentModels/delivery-note-v1?api-version=2024-11-30" \
  -H "Authorization: Bearer $TOKEN"
az storage container delete --account-name stbookshelf --name training-delivery-notes --auth-mode login