Batch Inference with ai_query(): Every Argument, Structured Output and Error Handling
Databricks GenAI Engineer · Deep dive

Batch Inference with ai_query(): Every Argument, Structured Output and Error Handling

ai_query() is the Databricks SQL function that sends each row of a query to a Model Serving endpoint and returns the model's response as a column. It takes an endpoint and a request, plus optional arguments for the return type, error handling, model parameters, structured output and image files, and Databricks parallelises and retries the calls.

Last updated November 2026.

What this deep dive adds

Chapter 37 of the course covers when batch inference beats a real-time endpoint, the shaping arguments by name, and the failOnError default that sinks large jobs. This post is the reference behind it: every argument with its runtime requirement, the request shape for each endpoint type, structured output in both styles, a job that keeps its failed rows for a retry, and how to run and cost it in production.

Batch inference with ai_query() is a Section 4 (Assembling and Deploying Applications) objective in the 18 March 2026 exam guide. The serving endpoints it calls are covered in the Foundation Model APIs and AI Gateway post.

Every argument

ArgumentWhat it does
endpointRequired. A STRING literal naming a Foundation Model, external model or custom model endpoint in the same workspace. The caller needs CAN QUERY on it.
requestRequired. A STRING for Foundation Model and external endpoints; a column or a STRUCT whose field names match the model's inputs for a custom endpoint.
returnTypeThe expected type for a custom endpoint, written like the schema argument of from_json. Optional from Runtime 15.2, when it is inferred from the model schema.
failOnErrorDefault true. Set false to get a STRUCT of the response and an error message per row instead of a failed query. Runtime 15.3 or above.
modelParametersA struct of model parameters such as max_tokens and temperature. Values must be constants, not column-dependent. Runtime 15.3 or above.
responseFormatStructured output for chat foundation models only: a DDL-style schema string, or a JSON string of type text, json_object or json_schema.
filesImage input for multimodal models: files => content, where content is a binary column such as the one read_files returns. JPEG and PNG only.

Two details catch people. When modelParameters leaves temperature unset, ai_query() uses 0.0, not the endpoint's usual default, so batch output is deterministic unless you ask otherwise. And the function needs Databricks Runtime 15.4 LTS or above (the docs announce a move to 17.3 LTS) and does not run on Databricks SQL Classic warehouses.

From the Databricks SQL reference page "ai_query function" (last updated 5 November 2026). Newer examples there write models as system.ai.<model>; this post uses the databricks- endpoint names that the AI Functions overview recommends for batch work. Use the name your workspace's Serving page lists.

The request for each endpoint type

A chat or completion model on Foundation Model APIs takes a string, so build the prompt with ||, CONCAT() or format_string():

SELECT ticket_id,
       ai_query(
         'databricks-meta-llama-3-3-70b-instruct',
         'Summarise this support ticket in one sentence: ' || body
       ) AS summary
FROM support.tickets;

A custom model takes the features it was trained on, as a struct, and a returnType when its signature does not supply one:

SELECT order_id,
       ai_query(
         endpoint   => 'churn-classifier',
         request    => named_struct('tenure_months', tenure_months,
                                    'plan', plan,
                                    'monthly_spend', monthly_spend),
         returnType => 'DOUBLE'
       ) AS churn_score
FROM crm.customers;

A custom chat model or agent that expects a messages array gets one built with named_struct and ARRAY, with returnType describing the response shape. Wrapping a call in a SQL function (CREATE FUNCTION ... RETURN ai_query(...)) and granting EXECUTE on it lets analysts reuse a vetted prompt without seeing or editing it.

Structured output: parameters and schemas

For extraction and classification, ask for a schema instead of parsing free text. A JSON schema with "strict": true constrains the model to it, and an enum limits a field to fixed labels:

SELECT ticket_id,
       ai_query(
         'databricks-meta-llama-3-3-70b-instruct',
         'Classify this support ticket: ' || body,
         modelParameters => named_struct('max_tokens', 200),
         responseFormat  => '{
           "type": "json_schema",
           "json_schema": {
             "name": "ticket_triage",
             "schema": {
               "type": "object",
               "properties": {
                 "category": {"type": "string",
                              "enum": ["billing", "bug", "account", "other"]},
                 "urgent":   {"type": "boolean"}
               }
             },
             "strict": true
           }
         }'
       ) AS triage
