PAYATHON 2026

如何在 Huggingface 中不保存文件就向多模态聊天机器人传递数据?

技术老齐

可以。使用本地 Hugging Face Transformers 推理时,可以直接把内存中的图片对象、音频波形或视频帧传给模型的 processor,无须先保存成媒体文件。支持哪些数据类型、使用什么参数,取决于模型、processor 和 Transformers 版本。

调用远程推理 API 时,则需要按服务端协议传输数据,不能直接发送 Python 对象。

为什么示例中经常使用路径或 URL?

路径和 URL 便于演示媒体数据的获取过程。processor 仍需对媒体内容进行解码和预处理,再转换成模型需要的张量。多模态聊天模板和媒体预处理通常由 AutoProcessor 加载的 processor 负责。官方多模态聊天文档

数据已经在内存中时,可以采用两种方式:

  • 如果 processor 支持从 messages 中读取媒体对象,就直接填入对象。
  • 先生成聊天提示词,再通过 processor 的媒体参数传入实际数据。

部分模型无法直接从聊天消息中提取内存数据,也可以使用第二种方式。

音频:通过内存缓冲区传入波形

以 Qwen/Qwen2-Audio-7B-Instruct 为例,可以用 BytesIO 包装内存中的音频字节,解码成 NumPy 波形后传给 processor。

以下示例使用 Transformers v4.57.1 的接口,音频参数名为 audios。运行时需要安装对应版本的 transformers,以及 PyTorch、librosa 和音频解码依赖。使用 device_map="auto" 还需要安装 accelerate。Qwen2Audio v4.57.1 文档

from io import BytesIO

import librosa
from transformers import AutoProcessor, Qwen2AudioForConditionalGeneration

model_id = "Qwen/Qwen2-Audio-7B-Instruct"

# 在应用初始化时加载,供后续请求复用。
processor = AutoProcessor.from_pretrained(model_id)
model = Qwen2AudioForConditionalGeneration.from_pretrained(
    model_id,
    device_map="auto",
)


def answer_audio(audio_bytes: bytes) -> str:
    # audio_bytes 是内存中的 WAV、MP3 等编码数据。
    target_sr = processor.feature_extractor.sampling_rate
    waveform, _ = librosa.load(
        BytesIO(audio_bytes),
        sr=target_sr,
        mono=True,
    )

    # 此处只生成提示词,音频数据通过下面的 audios 参数传入。
    messages = [
        {
            "role": "user",
            "content": [
                {"type": "audio"},
                {"type": "text", "text": "What do you hear in this audio?"},
            ],
        }
    ]

    prompt = processor.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True,
    )

    inputs = processor(
        text=prompt,
        audios=[waveform],
        sampling_rate=target_sr,
        padding=True,
        return_tensors="pt",
    ).to(model.device)

    output_ids = model.generate(**inputs, max_new_tokens=128)
    new_ids = output_ids[:, inputs["input_ids"].shape[1]:]

    return processor.batch_decode(
        new_ids,
        skip_special_tokens=True,
    )[0]

调用时,将上传接口、网络响应或其他数据源提供的 bytes 传给 answer_audio(),无须创建临时音频文件。

处理前需要区分两类数据:

  • WAV、MP3 等编码后的字节,需要先解码。
  • 录音设备直接提供的波形数组,确认声道、采样率和数值格式符合要求后,就可以直接传给 processor。

设置 sampling_rate 参数不会自动对已有数组进行重采样。示例中的重采样由 librosa.load(..., sr=target_sr) 完成。

参数名也要与安装版本对应。上述版本使用 audios,当前 main 文档中的 Qwen2Audio 示例使用 audio,实际调用应以安装版本的接口为准。当前 Qwen2Audio 文档

图片:直接传入 PIL 对象

如果 processor 支持直接读取图片对象,可以将图片放在消息的 image 字段中。Transformers 的通用处理逻辑会读取该字段,具体模型仍需支持图片输入。Processor 实现

下面假设 image_bytes 是内存中的图片字节,processor 已加载为对应视觉聊天模型的 processor:

from io import BytesIO
from PIL import Image

image = Image.open(BytesIO(image_bytes)).convert("RGB")

messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": image},
            {"type": "text", "text": "Describe this image."},
        ],
    }
]

inputs = processor.apply_chat_template(
    messages,
    tokenize=True,
    add_generation_prompt=True,
    return_dict=True,
    return_tensors="pt",
)

如果已有 PIL.Image.Image 对象,可以直接使用,省去 BytesIO 和图片解码步骤。这里需要使用视觉模型的 processor,不能沿用前面的 Qwen2-Audio processor。

视频:传入已经解码的视频帧

支持视频输入的 processor 也可以接收已解码的视频数据。官方文档给出了通过 {"type": "video", "video": video_array} 传入内存对象的用法。视频输入文档

下面假设 frames 是按时间顺序排列、尺寸一致的 RGB NumPy 图像列表:

import numpy as np

# 常见布局:(num_frames, height, width, 3)
video_array = np.stack(frames, axis=0)

messages = [
    {
        "role": "user",
        "content": [
            {"type": "video", "video": video_array},
            {"type": "text", "text": "Summarize this video."},
        ],
    }
]

随后,用对应视频模型的 processor.apply_chat_template() 生成输入。部分模型还需要帧率或时间戳等信息,需按模型文档提供;仅有帧数组未必能保留完整的时间信息。

MP4 等视频的原始字节不能与已解码的帧数组直接互换,仍需通过支持内存输入的解码器处理。

使用时还要注意什么?

messages 的格式并非所有 Hugging Face 接口通用的协议。本地 Transformers、模型专用辅助库和远程聊天 API 可能接受不同字段。应使用接口明确支持的媒体字段或参数,不要直接把 url 的值替换成 bytes、NumPy 数组或 BytesIO。

多模态模型支持的输入范围也不同。支持图片的聊天模型不一定支持音频或视频;即使是同一类媒体,不同 processor 接受的对象类型也可能不同。

调用远程 API 时,通常需要使用接口支持的 Base64、data URL、二进制上传或其他传输格式。这些方式都需要服务端明确支持。本地 processor 能接收 PIL 对象,并不代表远程接口也能接收。

省去中间文件可以减少媒体文件的读写,解码、重采样、图像预处理和张量传输仍然需要完成。处理长音频和视频时,还要控制内存占用。以上示例省去了业务媒体临时文件;from_pretrained() 下载模型和配置时,仍可能写入本地缓存。

备注:内容仅供参考。