All Products
Search
Document Center

Realtime Compute for Apache Flink:General invocation

Last Updated:Sep 21, 2026

This topic describes how to use the ML_PREDICT function to call AI models in Flink, covering syntax and parameters, per-call configuration, content type configuration, column-level parameters, and examples for text, image, and multimodal inference.

Quick start

Prerequisites

The following example demonstrates how to use ML_PREDICT to call a Flink built-in model. Go to Data Development > ETL, create a job, paste the code, and click Debug.

CREATE TEMPORARY TABLE text_source (
  user_input STRING
) WITH ('connector' = 'datagen');

CREATE TEMPORARY TABLE result_sink (
  user_input STRING,
  ai_analysis STRING
) WITH ('connector' = 'print');

CREATE TEMPORARY MODEL text_model
INPUT (user_input STRING)
OUTPUT (content STRING)
WITH (
  'provider' = 'openai-compat',
  'model' = 'qwen3.6-flash',
  'task' = 'chat/completions',
  'system-prompt' = 'Rate the gibberish level of the input on a scale of 0 to 100'
);

INSERT INTO result_sink
SELECT user_input, content as ai_analysis FROM
    ML_PREDICT(
        TABLE text_source,
        MODEL text_model,
        DESCRIPTOR(user_input)
);

Limits

  • Realtime Compute engine VVR 11.1 or later is required.

  • Some parameters are only supported when using Flink AI Service (built-in models) and require VVR 11.8 or later.

  • The throughput of the ML_PREDICT operator is subject to rate limiting by Model Studio. When the rate limit is reached, backpressure occurs at the ML_PREDICT operator, which may cause timeout errors and job restarts. For more information, see Rate limits on Model Studio.

  • The number of types in content-types and the number of columns in DESCRIPTOR must match the number of INPUT columns defined in CREATE MODEL.

  • Columns of type image_url must be STRING. Columns of type multi_image_urls must be ARRAY<STRING>.

  • base64 images must include the data:image/<format>;base64, prefix. Raw base64 strings and local file paths are not supported.

Syntax

ML_PREDICT(TABLE <table_name>, MODEL <model_name>, DESCRIPTOR(<input_columns>) [, CONFIG => MAP[...]])        

Parameters

Parameter

Data type

Description

TABLE

TABLE

The input data stream for model inference. You can specify a physical table or a view.

MODEL

MODEL

The name of a registered model. For more information, see Model settings.

DESCRIPTOR()

—

The input columns for model inference.

Note

VVR 11.8 and later supports multiple input columns. This is only available when using Flink AI Service (built-in models). The number of DESCRIPTOR columns must match the number of CREATE MODEL INPUT columns.

CONFIG => MAP[...]

MAP

Optional. For more information, see Per-call configuration.

Note

Only supported in VVR 11.8 and later with Flink AI Service (built-in models).

Per-call configuration

You can specify per-call configuration when calling ML_PREDICT. If a parameter is already set in CREATE MODEL, the per-call value takes precedence but does not persist to the MODEL definition.

Parameter

Description

Example

user-prompt

Specifies the user prompt. Pass an empty string to bypass the MODEL-level value.

MAP['user-prompt', 'Answer in English']

content-type

Specifies the content type for single-column input.

MAP['content-type', 'text']

content-types

Specifies the content types for multi-column input.
The number of types in content-types must match the number of INPUT columns in CREATE MODEL.

MAP['content-types', 'text;image_url']

{column}.{param}

Specifies column-level parameters.

MAP['image_input.min_pixels', '100']

extra-body

Specifies additional parameters as a JSON string.

MAP['extra-body', '{"enable_search": true}']

bundle-size

The bundle size.

MAP[
  'bundle-size', '10',
  'bundle-allow-latency', '5s'
]
Note

Bundle processing is supported only in VVR 11.9 and later.

bundle-allow-latency

The allowed bundle latency.

Content type parameters

  • For single-column input, use content-type to specify the content type. Supported values: text, image_url.

  • For multi-column input, use content-types to specify the content type for each column. The supported values and their mapping to Flink SQL column types are listed below:

content-types value

Flink SQL type

Description

text

STRING

-

image_url

STRING

-

image_bytes

BYTES

Supported in VVR 11.9 and later.

multi_image_bytes

ARRAY<BYTES>

Supported in VVR 11.9 and later.

multi_image_urls

