三、VLM接入开发!服务化API调用实战!

456 阅读15分钟

声明:我是引用的 付费文章,文章搬过来只是为了自己学习方便,不用每次输入验证口令。如果侵权,第一时间删除。 原文链接: gxlbvdk4ilp.feishu.cn/wiki/Gu4ZwG…

跟着上节课的内容,我们把大模型都部署好了!并成功推理起来

要怎么使用?如何接入?

刚开始可能搞不清楚

但本质上推理起来的模型就是API!

下面开始今天的内容:

1.调用API,简单上手VLM,

2.接入VLM,部分参数讲解

3.LLM使用

4.代码实战

看完你一定会明白怎样使用API,轻松上手VLM!

GO!!!

背景

为了方便不同的应用程序对模型的调用和使用,模型服务化成为了一种重要趋势

之前也提到过,把VLM接入数据工程,能帮你解决几个问题:

1. 使用多模态模型处理非结构化文档,不管是文本文件,还是图示图表等,它都能处理

2. 高拓展性:本地推理VLM后,可以接入到数据处理的任务上,也可以接入到多模态对话任务中。

甚至可以提供对外服务,如:使用VLM做标书的识别提取,接入LLM对文本报告中错别字、书写错误等做查错修正

3. 开发周期短:VLM是一个单独的模块,它干的活包括:识别+提取+结构化+总结

一个模型就可以应对大部分的数据处理

本次课程旨在让大家熟练掌握VLM的调用方法,利用VLM强大的功能处理数据难题

一、VLM

#SGLANG启动指令 --model-path 是模型所在路径 --port是端口号
CUDA_VISIBLE_DEVICES=1
python -m sglang.launch_server \
    --model-path /media/ubu/文档/大模型/Qwen2.5-VL-7B-Instruct \
    --host 0.0.0.0 \
    --port 30000 \
    --chat-template=qwen2-vl

我们通过SGLang把多模态模型推理起来后,会有个ip+端口,后续通过这个ip端口来调用API(这边推理的是Qwen2.5-VL-7B-Instruct,推理起来后的ip为127.0.0.1,30000端口)

可以直接请求验证 curl ``http://127.0.0.1:30000/v1/models

1.1调用API

1.1.1简单示例

可以使用OpenAI的API发送请求,指定好base_url的ip地址以及端口,就可以使用推理的大模型了

base_url就是我们推理后的地址http://127.0.0.1:30000/v1

以下是python示例:

  1. 直接传入图像链接或者本地图片,这里我直接传的是本地的路径,如果用的是http的url,如:github.com/...example.…

import base64

import openai

client = openai.OpenAI(
    base_url="http://127.0.0.1:30000/v1",
    api_key="None"
)
with open("./images/example_image.png", "rb") as f:
    base64_image = base64.b64encode(f.read()).decode("utf-8")
print(len(base64_image))
dir='./images/example_image.png'
response = client.chat.completions.create(
    model="Qwen2.5-VL-7B-Instruct",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": '描述我的图片'},
            {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}},
        ]
    }],
    temperature=0.2,
    max_tokens=12800,
)

print(response.choices[0].message.content)

输出结果:

图片显示一名男子正在熨烫挂在停在城市街道上的黄色多功能车上的衣服。这名男子站在出租车车辆的后部附近,似乎正在熨烫挂在临时熨衣架上的衣服。车辆是福特探险者,背景中有出租车和其他街道元素,例如红绿灯和建筑物

2. 输入图像的base64编码字符串

图像经过base64编码处理后,把base64编码字符串传给大模型

