多模态函数使用最佳实践

更新时间:
复制为 MD 格式

本文介绍EMR Serverless Sparkai_queryai_embedding_multimodal函数的多模态用法,主要用于图片理解和图片向量生成场景。

适用版本

当前仅支持Spark 3.5.2版本,需要使用Serverless Spark esr-4.7.0及以上版本。

重要

多模态函数及相关模型服务仅在特定地域(Region)支持,请确认您的集群所在地域已开通相关服务。

函数签名

ai_query

ai_query函数用于调用大语言模型进行推理,支持传入图片数据实现多模态理解。函数签名如下:

ai_query(prompt [, service_name] [, options][, data][, data_type])

参数说明:

参数

是否必填

说明

prompt

发送给模型的完整提示词(Prompt),应包含上下文、指令和输入数据。建议明确指定输出格式以提升稳定性。

service_name

指定要调用的模型服务名称。若省略,则使用默认模型qwen3.6-plus。也可通过模型服务注册的模型服务名称,请参见模型服务注册与调用。

options

JSON字符串形式提供额外调用参数,用于控制生成行为。支持调整的参数详见option参数说明。

data

需要处理的图片数据列。仅在处理图片数据时需要填写此参数。可以是BINARY类型的图片数据或图片的 http(s) 地址,或STRING类型的图片文件路径列。

data_type

指定图片数据的传入方式。仅在处理图片数据时需要设置此参数。支持的参数值如下:

  • binary(默认):传入二进制图片或二进制图片的 http(s) 地址,data参数为BINARY类型列。

  • uri:传入文件路径,由函数内部读取文件,data参数为STRING类型列。

命名参数调用示例:

ai_query(
  '提示词',
  service_name => '模型服务名',
  options => '{"temperature":0.1}',
  data => image_col,
  data_type => 'binary'
)

支持的命名参数:service_nameoptionsdatadata_type

ai_embedding_multimodal

说明

仅下述地域支持使用该AI Function:北京、上海、杭州、深圳、乌兰察布、成都、张家口。

ai_embedding_multimodal函数用于生成图片的embedding向量,可用于后续的相似度计算、检索等场景。函数签名如下:

ai_embedding_multimodal(data [, service_name] [, options] [, data_type])

参数说明:

参数

是否必填

说明

data

需要生成embedding的图片数据列。可以是BINARY类型的图片数据或图片的 http(s) 地址,或STRING类型的图片文件路径列。

service_name

指定要调用的embedding模型服务名称。若省略,则使用默认模型tongyi-embedding-vision-plus。也可通过模型服务注册的模型服务名称,请参见模型服务注册与调用。

options

JSON字符串形式提供额外调用参数,用于控制生成行为。支持的参数取决于目标embedding服务本身。

data_type

指定图片数据的传入方式。仅在处理图片数据时需要设置此参数。支持的参数值如下:

  • binary(默认):传入二进制图片或二进制图片的 http(s) 地址,data参数为BINARY类型列。

  • uri:传入文件路径,由函数内部读取文件,data参数为STRING类型列。

命名参数调用示例:

ai_embedding_multimodal(
  image_col,
  service_name => 'tongyi-embedding-vision-plus',
  options => '{"dim":1024}',
  data_type => 'binary'
)

支持的命名参数:service_nameoptionsdata_type

说明

ai_query属于chat类型请求,当前默认行为如下:

  • 如果用户没有在options中传enable_thinking,系统会默认补上{"enable_thinking": false}

  • 如果用户显式传了enable_thinking,则以用户配置为准。

例如,以下两种写法等价,都会关闭thinking:

-- 写法一:不传 options,默认关闭 thinking
SELECT ai_query('描述图片内容', data => content) FROM image_table;

-- 写法二:显式关闭 thinking
SELECT ai_query(
  '描述图片内容',
  data => content,
  options => '{"enable_thinking": false}'
) FROM image_table;

如果确实需要打开thinking,需要显式传入:

SELECT ai_query(
  '描述图片内容',
  data => content,
  options => '{"enable_thinking": true}'
) FROM image_table;
说明

