GLM-4-9B-Chat-1M模型服务化部署从单机到高可用的RESTful API实战想把那个支持百万字长文本的GLM-4-9B-Chat-1M模型变成随时可调用的服务吗今天咱们就来聊聊怎么把这个大家伙服务化部署让它能稳定、高效地处理并发请求就像你平时用的那些云服务一样。我最近刚把一个GLM-4-9B-Chat-1M模型部署成生产环境可用的服务过程中踩了不少坑也积累了一些经验。这篇文章就带你走一遍完整的流程从单机部署开始一步步讲到怎么处理高并发、怎么做负载均衡让你也能轻松搭建自己的大模型服务。1. 为什么需要服务化部署你可能已经试过在本地跑GLM-4-9B-Chat-1M模型了用个Python脚本调用一下效果确实不错。但真要用到实际业务里问题就来了怎么让多个应用同时调用总不能每个应用都自己加载一遍模型吧怎么管理并发请求一个请求还没处理完另一个又来了怎么办怎么保证服务稳定万一服务挂了所有依赖它的应用都得跟着停摆怎么监控服务状态得知道服务现在忙不忙响应快不快服务化部署就是来解决这些问题的。简单说就是把模型包装成一个标准的Web服务提供统一的API接口任何应用都能通过HTTP请求来调用。这样既方便管理也容易扩展。2. 环境准备与模型选择2.1 硬件要求GLM-4-9B-Chat-1M这个模型对硬件要求不低特别是你要用它的1M上下文长度时。根据官方文档推理1M长度大概需要4张80G显存的卡比如A100/H100。不过别被吓到实际使用中我们很少真的用到1M长度。大部分场景下8192或32768的长度就够用了。这时候显存需求会大幅下降8192长度大约需要18-24G显存单张A10或3090就能跑32768长度可能需要2张24G卡做张量并行131072长度建议2-4张卡1M长度必须4张80G卡而且要用vLLM的enable_chunked_prefill参数我建议你先从8192长度开始这样单卡就能跑起来测试和开发都方便。等业务真需要更长上下文时再升级硬件。2.2 软件环境我推荐用Docker来部署这样环境隔离好也方便迁移。这里有个现成的vLLM Docker镜像可以用docker pull egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/vllm:0.4.0.post1-pytorch2.1.2-cuda12.1.1-cudnn8-ubuntu22.04这个镜像已经预装了vLLM和必要的CUDA环境省去了自己配置的麻烦。2.3 模型下载模型可以从魔搭社区ModelScope下载速度比Hugging Face快不少# 安装modelscope pip install modelscope # 下载GLM-4-9B-Chat-1M模型 modelscope download --model ZhipuAI/glm-4-9b-chat-1m下载完成后模型会保存在~/.cache/modelscope/hub/ZhipuAI/glm-4-9b-chat-1m目录下。记下这个路径后面启动服务要用。3. 单机服务部署3.1 基础服务启动我们先从最简单的单机服务开始。用vLLM启动一个兼容OpenAI API的服务# 启动Docker容器把模型目录映射进去 docker run -d -t --rm --nethost --gpus all \ --privileged \ --ipchost \ --name glm4-service \ -v /path/to/your/model:/models/glm4 \ egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/vllm:0.4.0.post1-pytorch2.1.2-cuda12.1.1-cudnn8-ubuntu22.04 \ python -m vllm.entrypoints.openai.api_server \ --host 0.0.0.0 \ --port 8000 \ --model /models/glm4 \ --served-model-name glm4-9b-chat \ --trust-remote-code \ --max-model-len 8192 \ --gpu-memory-utilization 0.9这里有几个关键参数需要解释一下--max-model-len 8192设置最大上下文长度根据你的显存调整--gpu-memory-utilization 0.9GPU内存使用率0.9表示使用90%的显存--trust-remote-codeGLM模型需要这个参数来加载自定义代码3.2 测试服务是否正常服务启动后用curl测试一下curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: glm4-9b-chat, messages: [ {role: system, content: 你是一个有帮助的助手}, {role: user, content: 你好请介绍一下你自己} ], temperature: 0.7, max_tokens: 100 }如果看到类似下面的响应说明服务启动成功了{ id: chat-123456, object: chat.completion, created: 1723716800, model: glm4-9b-chat, choices: [{ index: 0, message: { role: assistant, content: 你好我是GLM-4-9B-Chat一个由智谱AI开发的大语言模型... } }] }3.3 常见问题解决我在部署时遇到过一个典型问题对话无法停止模型一直输出。这是因为vLLM没有正确识别GLM模型的停止标记。解决方法是在启动命令中添加停止标记IDpython -m vllm.entrypoints.openai.api_server \ # ... 其他参数 ... --stop-token-ids 151329 151336 151338这三个ID151329, 151336, 151338是GLM模型特有的停止标记告诉模型什么时候该结束生成。4. RESTful API接口设计虽然vLLM提供了OpenAI兼容的接口但实际业务中我们可能需要定制化的接口。下面是我设计的一套RESTful API更适合企业级应用。4.1 基础聊天接口from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional import requests app FastAPI(titleGLM-4-9B-Chat-1M API服务) class Message(BaseModel): role: str # user, assistant, system content: str class ChatRequest(BaseModel): messages: List[Message] model: str glm4-9b-chat temperature: float 0.7 max_tokens: int 1024 stream: bool False class ChatResponse(BaseModel): id: str content: str model: str usage: dict app.post(/v1/chat/completions) async def chat_completion(request: ChatRequest): 聊天补全接口 支持多轮对话自动维护对话历史 try: # 调用底层的vLLM服务 vllm_response requests.post( http://localhost:8000/v1/chat/completions, jsonrequest.dict(), timeout30 ) if vllm_response.status_code ! 200: raise HTTPException( status_codevllm_response.status_code, detailvllm_response.text ) result vllm_response.json() return ChatResponse( idresult[id], contentresult[choices][0][message][content], modelresult[model], usageresult.get(usage, {}) ) except requests.exceptions.Timeout: raise HTTPException(status_code504, detail请求超时) except Exception as e: raise HTTPException(status_code500, detailstr(e))这个接口做了几件事统一了请求/响应格式添加了超时处理包装了错误信息保持了与OpenAI API的兼容性4.2 批量处理接口实际业务中经常需要批量处理请求比如同时处理100个用户的提问。vLLM本身支持连续批处理但我们需要一个接口来管理from concurrent.futures import ThreadPoolExecutor import asyncio class BatchChatRequest(BaseModel): requests: List[ChatRequest] max_workers: int 10 # 最大并发数 app.post(/v1/batch/chat) async def batch_chat(batch_request: BatchChatRequest): 批量聊天接口 同时处理多个聊天请求提高吞吐量 results [] # 使用线程池并发处理 with ThreadPoolExecutor(max_workersbatch_request.max_workers) as executor: loop asyncio.get_event_loop() tasks [] for req in batch_request.requests: # 将同步请求转换为异步任务 task loop.run_in_executor( executor, lambda rreq: requests.post( http://localhost:8000/v1/chat/completions, jsonr.dict(), timeout30 ).json() ) tasks.append(task) # 等待所有任务完成 responses await asyncio.gather(*tasks, return_exceptionsTrue) for i, resp in enumerate(responses): if isinstance(resp, Exception): results.append({ index: i, error: str(resp), success: False }) else: results.append({ index: i, content: resp[choices][0][message][content], success: True }) return {results: results}4.3 长文本处理接口GLM-4-9B-Chat-1M的核心优势就是长文本处理。我们可以设计专门的接口来处理长文档class LongTextRequest(BaseModel): text: str task: str # summarize, qa, extract chunk_size: int 32768 # 分块大小 overlap: int 512 # 块之间重叠部分 app.post(/v1/longtext/process) async def process_longtext(request: LongTextRequest): 长文本处理接口 支持总结、问答、信息提取等任务 # 如果文本超过chunk_size先进行分块 if len(request.text) request.chunk_size: chunks [] start 0 while start len(request.text): end min(start request.chunk_size, len(request.text)) chunk request.text[start:end] chunks.append(chunk) start end - request.overlap # 重叠一部分避免切分关键信息 else: chunks [request.text] # 根据任务类型构建不同的提示词 if request.task summarize: system_prompt 你是一个专业的文本总结助手。请用简洁的语言总结以下文本的核心内容。 elif request.task qa: system_prompt 你是一个问答助手。请根据文本内容回答用户的问题。 else: system_prompt 你是一个信息提取助手。请从文本中提取关键信息。 # 处理每个分块 results [] for i, chunk in enumerate(chunks): chat_request ChatRequest( messages[ Message(rolesystem, contentsystem_prompt), Message(roleuser, contentchunk) ], max_tokensmin(1024, len(chunk) // 4) # 根据输入长度动态调整输出长度 ) # 调用聊天接口 response await chat_completion(chat_request) results.append({ chunk_index: i, content: response.content }) # 如果需要可以将各分块的结果再合并 if len(results) 1 and request.task summarize: # 对分块总结再进行一次总结 combined_summary \n.join([r[content] for r in results]) final_request ChatRequest( messages[ Message(rolesystem, content请将以下多个分块的总结合并成一个连贯的完整总结。), Message(roleuser, contentcombined_summary) ] ) final_response await chat_completion(final_request) return {summary: final_response.content} return {results: results}5. 并发处理与性能优化单机服务处理几个请求没问题但真要面对成百上千的并发请求就得好好优化了。5.1 vLLM的批处理机制vLLM最大的优势就是它的连续批处理Continuous Batching机制。传统批处理要等一批请求都到齐了才开始处理而连续批处理可以随时加入新请求随时完成老请求。我们可以在启动服务时调整批处理相关参数python -m vllm.entrypoints.openai.api_server \ # ... 其他参数 ... --max-num-seqs 256 \ # 最大同时处理的序列数 --max-num-batched-tokens 8192 \ # 每批最大token数 --block-size 16 \ # 注意力块大小影响内存效率 --enable-prefix-caching # 启用前缀缓存加速重复提示5.2 异步处理与队列管理对于高并发场景我们需要在API层做请求队列管理from queue import Queue import threading import time class RequestQueue: def __init__(self, max_size1000): self.queue Queue(maxsizemax_size) self.processing False self.results {} self.lock threading.Lock() def add_request(self, request_id, request_data): 添加请求到队列 if self.queue.full(): return False self.queue.put((request_id, request_data)) self.results[request_id] {status: pending} return True def process_requests(self, batch_size8): 处理队列中的请求 self.processing True while not self.queue.empty() or self.processing: batch [] request_ids [] # 收集一批请求 for _ in range(min(batch_size, self.queue.qsize())): try: req_id, req_data self.queue.get_nowait() batch.append(req_data) request_ids.append(req_id) except: break if batch: # 批量处理 try: responses self._process_batch(batch) # 更新结果 with self.lock: for req_id, resp in zip(request_ids, responses): self.results[req_id] { status: completed, response: resp, completed_at: time.time() } except Exception as e: with self.lock: for req_id in request_ids: self.results[req_id] { status: failed, error: str(e) } time.sleep(0.1) # 避免空转 def get_result(self, request_id, timeout30): 获取请求结果 start_time time.time() while time.time() - start_time timeout: with self.lock: result self.results.get(request_id) if result and result[status] ! pending: return result time.sleep(0.1) return {status: timeout, error: 请求超时} # 全局请求队列 request_queue RequestQueue(max_size1000) # 启动处理线程 processing_thread threading.Thread( targetrequest_queue.process_requests, daemonTrue ) processing_thread.start() app.post(/v1/async/chat) async def async_chat(request: ChatRequest): 异步聊天接口 适用于需要长时间处理的请求 request_id str(uuid.uuid4()) # 添加到队列 if not request_queue.add_request(request_id, request.dict()): raise HTTPException(status_code429, detail请求队列已满) return {request_id: request_id, status: queued} app.get(/v1/async/result/{request_id}) async def get_async_result(request_id: str): 获取异步处理结果 result request_queue.get_result(request_id) if result[status] completed: return result[response] elif result[status] failed: raise HTTPException(status_code500, detailresult[error]) elif result[status] timeout: raise HTTPException(status_code408, detail请求处理超时) else: return {status: processing}5.3 性能监控与限流服务上线后监控和限流很重要from prometheus_client import Counter, Histogram, generate_latest from fastapi import Response import time # 定义监控指标 REQUEST_COUNT Counter( http_requests_total, Total HTTP requests, [method, endpoint, status] ) REQUEST_LATENCY Histogram( http_request_duration_seconds, HTTP request latency, [method, endpoint] ) ERROR_COUNT Counter( http_errors_total, Total HTTP errors, [method, endpoint, error_type] ) class RateLimiter: def __init__(self, requests_per_minute60): self.requests_per_minute requests_per_minute self.requests {} # ip - [timestamp1, timestamp2, ...] def is_allowed(self, client_ip: str) - bool: now time.time() if client_ip not in self.requests: self.requests[client_ip] [] # 清理一分钟前的记录 self.requests[client_ip] [ ts for ts in self.requests[client_ip] if now - ts 60 ] # 检查是否超过限制 if len(self.requests[client_ip]) self.requests_per_minute: return False # 记录本次请求 self.requests[client_ip].append(now) return True rate_limiter RateLimiter(requests_per_minute100) app.middleware(http) async def monitor_requests(request, call_next): start_time time.time() # 限流检查 client_ip request.client.host if not rate_limiter.is_allowed(client_ip): ERROR_COUNT.labels( methodrequest.method, endpointrequest.url.path, error_typerate_limit ).inc() return Response( content请求过于频繁请稍后再试, status_code429 ) try: response await call_next(request) # 记录请求 REQUEST_COUNT.labels( methodrequest.method, endpointrequest.url.path, statusresponse.status_code ).inc() # 记录延迟 latency time.time() - start_time REQUEST_LATENCY.labels( methodrequest.method, endpointrequest.url.path ).observe(latency) return response except Exception as e: ERROR_COUNT.labels( methodrequest.method, endpointrequest.url.path, error_typetype(e).__name__ ).inc() raise app.get(/metrics) async def metrics(): Prometheus监控指标 return Response(contentgenerate_latest(), media_typetext/plain)6. 负载均衡与高可用单个服务实例总有瓶颈也容易单点故障。生产环境需要多实例负载均衡。6.1 多实例部署我们可以用Docker Compose部署多个服务实例version: 3.8 services: glm4-service-1: image: egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/vllm:0.4.0.post1-pytorch2.1.2-cuda12.1.1-cudnn8-ubuntu22.04 command: python -m vllm.entrypoints.openai.api_server --host 0.0.0.0 --port 8000 --model /models/glm4 --served-model-name glm4-9b-chat --trust-remote-code --max-model-len 8192 --gpu-memory-utilization 0.8 --tensor-parallel-size 2 volumes: - /path/to/model:/models/glm4 deploy: resources: reservations: devices: - driver: nvidia count: 2 capabilities: [gpu] networks: - glm4-network glm4-service-2: image: egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/vllm:0.4.0.post1-pytorch2.1.2-cuda12.1.1-cudnn8-ubuntu22.04 command: python -m vllm.entrypoints.openai.api_server --host 0.0.0.0 --port 8000 --model /models/glm4 --served-model-name glm4-9b-chat --trust-remote-code --max-model-len 8192 --gpu-memory-utilization 0.8 --tensor-parallel-size 2 volumes: - /path/to/model:/models/glm4 deploy: resources: reservations: devices: - driver: nvidia count: 2 capabilities: [gpu] networks: - glm4-network load-balancer: image: nginx:alpine ports: - 8080:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf depends_on: - glm4-service-1 - glm4-service-2 networks: - glm4-network networks: glm4-network: driver: bridge6.2 Nginx负载均衡配置对应的Nginx配置events { worker_connections 1024; } http { upstream glm4_backend { # 最少连接数负载均衡 least_conn; server glm4-service-1:8000; server glm4-service-2:8000; # 健康检查 check interval3000 rise2 fall3 timeout1000; } server { listen 80; location / { proxy_pass http://glm4_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 超时设置 proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; # 缓冲设置 proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; } # 健康检查端点 location /health { access_log off; return 200 healthy\n; } } }6.3 服务发现与自动扩缩容对于更复杂的场景可以用Kubernetes实现自动扩缩容apiVersion: apps/v1 kind: Deployment metadata: name: glm4-service spec: replicas: 2 selector: matchLabels: app: glm4-service template: metadata: labels: app: glm4-service spec: containers: - name: glm4 image: egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/vllm:0.4.0.post1-pytorch2.1.2-cuda12.1.1-cudnn8-ubuntu22.04 command: [python, -m, vllm.entrypoints.openai.api_server] args: - --host0.0.0.0 - --port8000 - --model/models/glm4 - --served-model-nameglm4-9b-chat - --trust-remote-code - --max-model-len8192 - --gpu-memory-utilization0.8 - --tensor-parallel-size2 resources: limits: nvidia.com/gpu: 2 volumeMounts: - name: model-volume mountPath: /models/glm4 livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 5 periodSeconds: 5 volumes: - name: model-volume hostPath: path: /path/to/model type: Directory --- apiVersion: v1 kind: Service metadata: name: glm4-service spec: selector: app: glm4-service ports: - port: 80 targetPort: 8000 type: LoadBalancer --- apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: glm4-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: glm4-service minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 707. 实际部署建议根据我的经验给你几个实际部署的建议对于初创项目或内部工具单机部署就够了用一张24G显存的卡上下文长度设8192能处理大多数场景用Docker部署方便备份和迁移加上基础的健康检查和监控对于中小型生产环境至少2个实例做负载均衡每实例2张GPU卡做张量并行上下文长度可以提到32768设置完整的监控告警做好日志收集和分析对于大型生产环境多实例多区域部署用Kubernetes管理支持自动扩缩容实现灰度发布和回滚机制建立完整的DevOps流程考虑混合部署CPUGPU应对不同负载性能调优要点批处理大小根据实际请求模式调整--max-num-batched-tokens内存使用监控GPU内存调整--gpu-memory-utilization响应时间长文本请求单独处理避免阻塞短请求缓存策略对常见问题启用前缀缓存成本控制建议按需扩容用Kubernetes HPA流量低时自动缩容混合精度能用FP16就不用BF16能省显存请求合并相似请求合并处理提高GPU利用率冷热分离高频功能保持热实例低频功能用冷启动8. 总结把GLM-4-9B-Chat-1M做成服务化部署听起来复杂但一步步拆解下来其实挺清晰的。从单机服务开始慢慢加上并发处理、负载均衡、监控告警最后实现高可用架构。关键是要根据实际需求来设计别一开始就追求大而全。内部工具用单机就行对外服务再考虑多实例真正高并发场景再上K8s。我在这套方案里积累的经验是稳定性比性能重要监控比功能重要简单比复杂重要。先让服务稳定跑起来再慢慢优化性能先做好监控知道服务状态再加新功能架构尽量简单容易维护才是长久之计。GLM-4-9B-Chat-1M的长文本能力确实强但要用好它服务化部署是关键。希望这篇文章能帮你少走些弯路快速搭建起自己的大模型服务。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。