import base64
# 读取本地图片并转换为 Base64 编码
def encode_image_to_base64(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")
# 图片路径
local_image_path = "/mnt/c/Users/22687/Desktop/example_image.png"
# 转换为 Base64 编码
base64_image = encode_image_to_base64(local_image_path)
response = client.responses.create(
    model="Qwen2.5-VL-7B-Instruct",
    input=[
        {
            "role": "user",
            "content": [
                {"type": "input_text", "text": prompt},
                                                                    #传入上面处理后的base64编码
                {"type": "input_image", "image_url": f"data:image/png;base64,{base64_image}"},
            ],
        }
    ]
)

参数讲解

  • base_url="``http://127.0.0.1:30000/v1``"v1主要是用来区分api版本,如果你的服务未来升级到v2,客户端就可以通过/v2调用新的api,而不影响v1的使用

  • 如果在推理模型的时候没有指定api_key,则这里的api_key就不用写,可以随便传个参数值,但必须得有api_key参数

  • model,如果推理的时候指定了模型的名称 如--model-name my-model ,则调用的时候就需要使用指定的模型名称model="my-model";没有指定的话就用默认的模型名称model="olmOCR-7B-0225-preview"

  • max_tokens控制生成文本的最大长度(token为单位),如果没有指定该参数,则会默认使用模型配置文件里的参数

  • image_url可以直接传入图像链接,或者传入base64编码后的字符串

  • URL vs base64编码

    • base64是一种将二进制数据编码为ASCII字符串的方法,处理后的数据可以直接嵌入到请求中,无需再进行网络请求

      • 优点:不需要额外的网络请求获取图片
      • 缺点:base64编码直接包含在请求体中,会增加请求体大小
    • 传入url时,模型会先发起网络请求,请求传入的url获取图片资源,接收到图片后还要将其转为计算机能够处理的数据格式

      • 优点:请求体较小,仅包含URL字符串

      • 缺点:需要额外的网络请求获取图片,存在网络问题、链接失效或访问权限问题

此外还需要注意传入图片的格式、分辨率、清晰度等

图片格式: 常见的格式,JPEG、PNG、WEBP等

分辨率: 不同的多模态模型会有不同的限制和要求

清晰度: 尽量保证图片足够清晰,让模型准确识别图片内容

1.1.2多图像输入

如果模型支持,则服务器还支持多个图像以及交错文本和图像

请求的内容还可以是这样:


"content": [
    #传入多个图像链接
    {
        "type": "image_url",
        "image_url": {
            "url": "/mnt/c/Users/22687/Desktop/example_image.png",
        },
    },
    {
        "type": "image_url",
        "image_url": {
            "url": "/mnt/c/Users/22687/Desktop/logo.png",
        },
    },
    {
        "type": "text",
        "text": "我有两张截然不同的图片,它们完全没有关联"
        "请用一句话描述第一张图片,然后再用另一句话描述第二张图片",
    },
]

输出结果:

第一张图片显示一名男子站在出租车后座上,手里拄着一双拐杖熨烫衬衫。第二张图片是一个风格化的卡通式徽标,带有字母“SGL”和一个类似于计算机代码片段的小图标。

以上我们通过API把VLM接入到任务中去处理pdf文件

先掌握怎么用

后续我们再动手做应用!

二、LLM

我们之前通过vllm推理了qwen2.5-14B-Chat-GPTQ-Int4

CUDA_VISIBLE_DEVICES=0 vllm serve /media/ubu/文档/大模型/qwen-2.5-14B-GPTQ-int8 \
    --served-model-name Qwen2.5-14B-Instruct-GPTQ-Int8 \
    --dtype auto \
    --host 0.0.0.0 \
    --port 8001 \
    --max-model-len 4096 \
    --gpu-memory-utilization 0.9

2.1调用API

要调用推理后的这个服务,可以在python中使用OpenAI,也可以通过其他HTTP客户端调用

下面我们在python用OpenAI的API实现

from openai import OpenAI
client = OpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="None",
)

completion = client.chat.completions.create(
  model="Qwen2.5-14B-Instruct-GPTQ-Int8",
  messages=[
    {"role": "user", "content": "什么是VLM"}
  ]
)

print(completion.choices[0].message)