ARRAY<STRING>

Supported in VVR 11.8 and later.

video_bytes

BYTES

Supported in VVR 11.9 and later.

video_url

STRING

Supported in VVR 11.9 and later.

  • We recommend that you specify content-types in the parameters. If you set both content-type and content-types, the framework reports an error. Note: the content-type and content-types settings in model parameters and per-call settings affect each other:

CREATE MODEL setting

Allowed per-call option

Not allowed per-call option

Description

content-type (single column)

content-type

content-types

You can switch between text and image_url

content-types (multiple columns)

content-types

content-type

You can change the type combination, e.g. text;image_url to text;text

Neither content-type nor content-types specified

content-type
content-types

—

Same as above

Column-level parameters

Parameter

Description

Values

Example

{column}.min_pixels

Sets the minimum pixel threshold for input images or video frames. Images with fewer pixels than min_pixels are upscaled until they exceed the threshold.

Qwen3.7, Qwen3.6, Qwen3.5: default and minimum are both 65536.

MAP['image_input.min_pixels', '100']

{column}.max_pixels

Sets the maximum pixel threshold for input images or video frames. Images within [min_pixels, max_pixels] are processed at their original resolution. Images exceeding max_pixels are downscaled.

Qwen3.7, Qwen3.6, Qwen3.5: default is 2621440, maximum is 16777216.

MAP['image_input.max_pixels', '10000']

{column}.total_pixels

Limits the total pixels across all frames extracted from a video (single frame pixels x total frames). If the video exceeds this limit, frames are scaled down while keeping each frame within [min_pixels, max_pixels].
For long videos with many extracted frames, you can lower this value to reduce token consumption and processing time, but this may cause loss of image detail.

Qwen3.7 series, Qwen3.6 series, Qwen3.5 series: default and maximum are both 819200000. This value corresponds to 800000 image tokens (each 32x32 pixel block equals 1 image token).

MAP['image_input.total_pixels', '1000000']

{column}.cache_control

Enables explicit caching.

{"type": "ephemeral"}

MAP['content.cache_control', '{"type": "ephemeral"}']

{column}.fps

Sets the frame sampling rate for video understanding.

Valid values: [0.1, 10]. Default value: 2.0.

MAP['video_input.fps', '1.0']

Bundle processing

  • Processing: Bundle processing first aggregates multiple input records into a batch and then calls the AI model for the batch. This reduces the number of model calls but increases the model inference time for each request. When records can be effectively aggregated, bundle processing can significantly improve operator throughput.

  • Parameter description: bundle-size specifies the maximum number of records accumulated in a batch. bundle-allow-latency specifies the maximum wait time when a batch has not reached the bundle-size value. Processing starts when either the batch-size or wait-time condition is met.

  • Requirements: Bundle processing takes effect based on the input and output schema of the model.

    • Text generation: For models whose task is chat/completions, the input contains exactly one STRING column of text, and the output contains exactly one STRING or VARIANT column. Multi-column inputs and multimodal inputs such as images, videos, and audio are not supported.

    • Text embedding: For models whose task is embeddings, the input contains exactly one STRING column, and the output contains exactly one ARRAY<FLOAT> column.

  • Supported functions: ML_PREDICT, text classification (AI_CLASSIFY), sentiment analysis (AI_SENTIMENT), information extraction (AI_EXTRACT), text summarization (AI_SUMMARIZE), text translation (AI_TRANSLATE), data masking (AI_MASK), and text embedding (AI_EMBED). Among them, ML_PREDICT supports bundle processing only when the registered model meets the preceding requirements.

  • Global configuration: This configuration applies to the ML_PREDICT calls and the calls to the listed domain-specific AI functions in the job that meet the preceding requirements. Use the following global parameters to enable bundle processing:

    -- Bundle processing is supported only in VVR 11.9 and later.
    SET 'table.exec.ml-predict.bundle-size' = '10';
    SET 'table.exec.ml-predict.bundle-allow-latency' = '5s';
  • Per-call configuration: These parameters apply only to the function call in which they are specified. ML_PREDICT and the listed domain-specific AI functions use the same configuration method. For parameters and examples, see Per-call configuration.

Error handling

Limits

  • Supported only in VVR 11.9 and later.

  • You cannot enable error handling when model calls run in synchronous mode.

  • Error handling cannot be used together with Vectorization result cache (CACHE_TABLE) at this time.

