AI图鉴

AI图鉴首页 › AI 资讯 › Apache Doris + Vane:让多模态数据进入业务分析

Apache Doris + Vane:让多模态数据进入业务分析

来源:掘金 · 发布时间:10-29 · 由 AI图鉴每小时自动聚合

订单、工单和生产批次已经进入数据库,但客户对产品的很多具体反馈,仍然存在客服录音、文字记录和附件中。 当团队想知道“还有哪些客户遇到了类似问题?这些反馈分别对应哪些生产批次?”时,通常需要先听录音、整

订单、工单和生产批次已经进入数据库,但客户对产品的很多具体反馈,仍然存在客服录音、文字记录和附件中。

当团队想知道“还有哪些客户遇到了类似问题?这些反馈分别对应哪些生产批次?”时,通常需要先听录音、整理问题描述,再回到业务系统逐一核对。不同类型的数据虽然都已经存在,但还很难直接放在一起查询和分析。

Apache Doris 与 Vane 将这两类数据连接起来:Vane 将录音、图片、视频等多模态内容加工为文本、候选分类和向量;Doris 则将这些加工结果纳入已有业务数据体系,与订单、工单、生产批次等数据关联,让同一批内容既能用于相似案例检索,也能继续参与业务分析,并保留回到原始材料核查的线索。

Apache Doris:让多模态数据进入企业数据体系

企业里的 AI 检索,通常不只是“找到意思相近的内容”。真实的业务查询往往还带着明确的条件,例如产品型号、时间范围、设备类型,以及需要进一步核查的订单、工单和生产批次。

使用 Doris 承载业务数据,并在 Doris 中完成文本和向量检索,可以让这些业务条件与 AI 检索在同一套 SQL 查询中完成。

- 先用业务条件缩小范围,再查找相似内容。例如,要查找“X1 型号最近一个月无法启动的反馈”,可以先限定产品型号和时间范围,再通过向量检索找到“按开关没反应”“通电后没有动静”等不同表述;如果还需要排查某个故障码,也可以同时加入文本匹配条件。业务条件负责确定查询范围,文本和向量检索则帮助找到相关内容。

- 找到反馈后,还可以继续关联和分析。检索结果可以继续通过工单关联订单和生产批次,回答“这些相似反馈来自哪些客户、对应哪些批次”。在明确复核状态、统计范围和去重口径后,还可以进一步分析不同生产批次的问题工单分布及其随时间的变化,为质量排查提供依据。

- 已有的业务数据和 SQL 工作方式可以继续复用。检索、关联和分析都可以在同一套数据体系中完成,减少向另一套检索系统复制业务字段、同步数据,以及在应用代码中拼接查询结果的工作。数据团队也可以继续使用熟悉的 SQL 完成过滤、关联和聚合,让新增的多模态数据接入已有的分析流程。

Apache Doris 将 AI 检索与业务数据分析放在同一套数据体系中,让“找到相关内容”之后,还能继续完成业务追溯和分析。

Doris + Vane:企业数据进入 AI 的完整链路

一份文件成为 AI 资产,需要经过从原始内容到可用数据的加工:文档解析与切分、录音转写、视频抽帧,再提取业务信息、生成向量。例如,售后录音经过处理,可以形成带有工单号、反馈片段、候选故障类别和向量的数据记录,并保留原始录音地址与时间位置,支持后续检索、关联分析和回溯核验。

这条链路需要组织多步计算。文件大小和处理成本各不相同,一个输入可能展开为大量片段;读取、解析与模型推理的速度也不一致。用 Python 脚本跑通之后,团队还需持续维护批次、并发、模型复用和失败处理。

Vane 将 SQL、Python UDF 与 AI Function 组织在同一条数据流中,让业务标识、来源和处理结果在加工过程中保持关联,并协调数据读取、解码、模型推理和结果处理。

加工完成后,文档、图片、音频和视频被转换为文本、结构化字段和向量,并写入 Doris,与订单、工单、客户、生产批次等业务数据汇合。