写好base_url的ip地址以及端口,就可以使用推理的大模型了

如果推理时候没有指定--api-key,请求时的api_key就不需要管它

上面指定了--served-model-name qwen2.5-14B-Chat-GPTQ-Int4,请求时的model的参数值就要用qwen2.5-14B-Chat-GPTQ-Int4

2.2额外参数

此外,vllm还支持一些OpenAI不支持的参数,如:top_k

可以在请求时通过extra_bodytop_k传给vllm

如:

completion = client.chat.completions.create(
  model="Qwen2.5-14B-Instruct-GPTQ-Int8",
  messages=[
    {"role": "user", "content": "什么是VLM"}
  ],
  extra_body={
     "top_k":50
  }
)
  • top_k:控制要考虑的顶部 token 的数量,设置为 -1 以考虑所有 token
  • min_p:表示要考虑的 token 的最小概率,相对于最有可能的 token 的概率。必须在 [0, 1] 范围内。设置为 0 以禁用此功能
  • ····

2.3额外HTTP请求头

目前仅支持 X-Request-Id HTTP 请求头,通过extra_headers传递X-Request-Id请求标识

如:

completion = client.completions.create(
  model="Qwen2.5-14B-Instruct-GPTQ-Int8",
  prompt="机器人不可以伤害人类",
  extra_headers={
    "x-request-id": "completion-test",
  }
)
print(completion._request_id)

不过要注意,在高 QPS 速率(每秒查询次数)下启用该请求头可能会影响性能!

关于vllm那些额外的参数,可以自行找下资料学习,这边就不多阐述了

主要还是掌握如何用

三、代码实战

下面我们进行部分实战讲解

1.

from openai import OpenAI
client = OpenAI(
    base_url="http://192.168.1.39:30000/v1", 
    api_key="None"
)
response = client.chat.completions.create(
    model="Qwen2.5-VL-7B-Instruct",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "用中文描述图片",
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-VL/assets/demo.jpeg"
                    },
                },
            ],
        }
    ],
    max_tokens=300,
)

print(response.choices[0].message.content)

这里我用的是Qwen2.5-VL-7B-Instruct,上传了url的链接,让他去识别并描述一张jpg图片

最后模型返回的是:

这张图片展示了一位女士和一只狗在海滩上互动的温馨场景。女士坐在沙滩上,面对大海,手里拿着一只小狗的爪子。狗戴着彩色的项圈,看起来很开心,正在跟她握手。背景是广阔的海滩和远处的海浪,天空呈现出柔和的日落色彩,整个场景显得非常宁静和幸福。

可以看出多模态模型能够准确的识别出图片的内容,并根据提示细致地描述了图片的场景、人物动作等

2.

再举个例子

import base64
from openai import OpenAI
#转换成base64编码
def jpg_to_base64(file_path):
    try:
        with open(file_path, "rb") as image_file:
            encoded_string = base64.b64encode(image_file.read())
            return encoded_string.decode('utf-8')
    except FileNotFoundError:
        print(f"错误: 文件 {file_path} 未找到。")
    except Exception as e:
        print(f"错误: 发生了一个未知错误: {e}")
    return None
jpg_base64=jpg_to_base64("/mnt/c/Users/22687/Desktop/OIP.jpg")

response1 = client.chat.completions.create(
    model="Qwen2.5-VL-7B-Instruct",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "用中文描述图片,识别里面的文字信息,如果你识别到了数学题目,把这个结果计算出来",
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/jpg;base64,{jpg_base64}"
                    },
                },
            ],
        }
    ],
    max_tokens=300,
)
print(response1.choices[0].message.content)

这里我们将本地的jpg图片转成base64编码,再传给大模型

设置好提示词,让大模型去识别图片内容,并推理结果

是否可以推理出答案呢?

答案是可以的

图片显示了一块黑板,上面写着数学题目“2 + 2 = ?”。这是一个简单的加法题目。
计算结果是:(2 + 2 = 4)

