
1. 从图文数据到跨模态搜索MaxCompute 多模态检索要解决的真实问题如果你手里已经有一批商品图文数据想做一个「以文搜图」或者「以图搜图」的检索功能传统做法通常是把数据拆成好几段原始图片放对象存储文本和标签放数据仓库Embedding 用外部脚本调模型生成向量再灌进一个独立的向量数据库检索结果还要回流到数仓做 Join 和过滤。这条链路能跑但每加一个模态就多一段维护成本模型换一次、索引重建一次就要来回对齐好几个系统的状态。MaxCompute 多模态检索想做的事情是把这条链路收回到一张表、一套 SQL 里。它提供了三个关键能力BLOB类型用来存图片、音频、视频这类非结构化对象VECTOR(FLOAT, dim)原生向量类型用来存 EmbeddingAI_EMBEDDING函数让你在 SQL 里直接完成向量化不用再单独起一个模型服务。检索侧用VECTOR_SEARCH配合距离函数做批量 TopK 召回结果可以直接和业务表 Join、过滤、聚合、回写。这套能力适合谁我总结下来是三类团队一是已经有 MaxCompute 数仓、每天跑离线批量任务的团队想把向量召回也纳入现有调度和权限体系二是做搜推广告候选集生产的团队需要周期性生成千万级相似召回三是做 RAG 语料治理的团队要处理 PB 级文档、OCR 文本、问答记录的向量化和去重。它的定位是离线批量、大规模、需要和业务数据深度结合的场景不是替代在线低延迟检索。下面我会从建表、向量化、索引、检索验证到排错完整走一遍可复现的链路中间会说明怎么通过 TaoToken 统一 Key 和 API 通道接入模型服务避免在多个模型供应商之间来回切换配置。2. 前置准备MaxCompute 环境与 TaoToken 统一模型通道2.1 MaxCompute 侧需要确认的几件事在动手建表之前先确认你的 MaxCompute 项目已经满足几个条件。第一项目需要开启新版数据类型支持因为VECTOR和BLOB属于较新的类型建表时要带上data.evolution.enable和table.format.version这两个 TBLPROPERTIES。第二确认你使用的 odpscmd 或 DataWorks 版本支持AI_EMBEDDING和VECTOR_SEARCH函数老版本客户端可能识别不了这些语法。第三如果你要存图片这类 BLOB 数据确认项目已经开通了对应的存储能力否则写入时会报类型不支持。我建议先在测试项目里跑通一条最小链路再往生产数据上迁移。因为向量维度和索引参数一旦定下来后面改起来要重建表成本不低。2.2 为什么用 TaoToken 统一接入模型服务AI_EMBEDDING函数在 SQL 里调用大模型完成向量化背后需要一个可访问的模型服务端点。实际项目里常见的麻烦是文本 Embedding 用一个供应商图片 Embedding 用另一个Key 分散在好几个地方换模型时要在多处改配置。TaoToken 提供的是统一的 Key 和 API 通道你可以用同一个 Key 访问不同的模型Base URL 统一指向https://taotoken.net/api模型 ID 按需切换。这样做的好处是MaxCompute 侧只需要维护一套连接配置模型迭代时改的是 Model ID 而不是整条链路。对于多模态场景尤其明显——文本和图片可能用不同模型但走同一个通道排查问题时不用先判断是哪个供应商出的错。你需要先拿到一个 API Key。登录 TaoToken 控制台在 API Keys 页面创建一个新 Key复制保存好。这个 Key 后面会用在 MaxCompute 的外部函数或连接配置里。如果你还没决定用哪个模型可以先到模型对话页面测一下文本和图片 Embedding 的效果确认维度和语义质量符合预期再接入。注意API Key 属于敏感凭证不要直接硬编码在会提交到代码仓库的脚本里。建议放在 MaxCompute 的项目级配置或密钥管理里脚本里通过变量引用。2.3 三件套Base URL、Key、Model ID不管你是通过外部函数还是自定义连接接入核心就是三件套要对齐配置项值说明Base URLhttps://taotoken.net/api统一 API 入口不加 UTMAPI Key控制台创建的 Key建议用项目变量引用Model ID按场景选择文本 Embedding 和图片 Embedding 可不同这三项配好之后AI_EMBEDDING调用才有稳定的后端。很多人卡在第一步就是因为 Base URL 写错或者 Key 权限不对后面会专门讲这类报错怎么排查。3. 可复制配置建表、向量索引与 AI_EMBEDDING 接入3.1 建一张同时容纳图文和向量的表先建基础表。这张表把结构化字段、图片 BLOB、文本向量、图片向量放在一起按天分区。这样每天产出的候选集可以按分区沉淀下游任务按分区消费。CREATE TABLE IF NOT EXISTS item_multimodal ( item_id STRING, title STRING, category STRING, brand STRING, price DECIMAL(10,2), stock_status STRING, image BLOB, text_embedding VECTOR(FLOAT, 128), image_embedding VECTOR(FLOAT, 512) ) PARTITIONED BY (dt STRING) TBLPROPERTIES ( data.evolution.enable true, table.format.version 2 );这里有两个点容易踩坑。一是VECTOR(FLOAT, 128)里的维度必须和你实际模型输出的维度一致文本模型输出 128 维就写 128图片模型输出 512 维就写 512写错了写入时会直接报维度不匹配。二是data.evolution.enable和table.format.version必须同时设置缺一个建表可能成功但后续写入 BLOB 或 VECTOR 会失败。3.2 用 AI_EMBEDDING 在 SQL 里完成向量化建好表之后把原始文本和图片写进去的同时生成向量。下面这段 SQL 演示了从源表读取标题和图片调用AI_EMBEDDING生成向量后写入目标表。INSERT OVERWRITE TABLE item_multimodal PARTITION (dt 2026-06-22) SELECT s.item_id, s.title, s.category, s.brand, s.price, s.stock_status, s.image, AI_EMBEDDING(text-embedding-model, s.title) AS text_embedding, AI_EMBEDDING(image-embedding-model, s.image) AS image_embedding FROM item_source s WHERE s.dt 2026-06-22;AI_EMBEDDING的第一个参数是模型标识第二个参数是要向量化的内容。文本直接传字符串图片传 BLOB 字段。模型标识对应 TaoToken 通道里可用的 Model ID你可以在控制台或文档里查到当前支持的模型列表。如果你用的是外部函数方式接入配置片段大致长这样核心是把 Base URL 和 Key 指向 TaoToken{ endpoint: https://taotoken.net/api, api_key: ${TAOTOKEN_API_KEY}, model_mapping: { text-embedding-model: your-text-embedding-model-id, image-embedding-model: your-image-embedding-model-id } }把这段配置放在项目的连接管理里脚本中通过${TAOTOKEN_API_KEY}引用避免明文泄露。Model ID 按你实际选用的模型填文本和图片可以指向不同模型。3.3 向量索引与 VECTOR_SEARCH 检索配置数据写进去之后检索用VECTOR_SEARCH。它的结构是base 子查询给出候选集并做标量过滤query 子查询给出查询向量然后指定向量列和 TopK。SELECT r.query_id, r.item_id, r.distance, i.category, i.brand, i.price FROM VECTOR_SEARCH( ( SELECT item_id, category, brand, price, text_embedding FROM item_multimodal WHERE dt 2026-06-22 AND category 3C数码 AND price BETWEEN 100 AND 500 AND stock_status on_sale ), text_embedding, ( SELECT query_id, query_embedding FROM query_embedding WHERE dt 2026-06-22 AND scene search_recall ), query_embedding, 50 ) r JOIN item_multimodal i ON r.item_id i.item_id AND i.dt 2026-06-22 ORDER BY r.query_id, r.distance ASC;这段 SQL 的关键在于标量过滤类目、价格、库存在 base 子查询里就完成了不是先召回十万条再过滤。这样候选集规模可控检索效率也更高。TopK 的 50 表示每个 query 取最相似的 50 条你可以按业务需要调整。如果你要做图文跨模态检索比如用文本 Query 搜图片就把 query 侧的向量换成文本 Embeddingbase 侧的向量列换成image_embedding前提是文本和图片的向量在同一个语义空间里——这要求你选用的文本模型和图片模型输出空间对齐或者用同一个多模态模型生成两种向量。4. 验证请求跑通一条图文检索链路并确认结果4.1 先验证向量化是否成功配置写完不要直接跑检索先确认向量真的写进去了。跑一条简单的查询SELECT item_id, title, SIZE(text_embedding) AS text_dim, SIZE(image_embedding) AS image_dim FROM item_multimodal WHERE dt 2026-06-22 LIMIT 10;如果text_dim和image_dim返回的是你建表时定义的维度说明向量化写入成功。如果返回 NULL说明AI_EMBEDDING调用失败但没抛错这时候要去查模型通道的连通性。如果报维度不匹配说明模型实际输出维度和建表定义不一致需要改表或换模型。4.2 验证检索请求返回合理结果向量确认没问题后跑第 3.3 节那段VECTOR_SEARCH。观察返回的distance字段距离越小表示越相似。你可以拿一个已知的 Query 去搜看返回的 item 是不是语义相关的。比如用「无线蓝牙耳机」去搜返回的标题里应该出现耳机、蓝牙、降噪这类词而不是完全不相关的商品。如果返回结果为空先检查 base 子查询的过滤条件是不是太严把category和price条件去掉再试。如果返回结果距离都很大且语义不相关可能是 Query 向量和 Base 向量不在同一空间检查两边用的模型是否一致。4.3 用 TaoToken 模型对话做交叉验证有时候检索结果不理想你分不清是向量化的问题还是检索逻辑的问题。这时候可以到 TaoToken 的模型对话页面把同样的文本丢给模型看它生成的向量语义是否符合预期。如果模型对话里文本相似度判断正常但检索结果不对那问题多半在索引或 SQL 逻辑上如果模型对话里就不对那要换模型或调整向量化方式。这一步看起来多余但实际排障时能帮你快速定位问题在哪一层省去反复改 SQL 的时间。5. 本篇常见错排查401、维度不匹配与检索为空5.1 报错 401 Unauthorized这是接入模型服务时最常见的报错说明 Key 没通过校验。排查顺序第一确认 API Key 复制完整没有多余空格第二确认 Base URL 是https://taotoken.net/api不要多加路径或斜杠第三确认 Key 在控制台里是启用状态没有过期或被禁用第四如果 Key 放在项目变量里确认变量名和脚本里引用的一致。如果确认以上都没问题还是 401到 TaoToken 控制台的 API Keys 页面重新生成一个 Key 再试排除是 Key 本身的问题。5.2 报错 local proxy failed 或连接超时这个报错通常出现在 MaxCompute 作业访问外部模型服务时。先确认你的 MaxCompute 项目所在网络区域能访问外部 HTTPS 端点。如果项目配置了网络限制需要在项目级别放行taotoken.net域名。另外确认没有在脚本里错误地配置了本地代理地址MaxCompute 作业运行在服务端本地代理配置不会生效反而会导致连接失败。5.3 报错 reading choices 或返回结构解析失败这类报错说明请求发出去了但返回的 JSON 结构和预期不一致。常见原因是 Model ID 写错了请求打到了不支持的模型上返回了错误结构。检查你配置的 Model ID 是否在 TaoToken 支持的模型列表里文本模型和图片模型不要混用。另外确认请求参数里的字段名和模型要求的一致比如有些模型要求input字段有些要求messages字段。5.4 检索结果为空或距离异常如果VECTOR_SEARCH返回空按这个顺序查base 子查询的过滤条件是否把所有数据都排除了query 子查询是否有数据向量列是否真的非空。如果距离值异常大比如都是几百上千检查两边向量是否归一化以及是否用了正确的距离函数。cosine_distance适合语义相似度l2_distance适合欧氏距离场景选错了会导致排序不符合预期。5.5 OAuth 或鉴权相关报错如果你用的是需要 OAuth 流程的接入方式报错里出现 OAuth 字样说明 token 获取环节有问题。确认你的接入方式是否真的需要 OAuth大部分场景用 API Key 就够了。如果确实需要检查 client_id、client_secret 和回调地址是否配置正确。这类问题在 MaxCompute 外部函数接入里相对少见多数是 Key 方式直接调用。6. 把链路固化下来调度、权限与后续迭代链路跑通之后下一步是把它变成每天可重复执行的任务。在 DataWorks 里把向量化写入和检索 SQL 分别做成节点设置好依赖关系和调度周期。向量化节点产出当天的item_multimodal分区检索节点消费这个分区生成候选集再写入下游表。权限方面把模型服务的 Key 放在项目级配置里通过变量引用不要写在每个节点的脚本里。这样换 Key 或换模型时只改一处。血缘方面MaxCompute 的表、分区、SQL 任务本身就在血缘体系里检索结果表的下游消费链路可以正常追踪不需要额外维护。后续迭代时如果换 Embedding 模型注意新模型的输出维度可能和旧模型不同需要重建表或新增向量列。如果只是换模型但维度一致直接改 Model ID 重新跑向量化即可。索引参数如果调整也要重新生成向量数据。这套链路的价值在于它把原本分散在多个系统的向量化、检索、过滤、回写收回到一套 SQL 和一套调度里。你少维护几段脚本少搬几次数据模型迭代时也少对齐几个系统的状态。对于已经有 MaxCompute 数仓的团队来说这是把向量能力纳入现有数据生产链路的一条务实路径。如果你还没开始接入模型服务可以先到 TaoToken 的接入文档了解 Base URL 和 Key 的配置方式再到 API Keys 页面创建一个 Key然后按本文第 3 节的配置跑通第一条链路。跑通之后你会发现图文跨模态检索这件事比想象中少了很多跨系统拼装的麻烦。