通义千问1.5-1.8B-Chat-GPTQ-Int4从理论到实践完整AI项目开发工作流展示最近有不少朋友在问拿到一个像通义千问1.5-1.8B-Chat这样的轻量级大模型后到底怎么把它变成一个能实际用起来的小应用光会调用模型接口可不够从部署到封装再到做个简单界面这中间每一步都有不少细节。今天我就用一个“智能邮件助手”的迷你项目带大家走一遍完整的开发流程。咱们不聊虚的就实打实地看看怎么把模型部署好、怎么给它套个方便调用的壳、再做个能交互的网页最后把它们拼成一个能跑起来的整体。整个过程涉及的代码我都会贴出来你可以直接拿去用或者当成自己项目的起点。1. 项目全景与核心思路在动手写代码之前咱们先把这个小项目要干什么、怎么干理清楚。这个“智能邮件助手”想解决的问题很简单每天工作邮箱里塞满了各种邮件有会议通知、项目汇报、广告推广还有同事的闲聊。手动分类太费时间我们想让AI帮我们自动判断一封邮件的大致类别比如“工作安排”、“项目讨论”、“通知公告”或者“其他”。为什么选通义千问1.5-1.8B-Chat-GPTQ-Int4这个模型呢主要是它够“轻”。1.8B的参数规模再经过GPTQ量化到Int4精度对显存的要求大大降低普通消费级显卡甚至CPU都能跑起来非常适合我们这种想快速验证想法、搭建原型的小项目。它的对话能力也足够理解邮件的文本内容并做出分类。整个项目的骨架分为三层后端模型服务层这是核心负责把量化好的模型跑起来提供一个处理请求的接口。应用逻辑层我们在这里写主要的业务代码调用模型处理邮件文本返回分类结果。前端交互层做一个最简洁的网页让用户能输入邮件内容点击按钮看到分类结果。思路清晰了咱们就从最底层开始一步步往上搭。2. 第一步模型部署与本地API服务搭建模型不能直接当函数调用我们需要先把它部署成一个服务。这里我们用FastChat来启动模型服务它管理起来比较方便。2.1 环境准备与模型下载首先确保你的环境有Python然后安装必要的包。我习惯用conda新建一个独立环境避免包冲突。# 创建并激活环境 conda create -n qwen_chat python3.10 conda activate qwen_chat # 安装核心依赖 pip install fschat pip install transformers pip install torch # 根据你的CUDA版本选择安装命令接下来我们需要下载量化好的模型。模型文件通常托管在Hugging Face等平台。这里我们假设你已经下载了Qwen1.5-1.8B-Chat-GPTQ-Int4的模型文件并放在了本地目录./model/Qwen1.5-1.8B-Chat-GPTQ-Int4下。目录里应该包含config.json,model.safetensors等文件。2.2 启动模型Worker模型服务由多个“角色”组成其中Worker是干重活的负责加载模型并执行推理。我们通过命令行启动它。python -m fastchat.serve.model_worker \ --model-path ./model/Qwen1.5-1.8B-Chat-GPTQ-Int4 \ --model-name qwen1.5-1.8b-chat-gptq \ --worker-address http://127.0.0.1:21002 \ --controller-address http://127.0.0.1:21001 \ --host 0.0.0.0 \ --port 21002简单解释一下这几个参数--model-path: 你放模型文件的本地路径。--model-name: 给这个模型起个名字后面调用时用。--worker-address: 这个Worker服务自己的地址。--controller-address: 控制中心的地址所有Worker都向它注册。--host和--port: 指定服务监听的IP和端口。运行这个命令后你会看到模型开始加载加载成功后输出日志。这一步需要一些时间并且会占用一定的显存或内存。2.3 启动Controller与OpenAI兼容API光有Worker还不够我们需要一个控制中心Controller来管理所有Worker并启动一个我们熟悉的OpenAI格式的API服务。新开一个终端窗口激活同样的环境先启动Controllerpython -m fastchat.serve.controller --host 0.0.0.0 --port 21001然后再开一个终端启动OpenAI兼容的API服务python -m fastchat.serve.openai_api_server \ --controller-address http://127.0.0.1:21001 \ --host 0.0.0.0 \ --port 8000好了现在我们在8000端口就有了一个和OpenAI接口格式一样的服务。你可以用curl或者写段Python代码测试一下import openai # 注意这里需要设置openai库的base_url和api_key client openai.OpenAI( base_urlhttp://localhost:8000/v1, api_keyno-key-required # FastChat默认不需要key ) response client.chat.completions.create( modelqwen1.5-1.8b-chat-gptq, # 使用我们启动Worker时指定的model-name messages[ {role: user, content: 你好请介绍一下你自己。} ], max_tokens50 ) print(response.choices[0].message.content)如果看到模型回复了问候语恭喜你模型服务层已经搭建成功它现在就像一个本地版的ChatGPT API等着我们去调用。3. 第二步封装业务逻辑与模型调用模型服务跑起来了但直接让前端调用这个API不太灵活我们最好在后端再封装一层。这一层负责处理具体的业务逻辑比如构造适合邮件分类的提示词Prompt处理模型的返回结果可能还会加一些日志、错误处理之类的。我们用Python的FastAPI框架来写这个后端应用因为它轻快写API接口特别方便。3.1 构建应用与模型调用客户端新建一个文件叫mail_assistant_api.py。from fastapi import FastAPI, HTTPException from pydantic import BaseModel import openai import logging from typing import Literal # 配置日志 logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) # 初始化FastAPI应用 app FastAPI(title智能邮件助手API) # 初始化OpenAI客户端指向我们本地启动的模型服务 client openai.OpenAI( base_urlhttp://localhost:8000/v1, api_keyno-key-required ) MODEL_NAME qwen1.5-1.8b-chat-gptq # 定义请求和响应的数据格式 class MailClassificationRequest(BaseModel): 邮件分类请求体 mail_content: str class MailClassificationResponse(BaseModel): 邮件分类响应体 category: str reason: str # 我们预设的邮件类别 POSSIBLE_CATEGORIES Literal[工作安排, 项目讨论, 通知公告, 广告推广, 其他] def build_classification_prompt(mail_content: str) - list: 构建邮件分类的提示词 system_prompt 你是一个专业的邮件分类助手。请根据用户提供的邮件内容判断它最可能属于以下哪个类别 - 工作安排涉及会议、日程、任务分配、截止日期等。 - 项目讨论关于具体项目的进展、问题、方案、评审等讨论。 - 通知公告公司或部门的政策、制度、活动、人事变动等正式通知。 - 广告推广商品推销、课程推荐、活动营销等商业推广内容。 - 其他无法归入以上类别或内容过于简短、模糊。 请只输出最终的类别名称不要输出任何其他解释或说明。 user_prompt f请对以下邮件内容进行分类\n\n{mail_content} return [ {role: system, content: system_prompt}, {role: user, content: user_prompt} ] app.post(/classify, response_modelMailClassificationResponse) async def classify_mail(request: MailClassificationRequest): 邮件分类接口 mail_content request.mail_content logger.info(f收到分类请求邮件长度{len(mail_content)}字符) if not mail_content.strip(): raise HTTPException(status_code400, detail邮件内容不能为空) try: # 1. 构建提示词 messages build_classification_prompt(mail_content) # 2. 调用本地模型服务 response client.chat.completions.create( modelMODEL_NAME, messagesmessages, max_tokens10, # 我们只需要返回一个类别名不需要长文本 temperature0.1, # 低温度让输出更确定减少随机性 ) # 3. 解析模型回复 model_reply response.choices[0].message.content.strip() logger.info(f模型原始回复: {model_reply}) # 4. 简单清洗和匹配回复 # 模型可能回复“类别工作安排”或直接“工作安排”我们提取核心词 category None for cat in [工作安排, 项目讨论, 通知公告, 广告推广]: if cat in model_reply: category cat break if not category: category 其他 # 5. 构造返回结果 # 这里可以基于分类结果生成一个简单的理由实际项目中可以更复杂 reason_map { 工作安排: 邮件内容涉及任务、会议或时间安排。, 项目讨论: 邮件内容围绕特定项目展开讨论。, 通知公告: 邮件内容为正式的公司或部门通知。, 广告推广: 邮件内容包含商业推广信息。, 其他: 邮件内容简短或不属于上述常见类别。 } return MailClassificationResponse( categorycategory, reasonreason_map.get(category, 已成功分类。) ) except openai.APIError as e: logger.error(f调用模型API失败: {e}) raise HTTPException(status_code503, detail模型服务暂时不可用) except Exception as e: logger.error(f处理请求时发生未知错误: {e}) raise HTTPException(status_code500, detail服务器内部错误) if __name__ __main__: import uvicorn # 启动服务运行在 8001 端口避免和模型API服务冲突 uvicorn.run(app, host0.0.0.0, port8001)这段代码做了几件关键事定义了一个/classify的POST接口。收到邮件内容后会构造一个清晰的系统提示词Prompt来引导模型进行分类。调用我们之前部署在localhost:8000的模型服务。对模型的回复进行简单的清洗和匹配确保返回一个预设的类别。添加了基本的错误处理和日志。运行这个文件(python mail_assistant_api.py)我们的业务逻辑后端就在8001端口启动了。你可以用curl或者Postman测试一下curl -X POST http://localhost:8001/classify \ -H Content-Type: application/json \ -d {mail_content: 各位同事本周五下午两点在301会议室召开项目季度复盘会请项目组全体成员准时参加。}应该会收到一个JSON响应类似{category: 工作安排, reason: 邮件内容涉及任务、会议或时间安排。}。4. 第三步开发极简前端交互界面后端API准备好了我们做个最简单的网页让用户能方便地使用。为了极简我们用纯HTML、JavaScript加上一点点CSS。新建一个index.html文件。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title智能邮件助手/title style * { box-sizing: border-box; margin: 0; padding: 0; font-family: Segoe UI, system-ui, sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; } .container { background: white; border-radius: 20px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); width: 100%; max-width: 700px; padding: 40px; } h1 { color: #2d3436; margin-bottom: 10px; text-align: center; } .subtitle { color: #636e72; text-align: center; margin-bottom: 30px; font-size: 1.1em; } .input-area { margin-bottom: 25px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: #2d3436; } textarea { width: 100%; min-height: 180px; padding: 15px; border: 2px solid #dfe6e9; border-radius: 10px; font-size: 16px; resize: vertical; transition: border 0.3s; } textarea:focus { outline: none; border-color: #6c5ce7; } .button-area { text-align: center; margin-bottom: 30px; } button { background: linear-gradient(to right, #6c5ce7, #a29bfe); color: white; border: none; padding: 15px 40px; font-size: 18px; border-radius: 50px; cursor: pointer; font-weight: 600; transition: transform 0.2s, box-shadow 0.2s; } button:hover { transform: translateY(-2px); box-shadow: 0 7px 14px rgba(108, 92, 231, 0.3); } button:disabled { background: #b2bec3; cursor: not-allowed; transform: none; box-shadow: none; } .result-area { background: #f8f9fa; border-radius: 10px; padding: 25px; border-left: 5px solid #6c5ce7; } .result-area h3 { color: #2d3436; margin-bottom: 15px; } .category { font-size: 24px; font-weight: bold; color: #6c5ce7; margin: 10px 0; } .reason { color: #636e72; line-height: 1.6; } .loading { display: none; text-align: center; color: #636e72; margin: 20px 0; } .spinner { border: 4px solid rgba(108, 92, 231, 0.2); border-top: 4px solid #6c5ce7; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 10px; } keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /style /head body div classcontainer h1 智能邮件助手/h1 p classsubtitle基于通义千问大模型快速为您的邮件内容分类/p div classinput-area label formailContent请输入邮件正文/label textarea idmailContent placeholder例如各位同事下周一下午三点将进行系统升级请提前保存好工作文件。升级期间服务将暂停访问.../textarea /div div classbutton-area button idclassifyBtn onclickclassifyMail()开始智能分类/button /div div classloading idloadingIndicator div classspinner/div pAI正在分析邮件内容请稍候.../p /div div classresult-area idresultArea styledisplay: none; h3分类结果/h3 pstrong邮件类别/strongspan classcategory idresultCategory-/span/p pstrong分析理由/strongbrspan classreason idresultReason-/span/p /div /div script async function classifyMail() { const mailContent document.getElementById(mailContent).value.trim(); const btn document.getElementById(classifyBtn); const loading document.getElementById(loadingIndicator); const resultArea document.getElementById(resultArea); if (!mailContent) { alert(请输入邮件内容); return; } // 禁用按钮显示加载动画隐藏结果 btn.disabled true; loading.style.display block; resultArea.style.display none; try { const response await fetch(http://localhost:8001/classify, { method: POST, headers: { Content-Type: application/json, }, body: JSON.stringify({ mail_content: mailContent }) }); if (!response.ok) { throw new Error(请求失败: ${response.status}); } const data await response.json(); // 更新页面显示结果 document.getElementById(resultCategory).textContent data.category; document.getElementById(resultReason).textContent data.reason; resultArea.style.display block; } catch (error) { console.error(分类出错:, error); alert(分类失败请检查后端服务是否运行正常。错误信息 error.message); } finally { // 恢复按钮隐藏加载动画 btn.disabled false; loading.style.display none; } } // 按回车键触发分类可选功能 document.getElementById(mailContent).addEventListener(keydown, function(event) { if (event.ctrlKey event.key Enter) { event.preventDefault(); classifyMail(); } }); /script /body /html这个页面非常直白一个文本框用来输入邮件一个按钮用来触发分类一个区域用来展示结果和加载状态。JavaScript代码负责把文本框里的内容发送到我们刚才启动的后端API(http://localhost:8001/classify)然后把返回的分类结果和理由显示出来。现在用浏览器打开这个index.html文件输入一段邮件内容点击按钮你应该就能看到AI返回的分类结果了。一个完整的、前后端分离的迷你AI应用就完成了。5. 总结走完这一遍你会发现把一个量化大模型变成可交互的小应用其实并没有想象中那么复杂。整个过程就像搭积木一层一层来首先部署模型服务是基础。我们用FastChat把Qwen1.5-1.8B-Chat-GPTQ-Int4这个“轻量化”的模型跑起来变成一个提供标准API接口的服务。这一步解决了模型怎么用的问题。接着封装业务逻辑是关键。直接让前端调模型API不灵活也不安全。我们写了一个FastAPI应用在这里面定制了适合邮件分类的提示词处理了模型的返回结果还加上了错误处理和日志。这让我们的核心功能更健壮也更容易维护和扩展。最后做个简单界面是让想法落地的最后一步。一个清晰的网页哪怕只有最基本的功能也能立刻把AI能力呈现给用户完成从代码到产品的闭环。这个“智能邮件助手”项目麻雀虽小但完整展示了AI应用开发的核心工作流。你可以基于这个模板轻松替换成其他模型或者实现更复杂的功能比如情感分析、内容摘要、自动回复等等。希望这个具体的例子能给你带来一些动手实践的灵感。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
通义千问1.5-1.8B-Chat-GPTQ-Int4从理论到实践:完整AI项目开发工作流展示
通义千问1.5-1.8B-Chat-GPTQ-Int4从理论到实践完整AI项目开发工作流展示最近有不少朋友在问拿到一个像通义千问1.5-1.8B-Chat这样的轻量级大模型后到底怎么把它变成一个能实际用起来的小应用光会调用模型接口可不够从部署到封装再到做个简单界面这中间每一步都有不少细节。今天我就用一个“智能邮件助手”的迷你项目带大家走一遍完整的开发流程。咱们不聊虚的就实打实地看看怎么把模型部署好、怎么给它套个方便调用的壳、再做个能交互的网页最后把它们拼成一个能跑起来的整体。整个过程涉及的代码我都会贴出来你可以直接拿去用或者当成自己项目的起点。1. 项目全景与核心思路在动手写代码之前咱们先把这个小项目要干什么、怎么干理清楚。这个“智能邮件助手”想解决的问题很简单每天工作邮箱里塞满了各种邮件有会议通知、项目汇报、广告推广还有同事的闲聊。手动分类太费时间我们想让AI帮我们自动判断一封邮件的大致类别比如“工作安排”、“项目讨论”、“通知公告”或者“其他”。为什么选通义千问1.5-1.8B-Chat-GPTQ-Int4这个模型呢主要是它够“轻”。1.8B的参数规模再经过GPTQ量化到Int4精度对显存的要求大大降低普通消费级显卡甚至CPU都能跑起来非常适合我们这种想快速验证想法、搭建原型的小项目。它的对话能力也足够理解邮件的文本内容并做出分类。整个项目的骨架分为三层后端模型服务层这是核心负责把量化好的模型跑起来提供一个处理请求的接口。应用逻辑层我们在这里写主要的业务代码调用模型处理邮件文本返回分类结果。前端交互层做一个最简洁的网页让用户能输入邮件内容点击按钮看到分类结果。思路清晰了咱们就从最底层开始一步步往上搭。2. 第一步模型部署与本地API服务搭建模型不能直接当函数调用我们需要先把它部署成一个服务。这里我们用FastChat来启动模型服务它管理起来比较方便。2.1 环境准备与模型下载首先确保你的环境有Python然后安装必要的包。我习惯用conda新建一个独立环境避免包冲突。# 创建并激活环境 conda create -n qwen_chat python3.10 conda activate qwen_chat # 安装核心依赖 pip install fschat pip install transformers pip install torch # 根据你的CUDA版本选择安装命令接下来我们需要下载量化好的模型。模型文件通常托管在Hugging Face等平台。这里我们假设你已经下载了Qwen1.5-1.8B-Chat-GPTQ-Int4的模型文件并放在了本地目录./model/Qwen1.5-1.8B-Chat-GPTQ-Int4下。目录里应该包含config.json,model.safetensors等文件。2.2 启动模型Worker模型服务由多个“角色”组成其中Worker是干重活的负责加载模型并执行推理。我们通过命令行启动它。python -m fastchat.serve.model_worker \ --model-path ./model/Qwen1.5-1.8B-Chat-GPTQ-Int4 \ --model-name qwen1.5-1.8b-chat-gptq \ --worker-address http://127.0.0.1:21002 \ --controller-address http://127.0.0.1:21001 \ --host 0.0.0.0 \ --port 21002简单解释一下这几个参数--model-path: 你放模型文件的本地路径。--model-name: 给这个模型起个名字后面调用时用。--worker-address: 这个Worker服务自己的地址。--controller-address: 控制中心的地址所有Worker都向它注册。--host和--port: 指定服务监听的IP和端口。运行这个命令后你会看到模型开始加载加载成功后输出日志。这一步需要一些时间并且会占用一定的显存或内存。2.3 启动Controller与OpenAI兼容API光有Worker还不够我们需要一个控制中心Controller来管理所有Worker并启动一个我们熟悉的OpenAI格式的API服务。新开一个终端窗口激活同样的环境先启动Controllerpython -m fastchat.serve.controller --host 0.0.0.0 --port 21001然后再开一个终端启动OpenAI兼容的API服务python -m fastchat.serve.openai_api_server \ --controller-address http://127.0.0.1:21001 \ --host 0.0.0.0 \ --port 8000好了现在我们在8000端口就有了一个和OpenAI接口格式一样的服务。你可以用curl或者写段Python代码测试一下import openai # 注意这里需要设置openai库的base_url和api_key client openai.OpenAI( base_urlhttp://localhost:8000/v1, api_keyno-key-required # FastChat默认不需要key ) response client.chat.completions.create( modelqwen1.5-1.8b-chat-gptq, # 使用我们启动Worker时指定的model-name messages[ {role: user, content: 你好请介绍一下你自己。} ], max_tokens50 ) print(response.choices[0].message.content)如果看到模型回复了问候语恭喜你模型服务层已经搭建成功它现在就像一个本地版的ChatGPT API等着我们去调用。3. 第二步封装业务逻辑与模型调用模型服务跑起来了但直接让前端调用这个API不太灵活我们最好在后端再封装一层。这一层负责处理具体的业务逻辑比如构造适合邮件分类的提示词Prompt处理模型的返回结果可能还会加一些日志、错误处理之类的。我们用Python的FastAPI框架来写这个后端应用因为它轻快写API接口特别方便。3.1 构建应用与模型调用客户端新建一个文件叫mail_assistant_api.py。from fastapi import FastAPI, HTTPException from pydantic import BaseModel import openai import logging from typing import Literal # 配置日志 logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) # 初始化FastAPI应用 app FastAPI(title智能邮件助手API) # 初始化OpenAI客户端指向我们本地启动的模型服务 client openai.OpenAI( base_urlhttp://localhost:8000/v1, api_keyno-key-required ) MODEL_NAME qwen1.5-1.8b-chat-gptq # 定义请求和响应的数据格式 class MailClassificationRequest(BaseModel): 邮件分类请求体 mail_content: str class MailClassificationResponse(BaseModel): 邮件分类响应体 category: str reason: str # 我们预设的邮件类别 POSSIBLE_CATEGORIES Literal[工作安排, 项目讨论, 通知公告, 广告推广, 其他] def build_classification_prompt(mail_content: str) - list: 构建邮件分类的提示词 system_prompt 你是一个专业的邮件分类助手。请根据用户提供的邮件内容判断它最可能属于以下哪个类别 - 工作安排涉及会议、日程、任务分配、截止日期等。 - 项目讨论关于具体项目的进展、问题、方案、评审等讨论。 - 通知公告公司或部门的政策、制度、活动、人事变动等正式通知。 - 广告推广商品推销、课程推荐、活动营销等商业推广内容。 - 其他无法归入以上类别或内容过于简短、模糊。 请只输出最终的类别名称不要输出任何其他解释或说明。 user_prompt f请对以下邮件内容进行分类\n\n{mail_content} return [ {role: system, content: system_prompt}, {role: user, content: user_prompt} ] app.post(/classify, response_modelMailClassificationResponse) async def classify_mail(request: MailClassificationRequest): 邮件分类接口 mail_content request.mail_content logger.info(f收到分类请求邮件长度{len(mail_content)}字符) if not mail_content.strip(): raise HTTPException(status_code400, detail邮件内容不能为空) try: # 1. 构建提示词 messages build_classification_prompt(mail_content) # 2. 调用本地模型服务 response client.chat.completions.create( modelMODEL_NAME, messagesmessages, max_tokens10, # 我们只需要返回一个类别名不需要长文本 temperature0.1, # 低温度让输出更确定减少随机性 ) # 3. 解析模型回复 model_reply response.choices[0].message.content.strip() logger.info(f模型原始回复: {model_reply}) # 4. 简单清洗和匹配回复 # 模型可能回复“类别工作安排”或直接“工作安排”我们提取核心词 category None for cat in [工作安排, 项目讨论, 通知公告, 广告推广]: if cat in model_reply: category cat break if not category: category 其他 # 5. 构造返回结果 # 这里可以基于分类结果生成一个简单的理由实际项目中可以更复杂 reason_map { 工作安排: 邮件内容涉及任务、会议或时间安排。, 项目讨论: 邮件内容围绕特定项目展开讨论。, 通知公告: 邮件内容为正式的公司或部门通知。, 广告推广: 邮件内容包含商业推广信息。, 其他: 邮件内容简短或不属于上述常见类别。 } return MailClassificationResponse( categorycategory, reasonreason_map.get(category, 已成功分类。) ) except openai.APIError as e: logger.error(f调用模型API失败: {e}) raise HTTPException(status_code503, detail模型服务暂时不可用) except Exception as e: logger.error(f处理请求时发生未知错误: {e}) raise HTTPException(status_code500, detail服务器内部错误) if __name__ __main__: import uvicorn # 启动服务运行在 8001 端口避免和模型API服务冲突 uvicorn.run(app, host0.0.0.0, port8001)这段代码做了几件关键事定义了一个/classify的POST接口。收到邮件内容后会构造一个清晰的系统提示词Prompt来引导模型进行分类。调用我们之前部署在localhost:8000的模型服务。对模型的回复进行简单的清洗和匹配确保返回一个预设的类别。添加了基本的错误处理和日志。运行这个文件(python mail_assistant_api.py)我们的业务逻辑后端就在8001端口启动了。你可以用curl或者Postman测试一下curl -X POST http://localhost:8001/classify \ -H Content-Type: application/json \ -d {mail_content: 各位同事本周五下午两点在301会议室召开项目季度复盘会请项目组全体成员准时参加。}应该会收到一个JSON响应类似{category: 工作安排, reason: 邮件内容涉及任务、会议或时间安排。}。4. 第三步开发极简前端交互界面后端API准备好了我们做个最简单的网页让用户能方便地使用。为了极简我们用纯HTML、JavaScript加上一点点CSS。新建一个index.html文件。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title智能邮件助手/title style * { box-sizing: border-box; margin: 0; padding: 0; font-family: Segoe UI, system-ui, sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; } .container { background: white; border-radius: 20px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); width: 100%; max-width: 700px; padding: 40px; } h1 { color: #2d3436; margin-bottom: 10px; text-align: center; } .subtitle { color: #636e72; text-align: center; margin-bottom: 30px; font-size: 1.1em; } .input-area { margin-bottom: 25px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: #2d3436; } textarea { width: 100%; min-height: 180px; padding: 15px; border: 2px solid #dfe6e9; border-radius: 10px; font-size: 16px; resize: vertical; transition: border 0.3s; } textarea:focus { outline: none; border-color: #6c5ce7; } .button-area { text-align: center; margin-bottom: 30px; } button { background: linear-gradient(to right, #6c5ce7, #a29bfe); color: white; border: none; padding: 15px 40px; font-size: 18px; border-radius: 50px; cursor: pointer; font-weight: 600; transition: transform 0.2s, box-shadow 0.2s; } button:hover { transform: translateY(-2px); box-shadow: 0 7px 14px rgba(108, 92, 231, 0.3); } button:disabled { background: #b2bec3; cursor: not-allowed; transform: none; box-shadow: none; } .result-area { background: #f8f9fa; border-radius: 10px; padding: 25px; border-left: 5px solid #6c5ce7; } .result-area h3 { color: #2d3436; margin-bottom: 15px; } .category { font-size: 24px; font-weight: bold; color: #6c5ce7; margin: 10px 0; } .reason { color: #636e72; line-height: 1.6; } .loading { display: none; text-align: center; color: #636e72; margin: 20px 0; } .spinner { border: 4px solid rgba(108, 92, 231, 0.2); border-top: 4px solid #6c5ce7; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 10px; } keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /style /head body div classcontainer h1 智能邮件助手/h1 p classsubtitle基于通义千问大模型快速为您的邮件内容分类/p div classinput-area label formailContent请输入邮件正文/label textarea idmailContent placeholder例如各位同事下周一下午三点将进行系统升级请提前保存好工作文件。升级期间服务将暂停访问.../textarea /div div classbutton-area button idclassifyBtn onclickclassifyMail()开始智能分类/button /div div classloading idloadingIndicator div classspinner/div pAI正在分析邮件内容请稍候.../p /div div classresult-area idresultArea styledisplay: none; h3分类结果/h3 pstrong邮件类别/strongspan classcategory idresultCategory-/span/p pstrong分析理由/strongbrspan classreason idresultReason-/span/p /div /div script async function classifyMail() { const mailContent document.getElementById(mailContent).value.trim(); const btn document.getElementById(classifyBtn); const loading document.getElementById(loadingIndicator); const resultArea document.getElementById(resultArea); if (!mailContent) { alert(请输入邮件内容); return; } // 禁用按钮显示加载动画隐藏结果 btn.disabled true; loading.style.display block; resultArea.style.display none; try { const response await fetch(http://localhost:8001/classify, { method: POST, headers: { Content-Type: application/json, }, body: JSON.stringify({ mail_content: mailContent }) }); if (!response.ok) { throw new Error(请求失败: ${response.status}); } const data await response.json(); // 更新页面显示结果 document.getElementById(resultCategory).textContent data.category; document.getElementById(resultReason).textContent data.reason; resultArea.style.display block; } catch (error) { console.error(分类出错:, error); alert(分类失败请检查后端服务是否运行正常。错误信息 error.message); } finally { // 恢复按钮隐藏加载动画 btn.disabled false; loading.style.display none; } } // 按回车键触发分类可选功能 document.getElementById(mailContent).addEventListener(keydown, function(event) { if (event.ctrlKey event.key Enter) { event.preventDefault(); classifyMail(); } }); /script /body /html这个页面非常直白一个文本框用来输入邮件一个按钮用来触发分类一个区域用来展示结果和加载状态。JavaScript代码负责把文本框里的内容发送到我们刚才启动的后端API(http://localhost:8001/classify)然后把返回的分类结果和理由显示出来。现在用浏览器打开这个index.html文件输入一段邮件内容点击按钮你应该就能看到AI返回的分类结果了。一个完整的、前后端分离的迷你AI应用就完成了。5. 总结走完这一遍你会发现把一个量化大模型变成可交互的小应用其实并没有想象中那么复杂。整个过程就像搭积木一层一层来首先部署模型服务是基础。我们用FastChat把Qwen1.5-1.8B-Chat-GPTQ-Int4这个“轻量化”的模型跑起来变成一个提供标准API接口的服务。这一步解决了模型怎么用的问题。接着封装业务逻辑是关键。直接让前端调模型API不灵活也不安全。我们写了一个FastAPI应用在这里面定制了适合邮件分类的提示词处理了模型的返回结果还加上了错误处理和日志。这让我们的核心功能更健壮也更容易维护和扩展。最后做个简单界面是让想法落地的最后一步。一个清晰的网页哪怕只有最基本的功能也能立刻把AI能力呈现给用户完成从代码到产品的闭环。这个“智能邮件助手”项目麻雀虽小但完整展示了AI应用开发的核心工作流。你可以基于这个模板轻松替换成其他模型或者实现更复杂的功能比如情感分析、内容摘要、自动回复等等。希望这个具体的例子能给你带来一些动手实践的灵感。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。