Notebook入门:一键部署Qwen3-8B模型并搭建聊天机器人
操作场景
对于AI开发者而言,传统的本地开发环境由于资源限制和工具链不完善,导致在进行AI模型的部署和测试时效率低下。例如,当尝试部署Qwen3-8B模型时,本地环境可能无法提供足够的计算资源,也无法支持高效的模型调试和测试。如何在不增加成本的情况下提高AI模型的开发效率?ModelArts开发环境通过云原生的资源使用和开发工具链的集成,旨在解决这些问题,为用户提供更优质的云化AI开发体验。本文聚焦于Qwen3-8B模型的本地高效部署,基于华为昇腾NPU环境,使用vLLM-Ascend推理引擎推理API服务。通过JupyterLab集成调试,展示从模型加载到RESTful接口调用的完整流程,最后通过Gradio组件来生成Chatbot类型的前端UI展示,快速搭建一个聊天机器人。
本案例的执行时间大约为20分钟。
相关概念
vLLM-Ascend
vLLM-Ascend是一个关键的硬件适配插件,旨在将大型语言模型(LLM)框架vLLM高效地引入华为Ascend NPU(神经网络处理单元)生态系统。它充当了vLLM核心逻辑与华为NPU硬件之间的桥梁,通过解耦的方式,实现了vLLM的核心优化技术(例如PagedAttention内存管理、连续批处理、快速量化等)在Ascend平台上的无缝对接与高效执行。
Qwen3-8B
Qwen3-8B是阿里巴巴在2025年推出的Qwen3系列中的旗舰开源语言模型,以其出色的性能和高效的资源利用率成为行业标杆。该模型拥有82亿参数,在多项基准测试中表现优异。
前提条件
已完成华为云账号注册、实名认证及相关权限授权。具体操作,请参见一、前置准备:账号与权限。
约束限制
本案例仅支持西南-贵阳一区域。控制台界面为新版样式。
计费说明
在ModelArts开发环境中运行Notebook实例时,会使用计算资源和存储资源,产生计算资源和存储资源的累计值计费。计费详情请参见开发环境计费项。
步骤一:快速创建/运行Notebook实例
- 登录ModelArts管理控制台,在左侧导航栏选择“快速入门”。
- 在“开发实践”页签,单击“基于vllm-ascend部署Qwen3-8B并搭建聊天机器人.ipynb”卡片中的“开发”,按需选择“在已有 Notebook 中打开”或“新建 Notebook”。
图1 打开已有/创建Notebook实例
- 在已有Notebook中打开
如果您之前已经创建了Notebook,单击“在已有 Notebook 中打开”,系统会筛选出符合案例推荐规格/镜像的Notebook,您可以在Notebook列表选择目标Notebook,单击“打开 Notebook”。
- 新建Notebook
如果您没有创建过Notebook,或者Notebook列表中没有符合本案例的Notebook,可以单击“新建 Notebook”,“新建 Notebook”页面已预置了符合本案例的参数配置,您可以查看配置费用,单击“确定”。在“计费提醒”对话框,仔细阅读计费信息,单击“确定”。创建过程需2~5分钟,请您耐心等待。
表1 新建Notebook参数说明 参数
说明
名称
Notebook的名称。系统会自动生成一个名称,您可以根据业务需求重新命名,命名规则:只能包含数字、大小写字母、下划线和中划线,长度不能超过128位且不能为空。
选择镜像
选择ModelArts官方镜像pytorch_2.7.1-cann_8.3.rc1-py_3.11-hce_2.0.2509-aarch64-snt9b。
资源池类型
公共资源池:无需单独购买,即开即用,按需付费,即按您的Notebook实例运行时长进行收费。
实例规格
NPU推荐使用单卡规格(Ascend: 1*ascend-snt9b1)或更高配置。
磁盘容量
建议20GB以上。
自动停止
开启后,可设置Notebook实例自动停止方式及对应时长,超出您预设的时长,它将自动停止运行(可能存在2-5分钟的延迟,此过程正常计费)。
- 在已有Notebook中打开
- (可选)如果出现“Select Kernel”对话框,请选择PyTorch-2.7.1,单击“Select”。
步骤二:下载Qwen3-8B模型
- 执行以下命令,安装ModelScope。
!pip install modelscope
在命令左侧,单击
图标,执行命令。
- 执行以下命令,下载Qwen3-8B模型。
!modelscope download --model 'Qwen/Qwen3-8B' --local_dir ./Qwen3-8B
下载完成后,Qwen3-8B模型将出现在左侧目录下的“Qwen3-8B”文件夹中。
图2 Qwen3-8B文件夹
步骤三:安装vLLM和vLLM-Ascend
请先执行步骤1,待步骤1执行成功后,再执行步骤2。如果操作顺序错误,可能导致版本不匹配,进而影响后续操作。
步骤四:启动推理服务
- 设置推理服务端口、模型路径和模型名称。
import os # 设置推理服务的端口,用户可自定义 os.environ['port'] = '9001' port = os.environ['port'] # 设置模型存储的路径 os.environ['model_path'] = './Qwen3-8B' # 模型名称,用户可自定义 os.environ['model_name'] = 'qwen3' model_name = os.environ['model_name']
- 执行以下命令,通过后台启动推理服务。
%%bash source /usr/local/Ascend/ascend-toolkit/set_env.sh source /usr/local/Ascend/nnal/atb/set_env.sh export MODEL_PATH=$model_path export PORT=$port export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 export OMP_PROC_BIND=false export OMP_NUM_THREADS=10 export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True export HCCL_BUFFSIZE=256 export TASK_QUEUE_ENABLE=1 export HCCL_OP_EXPANSION_MODE="AIV" export VLLM_USE_V1=1 export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages/mooncake:$LD_LIBRARY_PATH nohup vllm serve ${MODEL_PATH} \ --port ${PORT} \ --served-model-name ${model_name} \ --max-model-len 5500 \ --max-num-batched-tokens 40960 \ --gpu-memory-utilization 0.90 \ --enable-prefix-caching \ --data-parallel-size 1 \ --tensor-parallel-size 1 \ --enforce-eager > vllm_qwen3.log 2>&1 & - 执行以下命令,查看启动日志。
执行启动推理服务命令后,多次运行以下命令查看启动日志,显示Application startup complete即为服务启动成功。
%%bash # 查看vllm日志,查看启动结果/运行日志 tail -n 100 vllm_qwen3.log
- 测试服务是否正常运行。
推理服务启动完成后,运行以下脚本,测试推理服务是否正常运行,用户可修改content中问题内容。
import subprocess import json data = { "messages": [{"role": "user", "content": "一周有几天"}], "stream": False, "max_tokens": 300 } result = subprocess.run([ "curl", "-X", "POST", f"http://127.0.0.1:{port}/v1/chat/completions", "-H", "Content-Type: application/json", "-d", json.dumps(data) ], capture_output=True, text=True) if result.returncode != 0: print("请求失败,错误信息:") print(result.stderr) else: try: response = json.loads(result.stdout) if "choices" in response and len(response["choices"]) > 0: message = response["choices"][0]["message"]["content"] print("模型回复:") print(message.strip()) else: print("未找到有效回复内容。完整响应:") print(json.dumps(response, indent=2, ensure_ascii=False)) except json.JSONDecodeError: print("无法解析 JSON 响应。原始输出:") print(result.stdout)输出示例:
模型回复: <think> 嗯,用户问“一周有几天”,这看起来是一个很基础的问题,但可能需要仔细考虑。首先,我需要确认用户的需求是什么。他们可能是在学习基础的时间单位,或者在做某个需要知道一周天数的任务,比如安排日程、计划活动等。也有可能用户对时间系统不太熟悉,或者想确认不同文化中的周天数是否一致。 接下来,我得回想一下标准的周结构。通常来说,一周是7天,这在大多数国家都是通用的,比如星期一到星期日。不过,有时候可能会有不同的说法,比如有些地方可能把周日作为一周的开始,而有些地方则是周一开始。不过,国际标准通常是周日作为一周的结束,周一开始作为一周的开始,这可能因地区而异,但天数都是7天。 然后,我需要考虑用户可能的背景。如果是孩子,可能需要更简单的解释,比如用例子说明每一天的名字,或者用日常活动来举例。如果是成年人,可能只需要直接回答7天,但也可以补充一些额外的信息,比如不同文化中的差异,或者一周在不同历法中的应用,比如公历和农历。 另外,用户可能有更深层的需求。比如,他们可能在计划一周的活动,需要知道每天的安排;或者他们可能在学习语言,需要知道一周的英文名称;或者他们可能对时间管理感兴趣,想了解如何高效利用一周的时间
步骤五:使用Chatbot进行对话问答
- 安装Gradio组件,提供UI展示功能。
!pip install gradio==5.50.0
- 设置Chatbot UI端口。
server_port = 7890 # chat bot的端口,用户可自定义
- 启动Chatbot UI。
执行以下脚本,输出"Running on local URL: http:127.0.0.1:server_port",表示启动成功。
import json import os import gradio as gr import requests region_name = os.environ["REGION_NAME"] instance_id = os.environ["INSTANCE_ID"] base_path = f"/{instance_id}/proxy/{server_port}" console_url = f"https://authoring-modelarts.{region_name}.huaweicloud.com" server_name = "0.0.0.0" def chat_with_openai_stream(message, history): url = f"http://127.0.0.1:{port}/v1/chat/completions" messages = [] for history_item in history: messages.append({"role": history_item["role"], "content": history_item["content"]}) messages.append({"role": "user", "content": message}) payload = { "model": model_name, "messages": messages, "max_tokens": 2048, "stream": True # 开启流式响应 } try: response = requests.post(url, json=payload, stream=True, timeout=120) response.raise_for_status() full_answer = "" # 累计:提取后的【纯正式回复】内容 full_think = "" # 累计:提取后的【纯思考】内容 has_think = False # 标记:是否检测到思考内容,无则不展示思考模块 think_over = False # 是否思考完 think_start = False # 是否开始思考完 # 逐行处理流式响应 for line in response.iter_lines(): if line: line_str = line.decode('utf-8') if line_str.startswith('data: '): line_str = line_str[6:] if line_str.strip() == '[DONE]': continue try: data = json.loads(line_str) if 'choices' in data and len(data['choices']) > 0: delta = data['choices'][0].get('delta', {}) current_content = delta.get('content', '') if current_content: if current_content == '<think>': has_think = True think_start = True continue if think_start: current_content = current_content.replace('\n\n', '<br>').replace('\n', '<br>') full_think += current_content if has_think and current_content == '</think>': think_over = True think_start = False continue if think_over: full_answer += current_content if not has_think: full_answer += current_content if has_think and full_think: # 有思考内容:思考文本(灰色小字+思考中前缀) + 正式回复,分行展示,视觉区分明显 show_text = f"<span style='color:#888; font-size:0.9em;'>【模型思考】{full_think}</span>\n\n{full_answer}" if not has_think: # 无思考内容:只展示纯正式回复,和你原代码效果完全一致,无任何多余内容 show_text = full_answer # 流式返回,保留良好的打字机逐字效果 yield show_text except json.JSONDecodeError: continue except Exception as e: print(f"处理流数据时出错: {e}") continue except Exception as e: error_msg = f"错误: {str(e)}" yield error_msg examples = [ "你好,介绍一下你自己。", "32乘以12得多少。", ] # 创建 Gradio 界面 demo = gr.ChatInterface( type="messages", fn=chat_with_openai_stream, title="Chat", description="与本地 qwen3 模型聊天", flagging_mode="manual", flagging_options=["Like", "Spam", "Inappropriate", "Other"], save_history=True, examples=examples ) # 启动应用 gradio_share = os.environ.get("GRADIO_SHARE", "0").lower() in ["true", "1"] demo.launch( share=gradio_share, inline=False, server_name=server_name, server_port=server_port, root_path=base_path ) - 展示Chatbot UI。
运行以下脚本后,会展示Chatbot UI,您可以进行聊天对话。
proxy_url = f"{console_url}{base_path}/" from IPython.display import IFrame, display display(IFrame(src=proxy_url, width="100%", height="800"))图3 与机器人进行对话
更多案例
ModelArts新版控制台提供了很多Notebook的入门案例,您可以登录ModelArts新版控制台,在左侧导航栏选择“快速入门”,在“开发实践”页签单击案例卡片,了解案例详细说明,也可以在案例卡片中单击“开发”,快速实现对应的功能。部分开发实践案例名称如下:
- 使用profiling工具采集Qwen3模型训练性能数据及tensorboard可视化
- 基于Ascend和ComfyUI实现AI视频生成
- 使用llama-factory进行交互式lora微调实现中国历史人物角色扮演