FROM support.tickets;

With the json_schema type the column holds a JSON string, so read fields with get_json_object(triage, '$.category') or convert it with from_json. The DDL style ('STRUCT<category:STRING, urgent:BOOLEAN>') is a shorter way to state the same schema. responseFormat works only against chat foundation models; for a custom model, the shape comes from returnType.

failOnError: a job that keeps its failures

With the default failOnError => true, one row that the endpoint rejects (an input over the model's limit, for example) fails the whole query, and a ten-million-row run loses all its work. Set it to false and each row returns a struct with two fields:

The same batch with failOnError true and false Four rows go to ai_query and the third row fails at the endpoint. With failOnError true, the whole query fails and no results are written. With failOnError false, every row returns a struct: rows one, two and four have a response and a null errorMessage, row three has a null response and an error message, so the job finishes and the failed row can be retried. FAILONERROR => TRUE (DEFAULT) r1 r2 r3 r4 Query fails One endpoint error, and no rows are written. FAILONERROR => FALSE response errorMessage r1"Refund issued..."null r2"Password reset..."null r3null"...too long" r4"Bug logged..."null The job finishes; r3 is kept for a retry.
failOnError decides whether one bad row costs you one row or the whole run.

That turns a fragile job into a two-step pattern: write everything, then retry only what failed.

CREATE OR REPLACE TABLE support.ticket_summaries AS
SELECT ticket_id,
       ai_query(
         'databricks-meta-llama-3-3-70b-instruct',
         'Summarise this support ticket in one sentence: ' || body,
         failOnError => false
       ) AS result
FROM support.tickets;

-- Rows to fix and rerun
SELECT ticket_id, result.errorMessage
FROM support.ticket_summaries
WHERE result.errorMessage IS NOT NULL;

Successful rows have a null errorMessage; failed rows have a null response. The flag covers errors from the model endpoint only; per the reference, a row that fails for any other reason still fails the whole query.

Running it in production

For common tasks, the task-specific functions (ai_classify, ai_extract, ai_summarize, ai_parse_document and others) need no endpoint or prompt, and Databricks recommends them for getting started. ai_query() is the general-purpose option when you choose the model, write the prompt or call a custom endpoint.

From the Databricks pages "Transform unstructured data using AI Functions" and "Deploy batch inference pipelines".

What this means for the exam

Exam tip: a whole-table job that dies on a few bad rows points to failOnError => false; free text that downstream code cannot parse points to responseFormat; a custom model endpoint points to a STRUCT request and returnType. Offline scoring of a table is ai_query(), not a loop calling a real-time endpoint.

Distractors fix the wrong layer: a lower temperature for errors, a Python loop for scale, or a classic warehouse, where AI Functions do not run.

FAQ

What does failOnError do in Databricks ai_query?

failOnError controls what happens when the endpoint rejects a row. The default, true, fails the whole query; false returns a struct per row with a response field and an errorMessage field, so the job finishes and failed rows can be found and retried.

How do I get structured JSON output from ai_query?

Pass responseFormat with a JSON schema (type json_schema, ideally with strict set to true) or a DDL-style schema string. It works only for chat foundation models, and with json_schema the column holds a JSON string that get_json_object or from_json can read.

Can ai_query call a custom model, not just an LLM?

Yes. ai_query calls custom model serving endpoints too: pass the input features as a STRUCT whose field names match the model's inputs, and give returnType when the model schema does not define the output, for example 'DOUBLE' for a score.

What is the default temperature in ai_query?

ai_query uses a temperature of 0.0 when modelParameters does not set one, which differs from the usual endpoint defaults. Other model parameters fall back to the defaults in the Foundation Model REST API reference.

Back to the chapter

Batch inference with ai_query() is Chapter 37 of the Databricks Generative AI Engineer Associate course, in Unit 4, Assembling and Deploying Applications, with exam-style checks on failOnError and structured output.

Open Chapter 37 →