#!/usr/bin/env python3 """ 启动脚本:同时运行 vLLM 服务器和 Streamlit 应用 保留原有的 Streamlit 入口,添加 vLLM 后台服务 """ import subprocess import time import os import signal import sys import threading import logging from pathlib import Path # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # 添加项目根目录到路径 sys.path.append(str(Path(__file__).parent.parent)) class ServiceManager: def __init__(self): self.processes = [] self.running = True def run_vllm(self): """启动 vLLM 服务器(后台服务)""" logger.info("🚀 正在启动 vLLM 推理服务器...") # vLLM 启动命令(优化显存使用) cmd = [ "python", "-m", "vllm.entrypoints.openai.api_server", "--model", "Qwen/Qwen3.5-27B-GPTQ-Int4", "--port", "8000", "--host", "0.0.0.0", "--tensor-parallel-size", "1", "--quantization", "gptq", "--max-model-len", "32768", "--gpu-memory-utilization", "0.85", # 保留 15% 显存给 Streamlit 等 "--enforce-eager", "--max-num-batched-tokens", "8192", "--max-num-seqs", "4", "--disable-log-stats", # 减少日志输出 ] # 设置 CUDA 环境 env = os.environ.copy() #env["CUDA_VISIBLE_DEVICES"] = "0" #env["VLLM_USE_TRITON"] = "1" # 使用 Triton 加速 # 启动进程 process = subprocess.Popen( cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, bufsize=1 ) self.processes.append(("vllm", process)) # 在单独的线程中读取输出 def log_output(): for line in process.stdout: if line.strip(): logger.info(f"[vLLM] {line.strip()}") threading.Thread(target=log_output, daemon=True).start() # 等待 vLLM 就绪 self.wait_for_vllm() def wait_for_vllm(self, max_retries=60): """等待 vLLM 服务器就绪""" import requests logger.info("⏳ 等待 vLLM 服务器初始化...") for i in range(max_retries): try: response = requests.get("http://localhost:8000/health") if response.status_code == 200: logger.info("✅ vLLM 服务器已就绪!") return True except: pass # 显示进度 if i % 10 == 0: logger.info(f"⏳ 仍在等待 vLLM... ({i+1}/{max_retries})") time.sleep(2) logger.error("❌ vLLM 启动超时") return False def run_streamlit(self): """启动 Streamlit 应用(主服务)""" logger.info("🖥️ 正在启动 Streamlit 应用...") # 使用原有的入口点 cmd = [ "streamlit", "run", "streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0", "--server.enableCORS=false", "--server.enableXsrfProtection=false", "--server.maxUploadSize=10", # 限制上传大小 ] process = subprocess.Popen(cmd) self.processes.append(("streamlit", process)) logger.info("✅ Streamlit 应用已启动") def monitor_services(self): """监控服务状态""" while self.running: time.sleep(10) for name, process in self.processes: if process.poll() is not None: logger.error(f"❌ {name} 服务意外停止,退出码: {process.returncode}") self.stop_all() sys.exit(1) def stop_all(self, signum=None, frame=None): """停止所有服务""" logger.info("🛑 正在停止所有服务...") self.running = False for name, process in self.processes: logger.info(f"正在停止 {name}...") process.terminate() # 等待进程结束 for name, process in self.processes: try: process.wait(timeout=5) except subprocess.TimeoutExpired: logger.warning(f"强制终止 {name}") process.kill() logger.info("✅ 所有服务已停止") sys.exit(0) def run(self): """运行所有服务""" # 注册信号处理 signal.signal(signal.SIGINT, self.stop_all) signal.signal(signal.SIGTERM, self.stop_all) # 启动 vLLM(后台) self.run_vllm() # 启动 Streamlit(前台) self.run_streamlit() # 开始监控 self.monitor_services() if __name__ == "__main__": manager = ServiceManager() manager.run()