下面以设备售后录音为例,看看一段录音如何逐步变成可以进入业务查询的数据。代码主要节选自Vane + Doris 客服录音检索教程。

从售后录音到业务分析:Doris + Vane 实践

以下按“Doris 建表 → Vane 加工并写入 → Doris 查询与分析”的顺序展开。

在 Doris 中准备数据表与索引

首先在 Doris SQL 客户端中创建目标表。feedback_segments 按录音片段保存文本、候选分类、384 维向量和来源位置,同时保留工单、型号与日期。文本倒排索引供关键词过滤使用,ANN 索引为后续近似向量检索准备。

-- 在 Doris 中执行:创建按录音片段存储的结果表。

CREATE TABLE vane_support_demo.feedback_segments (

ticket_id VARCHAR(64) NOT NULL,

segment_id INT NOT NULL,

-- 型号和日期用于限定业务查询范围。

product_model VARCHAR(64),

event_date INT,

-- 保存转写文本、AI 候选分类和独立的复核状态;入库时状态为 pending。

text STRING,

fault_category VARCHAR(64),

review_status VARCHAR(32),

-- 原始录音路径与片段起止时间(毫秒),用于检索后回听核查。

source_uri STRING,

start_ms BIGINT,

end_ms BIGINT,

embedding ARRAY<FLOAT> NOT NULL, -- 与 ai_embed 的 384 维输出对应。

-- 倒排索引用于文本过滤

INDEX idx_text(text) USING INVERTED PROPERTIES("parser" = "chinese"),

-- HNSW 使用 L2 距离;索引维度必须与模型输出、写入配置一致。

INDEX idx_embedding(embedding) USING ANN PROPERTIES(

"index_type" = "hnsw", "metric_type" = "l2_distance", "dim" = "384"

)

) ENGINE=OLAP

DUPLICATE KEY(ticket_id, segment_id)

DISTRIBUTED BY HASH(ticket_id) BUCKETS 1

PROPERTIES("replication_num" = "1");

再准备业务关联表:ticket_orders 记录工单与订单的关系,orders 记录订单所属的生产批次。这里沿用教程的演示数据,假定一个工单对应一个订单、一个订单对应一个批次;实际应用中可对接 Doris 中已有的业务表。

用 Vane 将录音加工为可检索的数据

接入录音,关联工单信息

首先,录音和工单信息作为 Pipeline 的输入。Vane 可以直接管理文件引用,并将文件与工单、产品型号等业务元数据放在同一条数据流中:

-- 在 Vane 中执行:将文件引用和工单元数据组成同一条记录。

WITH files AS (

SELECT

ticket_id,

product_model,

event_date,

-- FILE 保存文件引用,再转换为转写 UDF 接收的 AUDIOFILE。

audio_file(

file(f.url, NULL, NULL, NULL, NULL)

) AS audio

-- 枚举录音文件;真正读取音频内容由后续转写步骤完成。

FROM list_files('./recordings/*.wav') AS f

-- 工单清单提供型号和日期;ticket_id 应唯一。

JOIN read_csv('tickets.csv', header = true) AS t

-- 从 T1024.wav 提取 T1024,与工单 ID 匹配;未匹配文件不会进入结果。

ON regexp_extract(f.url, '([^/]+).wav$', 1) = t.ticket_id

)

SELECT

ticket_id,

product_model,

event_date,

audio

FROM files;

这里原始文件从一开始就带着业务上下文进入处理链路。后面的转写、抽取和向量化,都可以沿着这条数据流继续处理。

转写录音,保留片段与时间位置

对于录音,转写阶段不仅生成文本,还可以保留片段的时间位置。这样,后续检索到一条反馈时,仍然能够定位回原始录音:

# 在 Vane 中定义批处理 UDF。

@vane.cls.batch(actor_number=1, gpus=0, return_dtype="VARCHAR")

class SpeechRecognizer:

# 每个 Actor 初始化时加载模型,后续批次复用同一实例。

def __init__(self, model_name):

from faster_whisper import WhisperModel

self.model = WhisperModel(

model_name,

device="cpu",

compute_type="int8"

)

