vLLM-v0.17.1 API设计详解:从零构建类似OpenAI的接口服务

1. 为什么需要兼容OpenAI的API接口

大模型服务生态中,OpenAI的API格式已经成为事实标准。许多第三方工具和应用都内置了对OpenAI API格式的支持。如果你的服务能兼容这种格式,开发者就能直接使用他们熟悉的工具链来调用你的服务,而不需要额外适配。

举个例子,像LangChain这样的流行框架默认就支持OpenAI的API格式。如果你的服务也采用相同格式,开发者就能无缝切换不同的模型服务提供商。

2. vLLM基础API快速入门

vLLM本身提供了一套原生的API接口,我们先快速了解一下它的基本用法。安装最新版vLLM很简单:

pip install vllm==0.17.1

启动一个基础服务只需要几行代码:

from vllm import LLM, SamplingParams

llm = LLM(model="meta-llama/Llama-2-7b-chat-hf")
sampling_params = SamplingParams(temperature=0.7, top_p=0.9)

outputs = llm.generate(["你好,介绍一下你自己"], sampling_params)
print(outputs[0].text)

这个原生API虽然简单直接,但缺少企业级服务需要的许多功能,比如标准化响应格式、身份验证等。

3. 设计兼容OpenAI的API接口

3.1 请求和响应格式

OpenAI的API主要使用JSON格式进行数据交换。一个典型的聊天补全请求如下:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "system", "content": "你是一个有帮助的助手"},
    {"role": "user", "content": "你好,你是谁?"}
  ],
  "temperature": 0.7
}

对应的响应格式应该是:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "我是一个AI助手"
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

3.2 使用FastAPI实现基础路由

我们可以用FastAPI来构建这个接口服务。首先创建一个基础路由:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class ChatMessage(BaseModel):
    role: str
    content: str

class ChatCompletionRequest(BaseModel):
    model: str
    messages: list[ChatMessage]
    temperature: float = 0.7

@app.post("/v1/chat/completions")
async def create_chat_completion(request: ChatCompletionRequest):
    # 这里将实现vLLM调用逻辑
    pass

4. 集成vLLM引擎

现在我们需要把vLLM的推理能力集成到这个API中。关键是要把OpenAI格式的消息列表转换为vLLM能理解的提示词:

def convert_messages_to_prompt(messages):
    prompt = ""
    for msg in messages:
        if msg.role == "system":
            prompt += f"<|system|>\n{msg.content}</s>\n"
        elif msg.role == "user":
            prompt += f"<|user|>\n{msg.content}</s>\n"
        elif msg.role == "assistant":
            prompt += f"<|assistant|>\n{msg.content}</s>\n"
    prompt += "<|assistant|>\n"
    return prompt

然后完善我们的API端点:

from vllm import SamplingParams

@app.post("/v1/chat/completions")
async def create_chat_completion(request: ChatCompletionRequest):
    prompt = convert_messages_to_prompt(request.messages)
    sampling_params = SamplingParams(
        temperature=request.temperature,
        top_p=0.9,
        max_tokens=1024
    )
    
    outputs = llm.generate([prompt], sampling_params)
    completion = outputs[0].text
    
    return {
        "id": f"chatcmpl-{uuid.uuid4()}",
        "object": "chat.completion",
        "created": int(time.time()),
        "choices": [{
            "index": 0,
            "message": {
                "role": "assistant",
                "content": completion
            },
            "finish_reason": "length"
        }],
        "usage": {
            "prompt_tokens": len(outputs[0].prompt_token_ids),
            "completion_tokens": len(outputs[0].output_token_ids),
            "total_tokens": len(outputs[0].prompt_token_ids) + len(outputs[0].output_token_ids)
        }
    }

5. 添加企业级功能

5.1 身份验证

生产环境必须要有身份验证。我们可以使用API密钥:

from fastapi import Depends, Header

async def verify_api_key(api_key: str = Header(...)):
    if api_key != "your-secret-key":
        raise HTTPException(status_code=401, detail="Invalid API key")

@app.post("/v1/chat/completions", dependencies=[Depends(verify_api_key)])
async def create_chat_completion(request: ChatCompletionRequest):
    # 原有实现

5.2 速率限制

防止滥用需要添加速率限制。可以使用FastAPI的中间件:

from fastapi import Request
from fastapi.middleware import Middleware
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.post("/v1/chat/completions")
@limiter.limit("10/minute")
async def create_chat_completion(request: ChatCompletionRequest, request: Request):
    # 原有实现

5.3 日志记录

记录请求和响应有助于监控和调试:

import logging

logging.basicConfig(filename='api.log', level=logging.INFO)

@app.post("/v1/chat/completions")
async def create_chat_completion(request: ChatCompletionRequest):
    start_time = time.time()
    
    # 原有实现
    
    duration = time.time() - start_time
    logging.info(f"Request: {request.model} | Duration: {duration:.2f}s | Tokens: {response['usage']['total_tokens']}")
    return response

6. 部署和优化建议

现在你已经有了一个功能完整的API服务,接下来可以考虑:

  1. 使用uvicorn或gunicorn部署服务
  2. 添加健康检查端点
  3. 实现批处理请求以提高吞吐量
  4. 添加模型预热功能
  5. 考虑使用Redis等缓存常见请求

完整的服务代码可以打包成Docker镜像,方便部署到各种云平台。记得在部署前进行充分的压力测试,确保服务能够处理预期的请求量。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