通义千问1.5-1.8B-Chat-GPTQ-Int4 WebUI项目实战:从Python入门到完成第一个AI应用集成
本文介绍了如何在星图GPU平台上自动化部署通义千问1.5-1.8B-Chat-GPTQ-Int4 WebUI镜像,快速搭建个人AI聊天助手。通过该平台,用户可轻松集成该轻量级大语言模型,并利用Flask框架构建交互式Web界面,实现智能对话、问答等核心应用,为AI入门和项目实践提供便捷路径。
通义千问1.5-1.8B-Chat-GPTQ-Int4 WebUI项目实战:从Python入门到完成第一个AI应用集成
你是不是一直觉得AI模型很酷,但总感觉离自己很远?看着别人用代码调用模型,做出各种有趣的应用,自己却不知道从何下手?别担心,这篇教程就是为你准备的。
假设你只学过一些最基础的Python语法,比如知道什么是变量、循环和函数,但还没真正用Python做过一个完整的项目。今天,我们就从零开始,手把手带你完成一个超有成就感的任务:搭建一个属于你自己的、带网页界面的AI聊天助手。我们会用到通义千问的一个轻量级模型,它已经过优化,在普通电脑上也能跑起来。
整个过程就像搭积木:先学会怎么和模型的“服务窗口”(API)对话,再学怎么把对话内容整理好(处理JSON),然后给自己建一个好看的聊天窗口(用Flask做Web界面),最后把所有积木拼在一起。完成之后,你不仅能收获一个可用的AI应用,更能真正理解一个AI项目是如何从想法变成现实的。让我们开始吧。
1. 项目准备:理解我们要做什么
在写第一行代码之前,我们先花几分钟,看看这个项目的全貌,搞清楚每一步的目的。这样你学起来会更有方向感。
我们的最终目标是做出一个简单的网页。你在这个网页的输入框里打字提问,网页会把问题发送给后台的AI模型,拿到模型的回答后,再显示在网页上给你看。听起来很简单,对吧?为了实现它,我们需要三个核心部分:
- 模型服务:这是AI大脑本身。我们已经有了一个现成的、优化过的通义千问模型服务在运行。我们的程序需要能和它“说话”。
- 后台程序:这是用Python写的大脑指挥官。它负责两件事:一是接收你从网页发来的问题;二是把问题转发给模型服务,并把模型的回答整理好,送回网页。
- 网页界面:这是你看到和操作的聊天窗口。一个简单的输入框和一个显示对话的区域。
技术上说,后台程序是一个基于Flask框架的微型网站,模型服务通过HTTP API提供功能。我们的任务就是编写这个后台程序,让它能“粘合”网页和模型。
为了让环境干净,我们首先创建一个专属的项目文件夹,并安装必要的工具。
打开你的命令行终端(Windows上是CMD或PowerShell,Mac或Linux上是Terminal),依次执行以下命令:
# 创建一个新的项目文件夹,名字可以自己定,这里叫qwen_chatbot
mkdir qwen_chatbot
# 进入这个文件夹
cd qwen_chatbot
接下来,我们需要安装Python的几个库。请执行下面的安装命令:
pip install flask requests
flask:用来快速搭建我们网页后台的轻量级工具。requests:一个非常流行、好用的库,专门用来让我们的Python程序能够轻松地访问网络,比如向模型服务发送请求。
如果安装过程比较慢,可以考虑临时使用国内的镜像源,例如在命令后加上 -i https://pypi.tuna.tsinghua.edu.cn/simple。
安装成功后,准备工作就完成了。你可以用 pip list 命令看看 flask 和 requests 是不是已经在列表里了。
2. 第一步:学会和AI模型“对话”(调用API)
现在,我们暂时先不管网页,专注于最核心的一步:如何用Python程序向那个已经存在的AI模型服务提问,并拿到回答。
你可以把模型服务想象成一个24小时在线的、非常专业的客服。它有一个固定的“电话号”(API地址)和一套标准的“提问流程”(请求格式)。我们的程序要按照这个流程打电话过去,才能得到有效的回答。
假设模型服务的“电话号”(API地址)是 http://localhost:8000/v1/chat/completions。我们通过发送一段特定格式的“话”(JSON数据)来提问。
下面,我们来写第一个Python脚本,体验一下这个过程。在你的项目文件夹 qwen_chatbot 里,创建一个新文件,命名为 test_api.py。
# test_api.py - 测试如何调用模型API
import requests
import json
# 1. 定义模型服务的API地址
api_url = "http://localhost:8000/v1/chat/completions"
# 2. 准备我们要发送的“话”,这必须是一个符合API要求的字典
# 通常,这类聊天API都要求我们提供“消息”列表,每条消息有“角色”和“内容”
payload = {
"model": "Qwen1.5-1.8B-Chat-GPTQ-Int4", # 指定要使用的模型名称
"messages": [
{
"role": "user", # 角色是“用户”,代表是我们提的问题
"content": "你好,请介绍一下你自己。" # 这是我们提的问题内容
}
],
"stream": False # 我们先不用流式输出,一次性拿到完整回复
}
# 3. 设置请求头,告诉服务器我们发送的是JSON格式的数据
headers = {
"Content-Type": "application/json"
}
# 4. 正式“打电话”:发送POST请求
try:
print("正在向模型发送请求...")
response = requests.post(url=api_url, headers=headers, data=json.dumps(payload))
print(f"状态码: {response.status_code}") # 打印HTTP状态码,200表示成功
# 5. 处理回复
if response.status_code == 200:
# 请求成功,解析返回的JSON数据
response_data = response.json()
# 从复杂的返回结构中,提取出我们需要的AI回复文本
# 通常回复在 ['choices'][0]['message']['content'] 这个路径下
ai_reply = response_data['choices'][0]['message']['content']
print("模型回复:")
print("-" * 20)
print(ai_reply)
print("-" * 20)
else:
# 请求失败,打印错误信息
print(f"请求失败!状态码:{response.status_code}")
print(f"错误信息:{response.text}")
except requests.exceptions.ConnectionError:
print("连接错误!请确认模型服务是否已经启动,并且API地址是否正确。")
except Exception as e:
print(f"发生未知错误:{e}")
代码解读与运行:
- 导入工具:
requests用来发请求,json用来处理数据格式。 - 准备数据:
payload字典就是我们要说的“话”。messages列表里可以放多轮对话,这里我们只放了一轮用户提问。 - 发送请求:
requests.post方法发送一个POST请求到指定的URL。我们把payload用json.dumps()转换成JSON字符串传过去。 - 处理结果:如果服务器返回状态码200(成功),我们就用
.json()方法把返回的文本解析成Python字典,然后像剥洋葱一样,一层层找到最终的回复内容ai_reply。 - 错误处理:我们用
try...except捕获可能出现的网络连接错误或其他异常,让程序更健壮。
现在,先别运行! 因为我们的模型服务(localhost:8000)还没启动呢。这一步的代码是为了让你理解原理。你可以先通读一遍,想象一下它工作的流程。等我们后续把模型服务跑起来,再回头运行这个测试脚本。
3. 第二步:搭建聊天网页的“后台”(Flask应用)
学会了怎么和模型对话,我们接下来给自己建一个“接待处”和“传达室”,也就是网页的后台。这个后台需要做两件事:
- 当用户访问网站时,给用户展示一个聊天网页(接待处)。
- 当用户在网页上发送消息时,接收这个消息,调用我们刚学的API去问模型,然后把答案送回网页(传达室)。
我们用Flask来搭建这个后台,它非常轻巧,适合我们这样的小项目。
在项目根目录下,创建一个新的Python文件,命名为 app.py。这将是我们的主程序文件。
# app.py - Flask网页应用主程序
from flask import Flask, render_template, request, jsonify
import requests
import json
# 初始化Flask应用
app = Flask(__name__)
# 配置
API_URL = "http://localhost:8000/v1/chat/completions" # 模型API地址
HEADERS = {"Content-Type": "application/json"} # 请求头
# 1. “接待处”:处理用户访问网站根目录的请求,返回聊天页面
@app.route('/')
def home():
# render_template会去寻找并渲染一个叫‘index.html’的模板文件
# 我们先返回一个简单的字符串,下一节再做漂亮的页面
return """
<h1>我的AI聊天助手</h1>
<p>聊天界面正在建设中...请访问 <a href='/chat'>/chat</a> 使用简易版。</p>
"""
# 2. “传达室”核心:处理网页发来的聊天消息
@app.route('/chat', methods=['GET', 'POST'])
def chat():
if request.method == 'GET':
# 如果是GET请求,就返回一个最简单的聊天输入表单
return '''
<!DOCTYPE html>
<html>
<head><title>简易聊天</title></head>
<body>
<h2>和AI聊天</h2>
<div id="chat-box" style="border:1px solid #ccc; height:300px; overflow-y: scroll; padding:10px; margin-bottom:10px;">
<p>AI: 你好!我是你的助手。有什么可以帮你的?</p>
</div>
<form method="POST">
<input type="text" name="user_message" placeholder="输入你的消息..." style="width:70%; padding:8px;">
<button type="submit">发送</button>
</form>
</body>
</html>
'''
else:
# 如果是POST请求,说明用户提交了消息
user_message = request.form.get('user_message', '').strip()
if not user_message:
return jsonify({"error": "消息不能为空"}), 400
# 准备发送给模型API的数据,和之前test_api.py里类似
payload = {
"model": "Qwen1.5-1.8B-Chat-GPTQ-Int4",
"messages": [{"role": "user", "content": user_message}],
"stream": False
}
try:
# 调用模型API
response = requests.post(API_URL, headers=HEADERS, data=json.dumps(payload))
if response.status_code == 200:
response_data = response.json()
ai_reply = response_data['choices'][0]['message']['content']
# 返回AI的回复
return jsonify({"reply": ai_reply})
else:
return jsonify({"error": f"模型服务异常: {response.status_code}"}), 500
except requests.exceptions.ConnectionError:
return jsonify({"error": "无法连接到模型服务,请检查是否启动。"}), 503
except Exception as e:
return jsonify({"error": f"内部错误: {str(e)}"}), 500
# 运行应用
if __name__ == '__main__':
# debug=True 表示开启调试模式,代码修改后会自动重启,方便开发
# host='0.0.0.0' 表示让服务器监听所有公开的IP,这样在同一网络下的其他设备也能访问
# port=5000 是Flask默认端口,如果被占用可以改成其他,如5001
app.run(debug=True, host='0.0.0.0', port=5000)
代码解读:
- 路由:
@app.route(‘/’)和@app.route(‘/chat’, methods=[‘GET’, ‘POST’])是Flask的核心概念,它们把特定的URL地址和我们的Python函数绑定在一起。- 访问
http://localhost:5000/会触发home()函数。 - 访问
http://localhost:5000/chat会触发chat()函数。这个函数能处理两种请求:GET(获取页面)和POST(发送消息)。
- 访问
- 处理请求:在
chat()函数里,我们用request.method判断请求类型。GET时返回一个内嵌了简单HTML的表单页面;POST时,通过request.form.get(‘user_message’)拿到用户输入。 - 调用API:拿到用户输入后,逻辑就和
test_api.py几乎一模一样了:构造数据、发送请求、解析回复。 - 返回响应:对于API调用结果,我们使用
jsonify()将其转换为JSON格式返回给网页。这样网页端的JavaScript就能方便地处理了。
现在可以试运行了!
在终端里,确保你在 qwen_chatbot 目录下,然后运行:
python app.py
你会看到类似这样的输出:
* Serving Flask app 'app'
* Debug mode: on
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://你的局域网IP:5000
打开你的浏览器,访问 http://127.0.0.1:5000/chat。你应该能看到一个非常简陋的聊天界面。试着输入一句话并点击发送。
你会遇到错误! 因为我们的模型服务还没启动,所以后台在调用API时会失败,页面上会显示连接错误。这完全正常,说明我们的后台逻辑(发现错误并报告)是通的。接下来,我们就来解决模型服务这个“最后一块积木”。
4. 第三步:启动AI模型服务
要让我们的聊天助手真正“智能”起来,必须启动通义千问模型服务。这个过程可能会因你的具体部署方式而略有不同,但核心思路是:运行一个服务程序,它加载好模型,并开放出我们在代码中一直使用的那个API地址(http://localhost:8000/v1/chat/completions)。
这里提供一种基于 Ollama 或类似 OpenAI兼容API框架 的通用思路。你需要先根据模型提供方的文档,将 Qwen1.5-1.8B-Chat-GPTQ-Int4 这个模型文件准备好。
假设你使用一个提供OpenAI兼容API的框架,启动命令通常类似于:
# 这是一个示例,具体命令请参考你所使用框架的文档
python -m vllm.entrypoints.openai.api_server \
--model /你的/模型/路径/Qwen1.5-1.8B-Chat-GPTQ-Int4 \
--served-model-name Qwen1.5-1.8B-Chat-GPTQ-Int4 \
--api-key token-abc123 \
--host 0.0.0.0 \
--port 8000
或者,如果你使用的是已经封装好的Docker镜像,命令可能类似于:
docker run -d --gpus all -p 8000:8000 \
-v /你的/模型/路径:/models \
镜像名称 \
--model /models/Qwen1.5-1.8B-Chat-GPTQ-Int4 \
--host 0.0.0.0 --port 8000
关键点:
- 端口:确保服务启动在
8000端口,这样我们的app.py才能正确连接到localhost:8000。 - API路径:确保服务提供的API端点确实是
/v1/chat/completions。大多数兼容OpenAI的框架都使用这个标准路径。 - 模型名称:在
app.py的payload里,我们指定的model参数值需要和服务端识别的名称一致。
启动成功后,你应该能在终端看到模型加载的日志,并最终提示服务已在指定端口运行。
现在,进行终极测试:
- 确保模型服务在运行(端口8000)。
- 确保Flask应用在运行(端口5000,之前运行的
app.py如果退出了,就重新运行python app.py)。 - 打开浏览器,再次访问
http://127.0.0.1:5000/chat。 - 在输入框里问一个问题,比如“Python是什么?”
- 点击发送。
如果一切顺利,页面会刷新,并在聊天区域上方或下方显示AI模型的回复!恭喜你,最核心的流程已经跑通了!
5. 第四步:美化前端界面与功能完善
虽然功能实现了,但那个页面实在太简陋了,而且每次发送消息页面都会刷新,体验不好。现在我们来用一点点HTML、CSS和JavaScript,做一个不刷新页面、更像现代聊天工具的单页应用。
我们在项目根目录下创建一个 templates 文件夹,然后在里面创建一个 index.html 文件。Flask会自动在这个文件夹里寻找模板文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的通义千问聊天助手</title>
<style>
* { box-sizing: border-box; font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif; }
body { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); margin: 0; padding: 20px; min-height: 100vh; }
.container { max-width: 800px; margin: 0 auto; background: white; border-radius: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); overflow: hidden; }
.header { background: linear-gradient(90deg, #4776E6, #8E54E9); color: white; padding: 20px 30px; text-align: center; }
.chat-box { height: 450px; padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 15px; }
.message { max-width: 80%; padding: 12px 18px; border-radius: 18px; line-height: 1.5; word-wrap: break-word; }
.user-message { align-self: flex-end; background-color: #4776E6; color: white; border-bottom-right-radius: 4px; }
.ai-message { align-self: flex-start; background-color: #f0f2f5; color: #333; border-bottom-left-radius: 4px; }
.input-area { border-top: 1px solid #eee; padding: 20px 30px; display: flex; gap: 10px; }
#userInput { flex: 1; padding: 15px; border: 2px solid #ddd; border-radius: 25px; font-size: 16px; outline: none; transition: border 0.3s; }
#userInput:focus { border-color: #4776E6; }
#sendButton { padding: 15px 30px; background: linear-gradient(90deg, #4776E6, #8E54E9); color: white; border: none; border-radius: 25px; font-size: 16px; font-weight: bold; cursor: pointer; transition: transform 0.2s; }
#sendButton:hover { transform: scale(1.05); }
#sendButton:disabled { background: #ccc; cursor: not-allowed; }
.typing-indicator { align-self: flex-start; color: #888; font-style: italic; padding: 10px; display: none; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 我的AI聊天助手</h1>
<p>基于 通义千问1.5-1.8B-Chat-GPTQ-Int4 模型</p>
</div>
<div id="chatBox" class="chat-box">
<!-- 初始欢迎消息 -->
<div class="message ai-message">
你好!我是一个轻量级的AI助手。虽然我体积小,但也能帮你解答问题、进行对话。试试问我点什么吧!
</div>
</div>
<div class="input-area">
<input type="text" id="userInput" placeholder="输入你想聊的内容..." autocomplete="off">
<button id="sendButton" onclick="sendMessage()">发送</button>
</div>
<div id="typingIndicator" class="typing-indicator">AI正在思考...</div>
</div>
<script>
const chatBox = document.getElementById('chatBox');
const userInput = document.getElementById('userInput');
const sendButton = document.getElementById('sendButton');
const typingIndicator = document.getElementById('typingIndicator');
// 添加用户消息到聊天框
function addUserMessage(text) {
const msgDiv = document.createElement('div');
msgDiv.className = 'message user-message';
msgDiv.textContent = text;
chatBox.appendChild(msgDiv);
scrollToBottom();
}
// 添加AI消息到聊天框
function addAiMessage(text) {
const msgDiv = document.createElement('div');
msgDiv.className = 'message ai-message';
msgDiv.textContent = text;
chatBox.appendChild(msgDiv);
scrollToBottom();
}
// 滚动到底部
function scrollToBottom() {
chatBox.scrollTop = chatBox.scrollHeight;
}
// 发送消息到后端
async function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
// 禁用输入和按钮,显示用户消息
userInput.value = '';
userInput.disabled = true;
sendButton.disabled = true;
addUserMessage(message);
// 显示“正在思考”提示
typingIndicator.style.display = 'block';
scrollToBottom();
try {
// 使用FormData构造请求数据,与后端@app.route('/chat', methods=['POST'])对应
const formData = new FormData();
formData.append('user_message', message);
const response = await fetch('/chat', {
method: 'POST',
body: formData
});
const result = await response.json();
// 隐藏“正在思考”提示
typingIndicator.style.display = 'none';
if (response.ok && result.reply) {
addAiMessage(result.reply);
} else {
addAiMessage(`抱歉,出错了: ${result.error || '未知错误'}`);
}
} catch (error) {
typingIndicator.style.display = 'none';
addAiMessage('网络请求失败,请检查后端服务是否运行。');
console.error('请求失败:', error);
} finally {
// 重新启用输入和按钮
userInput.disabled = false;
sendButton.disabled = false;
userInput.focus();
}
}
// 支持按回车键发送
userInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
sendMessage();
}
});
// 页面加载后自动聚焦到输入框
window.onload = function() {
userInput.focus();
};
</script>
</body>
</html>
然后,我们需要修改 app.py 中的 home() 函数,让它返回这个漂亮的模板,并且简化 chat 函数,让它只处理POST请求(因为页面逻辑已经由前端JavaScript接管了)。
更新 app.py 文件:
# app.py - 更新后的版本
from flask import Flask, render_template, request, jsonify
import requests
import json
import time
app = Flask(__name__)
API_URL = "http://localhost:8000/v1/chat/completions"
HEADERS = {"Content-Type": "application/json"}
# 首页,返回我们制作好的漂亮界面
@app.route('/')
def home():
return render_template('index.html') # 这行代码会渲染 templates/index.html
# 聊天API端点,现在只处理POST请求
@app.route('/chat', methods=['POST'])
def chat():
user_message = request.form.get('user_message', '').strip()
if not user_message:
return jsonify({"error": "消息不能为空"}), 400
payload = {
"model": "Qwen1.5-1.8B-Chat-GPTQ-Int4",
"messages": [{"role": "user", "content": user_message}],
"stream": False
}
try:
# 可以加一个简单的超时设置
response = requests.post(API_URL, headers=HEADERS, data=json.dumps(payload), timeout=30)
if response.status_code == 200:
response_data = response.json()
ai_reply = response_data['choices'][0]['message']['content']
return jsonify({"reply": ai_reply})
else:
app.logger.error(f"模型API错误: {response.status_code}, {response.text}")
return jsonify({"error": f"模型服务返回错误: {response.status_code}"}), 500
except requests.exceptions.Timeout:
return jsonify({"error": "请求模型超时,请稍后再试。"}), 504
except requests.exceptions.ConnectionError:
return jsonify({"error": "无法连接到模型服务,请确认服务已启动。"}), 503
except Exception as e:
app.logger.error(f"处理请求时发生未知错误: {e}")
return jsonify({"error": "服务器内部错误"}), 500
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
现在,重启你的Flask应用(先按Ctrl+C停止,再运行 python app.py),然后刷新浏览器访问 http://127.0.0.1:5000/。
一个美观、交互流畅的聊天助手界面就出现了!输入消息,点击发送,消息会立刻出现在对话框里,然后AI的回复也会无刷新地显示出来。这就是一个完整的、前后端分离的迷你AI应用了。
6. 总结与后续探索
走完这个完整的项目,你应该已经不再是一个仅仅知道Python语法的初学者了。你实际动手完成了一次小型的全栈开发体验:从后端的API调用、Web服务器搭建,到前端的界面交互。
回顾一下我们搭建的积木:用 requests 库与AI模型通信,用 Flask 搭建应用骨架和API,用 HTML/CSS/JavaScript 构建用户界面,最后将它们无缝集成。这个模式具有很强的扩展性。比如,你可以轻松地更换另一个支持相同OpenAI API格式的模型,只需要修改 API_URL 和 model 参数。
这个项目还有很多可以完善和探索的方向。例如,你可以为聊天记录加上持久化存储,这样关闭网页后对话不会丢失;可以增加多轮对话的记忆功能,让AI能联系上下文;或者尝试集成语音输入输出,让交互更自然。每一步都可以拆解成类似的小任务,用你在这个项目中学到的方法去攻克。
最重要的是,你证明了从想法到实现之间并没有不可逾越的鸿沟。带着这个成功的经验,你可以更有信心地去探索更复杂的AI应用,或者将AI能力融入到你的其他编程项目中去。编程和AI工具的学习,正是在这样一个个具体项目的实践中不断进步的。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)