# 输入为一批 AUDIOFILE;完整实现返回与输入行数一致的 JSON 文本数组。

def __call__(self, audios):

# 对一批 AUDIOFILE 进行转写,

# 同时保留每个片段的起止时间。

# JSON 中包含片段编号、文本和毫秒级起止时间,后续 SQL 展开为片段行。

# 此处省略实现与注册,完整代码见教程。

...

提取候选故障类别,生成文本向量

转写结果随后可以继续作为 SQL 数据参与处理。例如,从文本中提取候选故障类别:

提示词约束 JSON 字段和类别范围,并要求对证据不足的描述保留不确定性:

-- 在 Vane 中执行;segments 来自前序转写和片段展开步骤。

SELECT

ticket_id,

segment_id,

text,

-- 对每个片段提取候选类别,限制 JSON 字段与枚举范围。

ai_prompt(

'仅根据下面的售后录音片段提取故障类别。'

|| '只返回 JSON 对象,键为 fault_category;'

|| '值只能是:无法启动、正常咨询、其他故障、待确认。'

|| '不要把否定、假设或维修后已恢复的描述当作已确认故障;'

|| '证据不足填待确认。片段:' || text,

provider := 'openai',

model := '...', -- 替换为账号可用的文本模型 ID

-- 模型调用出错时抛出异常,避免将调用失败当作有效分类。

on_error := 'raise'

) AS fault_json

FROM segments;

分类结果经 JSON 格式校验和类别归一后入库,仍属于待复核的候选标签;校验不通过或类别不在枚举内时归为“待确认”。

同一段文本还可以在 Vane 中生成向量:

-- Vane 中的 SELECT 表达式节选:对转写原文生成语义向量。

ai_embed(

text,

-- 使用 Transformers 模型;新查询文本也应使用相同模型和处理方式。

provider := 'transformers',

model := 'sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2',

-- 与 Doris 向量列的写入约束和 ANN 索引 dim 保持一致。

dimensions := 384,

-- 对向量做归一化,入库与查询端需保持相同配置。

options := struct_pack(normalize := true)

) AS embedding

到这里,一段录音已经从一个原始文件变成了一组可以进入 Doris 的字段:文本、候选分类、向量,以及能够定位原始内容的来源和时间位置。

将加工结果写入 Doris

接下来由 Vane 通过 DorisStreamLoadSink 调用 Doris Stream Load,将加工结果写入 Doris。写入内容包括文本、候选分类、审核状态、向量,以及工单标识、原始文件路径和片段起止时间。至此,Vane 完成加工与写入,后续查询在 Doris 中执行。

用 Doris 检索反馈、追溯业务并分析问题分布

下面的 SQL 均在 Doris SQL 客户端中执行。

结合业务条件,检索相似反馈

检索相似反馈。先查看工单 T1024 的第一个非空片段,再复用它的向量,在 X1 型号、2026 年 9 月的范围内查找其他工单的相似反馈。查询返回样本文本,便于判断比较的内容是否符合预期。

-- 先检查作为查询样本的片段;下方检索使用相同的选择条件。

SELECT ticket_id, segment_id, text

FROM vane_support_demo.feedback_segments

WHERE ticket_id = 'T1024'

AND length(trim(text)) > 0

ORDER BY segment_id

LIMIT 1;

-- 以 T1024 的第一个非空片段为样本,寻找其他工单的相似反馈。

-- LIMIT 1 使查询样本最多一行;直接复用已有向量,无需再次调用模型。

WITH query_feedback AS (

SELECT ticket_id, segment_id, text, embedding

FROM vane_support_demo.feedback_segments

WHERE ticket_id = 'T1024'

AND length(trim(text)) > 0

ORDER BY segment_id

LIMIT 1

)

-- 同时返回样本文本和候选文本,便于核查实际比较的内容。

SELECT q.ticket_id AS query_ticket_id,

q.segment_id AS query_segment_id,

q.text AS query_text,

f.ticket_id, f.segment_id, f.text, f.fault_category,

f.source_uri, f.start_ms, f.end_ms,

-- 比较候选向量与样本向量,L2 距离越小越相似。

