REST API

提供了 REST API,供用户在自己的程序中与 MLC-LLM 进行交互。

安装 MLC-LLM 包

SERVE 是 MLC-LLM 包的一部分,其安装说明可以在 这里 找到。安装 MLC-LLM 包后,您可以运行以下命令来检查安装是否成功:

mlc_llm serve --help

如果安装成功,您应该会看到服务帮助信息。

快速上手

本节提供了使用 MLC-LLM REST API 的快速入门指南。要启动服务器,请运行以下命令:

mlc_llm serve MODEL [--model-lib PATH-TO-MODEL-LIB]

其中 MODEL 是使用 MLC-LLM 构建过程 编译后的模型文件夹。有关其他参数的信息可以在 启动服务器 部分找到。

启动服务器后,您可以在自己的程序中使用 API 发送请求。以下是在 Python 中使用 API 与 MLC-LLM 交互的示例(假设服务器运行在 http://127.0.0.1:8080/):

import requests

# Get a response using a prompt without streaming
payload = {
   "model": "./dist/Llama-2-7b-chat-hf-q4f16_1-MLC/",
   "messages": [
      {"role": "user", "content": "Write a haiku about apples."},
   ],
   "stream": False,
   # "n": 1,
   "max_tokens": 300,
}
r = requests.post("http://127.0.0.1:8080/v1/chat/completions", json=payload)
choices = r.json()["choices"]
for choice in choices:
   print(f"{choice['message']['content']}\n")

使用多 GPU 运行 CLI

如果您希望启用张量并行以在多个 GPU 上运行大语言模型,请指定参数 --overrides "tensor_parallel_shards=$NGPU"。例如,

mlc_llm serve HF://mlc-ai/Llama-3-8B-Instruct-q4f16_1-MLC --overrides "tensor_parallel_shards=2"

启动服务器

要启动 MLC-LLM 的 MLC 服务器,请在终端中运行以下命令。

mlc_llm serve MODEL [--model-lib PATH-TO-MODEL-LIB] [--device DEVICE] [--mode MODE] \
    [--additional-models ADDITIONAL-MODELS] \
    [--speculative-mode SPECULATIVE-MODE] \
    [--overrides OVERRIDES] \
    [--enable-tracing] \
    [--host HOST] \
    [--port PORT] \
    [--allow-credentials] \
    [--allowed-origins ALLOWED_ORIGINS] \
    [--allowed-methods ALLOWED_METHODS] \
    [--allowed-headers ALLOWED_HEADERS]
MODEL 使用 MLC-LLM 构建过程编译后的模型文件夹。该参数

可以是带有量化方案的模型名称(例如 Llama-2-7b-chat-hf-q4f16_1),也可以是模型文件夹的完整路径。在前一种情况下,我们将使用提供的名称在可能的路径中搜索模型文件夹。

--model-lib

字段,用于指定要使用的模型库文件的完整路径(例如 .so 文件)。

--device

运行设备的描述。用户应提供格式为 device_name:device_iddevice_name 的字符串,其中 device_namecudametalvulkanrocmopenclauto (自动检测本地设备)之一,device_id 是要运行的设备 ID。默认值为 auto,设备 ID 默认为 0。

--mode

MLC LLM 中的引擎模式。提供了三种预设模式:localinteractiveserver。默认模式是 local

模式的选择决定了未明确指定时 "max_num_sequence"、"max_total_sequence_length" 和 "prefill_chunk_size" 的值。

1. Mode "local" refers to the local server deployment which has low request concurrency. So the max batch size will be set to 4, and max total sequence length and prefill chunk size are set to the context window size (or sliding window size) of the model.

2. Mode "interactive" refers to the interactive use of server, which has at most 1 concurrent request. So the max batch size will be set to 1, and max total sequence length and prefill chunk size are set to the context window size (or sliding window size) of the model.

3. Mode "server" refers to the large server use case which may handle many concurrent request and want to use GPU memory as much as possible. In this mode, we will automatically infer the largest possible max batch size and max total sequence length.

您可以通过 --overrides 手动指定参数 "max_num_sequence"、"max_total_seq_length" 和 "prefill_chunk_size" 来覆盖自动推断的值。例如:--overrides "max_num_sequence=32;max_total_seq_length=4096"

--additional-models

附加模型(除主模型外)的模型路径和(可选的)模型库路径。

当引擎启用推测解码时,需要附加模型。现在只支持附加模型用于推测解码。 指定附加模型的方式是:--additional-models model_path_1--additional-models model_path_1,model_lib_1

当未提供模型的模型库时,将激活 JIT 模型编译以自动编译模型。

--speculative-mode

推测解码模式。目前支持四种选项:

  • disable,未启用推测解码,

  • small_draft,表示正常的推测解码(小草案)风格,

  • eagle,表示 eagle 风格的推测解码。

  • medusa,指的是 medusa 风格的推测解码。

--overrides

覆盖 EngineConfig 的可配置额外字段。

支持可被覆盖的字段包括:tensor_parallel_shards (张量并行分片数)

请查阅 mlc_llm/serve/config.py 中 EngineConfig 的文档,以获取每个字段的详细说明。示例:--overrides "max_num_sequence=32;max_total_seq_length=4096;tensor_parallel_shards=2"

--enable-tracing

布尔值,指示是否启用请求的事件日志记录功能。

--host

服务器应启动的主机,默认为 127.0.0.1

--port

服务器应启动的端口,默认为 8000

--allow-credentials

标志,指示服务器是否应允许凭据。如果设置,服务器将在响应中包含 CORS 头。

--allowed-origins

指定允许的来源。它需要字符串的 JSON 列表,默认值为 ["*"],允许所有来源。

--allowed-methods

指定允许的方法。它需要字符串的 JSON 列表,默认值为 ["*"],允许所有方法。

--allowed-headers

指定允许的头部。它需要字符串的 JSON 列表,默认值为 ["*"],允许所有头部。

您可以访问 http://127.0.0.1:PORT/docs (将 PORT 替换为您指定的端口号)以查看支持的端点列表。

API 端点

REST API 提供以下端点:

GET /v1/models

获取可用于 MLC-LLM 的模型列表。

示例

import requests

url = "http://127.0.0.1:8000/v1/models"
headers = {"accept": "application/json"}

response = requests.get(url, headers=headers)

if response.status_code == 200:
   print("Response:")
   print(response.json())
else:
   print("Error:", response.status_code)
POST /v1/chat/completions

使用提示从 MLC-LLM 获取响应,可选择是否使用流式传输。

聊天补全请求对象

  • messages (List[ChatCompletionMessage], 必填): 到目前为止在对话中交换的消息序列。对话中的每条消息由 ChatCompletionMessage 对象表示,该对象包含以下字段:
    • content (Optional[Union[str, List[Dict[str, str]]]]): 消息的文本内容,或在工具生成消息的情况下的结构化数据。

    • role (Literal["system", "user", "assistant", "tool"]): 消息发送者的角色,指示消息是来自系统、用户、助手还是工具。

    • name (Optional[str]): 消息发送者的可选名称。

    • tool_calls (Optional[List[ChatToolCall]]): 在此消息中对外部工具或函数的调用列表,适用于角色为 tool 的情况。

    • tool_call_id (Optional[str]): 工具调用的唯一标识符,在集成外部工具或服务时相关。

  • model (str, 必填): 用于生成响应的模型。

  • frequency_penalty (float, 可选, 默认=0.0): 正值根据新标记在文本中的现有频率对其进行惩罚,从而降低模型重复标记的可能性。

  • presence_penalty (float, 可选, 默认=0.0): 正值对新标记进行惩罚,如果它们已经存在于文本中,从而降低模型重复标记的可能性。

  • logprobs (bool, 可选, 默认=False): 指示是否在响应中包含每个标记的对数概率。

  • top_logprobs (int, 可选, 默认=0): 范围从 0 到 20 的整数。它确定在每个位置最可能出现的标记数量,并返回这些标记。每个标记都附带一个对数概率。如果使用此参数,必须将 'logprobs' 设置为 true。

  • logit_bias (Optional[Dict[int, float]]): 允许在生成过程中指定对特定标记的偏好或偏见。

  • max_tokens (Optional[int]): 在响应中生成的最大标记数。

  • n (int, 可选, 默认=1): 为给定提示生成的响应数量。

  • seed (Optional[int]): 用于确定性生成的种子。使用相同的种子和输入将产生相同的输出。

  • stop (Optional[Union[str, List[str]]]): 一个或多个字符串,如果遇到这些字符串,将导致生成停止。

  • stream (bool, 可选, 默认=False): 如果为 True,响应将在生成时流式传输回客户端。

  • temperature (float, 可选, 默认=1.0): 控制生成的随机性。较低的值会导致更少随机的完成。

  • top_p (float, 可选, 默认=1.0): 控制生成响应多样性的核心采样参数。

  • tools (Optional[List[ChatTool]]): 指定可以作为聊天一部分调用的外部工具或函数。

  • tool_choice (Optional[Union[Literal["none", "auto"], Dict]]): 控制如何选择工具以用于响应中。

  • user (Optional[str]): 发起请求的用户的可选标识符。

  • response_format (RequestResponseFormat, 可选): 指定响应的格式。可以是 "text" 或 "json_object",对于 JSON 响应,还可以选择定义模式。

Returns

  • 如果 streamFalse,则返回包含生成响应的 ChatCompletionResponse 对象。

  • 如果 streamTrue,则返回 ChatCompletionStreamResponse 对象流,提供生成响应的实时反馈。

ChatCompletionResponseChoice

  • finish_reason (Optional[Literal["stop", "length", "tool_calls", "error"]], 可选): 完成过程终止的原因。可能是由于达到停止条件、最大长度、工具调用输出或错误。

  • index (int, 必填, 默认=0): 指示此选项在选项列表中的位置。

  • message (ChatCompletionMessage, 必填): 聊天完成的消息部分,包含聊天响应的内容。

  • logprobs (Optional[LogProbs], 可选): 可选地包含每个输出标记的对数概率。

ChatCompletionStreamResponseChoice

  • finish_reason (Optional[Literal["stop", "length", "tool_calls"]], 可选): 指定流式完成过程结束的原因。有效原因包括 "stop"、"length" 和 "tool_calls"。

  • index (int, 必填, 默认=0): 指示此选项在选项列表中的位置。

  • delta (ChatCompletionMessage, 必填): 表示流中聊天完成消息的增量更新或添加。

  • logprobs (Optional[LogProbs], 可选): 可选地包含每个输出标记的对数概率。

ChatCompletionResponse

  • id (str, 必填): 聊天完成会话的唯一标识符。

  • choices (List[ChatCompletionResponseChoice], 必填): 一组 ChatCompletionResponseChoice 对象,表示模型生成的潜在响应。

  • created (int, 必填, 默认=当前时间): 表示响应生成时间的 UNIX 时间戳。

  • model (str, 必填): 用于生成聊天完成的模型名称。

  • system_fingerprint (str, 必填): 系统生成的指纹,唯一标识计算环境。

  • object (Literal["chat.completion"], 必填, 默认="chat.completion"): 表示对象类型的字符串字面量,此处始终为 "chat.completion"。

  • usage (UsageInfo, 必填, 默认=空的 UsageInfo 对象): 包含此特定请求的 API 使用情况信息。

ChatCompletionStreamResponse

  • id (str, 必填): 流式聊天完成会话的唯一标识符。

  • choices (List[ChatCompletionStreamResponseChoice], 必填): 一组 ChatCompletionStreamResponseChoice 对象,每个对象表示流式聊天响应的一部分。

  • created (int, 必填, 默认=当前时间): 流式响应的创建时间,表示为 UNIX 时间戳。

  • model (str, 必填): 指定用于生成流式聊天完成的模型。

  • system_fingerprint (str, 必填): 生成流式完成的系统的唯一标识符。

  • object (Literal["chat.completion.chunk"], 必填, 默认="chat.completion.chunk"): 字面量,表示此对象代表流式聊天完成的块。


示例

以下是使用 API 与 MLC-LLM 进行交互的 Python 示例,包含流式传输。

import requests
import json

# Get a response using a prompt with streaming
payload = {
 "model": "./dist/Llama-2-7b-chat-hf-q4f16_1-MLC/",
 "messages": [{"role": "user", "content": "Write a haiku"}],
 "stream": True,
}
with requests.post("http://127.0.0.1:8080/v1/chat/completions", json=payload, stream=True) as r:
   for chunk in r.iter_content(chunk_size=None):
      chunk = chunk.decode("utf-8")
      if "[DONE]" in chunk[6:]:
         break
      response = json.loads(chunk[6:])
      content = response["choices"][0]["delta"].get("content", "")
      print(content, end="", flush=True)
print("\n")

还支持类似于 OpenAI 的函数调用功能(https://platform.openai.com/docs/guides/function-calling)。以下是如何在 Python 中使用函数调用的示例。

import requests
import json

tools = [
   {
      "type": "function",
      "function": {
            "name": "get_current_weather",
            "description": "Get the current weather in a given location",
            "parameters": {
               "type": "object",
               "properties": {
                  "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA",
                  },
                  "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
               },
               "required": ["location"],
            },
      },
   }
]

payload = {
   "model": "./dist/gorilla-openfunctions-v1-q4f16_1-MLC/",
   "messages": [
      {
            "role": "user",
            "content": "What is the current weather in Pittsburgh, PA in fahrenheit?",
      }
   ],
   "stream": False,
   "tools": tools,
}

r = requests.post("http://127.0.0.1:8080/v1/chat/completions", json=payload)
print(f"{r.json()['choices'][0]['message']['tool_calls'][0]['function']}\n")

# Output: {'name': 'get_current_weather', 'arguments': {'location': 'Pittsburgh, PA', 'unit': 'fahrenheit'}}

还支持流式传输的函数调用。以下是如何在 Python 中使用流式传输的函数调用的示例。

import requests
import json

tools = [
   {
      "type": "function",
      "function": {
            "name": "get_current_weather",
            "description": "Get the current weather in a given location",
            "parameters": {
               "type": "object",
               "properties": {
                  "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA",
                  },
                  "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
               },
               "required": ["location"],
            },
      },
   }
]

payload = {
   "model": "./dist/gorilla-openfunctions-v1-q4f16_1-MLC/",
   "messages": [
      {
            "role": "user",
            "content": "What is the current weather in Pittsburgh, PA and Tokyo, JP in fahrenheit?",
      }
   ],
   "stream": True,
   "tools": tools,
}

with requests.post("http://127.0.0.1:8080/v1/chat/completions", json=payload, stream=True) as r:
 for chunk in r.iter_content(chunk_size=None):
     chunk = chunk.decode("utf-8")
     if "[DONE]" in chunk[6:]:
         break
     response = json.loads(chunk[6:])
     content = response["choices"][0]["delta"].get("content", "")
     print(f"{content}", end="", flush=True)
print("\n")

# Output: ["get_current_weather(location='Pittsburgh,PA',unit='fahrenheit')", "get_current_weather(location='Tokyo,JP',unit='fahrenheit')"]

备注

该 API 是统一的接口,支持多种语言。您也可以在 Python 以外的语言中使用这些功能。