Skip to content

端侧部署 Qwen3-VL 系列 ​

介绍 ​

Qwen3-VL 是Qwen 系列中视觉-语言模型。 这一代模型实现了全方位升级:在文本理解与生成能力上更为出色,具备更深层次的视觉感知与推理能力,支持更长的上下文长度,并在空间理解、视频动态感知以及智能体交互能力方面显著增强。 模型提供 Dense 和 MoE 两种架构形态,可从端侧扩展到云端,同时支持 Instruct 版本和增强推理能力的 Thinking 版本,满足灵活、按需的部署需求。

本章节将演示如何在边缘设备上完成 Qwen3-VL 系列模型部署、加载与对话流程。提供以下两种方式部署:

  • AidGen C++ API
  • AidGenSE OpenAI API

在本案例中,大语言模型推理运行在设备端,通过代码调用相关接口接收用户输入并实时返回对话结果。

  • 设备:Rhino Pi-X1
  • 系统:Ubuntu 22.04
  • 模型:Qwen3-VL-4B-Instruct (448x448)

支持平台 ​

平台运行方式
Rhino Pi-X1Ubuntu 22.04, AidLux

准备工作 ​

  1. Rhino Pi-X1 硬件

  2. Ubuntu 22.04 系统或 AidLux 系统

AidGen 案例部署 ​

步骤一:安装 AidGen SDK ​

bash
# 安装 AidGen SDK
sudo aid-pkg update
sudo aid-pkg -i aidgen-sdk
sudo aid-pkg -i aidgen-qnn240
sudo aid-pkg -i aidgen-qnn248

# 拷贝测试代码
cd /home/aidlux/aidmlm

cp -r /usr/local/share/aidgen/examples/ ./

步骤二:下载模型资源 ​

由于 Qwen3-VL-4B-Instruct (448x448) 目前位于 Model Farm 预览板块中,需要通过 mms 命令获取

bash
# 登录
mms login

# 查找模型
mms list qwen3-vl

# 下载模型
mms get -m "Qwen3-VL-4B-Instruct (448x448)" -p w4a16 -c qcs8550 -b qnn2.40 -d /home/aidlux/aidmlm/

cd /home/aidlux/aidmlm/
unzip qnn240_qcs8550_cl2048.zip

步骤三:资源文件确认 ​

文件分布如下:

bash
/home/aidlux/aidmlm/qnn240_qcs8550_cl2048
├── qwen3-v1-4b_qnn240_qcs8550_c12048_3_of_3.serialized.bin.aidem
├── qwen3-v1-4b_qnn240_qcs8550_cl2048_2_of_3.serialized.bin.aidem
├── qwen3-v1-4b_qnn240_qcs8550_cl2048_1_of_3.serialized.bin.aidem
├── qwen3-v1-4b-vit.serialized.bin.aidem
├── position_ids_sin.raw
├── position_ids_cos.raw
├── ingredients.png
├── embedding_fp32.bin
├── aidgen_config.json
├── examples

步骤四:编译运行 ​

bash
cd /home/aidlux/aidmlm/examples