l2_distance_approximate(f.embedding, q.embedding) AS distance

FROM vane_support_demo.feedback_segments f

CROSS JOIN query_feedback q

-- 仅在指定型号和日期范围内寻找相似反馈。

WHERE f.product_model = 'X1'

AND f.event_date >= 20260901 AND f.event_date < 20261001

-- 排除样本工单的全部片段,避免把自身反馈作为相似案例。

AND f.ticket_id <> q.ticket_id

-- 优先按距离排序;距离相同时按工单和片段编号排序。

ORDER BY distance ASC, f.ticket_id, f.segment_id

-- 最多返回 3 个片段,同一工单可出现多次;相似度不代表故障已确认。

LIMIT 3;

距离越小表示向量越接近;查询最多返回 3 个片段,同一工单可能出现多个片段。若还要求原文包含“指示灯”,可在检索 SQL 的 WHERE 条件末尾、ORDER BY 之前增加 AND f.text MATCH_ANY '指示灯',组合文本匹配与向量排序。

关联订单与生产批次,追溯反馈来源

关联订单与生产批次。查询从录音片段表出发,通过工单关联订单,再找到对应的生产批次。使用 LEFT JOIN 保留尚未匹配到业务关系的反馈,方便检查数据完整性。

-- 将录音片段关联到订单和生产批次;保留未匹配的记录以便检查。

SELECT f.ticket_id, f.segment_id, f.text, f.fault_category,

t.order_id, o.production_batch,

-- 保留原始录音位置,便于从业务记录回到证据片段。

f.source_uri, f.start_ms, f.end_ms

FROM vane_support_demo.feedback_segments f

-- 通过工单 ID 找到订单;LEFT JOIN 保留未匹配记录,相应字段为 NULL。

LEFT JOIN vane_support_demo.ticket_orders t ON f.ticket_id = t.ticket_id

-- 再通过订单 ID 找到生产批次;教程假定一个订单对应一个批次。

LEFT JOIN vane_support_demo.orders o ON t.order_id = o.order_id

-- 查询指定业务范围内的所有片段

WHERE f.product_model = 'X1'

AND f.event_date >= 20260901 AND f.event_date < 20261001

ORDER BY f.ticket_id, f.segment_id;

按演示数据,T1024 和 T1025 分别关联 O9001、O9002,均属于 B202608;T1026 关联 O9003,属于 B202609。这些关系来自业务表。查询同时保留原始文件路径和毫秒级时间位置,供回听核查;source_uri 是来源路径。

按批次汇总候选工单,辅助质量排查

按生产批次分析候选工单分布。下面从整张片段表中筛选 X1 型号在 2026 年 9 月被 AI 分类为“无法启动”的记录,按工单去重后关联批次并计数。统计范围独立于前面的 Top-3 检索结果,用于为人工排查提供批次维度的线索。

-- 统计:按批次汇总 AI 分类为“无法启动”的候选工单。

WITH candidate_tickets AS (

-- 一个工单可有多个命中片段,先去重为工单集合。

SELECT DISTINCT ticket_id

FROM vane_support_demo.feedback_segments

WHERE product_model = 'X1'

AND event_date >= 20260901 AND event_date < 20261001

-- 至少一个片段被 AI 标为“无法启动”即进入候选集,不要求已人工确认。

AND fault_category = '无法启动'

)

-- 未找到批次的工单单独成组,避免在统计中悄悄丢失。

SELECT COALESCE(o.production_batch, '未关联到批次') AS production_batch,

-- 按工单 ID 去重计数,统计的是候选工单数,不是片段数或故障率。

COUNT(DISTINCT f.ticket_id) AS candidate_ticket_count

FROM candidate_tickets f

-- 沿“工单 → 订单 → 生产批次”的业务关系补齐统计维度。

LEFT JOIN vane_support_demo.ticket_orders t ON f.ticket_id = t.ticket_id

LEFT JOIN vane_support_demo.orders o ON t.order_id = o.order_id

-- 按批次汇总,优先展示候选工单较多的批次,供后续人工排查。