ai_embedding_multimodal不属于chat请求,是否支持某个options字段取决于目标embedding服务本身。

使用场景

场景一:基于图片路径进行多模态数据处理

当图片存储在OSS、HDFS或其他Hadoop兼容文件系统中,表中只保存图片路径时,可通过URI模式让函数内部读取文件内容。

示例:通过图片路径识别图片中的车牌号。

SELECT
  path,
  ai_query(
    '返回图中车牌号。IMPORTANT:只回复车牌信息;如果图片模糊无法辨认,回复''无法识别''。',
    service_name => 'qwen3.5-plus',
    data => path,
    data_type => 'uri'
  ) AS plate_number
FROM (
  SELECT /*+ REPARTITION(10) */ path
  FROM ccpd_1m_1000
) t;
说明
  • data => path传入的是路径列,data_type => 'uri'表示函数内部按路径读取文件。

  • 分区数建议在内层子查询中通过REPARTITION hint控制,而不是直接写在包含AI函数的外层投影上。

  • 如果不传options.enable_thinking,默认为false

如需显式控制thinking配置,可通过options参数设置:

SELECT
  path,
  ai_query(
    '返回图中车牌号。IMPORTANT:只回复车牌信息;如果图片模糊无法辨认,回复''无法识别''。',
    service_name => 'qwen3.5-plus',
    data => path,
    data_type => 'uri',
    options => '{"enable_thinking": false}'
  ) AS plate_number
FROM (
  SELECT /*+ REPARTITION(10) */ path
  FROM ccpd_1m_1000
) t;

场景二:基于图片二进制进行多模态数据处理

当需要直接从目录批量读取图片内容时,可使用read_files函数读取图片文件,将返回的content列(BINARY类型)作为多模态输入。

示例:从OSS目录批量读取图片并识别车牌号。

SELECT
  path,
  ai_query(
    '返回图中车牌号。IMPORTANT:只回复车牌信息。',
    service_name => 'qwen3.5-plus',
    data => content
  ) AS plate_number
FROM read_files(
  'oss://bucket/path/to/images/',
  suffix => 'jpg,jpeg,png'
);
说明
  • read_files返回pathcontentmodificationTimelength四个字段,其中contentBINARY类型,可直接传给data参数。

  • 此场景使用默认的data_type => 'binary',无需显式指定。

  • suffix为逗号分隔的后缀列表,大小写不敏感,jpg.jpg均可。

  • read_files默认不递归子目录;如需递归读取,传入recursive => true

  • read_files一般不需要额外手动REPARTITION,扫描分区粒度建议通过spark.sql.files.maxPartitionBytes参数控制。

场景三:生成图片Embedding向量

使用ai_embedding_multimodal函数可以将图片转换为embedding向量,用于后续的相似度检索、聚类分析等场景。支持URI模式和Binary模式两种方式。

方式一:通过图片路径生成embedding(URI模式)。

SELECT
  path,
  ai_embedding_multimodal(
    path,
    service_name => 'tongyi-embedding-vision-plus',
    data_type => 'uri'
  ) AS embedding
FROM image_paths_table;

方式二:通过图片二进制内容生成embedding(Binary模式)。

SELECT
  path,
  ai_embedding_multimodal(
    content,
    service_name => 'tongyi-embedding-vision-plus'
  ) AS embedding
FROM read_files(
  'oss://bucket/path/to/images/',
  suffix => 'jpg,png'
);

read_files使用说明

read_files函数用于从文件系统中批量读取文件内容,常与多模态函数配合使用。函数签名如下:

read_files(path [, suffix] [, recursive])

参数说明:

参数

是否必填

说明

path

目录或单个文件路径。

suffix

逗号分隔的文件后缀列表,例如'jpg,png''.jpg,.png',大小写不敏感。

recursive

BOOLEAN类型,是否递归读取子目录,默认false

返回列:

列名

类型

说明

path

STRING

文件完整路径。

content

BINARY

文件二进制内容。

modificationTime

TIMESTAMP

文件修改时间。

length

BIGINT