Enable error handling

Add the FAIL_ON_ERROR => FALSE parameter when you call an AI function.

Prerequisite: Keep the default retry settings of the model: error-handling-strategy='retry' and retry-fallback-strategy='failover'. For more information about model parameters, see Model settings.

Parameter

Description

Required

Default value

FAIL_ON_ERROR

Specifies whether the job fails when a call ultimately fails. If you set this parameter to FALSE, failed records are output as error rows and the job keeps running.

No

TRUE

Note

FAIL_ON_ERROR defaults to TRUE, in which case the job fails after all retries are exhausted. Setting this parameter to FALSE changes only how failed records are handled, not the retry behavior.

Output changes

After you enable error handling, the system appends an error column err_msg of the nullable VARIANT type to the end of the original output fields. This column is generated by the system. You do not need to declare it in the input table or in the OUTPUT clause of CREATE MODEL.

  • Call succeeds: err_msg is NULL.

  • Call ultimately fails: all model result fields are NULL, and err_msg contains the error information.

If you use SELECT *, the result includes the new error column. If you select fields explicitly, you must specify the column manually. The default column name is err_msg. If the name conflicts with an existing output column, the system appends a numeric suffix, such as err_msg0. Use the actual column name to reference the column.

Important

Use the error column to determine whether a call failed: a value that is not NULL indicates a failure. Model result fields that are NULL do not necessarily indicate a failed call.

Field in the object

Content

SQL read pattern

message

The cause of the error. Check this field first when you troubleshoot issues.

CAST(err_msg['message'] AS STRING)

stack_trace

More detailed diagnostic information. Check this field when you need to locate the root cause.

CAST(err_msg['stack_trace'] AS STRING)

details (optional field)

Present only if the underlying error carries additional information.

err_msg['details'] returns NULL if the field does not exist, or a VARIANT value if the field exists.

Examples

AI_SENTIMENT keeps failed records

Prepare a sentiment analysis model named ai_sentiment_model, which is registered and supports asynchronous calls.

CREATE TEMPORARY VIEW input_data AS
SELECT *
FROM (VALUES
  (1, CAST('xxxx (a description of violent conflict that violates humanity)' AS STRING), 'negative'),
  (2, CAST('The customer service of this store has always been among the best' AS STRING), 'positive')
) AS t(id, input_text, expected_label);

CREATE TEMPORARY VIEW ai_results AS
SELECT i.id, i.input_text, i.expected_label,
       r.score, r.label, r.confidence, r.err_msg
FROM input_data AS i,
LATERAL TABLE(AI_SENTIMENT(
  MODEL => MODEL ai_sentiment_model,
  INPUT => i.input_text,
  FAIL_ON_ERROR => FALSE,
  CONFIG => MAP['async', 'true']
)) AS r(score, label, confidence, err_msg);

SELECT * FROM ai_results;

The query returns the following columns in order.

Output column

Data type

Source and description

id

INT

The ID of the input record.

input_text

STRING

The original text to be processed.

score / label / confidence

STRING

Returned by AI_SENTIMENT. NULL if the call fails.

err_msg

VARIANT, can be NULL

Added after error handling is enabled. NULL for a successful call, or an error VARIANT object for a call that ultimately fails.

The query returns the following result. The summaries and error messages are examples. Actual results may vary.

id

input_text

score / label / confidence

err_msg

1

xxxx (a description of violent conflict that violates humanity)

NULL

{"message":"com.openai.errors.BadRequestException: 400: <400> InternalError.Algo.DataInspectionFailed: Input text data may contain inappropriate content..... "stack_trace":"org.apache.flink.table.api.TableException: Failed to execute asynchronously prediction with input row xxx}

2

The customer service of this store has always been among the best

1.0 / positive / 0.99

NULL

Other error examples

The following example shows a timeout error in general invocation.

message: 
java.util.concurrent.TimeoutException: AsyncPredictFunction did not complete within the configured timeout. Increase the ML_PREDICT timeout or check external service connectivity.