GROUP BY COALESCE(o.production_batch, '未关联到批次')

ORDER BY candidate_ticket_count DESC, production_batch;

candidate_ticket_count 表示至少有一个片段被 AI 分类为“无法启动”的候选工单数;没有该类别时返回空集。

这条链路中,Vane 将录音加工成可入库的数据,Doris 将加工结果与工单、订单和生产批次连接起来。从相似反馈检索,到业务关系追溯,再到按批次汇总候选问题,多模态信息由此进入同一套 SQL 查询与分析流程。

某制造企业 Doris + Vane 场景实践

某制造企业以 Doris 作为统一实时数据分析底座,汇集生产、质检、设备与售后数据,支撑产线监控、良率分析、批次追溯和故障统计等场景。随着 AI 需求深入业务,企业需要进一步将图片、文档和录音纳入现有数据体系。Doris 在已有实时分析能力之上,引入全文与向量检索能力,进一步承载企业 AI 场景中的多模态数据检索与分析。同时结合 Vane 作为多模态数据加工引擎,实现多个 AI 场景的落地。

工艺异常分析:让良率波动关联历史改善经验

企业在 Doris 中汇集了工艺参数、测试结果、设备状态及批次信息,实时分析良率趋势,并按工序、设备和班次下钻。当某工序良率下降时,工程师还需要查阅历史异常报告、8D 报告和试验记录,寻找类似问题及有效的改善措施。

使用 Vane 解析这些文档,提取异常现象、参数条件、改善措施与验证结论,生成文本向量,并保留业务标识、文档版本和页码。加工结果写入 Doris 后,可结合产品、工序等条件,通过关键词与向量混合检索查找相似案例,再关联当前批次的参数分布、历史试验和改善前后指标。

由此,实时分析发现的异常可以直接连接历史处理经验。AI 根据业务数据与文档证据提出排查建议,工程师通过试验验证原因和措施,减少跨系统查资料、核对参数的工作,缩短异常排查过程。

售后质量分析:让客户描述关联产品运行与制造数据

企业利用 Doris 分析售后工单、产品故障码、运行记录和生产批次,开展故障统计与产品追溯。随着 AI 深入售后业务,录音、文字和照片中的客户描述也需要参与分析:例如“充不进去电”和“充电到一半就停”,需要结合实际运行情况判断是否属于同类问题。

使用 Vane 转写录音、解析附件,提取故障现象和候选类别,生成向量,并保留工单号、原图或录音时间位置。Doris 结合型号、时间和故障关键词开展混合检索,再将相似反馈与产品运行记录、维修结果及生产批次关联,按工单或产品去重统计问题分布。

客户反馈由此进入已有的质量分析体系。业务人员既能回看原始证据,也能判断相似问题是否集中于特定批次或运行条件,帮助更早发现集中性质量问题,缩短从客户描述到生产追溯和影响范围排查的路径。

总结

多模态 AI 的价值,不只是把录音、图片和视频“搜出来”,而是让其中的信息能够与客户、订单、工单和生产批次关联起来,进一步参与业务分析。

Vane 让原始内容变得可计算,Doris 让这些内容进入业务。从一个具体场景开始,把一类多模态数据接入现有数据体系,就可以逐步建立从内容理解、语义检索到业务分析的完整链路。

与其让更多数据继续留在文件里,不如先让它成为可以被检索、关联和分析的数据。欢迎从一类真实数据开始,探索 Apache Doris 与 Vane 的组合。你可以跟随双方联合实践中的客服录音检索教程复现本文场景,并进一步了解 Apache Doris 在全文检索、向量检索和多模态数据分析方面的能力。

本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。

相关 AI 工具

相关免费羊毛

同源资讯

阅读原文(juejin.cn)

标题、摘要与正文均来自该信源的公开页面,版权归原作者所有;本站自动聚合与翻译,仅作出处跳转。

← 返回 AI 资讯列表AI工具图鉴首页

返回 AI图鉴首页 · 提交工具 · 商务合作 · 关于本站 · 598 款 AI 工具分类导航 · 每日 AI 热门项目与动态