Azure AI Document Intelligence (formerly Form Recognizer) is Microsoft's document-AI service. It extracts printed and handwritten text, layout (lines, paragraphs, tables, figures), key-value pairs, and semantic fields from forms, invoices, receipts, IDs, and contracts. Unlike a pure OCR engine, it preserves document structure and provides prebuilt models for common document types — the Azure counterpart to AWS Textract.
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import AnalyzeDocumentRequest, ContentFormat
from azure.core.credentials import AzureKeyCredential
client = DocumentIntelligenceClient(
endpoint="https://myco-docintel.cognitiveservices.azure.com/",
credential=AzureKeyCredential("<key>"),
)
with open("contract.pdf", "rb") as f:
poller = client.begin_analyze_document(
"prebuilt-layout",
AnalyzeDocumentRequest(bytes_source=f.read()),
output_content_format=ContentFormat.MARKDOWN,
)
result = poller.result()
print(result.content[:2000]) # Markdown with headings, tables, etc.
poller = client.begin_analyze_document(
"prebuilt-invoice",
AnalyzeDocumentRequest(url_source="https://myco.blob.core.windows.net/inv/inv-0421.pdf"),
)
invoice = poller.result().documents[0]
print("Vendor:", invoice.fields["VendorName"].value_string)
print("Total :", invoice.fields["InvoiceTotal"].value_currency.amount)
for item in invoice.fields.get("Items", {}).value_array or []:
desc = item.value_object["Description"].value_string
amt = item.value_object["Amount"].value_currency.amount
print(f" - {desc}: {amt}")
poller = client.begin_analyze_document(
"prebuilt-layout",
AnalyzeDocumentRequest(url_source="https://myco.blob.core.windows.net/claims/claim-88.pdf"),
features=["queryFields"],
query_fields=["PolicyNumber", "DateOfIncident", "ClaimedAmount"],
)
result = poller.result()
for doc in result.documents:
for name, field in doc.fields.items():
print(name, "->", field.content)
The typical pattern for document-heavy RAG: Document Intelligence → chunks of Markdown → Azure OpenAI embeddings → Azure AI Search index.
# 1) Parse PDF to Markdown via Document Intelligence Layout
md = client.begin_analyze_document(
"prebuilt-layout",
AnalyzeDocumentRequest(bytes_source=pdf_bytes),
output_content_format=ContentFormat.MARKDOWN,
).result().content
# 2) Chunk by headings / token count (use langchain MarkdownHeaderTextSplitter, etc.)
chunks = chunk_markdown(md, max_tokens=500)
# 3) Embed chunks with Azure OpenAI
from openai import AzureOpenAI
aoai = AzureOpenAI(azure_endpoint="...", api_key="...", api_version="2024-10-21")
vectors = aoai.embeddings.create(model="embedding-3-large-prod", input=chunks).data
# 4) Upload to Azure AI Search (see the AI Search page for index schema)
documents = [{"id": f"doc-{i}", "content": c, "content_vector": v.embedding}
for i, (c, v) in enumerate(zip(chunks, vectors))]
search_client.upload_documents(documents)
Document Intelligence turns documents into structured data. Its models form a hierarchy: Read extracts text, Layout adds structure such as paragraphs, tables, selection marks and reading order, prebuilt models add domain fields for common document types, and custom models learn your own layouts. Results are returned as JSON with coordinates and confidences, or, for Layout, as Markdown that keeps headings and tables intact for language models. It is typically the first step of a document pipeline: ingestion for RAG, automated data entry from invoices and receipts, or classification and routing of mixed document batches.
Each analysis call is a long-running operation. The SDK's begin_analyze_document uploads the bytes (or passes a URL the service can read, such as a Blob SAS URL) and returns a poller; result() waits until the service finishes. The AnalyzeResult contains pages with words and lines, tables with cell spans, paragraphs with roles such as title or section heading, and, for field-extraction models, a list of documents with typed fields. Options such as page ranges, add-on features (high-resolution OCR, formulas, barcodes, query fields) and output format are set per request.
Prebuilt models save labelling work but return a fixed schema; if a field you need is missing, query fields can ask for it by name. Custom extraction models are trained from labelled samples in Document Intelligence Studio, and a custom classifier can split and route mixed batches to the right extractor. For high-volume pipelines, the batch API processes a whole container of files and writes results to another container.
from azure.identity import DefaultAzureCredential
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import AnalyzeDocumentRequest
client = DocumentIntelligenceClient(
endpoint="https://myco-docintel.cognitiveservices.azure.com/",
credential=DefaultAzureCredential(), # Entra ID instead of a key
)
REQUIRED = ["VendorName", "InvoiceId", "InvoiceDate", "InvoiceTotal"]
THRESHOLD = 0.85
def extract_invoice(path):
with open(path, "rb") as f:
poller = client.begin_analyze_document(
"prebuilt-invoice", AnalyzeDocumentRequest(bytes_source=f.read()))
doc = poller.result().documents[0]
out, review = {}, []
for name in REQUIRED:
field = doc.fields.get(name)
if field is None or (field.confidence or 0) < THRESHOLD:
review.append(name)
out[name] = field.content if field else None
return out, review
data, needs_review = extract_invoice("inv-0421.pdf")
print(data)
print("route to human review:" if needs_review else "auto-approved", needs_review)
Real pipelines rarely trust every field blindly. This pattern auto-approves documents where all required fields are present with high confidence and sends the rest to a human queue, which keeps accuracy high while automating the bulk of the volume. Using DefaultAzureCredential with a managed identity avoids storing API keys in code.
| Option | Strengths | Consider when |
|---|---|---|
| Azure Document Intelligence | Prebuilt + custom models, Markdown output, containers for on-prem | You are on Azure or need disconnected deployment |
| Amazon Textract | Forms, tables, queries, AnalyzeExpense/ID | You are on AWS |
| Google Document AI | Specialised processors, Workbench custom extractors | You are on Google Cloud |
| Open-source (Tesseract, docTR, Docling) | No per-page cost, full control | Volume is high and you can host and tune models |
| Multimodal LLM directly | Flexible, no training | Small volumes; needs validation and is less deterministic |