stack_trace:
java.util.concurrent.TimeoutException: AsyncPredictFunction did not complete within the configured timeout. Increase the ML_PREDICT timeout or check external service connectivity.
at org.apache.flink.table.runtime.operators.predict.AsyncMLPredictRunner.timeout(AsyncMLPredictRunner.java:153)
at org.apache.flink.table.runtime.operators.predict.AsyncMLPredictRunner.timeout(AsyncMLPredictRunner.java:51)
at org.apache.flink.table.runtime.operators.TableKeyedAsyncWaitOperator$KeyedResultHandler.timerTriggered(TableKeyedAsyncWaitOperator.java:462)
at org.apache.flink.table.runtime.operators.TableKeyedAsyncWaitOperator$KeyedResultHandler.lambda$registerTimeout$1(TableKeyedAsyncWaitOperator.java:457)
at org.apache.flink.table.runtime.operators.TableKeyedAsyncWaitOperator.lambda$registerTimer$4(TableKeyedAsyncWaitOperator.java:486)
at org.apache.flink.streaming.runtime.tasks.StreamTask.invokeProcessingTimeCallback(StreamTask.java:2285)
at org.apache.flink.streaming.runtime.tasks.StreamTask.lambda$deferCallbackToMailbox$28(StreamTask.java:2276)
at org.apache.flink.streaming.runtime.tasks.StreamTaskActionExecutor$1.runThrowing(StreamTaskActionExecutor.java:50)
at org.apache.flink.streaming.runtime.tasks.mailbox.Mail.run(Mail.java:115)
at org.apache.flink.streaming.runtime.tasks.mailbox.MailboxProcessor.runMail(MailboxProcessor.java:415)
at org.apache.flink.streaming.runtime.tasks.mailbox.MailboxProcessor.processMailsWhenDefaultActionUnavailable(MailboxProcessor.java:384)
at org.apache.flink.streaming.runtime.tasks.mailbox.MailboxProcessor.processMail(MailboxProcessor.java:369)
at org.apache.flink.streaming.runtime.tasks.mailbox.MailboxProcessor.runMailboxLoop(MailboxProcessor.java:229)
at org.apache.flink.streaming.runtime.tasks.StreamTask.runMailboxLoop(StreamTask.java:1273)
at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:1217)
at org.apache.flink.runtime.taskmanager.Task.runWithSystemExitMonitoring(Task.java:1133)
at org.apache.flink.runtime.taskmanager.Task.restoreAndInvoke(Task.java:1110)
at org.apache.flink.runtime.taskmanager.Task.doRun(Task.java:914)
at org.apache.flink.runtime.taskmanager.Task.run(Task.java:716)
at java.base/java.lang.Thread.run(Thread.java:991)

How each error type is handled

The following behavior applies when error handling is enabled and the default retry settings are kept. An error row is a row that retains the input, returns empty model results, and records the failure reason in err_msg.

Error type or cause

System behavior

Final output

Network connection failures, throttling, or transient service errors (429, 500, 502, 503)

Waits for the configured period and then retries.

Normal output if a retry succeeds. An error row if the call ultimately fails.

Invalid parameters, input that is too long, invalid key, permission denied, or model not found (400, 401, 403, 404, 422)

Typically returns a failure directly without retries.

An error row that records the reason returned by the service.

Content moderation rejection, or insufficient balance or quota

Decides whether to retry based on the error returned by the service.

Normal output if the error recovers. An error row if the call ultimately fails.

A JSON result is required, but the model response cannot be parsed

Sends the request again.

Normal output if the request succeeds. An error row if the call ultimately fails.

The configured waiting period is exceeded

Ends the current wait.

An error row that indicates a timeout.

A call ultimately fails or times out during bundle processing

Records the failure for each input in the batch.

One error row per input, each recording the same failure reason.

Examples

Text

The following example registers and uses a Flink AI Service built-in model to classify input text by sentiment. Example 1 uses MODEL-level parameters. Example 2 overrides user-prompt at call time.

-- Register a built-in model. When content-type is not specified, it defaults to text
CREATE MODEL sentiment_model
INPUT (prompt STRING)
OUTPUT (response STRING)
WITH (
  'provider' = 'openai-compat',
  'task' = 'chat/completions',
  'model' = 'qwen3.6-flash',
  'system-prompt' = 'You are a sentiment classifier. Output one label: negative, positive, or neutral'
);

-- Create a source table: simulated product review data
CREATE TEMPORARY VIEW input_table(id, content)
AS VALUES
  (1, 'Great quality, soft fabric, fits perfectly'),
  (2, 'Had loose threads on arrival, faded badly after one wash'),
  (3, 'Received the item, looks as pictured'),
  (4, 'Started pilling after two weeks, customer service refused returns'),
  (5, 'Flattering fit, color is even better than the photo, already ordered a third one');

