news 2026/5/1 7:34:17

Python,一键给客户部署llama.cpp +qwen3

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python,一键给客户部署llama.cpp +qwen3

纯 Python搞定三件事:

一、自动下载/更新 llama.cpp 可执行文件

二、自动拉取 Qwen3-4B 权重并转 GGUF + 量化

三、自动生成start_server.py,双击即可起 OpenAI 兼容服务,客户浏览器打开http://localhost:8080就能聊天。

脚本只依赖标准库 +requests无需 conda、docker、cmake,Windows/macOS/Linux 通用。你把整个文件夹压缩发给客户,他只要:

python deploy.py

然后去喝咖啡,回来就能用。


目录结构(发客户前打包成 zip)

qwen3-deploy/

├─ deploy.py # 一键部署脚本(本文件)

├─ start_server.py # 启动服务脚本,部署完自动生成

└─ bin/ # 自动下载的 llama.cpp 可执行

├─ main

├─ server

└─ quantize


deploy.py (可直接复制运行)

#!/usr/bin/env python3 """ 一键部署 llama.cpp + Qwen3-4B-Q4_K_M > python deploy.py > python start_server.py # 部署完成后运行 """ import os, sys, zipfile, json, subprocess, shutil, platform, requests, hashlib from pathlib import Path URL_BASE = "https://github.com/ggerganov/llama.cpp/releases/download/b3616" # 写死最新 release MODEL_ID = "Qwen/Qwen3-4B" QUANT_TYPE = "Q4_K_M" CTX = 32768 NGPU_LAYERS = 35 # 默认全 offlod,老 GPU 可改小 PWD = Path(__file__).parent.resolve() BIN_DIR = PWD / "bin" MODEL_DIR = PWD / "model" GGUF_FP16 = MODEL_DIR / "Qwen3-4B-F16.gguf" GGUF_Q = MODEL_DIR / f"Qwen3-4B-{QUANT_TYPE}.gguf" def download(url: str, dst: Path, desc=""): """带进度条的下载""" resp = requests.get(url, stream=True, headers={'Accept-Encoding': None}) resp.raise_for_status() total = int(resp.headers.get('content-length', 0)) done = 0 with open(dst, "wb") as f: for chunk in resp.iter_content(chunk_size=1 << 20): f.write(chunk) done += len(chunk) if total: print(f"\r{desc} {done*100/total:.1f}%", end="", flush=True) print() def get_bin_name(): """根据平台返回 release 文件名""" arch = platform.machine().lower() sys_name = platform.system().lower() if sys_name == "darwin": return "llama-b3616-bin-macos-arm64.zip" if arch == "arm64" else "llama-b3616-bin-macos-x64.zip" if sys_name == "windows": return "llama-b3616-bin-win-avx-x64.zip" if "linux" in sys_name: return "llama-b3616-bin-ubuntu-x64.zip" raise RuntimeError("暂不支持的平台") def prepare_llamacpp(): """下载并解压可执行""" BIN_DIR.mkdir(exist_ok=True) zip_name = get_bin_name() zip_path = BIN_DIR / zip_name if not zip_path.exists(): url = f"{URL_BASE}/{zip_name}" print(">>> 下载 llama.cpp 可执行 …") download(url, zip_path, "llama.cpp") print(">>> 解压 …") with zipfile.ZipFile(zip_path) as zf: for member in zf.namelist(): if member.endswith(("main", "server", "quantize")) or member.endswith(".exe"): target = BIN_DIR / Path(member).name with zf.open(member) as src, open(target, "wb") as dst: dst.write(src.read()) target.chmod(0o755) # Linux/mac 需要可执行权限 print("✅ llama.cpp 就绪") def convert_to_gguf(): """下载 HF 权重 -> F16 GGUF""" MODEL_DIR.mkdir(exist_ok=True) if GGUF_Q.exists(): print("✅ 已存在量化模型,跳过转换") return print(">>> 下载 HF 权重(约 8 GB)…") subprocess.check_call([ sys.executable, "-m", "huggingface_hub", "download", MODEL_ID, "--local-dir", str(MODEL_DIR), "--resume-download" ], stdout=sys.stdout, stderr=sys.stderr) print(">>> 转换为 F16 GGUF …") subprocess.check_call([ sys.executable, "convert.py", str(MODEL_DIR), "--outfile", str(GGUF_FP16), "--outtype", "f16" ], cwd=PWD, stdout=sys.stdout, stderr=sys.stderr) print(">>> 量化 ->", QUANT_TYPE, "(约 2 min) …") subprocess.check_call([ str(BIN_DIR / "quantize"), str(GGUF_FP16), str(GGUF_Q), QUANT_TYPE ], stdout=sys.stdout, stderr=sys.stderr) # 可选:删除原始大文件 GGUF_FP16.unlink(missing_ok=True) print("✅ 量化完成,大小:", GGUF_Q.stat().st_size // 1024 // 1024, "MB") def gen_start_script(): """生成一键启动脚本""" pycode = f''' import os, sys, subprocess, webbrowser, time from pathlib import Path BIN = Path(__file__).with_name("bin") MODEL = Path(__file__).with_name("model") / "{GGUF_Q.name}" cmd = [str(BIN / "server"), "-m", str(MODEL), "-c", "{CTX}", "-ngl", "{NGPU_LAYERS}", "--host", "0.0.0.0", "--port", "8080"] print(">>> 启动服务 …") print(">>> 浏览器打开 http://localhost:8080 即可聊天") time.sleep(2) webbrowser.open("http://localhost:8080") subprocess.run(cmd) ''' (PWD / "start_server.py").write_text(pycode.strip(), encoding="utf8") print("✅ 生成 start_server.py,双击或在终端运行即可") def main(): try: prepare_llamacpp() convert_to_gguf() gen_start_script() print("\n🎉 部署完成!运行:") print(" python start_server.py") print("然后浏览器访问 http://localhost:8080") except Exception as e: print("❌ 错误:", e, file=sys.stderr) sys.exit(1) if __name__ == "__main__": main()