3.

再给他一张零件设计图纸看看

jpg_base64_2=jpg_to_base64("/mnt/c/Users/22687/Desktop/OIP (1).jpg")

response2 = client.chat.completions.create(
    model="Qwen2.5-VL-7B-Instruct",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "用中文描述图片,识别里面的内容,他能用来干什么,怎么用?",
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/jpg;base64,{jpg_base64_2}"
                    },
                },
            ],
        }
    ],
    max_tokens=300,
)

print(response2.choices[0].message.content)
这是一张标注了尺寸和技术细节的机械零件图纸。图纸中显示了多个零件的立体视图和平面视图,包括尺寸标注和公差标注。这些图纸主要用于工业设计、加工和制造领域,用来指导机械零件的设计、制造、检验和装配。
具体来说,这种图纸可以用来:
1. **设计**:工程师可以根据图纸绘制零件的实际形状和尺寸,为机械产品设计提供详细的参考。
2. **加工**:图纸上的尺寸和公差标注可以帮助机械加工人员确定零件的具体尺寸和公差范围,确保加工精度。
3. **检验**:在零件制造完成后,可以通过图纸上的标注对比实际加工的零件尺寸,确保零件符合设计要求。
4. **装配**:图纸中的立体视图可以帮助设计师和装配工人确定各个零件之间的相对位置和装配顺序。

使用这些图纸时,设计人员需要仔细阅读图纸上的每一项标注,确保设计的准确性。同时,制造人员也需要严格按照图纸进行加工,确保产品符合设计要求。

给他一张图纸,他也能准确是识别出来,并推理他的用途,看得出他的能力是很强大的

以上只是简单的例子,后面可以在自己应用中根据需求用多模态模型处理更复杂的任务

附加代码