-- Create a result table
CREATE TEMPORARY TABLE output_table (
  id INT,
  content STRING,
  sentiment STRING
) WITH (
  'connector' = 'print'
);

-- Use ML_PREDICT for real-time inference
-- Example 1: Use MODEL-level parameters
INSERT INTO output_table
SELECT
  id,
  content,
  response AS sentiment
FROM ML_PREDICT(
  TABLE input_table,
  MODEL sentiment_model,
  DESCRIPTOR(content));

-- Example 2: Specify per-call parameters
INSERT INTO output_table
SELECT
  id,
  content,
  response AS sentiment
FROM ML_PREDICT(
  TABLE input_table,
  MODEL sentiment_model,
  DESCRIPTOR(content),
  MAP['user-prompt', 'Reply in Chinese']);

Example 1 output:

id

content

sentiment

1

Great quality, soft fabric, fits perfectly

positive

2

Had loose threads on arrival, faded badly after one wash

negative

3

Received the item, looks as pictured

positive

4

Started pilling after two weeks, customer service refused returns

negative

5

Flattering fit, color is even better than the photo, already ordered a third one

positive

Example 2 output:

id

content

sentiment

1

Great quality, soft fabric, fits perfectly

Positive

2

Had loose threads on arrival, faded badly after one wash

Negative

3

Received the item, looks as pictured

Positive

4

Started pilling after two weeks, customer service refused returns

Negative

5

Flattering fit, color is even better than the photo, already ordered a third one

Positive

Image

The following example registers a multimodal model and classifies input images.

The image input column (when content-type is image_url) is of the STRING type and supports the following formats:

Input format

Usage

Limits

Public URL

Pass an HTTP or HTTPS URL string that the model service can access over the Internet. The model service pulls the image.

The URL must be accessible over the Internet from the environment in which the model service runs. If the URL is time-limited, its validity period must cover the duration of the model call. Image formats and sizes are limited by the model service.

Base64 data URL

Pass a string that is prefixed with data:image/<format>;base64,. Plain Base64 strings and local file paths are not supported.

The image bytes are transmitted by the Flink job, which increases the network overhead of the job. Base64 encoding also increases the data size. The data volume is limited by the input limits of the model service.

If images are stored in Blob columns of a Paimon Catalog, you can use the Paimon Blob presigned URL feature to generate a public URL as input. For more information, see Apache Paimon.

-- Register a built-in model with content-type set to image_url
CREATE TEMPORARY MODEL sentiment_model
INPUT (prompt STRING)
OUTPUT (response STRING)
WITH (
  'provider' = 'openai-compat',
  'task' = 'chat/completions',
  'model' = 'qwen3.6-flash',
  'content-type' = 'image_url'
);

-- Use ML_PREDICT for real-time inference
INSERT INTO output_table
SELECT
  id,
  content,
  response AS sentiment
FROM ML_PREDICT(
  TABLE input_table,
  MODEL sentiment_model,
  DESCRIPTOR(content));

Video

The following example registers a multimodal model to understand an input video.

CREATE TEMPORARY MODEL sentiment_model
INPUT (video_url STRING)
OUTPUT (response STRING)
WITH (
  'provider' = 'openai-compat',
  'task' = 'chat/completions',
  'model' = 'qwen3.6-plus',
  'content-types' = 'video_url',
  'system-prompt' = 'Briefly describe the video content'
);

CREATE TEMPORARY VIEW input_table(content)
AS VALUES ('https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251111/ckgcxt/%E5%8D%95%E4%BA%BA%E8%AF%B4%E8%AF%9D-1.mp4');

SELECT
  content,
  response AS sentiment
FROM ML_PREDICT(
  TABLE input_table,
  MODEL sentiment_model,
  DESCRIPTOR(content));

Text + single image

The following example registers a multimodal model for chat-based inference on text and image inputs.

CREATE MODEL vl_model
INPUT (text_input STRING, image_input STRING)
OUTPUT (content STRING)
WITH (
  'provider' = 'openai-compat',
  'model' = 'qwen3.5-plus',
  'task' = 'chat/completions',
  'content-types' = 'text;image_url'
);

INSERT INTO result_sink
SELECT content FROM TABLE(ML_PREDICT(
  TABLE image_source,
  MODEL vl_model,
  DESCRIPTOR(text_input, image_input)
));         

