面向企业 Agent 的数据基础设施

将多模态业务数据整理成带来源引用的可检索记录

用原生类型、SQL 和 Python UDF 处理文件、图像、音频与视频。保留业务 ID 和来源引用,再将文本与向量写入现有检索和分析系统。

复杂材料→可检索记录
原生文件类型 · SQL + Python · 向量与分析系统写入

杂乱材料

contract.pdfPDF
巡检照片图像
视频帧视频
通话音频音频
电子表格表格
系统日志日志
Vane

输出

Agent可用输出上下文已附加
上下文已附加
记录文本与模型输出
来源业务 ID · URI · 时间戳
向量用于检索与分析
问题

难点不只是调用模型,还在于保留完整的来源信息

如今这条链通常被拼接在 OCR 脚本、临时文件、模型调用、SQL 任务和审查工具之间。

之前 — 碎片化链路

杂乱材料↓
OCR 脚本↓
临时文件↓
LLM 调用↓
更多脚本↓
SQL 规则↓
人工审查

⚠ 系统分散 · 到处是 glue code · 来源引用丢失 · 难以调试 · 可复现性差

之后 — 一条流水线

杂乱材料↓VANE↓可检索记录文本 · 来源引用 · 向量
复杂材料→可检索记录
Vane 如何工作

从源文件到可检索记录,在一条数据流水线中完成

STEP 01

用 SQL 和 UDF 处理原生文件类型

原生文件类型媒体算子Python UDF
关系流水线

从 FILE、IMAGEFILE、AUDIOFILE 或 VIDEOFILE 引用开始,组合媒体算子、SQL 和 Python UDF;解析、OCR 和转写由你配置的库与模型完成。

STEP 02

把来源引用保留到最终结果里

模型输出
带来源引用的记录业务 ID · 来源 URI · 时间戳

在输出文本和向量时同时选择业务 ID、来源 URI 和片段时间戳。将模型分类与人工复核状态分开保存,便于下游用户核对原始材料。

STEP 03

写入现有检索与分析系统

文本与向量来源引用
Milvus · Qdrant · Doris

通过分布式 sink 向 Milvus、Qdrant 执行 upsert,或用 Arrow Stream Load 写入 Doris。按目标系统配置表结构、凭据和向量维度。

真实示例

客服录音 → Doris 中的可检索反馈

这段根据教程简化的 SQL 构造 FILE 和 AUDIOFILE 引用,调用教程中的转写 UDF,为带时间戳的片段生成向量。完整教程包含 Python UDF 注册、模型配置、候选分类和 DorisStreamLoadSink 写入。

客服录音
ticket_idformatsource_uri
T1024WAVT1024.wav
T1025WAVT1025.wav
T1026WAVT1026.wav
Vane · 一条流水线
1FILE → AUDIOFILE
2转写 UDF
3文本 → 向量
输出
片段文本
来源 URI 与时间戳
384 维向量
audio_segments.sql
-- Adapted excerpt: the tutorial registers transcribe_audio in prepare.py.
WITH recordings AS (
    SELECT regexp_extract(f.url, '([^/]+)[.]wav$', 1) AS ticket_id,
           audio_file(file(f.url, NULL, NULL, NULL, NULL)) AS audio
    FROM list_files('./recordings/*.wav') AS f
), transcripts AS (
    SELECT ticket_id, audio.url AS source_uri,
           transcribe_audio(audio) AS segments_json
    FROM recordings
), segments AS (
    SELECT ticket_id, source_uri,
           unnest(from_json(segments_json,
               '[{"segment_id":"INTEGER","text":"VARCHAR","start_ms":"BIGINT","end_ms":"BIGINT"}]'
           )) AS segment
    FROM transcripts
)
SELECT ticket_id, segment.segment_id AS segment_id,
       segment.text AS text, source_uri,
       segment.start_ms AS start_ms, segment.end_ms AS end_ms,
       ai_embed(
           segment.text, provider := 'transformers',
           model := 'sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2',
           dimensions := 384, on_error := 'raise',
           options := struct_pack(normalize := true, actor_number := 1, batch_size := 16)
       ) AS embedding
FROM segments
WHERE length(trim(segment.text)) > 0;

准备将多模态业务数据用于检索与分析?