点击查看 Jupyter Code
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "b0558baf-fbd1-42e5-85c0-7ff0738cde55",
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "import base64"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7f5a5ec0-0def-4560-beea-387c8a88e4c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "client = OpenAI(\n",
    "    base_url=\"http://192.168.1.39:30000/v1\", \n",
    "    api_key=\"None\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "58c7606f-92aa-493e-ab44-cdd9bd26eb2c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "这张图片展示了一位女士和一只狗在海滩上互动的温馨场景。女士坐在沙滩上,面对大海,手里拿着一只小狗的爪子。狗戴着彩色的项圈,看起来很开心,正在跟她握手。背景是广阔的海滩和远处的海浪,天空呈现出柔和的日落色彩,整个场景显得非常宁静和幸福。\n"
     ]
    }
   ],
   "source": [
    "response = client.chat.completions.create(\n",
    "    model=\"Qwen2.5-VL-7B-Instruct\",\n",
    "    messages=[\n",
    "        {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": [\n",
    "                {\n",
    "                    \"type\": \"text\",\n",
    "                    \"text\": \"用中文描述图片\",\n",
    "                },\n",
    "                {\n",
    "                    \"type\": \"image_url\",\n",
    "                    \"image_url\": {\n",
    "                        \"url\": \"https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-VL/assets/demo.jpeg\"\n",
    "                    },\n",
    "                },\n",
    "            ],\n",
    "        }\n",
    "    ],\n",
    "    max_tokens=300,\n",
    ")\n",
    "\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "be02df72-9bea-4759-af3f-517d2206b0ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "def jpg_to_base64(file_path):\n",
    "    try:\n",
    "        with open(file_path, \"rb\") as image_file:\n",
    "            encoded_string = base64.b64encode(image_file.read())\n",
    "            return encoded_string.decode('utf-8')\n",
    "    except FileNotFoundError:\n",
    "        print(f\"错误: 文件 {file_path} 未找到。\")\n",
    "    except Exception as e:\n",
    "        print(f\"错误: 发生了一个未知错误: {e}\")\n",
    "    return None\n",
    "jpg_base64=jpg_to_base64(\"/mnt/c/Users/22687/Desktop/OIP.jpg\")\n",
    "# print(jpg_base64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "95d2a5c5-f63c-4be6-a7df-f842f86f2bd4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "图片显示了一块黑板,上面写着数学题目“2 + 2 = ?”。这是一个简单的加法题目。\n",
      "\n",
      "计算结果是:\\(2 + 2 = 4\\)\n"
     ]
    }
   ],
   "source": [
    "response1 = client.chat.completions.create(\n",
    "    model=\"Qwen2.5-VL-7B-Instruct\",\n",
    "    messages=[\n",
    "        {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": [\n",
    "                {\n",
    "                    \"type\": \"text\",\n",
    "                    \"text\": \"用中文描述图片,识别里面的文字信息,如果你识别到了数学题目,把这个结果计算出来\",\n",
    "                },\n",
    "                {\n",
    "                    \"type\": \"image_url\",\n",
    "                    \"image_url\": {\n",
    "                        \"url\": f\"data:image/jpg;base64,{jpg_base64}\"\n",
    "                    },\n",
    "                },\n",
    "            ],\n",
    "        }\n",
    "    ],\n",
    "    max_tokens=300,\n",
    ")\n",
    "\n",
    "print(response1.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "7129bd3b-2d4c-43b0-bde0-7211840c5f8b",
   "metadata": {},
   "outputs": [],
   "source": [
    "jpg_base64_2=jpg_to_base64(\"/mnt/c/Users/22687/Desktop/OIP (1).jpg\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "9822bc36-c344-4053-8a9a-3750e58cedd7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "这是一张标注了尺寸和技术细节的机械零件图纸。图纸中显示了多个零件的立体视图和平面视图,包括尺寸标注和公差标注。这些图纸主要用于工业设计、加工和制造领域,用来指导机械零件的设计、制造、检验和装配。\n",
      "\n",
      "具体来说,这种图纸可以用来:\n",
      "\n",
      "1. **设计**:工程师可以根据图纸绘制零件的实际形状和尺寸,为机械产品设计提供详细的参考。\n",
      "2. **加工**:图纸上的尺寸和公差标注可以帮助机械加工人员确定零件的具体尺寸和公差范围,确保加工精度。\n",
      "3. **检验**:在零件制造完成后,可以通过图纸上的标注对比实际加工的零件尺寸,确保零件符合设计要求。\n",
      "4. **装配**:图纸中的立体视图可以帮助设计师和装配工人确定各个零件之间的相对位置和装配顺序。\n",
      "\n",
      "使用这些图纸时,设计人员需要仔细阅读图纸上的每一项标注,确保设计的准确性。同时,制造人员也需要严格按照图纸进行加工,确保产品符合设计要求。\n"
     ]
    }
   ],
   "source": [
    "response2 = client.chat.completions.create(\n",
    "    model=\"Qwen2.5-VL-7B-Instruct\",\n",
    "    messages=[\n",
    "        {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": [\n",
    "                {\n",
    "                    \"type\": \"text\",\n",
    "                    \"text\": \"用中文描述图片,识别里面的内容,他能用来干什么,怎么用?\",\n",
    "                },\n",
    "                {\n",
    "                    \"type\": \"image_url\",\n",
    "                    \"image_url\": {\n",
    "                        \"url\": f\"data:image/jpg;base64,{jpg_base64_2}\"\n",
    "                    },\n",
    "                },\n",
    "            ],\n",
    "        }\n",
    "    ],\n",
    "    max_tokens=300,\n",
    ")\n",
    "\n",
    "print(response2.choices[0].message.content)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}

总结

模型推理起来后,我们只需要几个简单的步骤即可调用API,接入到我们的项目中

多模态能力是很强大的,一个模型就能搞定很多事情!一定要会用!

这节内容重点先掌握怎么调用API

下节课我们再一起动手做应用!!