文件大小(字节)。

使用示例:

-- 读取目录下所有文件
SELECT * FROM read_files('oss://bucket/images/');

-- 按后缀过滤
SELECT path, content, length
FROM read_files('oss://bucket/images/', suffix => 'jpg,jpeg,png');

-- 递归读取子目录
SELECT path, content
FROM read_files(
  'oss://bucket/images/',
  suffix => 'jpg,png',
  recursive => true
);
说明
  • read_files只支持命名参数suffixrecursive

  • suffix过滤会下推到文件扫描阶段,避免先读取目录中的其他大文件。

  • read_files当前不支持formatHint参数。

使用示例

以下是一个完整的SQL使用示例,演示如何通过创建临时视图控制分区后调用多模态函数:

CREATE OR REPLACE TEMPORARY VIEW car_images AS
SELECT /*+ REPARTITION(8) */ path
FROM ccpd_1m_1000;

SELECT
  path,
  ai_query(
    '返回图中车牌号。IMPORTANT:只回复车牌信息;如果图片模糊无法辨认,回复''无法识别''。',
    service_name => 'qwen3.5-plus',
    data => path,
    data_type => 'uri'
  ) AS plate_number
FROM car_images
LIMIT 20;

常见错误

错误信息

原因

解决方案

Unsupported image format

图片格式不支持。

优先使用JPEG、PNG、WebP等常见格式,确认目标模型服务支持对应MIME类型。

Binary data is too short

文件内容不完整或不是有效图片。

检查源文件是否损坏,确认content列确实是图片二进制内容。

no model service found

service_name未配置或配置错误。

检查模型服务名是否存在,或确认默认模型服务配置正确。

data parameter with data_type='binary' must be a BINARY column or an image URL

data_type='binary'但传入了普通字符串列。

路径列请改用data_type => 'uri',二进制列才使用默认binary

性能优化建议

路径表场景使用内层子查询控制分区数

推荐把REPARTITION hint放到内层子查询,再在外层执行AI函数。也可以使用CTECREATE TEMPORARY VIEW的方式:

-- 方式一:子查询
SELECT
  path,
  ai_query('请描述图片内容', service_name => 'qwen3.5-plus', data => path, data_type => 'uri') AS result
FROM (
  SELECT /*+ REPARTITION(32) */ path FROM large_image_dataset
) t;

-- 方式二:CTE
WITH car_images AS (
  SELECT /*+ REPARTITION(32) */ path FROM ccpd_1m_1000
)
SELECT
  path,
  ai_query('请描述图片内容', service_name => 'qwen3.5-plus', data => path, data_type => 'uri') AS result
FROM car_images;

-- 方式三:临时视图
CREATE OR REPLACE TEMPORARY VIEW car_images AS
SELECT /*+ REPARTITION(32) */ path FROM ccpd_1m_1000;

SELECT
  path,
  ai_query('请描述图片内容', service_name => 'qwen3.5-plus', data => path, data_type => 'uri') AS result
FROM car_images;

read_files场景优先用文件扫描参数控制并行度

read_files直接扫描目录时,通常不需要先手动REPARTITION。如果希望提高并行度或减小单个输入分区大小,优先调整spark.sql.files.maxPartitionBytes

SET spark.sql.files.maxPartitionBytes = 134217728;

读取时提前做后缀过滤

通过suffix参数过滤文件类型,可以减少无关文件扫描和下游AI请求量。需要递归读取子目录时,再显式加上recursive => true

SELECT path, content
FROM read_files('oss://bucket/images/', suffix => 'jpg,jpeg,png');

支持的图片格式

格式

MIME Type

魔数检测

JPEG

image/jpeg

FF D8 FF

PNG

image/png

89 50 4E 47

GIF

image/gif

47 49 46 38

WebP

image/webp

RIFF....WEBP

BMP

image/bmp

42 4D

TIFF

image/tiff

49 49 2A 00 / 4D 4D 00 2A

ICO

image/x-icon

00 00 01 00

AVIF

image/avif

....ftypavif

HEIF

image/heif

....ftypheic