大模型 API 推理全指南 | OneAPI + Ollama + vLLM + ChatTool
OneAPI + vLLM + Ollama + ChatTool,探索如何通过 OpenAI 风格的 API 接口,优雅地管理和调用各种大模型。
唠唠闲话
随着模型训练和推理技术的成熟,我们如何在资源有限的情况下更有效地利用这些技术?
近年来,各种方案的出现极大地降低了科研门槛。从 vLLM 项目的内存优化到端侧小模型和代理运行超大模型,这些方案为模型推理提供了多样化的路径。
本文旨在探讨模型推理的技术方案,提供一个全面的入门指南,包括开源和闭源服务。
关联项目
我们从模型的性能效率和调用方式两个关键角度切入,涉及项目:
每部分都有很多优秀的开源项目,这里只列举一个有代表性。
实践目标:
- 在本地运行新发布的开源模型,且减少硬件限制(量化推理)增加推理效率(内存优化)
- 运行主流的 API 服务,包括 Gemini/Claude 等
- 更简单灵活地调用 API,以及并发处理数据
为什么用 API 接口?
自 2023 年 3 月推出 ChatGPT API 服务以来,几乎所有大模型服务和项目都支持 OpenAI 接口,这已然成为行业标准。使用 OpenAI 风格的 API 进行大模型推理有以下好处:
- 通用性:一套代码可适配调用各类大模型。
- 广泛支持:商用模型服务和开源项目均支持这一接口。
- 灵活性:API 化的大模型可在不使用时关闭服务,有效减少 GPU 资源占用。
- 易于配置:开源工具能轻松将任意模型服务转换为 OpenAI 接口规范的服务。
当然,这种方法也有局限,例如部分特性(如 system prompt 和 Function call)可能与某些模型不兼容。不过,诸如 Xinference 和 Langchain Tools 等项目可以弥补这些不足。
OneAPI 项目
OneAPI 是一个 API 管理和分发系统,支持几乎所有主流 API 服务。OneAPI 通过简单的配置允许使用一个 API 密钥调用不同的服务,实现服务的高效管理和分发。
讯飞/智谱/千问/Gemini/Claude,其模型调用方式各不相同,但借助 OneAPI 能统一转化为 OpenAI 格式。
官方提供了一键部署的 docker-compose 方案。部署完成后,访问 http://localhost:3000/ 并使用初始账号(用户名为 root,密码为 123456)进行登录,登录后根据提示修改密码。
类似的开源项目还有 AI GateWay 或者 LiteLLM等,各有优劣,但个人强推 OneAPI。
支持模型
下表列举了几个 OneAPI 支持的 API 服务,完整的模型列表参见 OneAPI 官方仓库。
所属公司 | 模型 | 文档地址 | 备注 |
---|---|---|---|
面壁智能 | 智谱 glm | 智谱 API 文档 | 新用户 1B Token 免费额度,1个月有效期 |
阿里云 | 通义千问 Qwen | 千问 API 文档 | 新用户 1B Token 免费额度,半年有效期 |
百川智能 | 百川大模型 | 百川 API 文档 | 新用户 8元免费额度,3个月有效期 |
讯飞 | SparkDesk | 讯飞 API 文档 | 新用户 100K Token 免费额度,1年有效期 |
谷歌 | Gemini/PaLM2 | Google API 文档 | 提供免费版 API,存在使用限制 |
OpenAI | GPT | OpenAI API 文档 | 网页版可免登录使用,API 需国外银行卡 |
微软 | Azure | Azure API 文档 | 需注册 Azure 账号,支持国内 visa 信用卡或双币卡 |
添加渠道
集成各类 API 服务添加到 OneAPI 中:
以谷歌的 Gemini 为例:点击渠道 => 新建渠道
内容说明:
- 渠道名称:自定义
- 渠道 API 地址:官方 API 地址或者反向代理地址
- 用户组:这个选项是给号商用的,可以不管
- 模型:填入用户调用模型
- 密钥:API 密钥
- 模型映射关系:用户调用模型 => 实际调用模型。比如
{ "dall-e-3": "cogview-3" }
:当用户请求dall-e-3
时,实际请求了cogview-3
模型。
模型映射关系在一些场景很有用,比如:
- LlamaIndex 中使用 OpenAI 对象,非 GPT 的模型名称会报错
- lobe-hub 自带的绘图插件只支持调用
dall-e-3
模型
创建密钥
添加渠道后,点击令牌,新建令牌,创建密钥,复制密钥。密钥作用等同于 OpenAI 的 API。
渠道存在优先级,如果同一模型有多个渠道支持,OneAPI 会按权重使用不同渠道。但 root 用户可通过 -k
指定渠道,比如下边添加了两个渠道:
通过 sk-xxxxxx-1
指定 ChatAnywhere
渠道,通过 sk-xxxxxx-2
指定 bichat
渠道。
除此之外,你可以让每个模型只对应一个渠道,这样指定模型时,渠道也是确定的。
创建密钥后,走服务地址作为 API 代理地址,比如在本地启动服务,走 localhost
:
OPENAI_API_BASE=http://localhost:3000/v1
分配用户
OneAPI 支持多用户管理,root 和管理员能管理模型渠道,配置额度。普通用户则在注册后,通过添加兑换码导入额度。
创建密钥的过程与前边一致。
配置 Nginx
假设服务运行在 3000
端口,配置访问域名为 one-api.example.com
server {
listen 80;
server_name one-api.example.com;
location /{
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# 流式
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
# 设置等待响应的时长
proxy_send_timeout 300;
# proxy_connect_timeout 300;
# proxy_read_timeout 300;
# send_timeout 300;
}
}
类似可配置 https 的访问。
反向代理
反向代理主要用于 OpenAI, Gemini, Claude 等限制国内 IP 访问服务。以 Gemini 为例,在支持访问的服务器上配置 Nginx:
server {
listen 80;
server_name your.domain.com;
location / {
proxy_pass https://generativelanguage.googleapis.com;
proxy_set_header Host generativelanguage.googleapis.com;
proxy_ssl_server_name on;
proxy_cache off;
proxy_buffering off;
proxy_connect_timeout 7200;
}
}
然后将代理链接 your.domain.com
并导入 OneAPI 的 Gemini 渠道。类似方法适用于对 Claude 和 OpenAI 等服务的转发。
模型代理站
如果硬件资源不足,可以用代理站作为补充。优点是省事,访问快,支持超大模型。缺点是数据经过一手,安全隐患增加一层,使用代理站更多出于实验方便。这里推荐几个站点:
代理站 | 服务地址 | 模型支持 | 备注 |
---|---|---|---|
Chatanywhere | chatanywhere/GPT_API_free | OpenAI 系列 | 速度快,价格低 |
沃卡 | wokaai.com | OpenAI/Claude/Gemini/Midjourney | 基于 OneAPI 项目 |
Chandler.ai | ChandlerAi | OpenAI/Claude/Grok 等 | 需国外信用卡 |
NeutrinoAPP | neutrinoapp.com | OpenAI/开源模型 | 需国外信用卡 |
monsterapi.ai | monsterapi.ai | 仅开源模型 | 支持模型微调,需国外信用卡 |
Predibase | Predibase AI | codellama/llama/gemma/mixtral 等 | 支持模型微调,需国外信用卡 |
后两个网站提供对开源模型的微调和推理服务,支持多种模型和微调方式,比如 MonsterAPI:
vllm
前边讲了闭源 API 转成 OpenAI 风格的方式,下边介绍开源模型如何以 OpenAI Style 启动,继而也能导入到 OneAPI 统一管理。这方面我们讲两个比较有代表性的项目。
vLLM 是去年6月推出的一个大模型推理加速框架,通过 PagedAttention 高效管理 attention 中缓存的张量,实现了比 HuggingFace Transformers 高 24 倍的吞吐量。vLLM 支持的开源模型包括 Llama,百川,千问等模型,也支持基于这些模型架构训练或微调得到的模型,比如 Lemur:
vLLM 提供了一个 OpenAI 风格的 API 服务,比如启动百川模型
# pip install vllm
python -m vllm.entrypoints.openai.api_server \
--model /sshfs/pretrains/baichuan-inc/Baichuan2-13B-Chat \
--trust-remote-code \
--tensor-parallel-size 2 \
--served-model-name baichuan \
--api-key sk-xxxx \
--port 8000
参数说明(Ref:官方文档 - OpenAI Compatible Server):
--model
:模型路径,本地路径需加上--trust-remote-code
参数--tensor-parallel-size
:模型使用的 GPU 数目--served-model-name
:用户访问的模型名称--api-key
:API 密钥,可不填,允许任意密钥访问--port
:服务端口
vLLM 还支持 推理量化,加载 Lora 参数和分布式推理等。
类似 vllm 的项目还有 LightLLM 和 FasterTransformer等。
Ollama
GGUF 格式以及 Ollama 更深入的介绍,另外再开帖子讨论
相比 vllm 或者直接使用 huggingface 的模型推理 Pipeline。ollama 极大降低了模型使用门槛:
- 零 Python 代码以 OpenAI 风格启动模型
- 支持在普通电脑上运行量化模型,低显存占用,支持 CPU 推理。
从 32 位量化到 4bit,会一定程度降低模型的表现,一种取舍,涉及模型压缩技术。
部署及使用
Docker 部署:https://ollama.com/blog/ollama-is-now-available-as-an-official-docker-image
API 文档:https://github.com/ollama/ollama/blob/main/docs/api.md
推荐使用 docker-compose 部署一键启动服务,方便修改端口,GPU 配置以及模型下载路径等:
version: '3.8'
services:
ollama:
image: ollama/ollama
container_name: ollama
ports:
- "11434:11434"
volumes: # 模型路径
- /sshfs/ollama:/root/.ollama
environment:
- CUDA_VISIBLE_DEVICES=6,7
# - OLLAMA_HOST="http://localhost:11434"
# - OLLAMA_KEEP_ALIVE="5m"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
restart: unless-stopped
http://localhost:11434
为 API 服务地址。
创建别名:
alias ollama='docker exec -it ollama ollama'
基本操作:
# 拉取模型,比如千问
ollama pull qwen:0.5b
# 查看拉取的模型列表
ollama list
GGUF 格式
GGUF: GPT-Generated Unified Format
GGUF:GPT 生成的统一格式
文档:https://github.com/ggerganov/ggml/blob/master/docs/gguf.md
模型量化方式:Which Quantization Method Is Best for You?: GGUF, GPTQ, or AWQ
GGUF 由llama.cpp团队介绍。它是一种为大型语言模型设计的量化方法。它允许用户在 CPU 上运行LLMs,同时通过提供速度改进将某些层卸载到 GPU。
GGUF 对于在 CPU 或 Apple 设备上运行模型的用户特别有用。在 GGUF 上下文中,量化涉及缩小模型权重(通常存储为 16 位浮点数)以节省计算资源。
GGUF 是一种更有效、更灵活的存储和用于LLMs推理的方式。它专为快速加载和保存模型而量身定制,采用用户友好的方法来处理模型文件。
开发者:Georgi Gerganov
文档:https://github.com/ggerganov/ggml/blob/master/docs/gguf.md
HuggingFace 大佬 Tom Jobbins 对大量的主流模型进行了量化。
量化模型的仓库地址:https://huggingface.co/TheBloke
模型列表
支持列表:https://ollama.com/library
Embedding:Embedding models
以 codellama 为例:
主要的关键字:模型参数量,模型类型,量化级别,量化方式。
模型类型 | 说明 |
---|---|
instruct | Fine-tuned to generate helpful and safe answers in natural language |
python | A specialized variation of Code Llama further fine-tuned on 100B tokens of Python code |
code | Base model for code completion |
内存占用方面,千问 Qwen-72b-1.5 模型,4-bit 量化,推理显存 40G 左右,两张 3090 可用:
加载本地模型
文档:https://github.com/ollama/ollama/blob/main/docs/import.md
启动 hf 模型
- safetensor 格式
- GGUF 格式
缺陷
- 切换模型问题
- 首次加载问题
- 并发问题(特性已更新):https://github.com/ollama/ollama/pull/3418
数据量大,当前仍需要 vllm 等项目。
flask
最后,如果需要对 API 进行灵活定制,可以用 flask 或 FastAPI 手写服务。举个例子,以 OpenAI 风格启动 HuggingFace 的 Embedding 模型:
from flask import Flask, request, jsonify
from sentence_transformers import SentenceTransformer
app = Flask(__name__)
# 加载模型
model_path = '/sshfs/pretrains/moka-ai/m3e-large'
model = SentenceTransformer(model_path)
@app.route('/v1/embeddings', methods=['POST'])
def get_embeddings():
data = request.get_json()
if not all((data, 'input' in data, 'model' in data)):
return jsonify({"error": "Missing required fields in request body"}), 400
input_text = data['input']
# 将单个输入转换为列表
if isinstance(input_text, str):
input_text = [input_text]
# 调用模型获取 embeddings
embeddings = model.encode(input_text)
# 构造响应
embeddings_response = []
for index, embedding in enumerate(embeddings):
embedding_dict = {
"object": "embedding",
"embedding": embedding.tolist(), # 将 numpy 数组转换为列表
"index": index
}
embeddings_response.append(embedding_dict)
# 可选: Token 计数
response = {
"object": "list",
"data": embeddings_response,
"model": data['model'],
"usage": {
"prompt_tokens": sum(len(text.split()) for text in input_text),
"total_tokens": sum(len(text.split()) for text in input_text)
}
}
return jsonify(response)
if __name__ == '__main__':
app.run(debug=True, port=5000, host='0.0.0.0')
测试请求:
curl -H "Content-Type: application/json" \
-X POST \
-d '{"input": "The food was delicious and the waiter...", "model": "text-embedding-ada-002"}' \
http://localhost:5000/v1/embeddings
除了常规策略,还有基于 ChatGPT 网页端进行逆向白嫖的,比如 FreeGPT35,GPT4Free 和 coze-discord 等,当前暂不讨论。
ChatTool
用 API 跑数据可以直接用官方库 openai
,也可以用 ChatTool,基于 API 的封装,支持多轮对话,异步处理数据等。
先进行配置:
export OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export OPENAI_API_BASE="https://one-api.example.com/v1"
或者在代码中设置:
import chattool
chattool.api_key = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
chattool.api_base = "https://one-api.example.com/v1"
举两个例子。
-
将数字翻译为罗马数字,串行处理数据,缓存文件为
chat.jsonl
:def data2chat(msg): chat = Chat() chat.system("你是一个熟练的数字翻译家。") chat.user(f"请将该数字翻译为罗马数字:{msg}") chat.model = "gpt-3.5-turbo" # 默认模型 # 注意: 在函数内执行 getresponse chat.getresponse(max_tries=3) return chat checkpoint = "chat.jsonl" # 缓存文件的名称 msgs = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] chats = process_chats(msgs, data2chat, checkpoint) # chats = load_chats(checkpoint)
-
用不同语言打印
hello world
,并行处理数据from chattool import async_chat_completion, load_chats, Chat langs = ["python", "java", "Julia", "C++"] def data2chat(msg): chat = Chat() chat.user("请用语言 %s 打印 hello world" % msg) # 注意:不需要 getresponse 而交给异步处理 return chat async_chat_completion(langs, chkpoint="async_chat.jsonl", nproc=2, data2chat=data2chat) chats = load_chats("async_chat.jsonl")
在 Jupyter Notebook 中运行,需要使用
await
关键字和wait=True
参数:await async_chat_completion(langs, chkpoint="async_chat.jsonl", nproc=2, data2chat=data2chat, wait=True)
以上,将模型整合到 API 网关,统一服务接口供代码调用。这样,我们就能轻松地集成各类大模型,也省去配置环境的麻烦。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)