十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

开源模型生产部署实战:Docker Compose + vLLM + LiteLLM 标准方案

开源模型生产部署实战:Docker Compose + vLLM + LiteLLM 标准方案 先给结论在2026年这个时间点把开源模型部署到生产环境最简单且稳妥的路线不是自己研究并行推理框架也不是从裸机开始装驱动、配环境、调CUDA而是直接用一套“Docker Compose 开源推理引擎 模型网关 基础监控”组成的标准闭环。这套方案既能满足真实业务的高并发调用又不需要一开始就上Kubernetes特别适合中小团队、独立开发者和那些第一次把开源模型从实验环境推到线上的同学。这篇文章会从部署方案的拆解思路讲起然后给出完整的选型理由、配置文件、启动命令和排障经验。内容不是我凭空想象的架构图而是过去一年里我在多个项目里实际跑过的方案。默认你会Docker的基本操作也熟悉命令行和Linux服务器如果没有这些基础建议先把相关操作过一遍再回来。1. 先想明白2026年的“最简单部署”到底解决什么问题1.1 从“能跑起来”到“能上生产”差的不是一步命令很多人第一次跑开源模型用的还是那种“一行命令启动”的方式。本地实验确实很爽ollama run qwen3:8b敲进去模型就起来了随便问两句也能得到像模像样的回答。但这和“生产环境部署”是两回事。生产环境到底意味着什么你面对的是真实的业务流量可能是几十个人同时在调用也可能是一个自动化任务在批量处理上千条文本。这时候模型服务必须满足几个硬性条件一是稳定不能跑几个小时就内存溢出挂掉二是可控服务挂了要能自动恢复出了问题要能看日志查原因三是可管理API接口要有鉴权、限流不能让任何人白嫖你的算力。我经常跟团队里的小伙伴说一句话本地跑通模型只是起点生产部署的本质是“让模型变成一项可靠的基础设施”。它不再是一个你打开终端手动启动的玩具而是一个开机自启、健康检查、异常能告警、日志能追踪的服务。这中间的差距不是一条命令能补齐的而是需要一套工程化的组合方案。1.2 为什么这两年开源模型部署的复杂度被大幅压缩放到2024年你想在自建服务器上跑一个大模型可能会被一系列问题劝退。模型权重动不动几十GB推理框架还不成熟跑起来要自己调显存分配遇到长文本还要处理各种溢出更别提并发请求一来GPU直接被打满然后报OOM。到了2026年事情变得简单很多。推理引擎已经非常成熟vLLM这种框架把连续批处理做到了近乎自动化的程度显存管理也由PagedAttention这类技术解决了大部分问题。各大模型厂商开始发布官方Docker镜像和标准的OpenAI兼容接口你不需要自己处理分词器细节和HTTP服务逻辑。再加上Docker Compose在服务器编排领域已经成为事实标准写一个十几个服务的模型部署文件跟写一个Web应用部署文件差不多复杂度。我说“最简单方法”并不是让你忽略生产环境的复杂度而是告诉你复杂度已经被行业沉淀成了工具和标准。我们要做的是学会用这些工具而不是重新发明轮子。2. 核心组件选型2026年最值得依赖的工具链2.1 推理引擎vLLM是生产中近乎默认的选择Ollama更适合本地开发推理引擎是整个部署方案的核心。它能决定你一台GPU服务器能扛多少并发也决定了显存利用率高不高。选型之前你要先分清楚自己处在什么阶段。如果你是做技术验证、本地跑通流程、或者只给三五个人内部使用Ollama确实很方便。它的优势在于模型管理简单一条命令就能拉起OpenAI兼容接口社区生态也好。但如果你要面向真实业务提供API并发稍微上来一点Ollama的吞吐就会比较吃力。它在批处理调度和显存管理上和专门为高吞吐设计的引擎相比还是有差距的。vLLM是生产环境最稳妥的选择。它的连续批处理Continuous Batching能把GPU的算力利用率拉得很高同样是跑一个Qwen3-8BvLLM能扛住的并发请求数量往往是单纯用Ollama的好几倍。它还实现了PagedAttention显存碎片问题处理得更好。更关键的是它原生提供OpenAI兼容API接入现有业务代码几乎不需要改动。选型建议很直接个人体验和开发调试用Ollama生产服务优先用vLLM。如果你只是内部小工具并发要求不高Ollama也够用但你要接受它在高并发场景下的短板。我绝大多数生产案例最终都落在vLLM上。2.2 部署与编排Docker Compose撑起小团队的最小生产形态很多人一提到生产环境就条件反射觉得要上Kubernetes。我不否认K8s在大规模场景下的优势但绝大部分开源模型部署项目一开始的规模就是一两台GPU服务器。在这个规模下Docker Compose是最合适的选择。原因很简单配置即代码一个项目目录下的YAML文件就能完整描述整个部署拓扑团队成员拉下来就能启动不需要额外维护一套复杂的编排系统。Compose的容器重启策略、健康检查、资源限制这些能力已经能满足模型服务的日常运维需求。以后如果业务真的增长到需要水平扩展Compose配置也能比较平滑地演进到容器编排平台。但如果一开始就上K8s光学习成本就能拖垮一个小团队。GPU调度、节点亲和性、设备插件这些概念对第一次部署模型的人来说是巨大的负担。2.3 面向业务的接入层用LiteLLM Proxy统一模型网关直接暴露vLLM的API端口给业务方虽然能跑但不够专业。生产环境需要鉴权、限流、请求日志、多模型路由这些能力。vLLM本身不是干这个的这是API网关的活。我一直用的是LiteLLM Proxy。它是一个非常轻量的AI网关可以统一管理多个模型后端对外提供标准OpenAI接口。你在配置里声明一下哪个模型指向哪个vLLM服务地址然后业务方只需要对着LiteLLM的地址发请求根本不需要知道后端到底跑在哪里、用的是vLLM还是别的引擎。LiteLLM还支持虚拟API Key可以为不同业务部门或者不同用户分配独立Key单独做额度限制和调用统计。这在真实业务中非常实用。就我实际体验它配置简单、文档全、社区活跃遇到问题基本都能在GitHub上找到答案。3. 从零到一一套可以直接抄作业的生产环境部署方案3.1 环境与容量规划先算清楚显存再动手动手部署之前最重要的一件事是算显存。显存不够一切配置都是白搭。GPU显存的占用主要来自三块模型权重、KV Cache、激活值和临时缓冲区。模型权重的计算最简单。一个7B参数的模型用FP16精度存储参数量乘以2字节大概需要14GB显存。8B模型大概16GB。如果你用AWQ或者GPTQ量化版本权重可以压缩到原来的四分之一到一半但牺牲的是极少量精度。生产环境我更建议优先用原生精度或仅做轻度量化先把稳定性和效果放第一位。KV Cache的大小取决于两个参数最大序列长度和并发数。假设你设置最大上下文长度是32768个Token并发序列数是32KV Cache的大小可能就要占掉8到16GB显存。这也是为什么显存规划一定要留出余量的原因。下面我根据常见的模型规模给一个粗略的显存参考表以单实例推理、批次大小适中为例方便你做初步判断。模型规模权重精度推荐最小显存推荐场景7B-8BFP1624GB单卡RTX 3090/4090即可覆盖多数场景13B-14BFP1648GB建议至少一张A6000或L4以上32B-72BFP1680GB以上建议多卡或使用量化方案8BAWQ 4bit12GB显存受限时的妥协方案这个表只是参考真实情况取决于你的并发数和请求长度。实操上我会先用一个较小的并发参数量做压测然后逐步往上加通过观察GPU显存使用率来确定最终配置。不要一开始就把显存利用率调到接近100%那样一旦遇到超长文本请求很容易OOM。3.2 项目目录与Compose配置主服务加网关的最小结构下面是我在实际项目里使用过的一套最小化部署结构不包含复杂的可观测性组件但已经能支撑真实业务流量。model-server/ ├── docker-compose.yml ├── .env ├── models/ # 模型权重挂载目录 │ └── Qwen3-8B/ └── litellm/ └── config.yaml # LiteLLM网关配置核心的docker-compose.yml我给出一个精简版本。这里以Qwen3-8B为例模型权重先下载到本地models目录。之所以不用镜像内置模型是因为模型文件体积大放容器里会导致镜像臃肿而且每次更新模型都要重新构建镜像太麻烦。直接挂载磁盘目录后续换模型只需改环境变量和挂载路径。services: vllm: image: vllm/vllm-openai:v0.10.0 container_name: vllm-server restart: unless-stopped ports: - 8001:8000 volumes: - ./models:/models environment: - HF_HOME/models command: --model /models/Qwen3-8B --served-model-name qwen3-8b --max-model-len 32768 --gpu-memory-utilization 0.9 --max-num-seqs 32 --trust-remote-code deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] healthcheck: test: [CMD, curl, -f, http://localhost:8000/health] interval: 30s timeout: 10s retries: 3 start_period: 120s lite-llm: image: ghcr.io/berriai/litellm:main-latest container_name: litellm-gateway restart: unless-stopped depends_on: vllm: condition: service_healthy ports: - 8000:4000 volumes: - ./lite-llm/config.yaml:/app/config.yaml command: [--config, /app/config.yaml] redis: image: redis:7-alpine container_name: model-redis restart: unless-stopped注意几个关键参数。--gpu-memory-utilization 0.9的意思是把90%的显存预留给模型加载和KV Cache保留10%给系统运行和其他开销。我踩过的坑是有人为了省显存设到0.98结果遇到长文本请求直接OOM而且容器内不会优雅报错只会在系统日志里看到进程被杀。--max-num-seqs 32表示最多同时处理32个请求超过这个数的请求会排队等待。这个参数需要根据业务量和GPU显存反复压测不能拍脑袋写死。3.3 LiteLLM网关配置让业务方只认一个地址LiteLLM的配置比较简单。它的作用是把自己伪装成一个OpenAI接口然后把请求转发给后端的vLLM服务。下面是一个最基本的配置model_list: - model_name: qwen3-8b litellm_params: model: openai/qwen3-8b api_base: http://vllm:8000/v1 api_key: none model_info: mode: chat supports_function_calling: true general_settings: master_key: sk-your-master-key database_url: redis://redis:6379这里有个容易踩的坑model参数必须通过openai/前缀指定使用OpenAI兼容格式调用api_base指向vLLM服务在Docker网络内的地址。Docker Compose会自动创建内部网络服务名vllm可以直接被lite-llm容器解析所以这里不需要写IP地址直接写服务名即可。master_key是你访问LiteLLM网关的主密钥。业务方调用的时候要带上这个KeyLiteLLM校验通过后才会把请求转发给vLLM。如果不想手动创建多个业务Key可以让业务方直接用主Key但更好的做法是为每个调用方创建独立的虚拟Key方便后期统计调用量。启动整个服务栈只需要一个命令在项目目录下执行docker compose up -d等vLLM容器健康检查通过后LiteLLM会自动开始接收请求。3.4 首次调用自测确认链路通了再交付业务方部署完成后一定要先自测一遍再通知业务方接入。我的自测方式是先用curl直接调用vLLM的接口确认模型服务本身没问题再通过LiteLLM网关调用确认链路畅通。直接测vLLMcurl http://localhost:8001/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen3-8b, messages: [{role: user, content: 你好介绍一下你自己}], max_tokens: 200 }然后再测LiteLLM网关curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-your-master-key \ -d { model: qwen3-8b, messages: [{role: user, content: 你好介绍一下你自己}], max_tokens: 200 }两个请求都能正常返回说明链路已经打通。这时候业务方接入的时候只需要把API地址改成你的服务器IP加8000端口模型名称填qwen3-8b认证Key填你分配的虚拟Key剩下的代码完全不用改因为他们看到的接口和OpenAI官方接口长得一模一样。4. 生产环境再加固监控、鉴权、并发调优4.1 模型服务必须挂在网关后面不要裸奔我见过一些团队为了省事直接把vLLM的端口暴露给内网应用使用。短期看确实少了一层服务但长期一定会出问题。没有网关就没有统一的鉴权入口任何服务只要能访问到这个端口就能免费调用模型。时间一长你根本不知道谁在调用、调了多少、哪些Prompt经常触发敏感内容。LiteLLM网关能帮你补上这块短板。它支持虚拟Key管理可以为不同业务方分配独立Key。某个业务线的Key调用量异常增长你可以直接禁用Key不影响其他业务方。它还天然支持限流可以在配置里为不同模型设置每分钟最大请求数避免某个调用方一次性把GPU资源打满。网关的另一个好处是你可以随时切换后端模型而不影响业务方。比如今天用Qwen3-8B明天开源社区出了更好的模型你只需要在LiteLLM配置里把模型指向新的vLLM服务业务方的代码一行都不用改。4.2 健康检查、日志规模和指标监控Docker Compose提供的healthcheck机制我建议一开始就配置好。vLLM服务加载模型较慢启动可能要一两分钟如果不设置健康检查LiteLLM可能会在vLLM还没就绪时就尝试连接导致大量请求失败。healthcheck可以帮助编排系统确定服务真正可用的时间点。日志管理是另一个很容易被忽略的点。vLLM在高并发下日志输出非常多如果Docker默认的json-file日志驱动不限制大小日志文件能把磁盘撑爆。我的经验是在compose文件里给每个服务都加上日志滚动限制或者统一配置daemon级的日志参数logging: driver: json-file options: max-size: 100m max-file: 3如果你的团队已经用了Prometheus和GrafanavLLM默认会暴露/metrics端点包含吞吐量、请求延迟、队列深度等关键指标。LiteLLM也有自己的Prometheus指标可以用来统计每个Key的调用次数和Token消耗量。这些指标对接起来很简单但我建议第一版部署先别急着弄全套监控把日志处理好把健康检查加上跑一段时间看情况再迭代。4.3 显存利用率与并发参数的调优经验并发调优是生产部署中最难的一步因为每个人的业务场景不一样。有些业务是短文本大量请求比如文本分类有些业务是长文本少请求比如文档总结。同一个模型不同业务特征最优参数差距很大。我先说一个通用的起点--gpu-memory-utilization设到0.85到0.9之间--max-num-seqs设成4或8跑一轮真实业务压测观察GPU显存峰值和平均延迟。如果显存还有大量富余逐步把max-num-seqs往上调。如果显存接近上限但GPU利用率还是不高通常意味着单请求生成长度太长占了大量显存这时候可以考虑限制单次请求的max_tokens。另外一个容易被忽视的参数是--max-model-len。它的作用是限制模型能处理的最大上下文长度直接影响KV Cache预分配大小。如果你设成128KvLLM启动时就会按128K长度预分配KV Cache即使你实际并没有那么长的请求显存也已经被占用了。所以不要盲目追求长上下文够用就好。对于绝大多数企业知识库问答场景32K已经非常宽裕。5. 我踩过的坑生产环境部署速查与排查5.1 镜像和权重下载慢、中断怎么办模型权重动辄十几个GB镜像也有几个GB在内网环境下载确实容易把时间耗光。如果是海外模型仓库网络不稳的情况下很容易出现下载到一半中断的问题。我的解决方案很朴素尽量提前准备好离线资源包或者通过企业内部镜像仓库做分发。操作上可以先用一台能访问公网的机器把容器镜像拉下来然后通过docker save导出为tar包再拷贝到生产服务器用docker load导入。模型权重文件则可以先在内部存储或对象存储上放一份部署时直接拷贝到模型目录。如果你所在地区访问常用模型社区比较慢也可以优先使用国内模型社区下载权重很多主流开源模型都有高速下载通道。核心原则只有一个生产服务器不要临到部署了才去拉大文件提前准备永远比临时解决更稳。5.2 服务启动就OOM或者一直显示启动中这个问题在首次部署时出现频率极高。最常见的原因是显存不够时vLLM启动阶段加载模型权重就会失败报CUDA out of memory。很多人第一反应是模型太大了但实际情况往往是--max-model-len设得太大导致KV Cache预分配占了过多显存。排查时先用nvidia-smi查看当前GPU显存占用确认是否已经被其他进程占用了。然后检查启动参数试着把--max-model-len调低比如从32768调到16384或者把--gpu-memory-utilization从0.9降到0.85看能否正常启动。还有一种情况是容器健康检查一直不通过。vLLM加载模型需要时间特别是大模型冷启动可能要几分钟。如果你的healthcheck的start_period设得太短容器会被反复重启看起来就像永远启动不起来。建议给大模型留够启动时间一般start_period设置180秒以上比较稳妥。5.3 服务能启动但调用超时或大量503这种现象通常和高并发参数设置有关系。vLLM不是无限并行的当排队请求超过max-num-seqs限制时后续请求会被挂起。如果你前面还叠加了API网关的默认超时时间请求等不到返回就被网关断开了业务方看到的就是超时或503。我的排查思路是先看vLLM日志确认请求是否正常进入处理队列。如果日志显示大量请求在排队说明并发能力已经到瓶颈要么调大max-num-seqs显存允许的前提下要么增加GPU实例做水平扩展。如果日志显示接收请求很快但响应很慢问题可能出在生成长度很多应用生成了非常长的max_tokens导致单个请求占坑太久。另一个容易被忽略的问题是上游超时设置。如果你用Nginx或者自有网关服务做了反向代理一定要把proxy_read_timeout从默认的60秒调大否则模型生成时间一旦超过60秒请求就会被代理服务器掐断。5.4 流式输出接不稳前端看到的内容一段一段跳流式输出是生产环境中比想象中更容易出问题的环节。很多开发者在本地测试时用的是非流式请求拿到完整结果看起来一切正常上线后改成流式输出才发现问题频发。流式问题绝大多数出在中间链路。如果你在模型服务前面挂了LiteLLM或Nginx这类代理需要确保它们支持并正确开启了流式转发。Nginx需要关闭缓冲配置proxy_buffering off否则前端会一直等不到第一块内容。LiteLLM对流式的支持比较成熟一般不需要特殊配置但要确认它的版本不是太老。排查时用curl加stream: true参数直接请求vLLM看第一块内容返回是否及时。如果直接访问vLLM正常、经过LiteLLM不正常问题就出在网关层。理论上Debug的过程就是逐层排除不要一上来就怀疑模型本身。5.5 模型更新后行为差异明显线上效果不可控开源模型迭代速度很快很可能你月初部署的版本月底原作者就发了新版本。但如果生产环境为了“追踪最新”而随意升级模型很容易出现线上效果突变用户反馈质量下降你却说不清楚变化来源。我的习惯是把模型版本和镜像版本都锁死。模型目录里不仅放权重文件还要放一个描述文件记录模型来源、版本号、部署日期和已知问题。每次升级模型先在测试环境跑一批固定的评测集确认关键指标没有退化再上生产。线上模型服务不要用latest这种不稳定的标签要锁定到具体版本。这种做法看起来多花了一点时间但可以避免大量“不知道为什么效果变了”的被动排查。最后再分享一个实际经验我在第一次把开源模型部署到生产环境时犯过一个很低级的错误没有做压测就直接通知业务方接入。结果业务上线第一波流量进来服务直接卡死所有请求超时。那次事件之后我总结了一条规矩任何模型服务上生产前必须先用压测工具模拟预期峰值的2倍流量跑一遍确认延迟和显存都还在安全范围内。根据我个人经验刚开始做开源模型生产化部署不需要追求一步到位。先用单机加Docker Compose跑通完整链路再逐步补上监控、限流、多模型网关这些能力这是性价比最高的路径。不要一上来就照搬大厂的Kubernetes架构那是给几十台GPU服务器准备的东西。对绝大多数场景来说先把一个vLLM实例稳定跑起来再接一个网关再学会看指标你就已经超过90%的初学者了。上面这套配置文件如果你只是验证方案可以直接复制后把模型路径改一改。跑通了再根据业务需求做参数调优。祝你的开源模型早日稳定服务生产流量。
返回列表