# 替换示例文件
cp ../qnn240_qcs8550_cl2048/examples/* ./

# 编译
mkdir build && cd build
cmake .. && make

# 将编译后的示例文件放到模型目录下
cp ./test_qwen3vl ../../qnn240_qcs8550_cl2048
cd /home/aidlux/aidmlm/qnn240_qcs8550_cl2048

# 运行示例程序
./test_qwen3vl qnn240
  • 模型运行成功后,有如下日志回显
bash
图文Embedding输入
这张图片展示了一组色彩丰富、种类多样的新鲜蔬菜和水果,以及两块生鱼片,摆放在深色背景上,构图简洁而有层次感。

从画面中可以看到:

1.  **蔬菜类**:
   - **黄瓜**:数根翠绿色的黄瓜,表面有自然的细纹,显得新鲜饱满。
   - **西红柿**:有成熟的红色西红柿,也有青绿色的未熟西红柿,颜色对比鲜明,展示了不同成熟阶段的果实。
   - **胡萝卜**:几根橙红色的胡萝卜,根部粗壮,顶部带叶,颜色鲜亮,充满生机。
   - **芹菜/香芹**:几根绿色的芹菜,茎叶茂盛,叶片舒展。
   - **洋葱/大蒜**:图中也出现了几颗洋葱和大蒜,它们是常见的调味蔬菜,通常与香料搭配使用。
   - **青椒/西葫芦**:图中还有几根绿色的西葫芦,它们的形状和颜色与黄瓜相似,但形状更圆润。
   - **姜**:几块生姜,外皮呈浅棕色,质地坚实,常用于烹饪调味。
   - **西兰花**:图中还出现了几朵西兰花,它们的花蕾饱满,色泽洁白或淡绿色,看起来非常新鲜。

2.  **水果类**:
   - **柠檬**:几颗黄色的柠檬,表皮光滑,颜色鲜亮,常用于调味或榨汁。
   - **橘子/橙子**:图中还有几个橘子,外皮呈橙黄色,果肉饱满。
   - **石榴**:图中也出现了几颗石榴,它们的外壳呈红棕色,果肉丰富,常被用于制作果酒或果酱。
   - **牛油果**:图中还出现了几个牛油果,它们的外壳呈深绿色,果肉呈橙色,常用于沙拉或甜点。
   - **苹果**:图中还出现了几个苹果,它们的外皮呈红棕色,果肉洁白,常用于制作果酱或果冻。

3.  **蛋白质类**:
   - **生鱼片**:图中还有两块生鱼片,它们的肉质鲜嫩,呈粉红色,外层有少许脂肪,这是常见的海鲜食材。

整张图片通过丰富的色彩、多样的形状和层次感的构图,展现了各种新鲜食材的自然之美。这些食材不仅色彩鲜艳、形态各异,而且摆放得错落有致,给人一种健康、自然、丰盛的感觉。这张图片不仅展示了食材的多样性,还通过色彩和形状的对比,增强了视觉吸引力,让人感受到大自然的馈赠和食材的新鲜与丰富。

这张图片不仅是一幅美食的展示,更是一幅充满生机与自然之美的画卷,让人仿佛置身于一个充满活力的厨房或市场之中。<|im_end|>

AidGenSE 案例部署 ​

步骤一:安装 AidGenSE ​

bash
sudo aid-pkg update

# 确保 aidgense 是最新版本
sudo aid-pkg remove aidgense
sudo aid-pkg -i aidgense
sudo aid-pkg -i aidgen-sdk
sudo aid-pkg -i aidgen-qnn240
sudo aid-pkg -i aidgen-qnn248

步骤二:模型查询 & 获取 ​

bash
# 查看模型
aidllm remote-list api | grep qwen3-vl

#------------------------可以看到 Qwen3-VL 模型------------------------

qwen3-vl-4b-instruct-llamacpp-llamacpp-q4_0-qcs8550            VLM     2026-09-10 19:44:12
qwen3-vl-2b-instruct-llamacpp-llamacpp-q4_0-qcs8550            VLM     2026-09-10 19:44:08
qwen3-vl-4b-instruct-448x448-qnn2.40-w4a16-qcs8550             VLM     2026-08-13 17:55:59
qwen3-vl-8b-instruct-qnn2.48-w4a16-qcs8550                     VLM     2026-08-13 17:55:43
...

# 下载模型

aidllm pull api qwen3-vl-4b-instruct-448x448-qnn2.40-w4a16-qcs8550

步骤三:启动 HTTP 服务 ​

bash
# 启动对应模型的 openai api 服务
aidllm start api -m qwen3-vl-4b-instruct-448x448-qnn2.40-w4a16-qcs8550

# 查看状态
aidllm status api

# 停止服务: aidllm stop api

# 重启服务: aidllm restart api

💡注意

默认端口号是 8888

步骤四:对话测试 ​

使用 Web UI 对话测试 ​

bash
# 安装 UI 前端服务
sudo aidllm install ui

# 启动 UI 服务
aidllm start ui

# 查看 UI 服务状态: aidllm status ui

# 停止 UI 服务: aidllm stop ui

UI 服务启动后访问 http://ip:51104

使用 Python 对话测试 ​

python
import os
import sys
import requests
import json
import base64


def stream_chat_completion(messages, model="qwen3-vl-4b-instruct-448x448-qnn2.40-w4a16-qcs8550"):

    url = "http://127.0.0.1:8888/v1/chat/completions"
    headers = {
        "Content-Type": "application/json"
    }
    payload = {
        "model": model,
        "messages": messages,
        "stream": True    # 打开流式
    }

    # 发起带 stream=True 的请求
    response = requests.post(url, headers=headers, json=payload, stream=True)
    try:
        response.raise_for_status()
    except requests.HTTPError as e:
        print(f"\nHTTP error: {e}", file=sys.stderr)
        if response.text:
            print(response.text, file=sys.stderr)
        raise

    # 逐行读取并解析 SSE 格式
    for line in response.iter_lines():
        if not line:
            continue
        # print(line)
        line_data = line.decode('utf-8')
        # SSE 每一行以 "data: " 前缀开头
        if line_data.startswith("data: "):
            data = line_data[len("data: "):]
            # 结束标志
            if data.strip() == "[DONE]":
                break
            try:
                chunk = json.loads(data)
            except json.JSONDecodeError:
                # 解析出错时打印并跳过
                print("无法解析JSON:", data)
                continue

            # 取出模型输出的 token
            content = chunk["choices"][0]["delta"].get("content")
            if content:
                print(content, end="", flush=True)

def image_to_base64(image_path):
    with open(image_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")

def image_to_data_url(image_path):
    """读取图片并转换为 data URL,兼容 OpenAI 风格的 image_url 字段"""
    ext = os.path.splitext(image_path)[1].lower()
    mime_map = {
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".png": "image/png",
        ".webp": "image/webp",
    }
    mime_type = mime_map.get(ext, "image/jpeg")
    b64_str = image_to_base64(image_path)
    return f"data:{mime_type};base64,{b64_str}"


if __name__ == "__main__":
    image_url = image_to_data_url("/path/to/your/image.jpg")
    # 示例对话
    messages = [
        {
            "role": "system", 
            "content": "You are a helpful assistant."
        },
        {
            "role": "user", 
            "content":[
                        {
                            "type": "text",
                            "text": "这张图片描述了什么内容?"
                        },
                        {
                            "type": "image_url",
                            "image_url": 
                            {
                                "url": image_url
                            }
                        }
                    ]   
        },
    ]
    print("Assistant:", end=" ")
    stream_chat_completion(messages)
    print()  # 换行