使用 AidGen 部署 VLM
介绍
端侧部署视觉多模态大模型 (Vision Language Model, VLM) 指将原本在云端运行的大模型压缩、量化并部署到本地设备上,实现离线、低时延的自然语言理解与生成。本章节以 AidGen 推理引擎为基础,演示如何在边缘设备上完成多模态大模型的部署、加载与对话流程。
在本案例中,多模态大模型推理运行在设备端,通过 C++ 代码调用相关接口接收用户输入并实时返回对话结果。
- 设备:Rhino Pi-X1
- 系统:Ubuntu 22.04
- 模型:Qwen2.5-VL-3B (392x392)
支持平台
| 平台 | 运行方式 |
|---|---|
| Rhino Pi-X1 | Ubuntu 22.04, AidLux |
准备工作
Rhino Pi-X1 硬件
Ubuntu 22.04 系统或 AidLux 系统
案例部署
步骤一:安装 AidGenSE
bash
sudo aid-pkg update
sudo aid-pkg -i aidgense
sudo aid-pkg -i aidgen-sdk
sudo aid-pkg -i aidgen-qnn236
sudo aid-pkg -i aidgen-qnn240步骤二:模型查询 & 获取
- 已支持模型查看
bash
# 查看已支持的模型
aidllm remote-list api
#------------------------示例输出如下------------------------
Current Soc : 8550
Name Url CreateTime
----- --------- ---------
qwen2.5-vl-3b-instruct-392x392-qnn2.36-w4a16-qcs8550 aplux/qwen2.5-vl-3b-instruct-392x392-qnn2.36-w4a16-qcs8550 2026-05-15 10:57:51
qwen2.5-vl-3b-instruct-672x672-qnn2.36-w4a16-qcs8550 aplux/qwen2.5-vl-3b-instruct-672x672-qnn2.36-w4a16-qcs8550 2026-05-15 10:57:49
...- 下载 qwen2.5-vl-3b-instruct-392x392-qnn2.36-w4a16-qcs8550
bash
# 下载模型
aidllm pull api aplux/qwen2.5-vl-3b-instruct-392x392-qnn2.36-w4a16-qcs8550
# 查看已下载模型
aidllm list api步骤三:启动 HTTP 服务
bash
# 启动对应模型的 openai api 服务
aidllm start api -m qwen2.5-vl-3b-instruct-392x392-qnn2.36-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 uiUI 服务启动后访问 http://ip:51104
使用 Python 对话测试
python
import os
import sys
import requests
import json
import base64
def stream_chat_completion(messages, model="qwen2.5-vl-3b-instruct-392x392-qnn2.36-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_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() # 换行