四、使用步骤(客户侧)

  1. 你把整个文件夹压缩发过去。

  2. 客户解压后双击deploy.py(或命令行python deploy.py)。

    • 脚本自动下载 llama.cpp 可执行(≈ 30 MB)

    • 自动下载 Qwen3-4B(≈ 8 GB)并转量化(≈ 4 GB)

  3. 完成后提示“部署完成”

  4. 再双击start_server.py,浏览器弹出http://localhost:8080,即可聊天。

五、可定制点

需求改这里
换模型MODEL_ID = "Qwen/Qwen3-1_8B"
换量化QUANT_TYPE = "Q8_0"
老 GPU 显存小NGPU_LAYERS = 20
要中文 UI
start_server.py里打开地址换成http://localhost:8080/?ui=chatgpt-chinese(llama.cpp 自带简易 UI)

六、一句话总结

把脚本丢给客户,“双击→等待→再双击”,llama.cpp + Qwen3-4B 服务就跑起来,完全零命令行,Python 一键搞定!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 1:18:49

原创丨对话清华“挑战杯”揭榜挂帅赛道擂主:科研就是要解决真问题

在科技创新深度融入国家战略需求、关键核心技术亟待突破的时代浪潮中&#xff0c;第十九届 “挑战杯” 全国大学生课外学术科技作品竞赛 “揭榜挂帅” 擂台赛&#xff0c;正成为汇聚高校科研力量、直击行业痛点、催生创新成果的核心平台。作为国内大学生科创领域的顶级赛事&…

作者头像 李华
网站建设 2026/5/1 5:04:22

Kotaemon如何与Kubernetes结合实现弹性伸缩?

Kotaemon 如何与 Kubernetes 结合实现弹性伸缩&#xff1f; 在现代企业级 AI 应用的部署场景中&#xff0c;一个常见的挑战是&#xff1a;如何在流量剧烈波动的情况下&#xff0c;既保证对话系统的响应速度和稳定性&#xff0c;又避免资源浪费&#xff1f;尤其是在电商大促、在…

作者头像 李华
网站建设 2026/5/1 5:03:48

Kotaemon校园导览机器人学生反馈汇总

Kotaemon校园导览机器人学生反馈汇总 在高校数字化转型不断加速的今天&#xff0c;学生们早已不再满足于“登录官网→点击导航栏→逐页查找”的传统信息获取方式。面对迎新季的路线咨询、考试周的空教室查询&#xff0c;或是临时讲座的时间确认&#xff0c;他们期待的是像与朋友…

作者头像 李华
网站建设 2026/4/23 7:57:49

Kotaemon能否自动识别并链接相关知识点?

Kotaemon 能否自动识别并链接相关知识点&#xff1f; 在智能客服系统日益普及的今天&#xff0c;一个常见却棘手的问题是&#xff1a;用户问完“合同违约金怎么算”&#xff0c;接着追问“那试用期被辞退有没有赔偿”&#xff0c;系统是否能意识到这两个问题其实同属劳动法知识…

作者头像 李华
网站建设 2026/5/1 5:04:06

如何评价谷歌发布新一代图像生成模型 Nano Banana Pro,有哪些亮点?

近期&#xff0c;谷歌发布了其最新的图像生成模型——Nano Banana Pro。这一新一代AI模型的发布迅速引起了业界的广泛关注&#xff0c;许多业内专家和开发者纷纷开始分析其在图像生成、深度学习和计算机视觉领域的创新性和技术优势。那么&#xff0c;Nano Banana Pro究竟有何亮…

作者头像 李华
网站建设 2026/4/30 15:47:18

Kotaemon支持对话意图识别前置路由

Kotaemon支持对话意图识别前置路由 在智能客服、企业助手和知识管理系统日益复杂的今天&#xff0c;用户一句话背后可能藏着完全不同的需求&#xff1a;有人想查订单&#xff0c;有人要技术支援&#xff0c;还有人只是随口问个问题。如果所有请求都一股脑扔给大模型处理&#x…

作者头像 李华