拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Datawhale self-llm 实战:Qwen2.5-Coder-7B-Instruct 基于 FastAPI 的本地推理服务部署与调用

Datawhale self-llm 实战Qwen2.5-Coder-7B-Instruct 基于 FastAPI 的本地推理服务部署与调用【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/datawhalechina/self-llm导读本文是《开源大模型食用指南》Datawhale / self-llm中 Qwen2.5-Coder 系列模型部署实战的第一篇聚焦如何基于FastAPI Transformers在 LinuxCUDA环境下将代码生成大模型 Qwen2.5-Coder-7B-Instruct 封装为一个可通过 HTTP 访问的本地推理服务。读完本文你将掌握环境与依赖的快速搭建、基于 ModelScope 的模型下载、api.py服务端完整实现含 Chat Template 应用、GPU 显存回收等关键细节以及用curl与 Pythonrequests两种方式调用服务的完整链路。文中还穿插了同仓库 LangChain 接入、WebDemo 与 vLLM 部署等姊妹篇的对比视角帮助你理解不同部署方案的适用场景。1. 部署方案概览与适用场景在进入实操前先明确本方案在整个项目中的定位。在 models/Qwen2.5-Coder 目录下官方围绕同一模型提供了多条部署/微调路径文档方案核心依赖适用场景01-Qwen2.5-Coder-7B-Instruct FastApi 部署调用.mdFastAPI 封装 Transformersfastapi / uvicorn / transformers自定义 HTTP 接口、与业务系统集成、深入理解模型调用细节02-Qwen2.5-7B-Instruct Langchain 接入.mdLangChain 自定义 LLMlangchain构建 Agent / 知识库等 LLM 应用框架03-Qwen2.5-Coder-7B-Instruct WebDemo部署.mdStreamlit 聊天界面streamlit快速可视化体验、交互式对话04-Qwen2.5-Coder-7B-Instruct vLLM 部署调用.mdvLLM 高性能推理vllm高吞吐、生产级推理、OpenAI 兼容 API本篇文章的核心是第一条链路自己手写一个 FastAPI 服务。它的优势在于代码完全透明、依赖最少、可自由定制请求/响应格式非常适合理解模型推理是如何被 HTTP 服务包装起来的完整过程也是后续学习 LangChain 接入、Streamlit 界面搭建的基础。环境提示仓库中 General-Setting/01-pip、conda换源.md 与 General-Setting/03-模型下载.md 提供了更通用的环境与模型下载指南可作为补充阅读。2. 环境准备本文的完整运行环境如下也是整个 self-llm 项目文档的基准环境之一---------------- ubuntu 22.04 python 3.12 cuda 12.1 pytorch 2.3.0 ----------------默认学习者已安装好以上 Pytorch(CUDA) 环境如未安装请自行安装。2.1 pip 换源与依赖安装考虑到国内网络环境先升级 pip 并将 pypi 源切换为清华镜像再按固定版本安装依赖保证可复现性# 升级pip python -m pip install --upgrade pip # 更换 pypi 源加速库的安装 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install requests2.31.0 pip install fastapi0.115.1 pip install uvicorn0.30.6 pip install transformers4.46.2 pip install huggingface-hub0.26.2 pip install accelerate0.34.2 pip install modelscope1.20.0各依赖在链路中的角色如下fastapiWeb 框架负责接收 HTTP 请求、路由分发、返回 JSON 响应uvicornASGI 服务器真正把 FastAPI 应用跑起来绑定主机与端口transformers加载模型与分词器执行对话模板与文本生成accelerate支持device_mapauto自动分配设备方便多卡/混合加载modelscope从 ModelScope 模型库下载模型权重requests本地调试时作为 HTTP 客户端调用服务。关于版本一致性可以留意FastAPI 部署篇与 LangChain 接入篇 均采用transformers4.46.2、modelscope1.20.0说明这两篇文档针对同一模型、同一镜像环境编写可无缝衔接。如果本机环境配置困难仓库在 AutoDL 平台提供了 Qwen2.5 系列的环境镜像codewithgpu 一键创建示例可直接使用而无需重复安装。3. 模型下载ModelScope 一行命令拉取权重本教程统一使用 ModelScope 的snapshot_download函数下载模型它会把模型的全部文件权重、配置、分词器词表等快照到本地目录。新建model_download.py文件并写入import torch from modelscope import snapshot_download, AutoModel, AutoTokenizer import os model_dir snapshot_download(qwen/Qwen2.5-Coder-7B-Instruct, cache_dir/root/autodl-tmp, revisionmaster)参数说明第一个参数qwen/Qwen2.5-Coder-7B-InstructModelScope 上的模型仓库 IDcache_dir模型下载保存路径务必修改为你自己的实际路径如/root/autodl-tmprevision模型仓库分支版本此处固定为master。保存后运行python model_download.py模型大小约 15 GB视网速一般需要几分钟。下载完成后模型会落在cache_dir下的qwen/Qwen2___5-Coder-7B-Instruct目录ModelScope 会将仓库 ID 中的/与-转换为___/_形式这个本地路径将直接用于后续代码中的model_name_or_path。4. 编写 FastAPI 推理服务api.py新建api.py文件写入以下完整代码。这段代码是整篇文章的核心包含环境变量配置、GPU 显存回收、POST 接口处理、对话模板应用、模型加载与服务启动五个部分注释已非常详尽from fastapi import FastAPI, Request from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig import uvicorn import json import datetime import torch # 设置设备参数 DEVICE cuda # 使用CUDA DEVICE_ID 0 # CUDA设备ID如果未设置则为空 CUDA_DEVICE f{DEVICE}:{DEVICE_ID} if DEVICE_ID else DEVICE # 组合CUDA设备信息 # 清理GPU内存函数 def torch_gc(): if torch.cuda.is_available(): # 检查是否可用CUDA with torch.cuda.device(CUDA_DEVICE): # 指定CUDA设备 torch.cuda.empty_cache() # 清空CUDA缓存 torch.cuda.ipc_collect() # 收集CUDA内存碎片 # 创建FastAPI应用 app FastAPI() # 处理POST请求的端点 app.post(/) async def create_item(request: Request): global model, tokenizer # 声明全局变量以便在函数内部使用模型和分词器 json_post_raw await request.json() # 获取POST请求的JSON数据 json_post json.dumps(json_post_raw) # 将JSON数据转换为字符串 json_post_list json.loads(json_post) # 将字符串转换为Python对象 prompt json_post_list.get(prompt) # 获取请求中的提示 messages [ {role: system, content: You are a helpful assistant.}, {role: user, content: prompt} ] # 调用模型进行对话生成 input_ids tokenizer.apply_chat_template(messages,tokenizeFalse,add_generation_promptTrue) model_inputs tokenizer([input_ids], return_tensorspt).to(cuda) generated_ids model.generate(model_inputs.input_ids,max_new_tokens512) generated_ids [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ] response tokenizer.batch_decode(generated_ids, skip_special_tokensTrue)[0] now datetime.datetime.now() # 获取当前时间 time now.strftime(%Y-%m-%d %H:%M:%S) # 格式化时间为字符串 # 构建响应JSON answer { response: response, status: 200, time: time } # 构建日志信息 log [ time ] , prompt: prompt , response: repr(response) print(log) # 打印日志 torch_gc() # 执行GPU内存清理 return answer # 返回响应 # 主函数入口 if __name__ __main__: # 加载预训练的分词器和模型 model_name_or_path /root/autodl-tmp/qwen/Qwen2___5-Coder-7B-Instruct tokenizer AutoTokenizer.from_pretrained(model_name_or_path, use_fastFalse) model AutoModelForCausalLM.from_pretrained(model_name_or_path, device_mapauto, torch_dtypetorch.bfloat16) # 启动FastAPI应用 # 用6006端口可以将autodl的端口映射到本地从而在本地使用api uvicorn.run(app, host0.0.0.0, port6006, workers1) # 在指定端口和主机上启动应用4.1 关键实现点逐段解析设备与显存管理DEVICE/DEVICE_ID组合出CUDA_DEVICEtorch_gc()在每次请求结束后调用empty_cache()清空 PyTorch 缓存的显存碎片并通过ipc_collect()回收 CUDA 上下文中的空闲内存块。对于长时运行的推理服务这是防止多轮请求后显存不断膨胀的重要习惯。接口处理app.post(/)注册根路径的 POST 端点。通过await request.json()异步读取请求体再经过json.dumps→json.loads的往返转换拿到字典最后用.get(prompt)提取用户提示词。这里刻意走了一遍 JSON 字符串化目的是统一处理不同客户端curl / requests / 其他语言可能带来的类型差异。对话模板Chat TemplateQwen2.5-Coder 采用的是 Qwen 系标准的 ChatML 模板在 LoRA 微调文档 中也有明确记录|im_start|system You are Qwen, created by Alibaba Cloud. You are a helpful assistant.|im_end| |im_start|user {user_prompt}|im_end| |im_start|assistant {assistant_response}|im_end|代码中tokenizer.apply_chat_template(messages, tokenizeFalse, add_generation_promptTrue)的作用正是把 messages 列表按上述模板拼成纯文本tokenizeFalse并在末尾追加|im_start|assistant\n生成提示符add_generation_promptTrue提示模型开始作答。这种写法比手工拼接模板更不易出错也是后续 LangChain 接入篇 与 vLLM 部署篇 统一采用的方式。生成与解码model.generate以max_new_tokens512限定本次生成的最大新 token 数。生成后通过zip(model_inputs.input_ids, generated_ids)将输出截掉输入前缀只保留新增部分再用batch_decode(..., skip_special_tokensTrue)解码为可读文本skip_special_tokens会去掉|im_end|等特殊符号。模型加载AutoTokenizer.from_pretrained(..., use_fastFalse)使用慢速Python 实现分词器use_fastFalse可避免部分模型在 fast tokenizer 下的兼容性问题模型则用torch_dtypetorch.bfloat16以半精度加载约需 15~16 GB 显存device_mapauto交由 accelerate 自动分配设备单卡或多卡均可。服务启动uvicorn.run(app, host0.0.0.0, port6006, workers1)将服务绑定到所有网卡接口的 6006 端口。6006 是 AutoDL 默认可端口映射的端口之一在 AutoDL 平台上把 6006 映射到本地后即可在本地浏览器/脚本中访问该 API。5. 启动服务并验证5.1 启动 api 服务在终端执行cd /root/autodl-tmp python api.py # or python /root/autodl-tmp/api.py首次启动会先加载模型权重约 15 GB输出Loading checkpoint shards等日志随后出现Application startup complete与Uvicorn running on http://0.0.0.0:6006即代表服务启动成功如下图所示5.2 用 curl 调用接口服务默认部署在 6006 端口通过 POST 方法调用。使用 curl 发起一次生成深度学习训练代码的请求curl -X POST http://127.0.0.1:6006 \ -H Content-Type: application/json \ -d {prompt: 帮我生成一份深度学习网络训练的python代码。}返回的 JSON 结构如下省略了过长的代码正文{response: 当然可以以下是一个使用TensorFlow和Keras构建和训练简单卷积神经网络CNN的Python代码示例。……,status:200,time:2024-11-15 13:47:30}响应中三个字段的含义response模型生成的文本代码内容status业务状态码固定为 200time服务端处理该请求的时间戳。模型实际生成的 TensorFlow/Keras 版 CNN 训练代码完整可运行如下import tensorflow as tf from tensorflow.keras import layers, models # 加载MNIST数据集 (train_images, train_labels), (test_images, test_labels) tf.keras.datasets.mnist.load_data() # 归一化像素值到0-1之间 train_images, test_images train_images / 255.0, test_images / 255.0 # 将标签转换为one-hot编码 train_labels tf.keras.utils.to_categorical(train_labels) test_labels tf.keras.utils.to_categorical(test_labels) # 构建卷积神经网络模型 model models.Sequential([ layers.Conv2D(32, (3, 3), activationrelu, input_shape(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activationrelu), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activationrelu), layers.Flatten(), layers.Dense(64, activationrelu), layers.Dense(10, activationsoftmax) ]) # 编译模型 model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy]) # 训练模型 history model.fit(train_images.reshape(-1, 28, 28, 1), train_labels, epochs5, validation_data(test_images.reshape(-1, 28, 28, 1), test_labels)) # 评估模型 test_loss, test_acc model.evaluate(test_images.reshape(-1, 28, 28, 1), test_labels, verbose2) print(f\nTest accuracy: {test_acc})curl 调用与返回结果的完整截图如下可以看到服务端返回的 JSON 中response字段携带了完整代码5.3 用 Python requests 调用接口在实际项目中更常见的是用 Python 脚本调用服务。新建测试脚本import requests import json def get_completion(prompt): headers {Content-Type: application/json} data {prompt: prompt} response requests.post(urlhttp://127.0.0.1:6006, headersheaders, datajson.dumps(data)) return response.json()[response] if __name__ __main__: print(get_completion(帮我生成一份深度学习网络训练的python代码(pytorch)。))运行后返回 PyTorch 版本的 CNN 训练代码import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms # 定义超参数 batch_size 64 learning_rate 0.001 num_epochs 5 # 数据预处理 transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) # 加载MNIST数据集 train_dataset datasets.MNIST(root./data, trainTrue, transformtransform, downloadTrue) test_dataset datasets.MNIST(root./data, trainFalse, transformtransform) # 创建数据加载器 train_loader torch.utils.data.DataLoader(datasettrain_dataset, batch_sizebatch_size, shuffleTrue) test_loader torch.utils.data.DataLoader(datasettest_dataset, batch_sizebatch_size, shuffleFalse) # 定义卷积神经网络模型 class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 nn.Conv2d(1, 32, kernel_size3, stride1, padding1) self.relu nn.ReLU() self.pool nn.MaxPool2d(kernel_size2, stride2, padding0) self.fc1 nn.Linear(32 * 14 * 14, 128) self.fc2 nn.Linear(128, 10) def forward(self, x): out self.conv1(x) out self.relu(out) out self.pool(out) out out.view(out.size(0), -1) out self.fc1(out) out self.relu(out) out self.fc2(out) return out model CNN() # 定义损失函数和优化器 criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lrlearning_rate) # 训练模型 for epoch in range(num_epochs): model.train() for i, (images, labels) in enumerate(train_loader): # 前向传播 outputs model(images) loss criterion(outputs, labels) # 反向传播和优化注意这里代码不完整是因为服务端设置了max_new_tokens512生成长度被截断——这是控制输出成本的正常现象如需更长的代码可调大该参数。Python 调用返回的代码生成效果截图如下6. 部署方案的横向延伸仓库佐证掌握了 FastAPI 自建服务后可以横向对比仓库中另外三种部署方式理解各自的定位LangChain 接入02 文档通过继承langchain.llms.base.LLM并重写构造函数与_call方法把本地 Qwen2.5-Coder 封装成自定义 LLM 类Qwen2_5_Coder。其内部推理逻辑与本文 api.py 完全一致同样的apply_chat_templategeneratebatch_decode三步区别在于把模型常驻内存、通过 LangChain 统一接口对外暴露适合构建 Agent 与知识库应用。WebDemo 部署03 文档基于 Streamlit 提供聊天界面引入TextIteratorStreamer配合多线程实现流式输出让用户体验打字机式逐字生成效果适合交互演示。vLLM 部署04 文档使用vllm.entrypoints.openai.api_server一键拉起兼容 OpenAI 协议的服务器/v1/models、/v1/completions、/v1/chat/completions并通过 PagedAttention 与连续批处理显著提升吞吐量。该文档在单卡 RTX3090 24G 上的实测对比显示vLLM 相比 HuggingFace Transformers 推理吞吐提升约 34%该数据仅为该文测试环境下的 case 参考非严谨基准读者应在自己环境中多次取平均验证。7. 常见问题与调试建议模型路径不对导致加载失败model_name_or_path必须与snapshot_download下载后的实际目录一致ModelScope 会把qwen/Qwen2.5-Coder-7B-Instruct落盘为qwen/Qwen2___5-Coder-7B-Instruct形式可先ls确认目录再启动服务。显存不足7B 模型以 bfloat16 加载约需 15 GB 显存。若 OOM可考虑改用 4-bit/8-bit 量化加载参考仓库中 Qwen 系列 Lora 低精度微调 的思路或改用 vLLM 部署 的--max-model-len控制内存占用。端口被占用修改uvicorn.run的port参数并在 curl/requests 中同步替换。请求无响应确认服务端日志是否打印了[时间] , prompt: ... , response: ...行——这是接口被正确触发的标志若没有检查客户端是否以 POST JSON 格式请求。需要流式输出本方案返回的是完整生成结果如需流式体验可参考 WebDemo 部署文档 中的TextIteratorStreamer写法。8. 总结通过本文你已完整走通模型下载 → FastAPI 服务封装 → HTTP 调用的整条链路用 ModelScope 拉取 Qwen2.5-Coder-7B-Instruct 权重用 Transformers FastAPI 构建了一个可复用的本地推理 API并验证了 curl 与 Python 两种客户端调用方式。这套服务的核心Chat Template 应用、generate参数控制、显存回收、device_map半精度加载与仓库中 LangChain、WebDemo、vLLM 等部署方案一脉相承是理解其余进阶部署的坚实基础。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/datawhalechina/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门