Text + multiple images (multiple columns)

Pass each image through a separate INPUT column. Specify image_url for each image column in content-types.

CREATE MODEL vl_model_multi
INPUT (prompt STRING, img1 STRING, img2 STRING)
OUTPUT (content STRING)
WITH (
  'provider' = 'openai-compat',
  'model' = 'qwen3.5-plus',
  'task' = 'chat/completions',
  'content-types' = 'text;image_url;image_url'
);

SELECT content FROM TABLE(ML_PREDICT(
  TABLE my_source,
  MODEL vl_model_multi,
  DESCRIPTOR(prompt, img1, img2)
));          

Text + multiple images (array)

Pass multiple images in an ARRAY<STRING> column. Use multi_image_urls in content-types.

CREATE MODEL vl_model_array
INPUT (prompt STRING, images ARRAY<STRING>)
OUTPUT (content STRING)
WITH (
  'provider' = 'openai-compat',
  'model' = 'qwen3.5-plus',
  'task' = 'chat/completions',
  'content-types' = 'text;multi_image_urls'
);

SELECT content FROM TABLE(ML_PREDICT(
  TABLE my_source,
  MODEL vl_model_array,
  DESCRIPTOR(prompt, images)
)); 

Text + video

CREATE TEMPORARY MODEL sentiment_model
INPUT (video_url STRING, question STRING)
OUTPUT (response STRING)
WITH (
  'provider' = 'openai-compat',
  'task' = 'chat/completions',
  'model' = 'qwen3.6-plus',
  'content-types' = 'video_url;text'
);

CREATE TEMPORARY VIEW input_table(content, question)
AS VALUES ('https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251111/ckgcxt/%E5%8D%95%E4%BA%BA%E8%AF%B4%E8%AF%9D-1.mp4', 'How many people are there?');

SELECT
  content,
  response AS sentiment
FROM ML_PREDICT(
  TABLE input_table,
  MODEL sentiment_model,
  DESCRIPTOR(content, question));

Per-call parameter examples

Example 1: Specify content type parameters

-- When content-type / content-types are not specified in CREATE MODEL, the default is content-type = text
CREATE MODEL model_single
INPUT (input STRING)
OUTPUT (content STRING)
WITH (
  'provider' = 'openai-compat',
  'model' = 'qwen3.5-plus',
  'task' = 'chat/completions'
);

-- Call 1: Use MODEL parameters, content type is text
SELECT content FROM TABLE(ML_PREDICT(
  TABLE source_text,
  MODEL model_single,
  DESCRIPTOR(input)
));

-- Call 2: Override content type to image at call time
SELECT content FROM TABLE(ML_PREDICT(
  TABLE source_img,
  MODEL model_single,
  DESCRIPTOR(input),
  MAP['content-type', 'image_url']
));

Example 2: Specify user-prompt and column-level parameters

-- Set default configuration in CREATE MODEL (multi-column model)
CREATE MODEL vl_model
INPUT (text_input STRING, image_input STRING)
OUTPUT (content STRING)
WITH (
  'provider' = 'openai-compat',
  'model' = 'qwen3.5-plus',
  'task' = 'chat/completions',
  'content-types' = 'text;image_url',
  'user-prompt' = 'Describe the image'
);

-- Call 1: Use default configuration
SELECT content FROM TABLE(ML_PREDICT(
  TABLE source_a, MODEL vl_model, DESCRIPTOR(text_input, image_input)
));

-- Call 2: Override user-prompt and column-level parameters
SELECT content FROM TABLE(ML_PREDICT(
  TABLE source_b, MODEL vl_model, DESCRIPTOR(text_input, image_input),
  MAP[
    'user-prompt', 'Answer in English',
    'image_input.min_pixels', '100',
    'image_input.max_pixels', '5000'
  ]
));

-- Call 3: Override content-types to change the type combination (treat both columns as text)
SELECT content FROM TABLE(ML_PREDICT(
  TABLE source_c, MODEL vl_model, DESCRIPTOR(text_input, image_input),
  MAP['content-types', 'text;text']
));

-- Call 4: Override content-types to change the type combination (reverse order)
SELECT content FROM TABLE(ML_PREDICT(
  TABLE source_c, MODEL vl_model, DESCRIPTOR(text_input, image_input),
  MAP['content-types', 'image_url;text']
));