☰
开源AI中台部署实战:vLLM+Dify+网关与显存规划
2026/9/30 5:54:16 网站建设 项目流程

在离线内网里把一套能对话、能检索、能接业务系统的 AI 能力跑起来,这件事我从零到一做过几轮,踩的坑比想象中多得多。开源 AI 中台部署运行这个题目,听起来像是"装几个容器就完事",实际上它横跨了驱动、容器运行时、推理引擎、编排平台、向量检索、网关、监控七个层面,每一层都有自己的脾气。有硬件只有一张 4090 的个人开发者,也有预算充足、机房里摆着八卡整机的团队,两类人遇到的问题完全不一样,但底层的判断逻辑是共通的。

我写这篇东西的目标很明确:把"开源 AI 中台"从一句口号翻译成一张能执行的清单——它由哪些组件拼成、为什么要这么分层、显存到底怎么算、配置文件里哪几个参数改错就会翻车、报错信息背后真正的含义是什么。适合正在做技术选型的架构同学,也适合第一次接触大模型部署、想在家用机器上跑通一套完整链路的工程师。代码我会尽量给全,至于硬件,你按自己的卡对号入座就行。

1. 先把"AI 中台"这件事说清楚,别一上来就 docker run

1.1 中台和"一个模型服务"的本质区别

很多人第一次做部署,脑子里想的是"我起一个模型接口,业务方调它就完了"。这个做法在只有一个业务、一个模型、一个团队的时候完全够用,但只要业务方超过三个,问题立刻暴露:A 团队要 GPT 风格的接口,B 团队要向量化接口,C 团队想上传自己的文档做问答;模型从 7B 换成 32B,所有调用方都得改代码;某天有人拿接口去跑批量脚本,把显卡占满,其他业务全部超时。

AI 中台要解决的正是这些"多对多"的问题。它在模型和业务之间插了一层,把模型接入、提示词编排、知识库检索、密钥与配额、调用日志这些通用能力收敛成公共服务,业务方只面对一套统一的 OpenAI 兼容协议。所以判断一套东西算不算中台,我的标准很朴素:把底层推理引擎从 vLLM 换成 Ollama,业务代码一行不用改,那它就是中台;如果换个模型就得改调用方,那它只是模型服务。

这里有个观念上的坎:中台不是"更高级的模型服务",而是"模型服务 + 治理能力"。治理能力包括限流、计费、灰度、审计,这些词听起来像大厂专有,实际上一套开源的网关加编排平台就能覆盖八成场景。想清楚这一点,后面的选型才不会跑偏——你不是在挑一个最好用的推理框架,而是组装一条流水线。

1.2 开源 AI 中台的分层与组件地图

我把这套东西拆成六层,从下往上依次是硬件层、运行时层、推理层、编排层、网关层、可观测层。这个分层不是为了画架构图好看,而是为了划定故障域:推理层崩了不影响编排层的元数据,网关重启不丢知识库索引。实际运维里能救命的就是这一点。

层次职责常见开源选择
硬件/系统层GPU、驱动、内核、存储无(基础设施)
容器运行时层隔离、GPU 透传Docker、containerd、NVIDIA Container Toolkit
推理层加载模型、批量调度、Token 生成vLLM、SGLang、Ollama、llama.cpp
编排层应用、提示词、知识库、工作流Dify、RAGFlow、FastGPT
网关层密钥分发、限流、多模型路由One-API/New-API、Higress
可观测层指标、日志、链路、评测Prometheus、Grafana、Loki、Langfuse

要特别注意一个常见误区:把编排层和推理层混在一台机器上共用一个 GPU。Dify 这类平台本身是 CPU 密集型的 Web 服务,它不该抢显卡;而 vLLM 会尽量占满显存。两者放同一台机器没问题,但要给推理容器留足显存,别让编排层的向量化模型(Embedding)和重排模型(Rerank)把显存吃干净——这两个小模型加起来通常要 2 到 4 GB,很多人算容量时忘了它们,结果上线第二天就开始 OOM。

2. 部署前的容量规划与选型,这一步省不得

2.1 显存到底怎么算,一张表说清

部署翻车最常见的原因不是配置写错,是显存从一开始就不够。模型体积的估算其实很简单:

权重显存 ≈ 参数量 × 每参数字节数 FP16/BF16 按 2 字节算,INT8 按 1 字节算,INT4 按 0.5 字节算,再乘 1.1 的量化元数据系数。

但真正吃掉显存的往往不是权重,是 KV Cache。它的公式是:

KV Cache = 2 × 层数 × KV 头数 × head_dim × 序列长度 × 并发数 × 数据类型字节数

以 Qwen2.5-7B 这类 GQA 结构为例,28 层、4 个 KV 头、head_dim 128,单条 8192 长度的序列在 FP16 下占用约 448 MB,十条并发同长度就是 4.4 GB。这个数字很有指导意义:上下文开得越长、并发越高,KV Cache 增长是线性的,跟参数量无关,所以"模型不大但一并发就崩"的情况非常常见。

模型规模量化权重占用建议单卡典型用途
7BINT4约 4.5 GB12–16 GB单机验证、个人开发
7BFP16约 15 GB24 GB小团队生产
14BINT4约 9 GB16–24 GB部门级应用
32BINT4约 19 GB24 GB(短上下文)/ 双卡效果优先场景
70BINT4约 40 GB双卡 48 GB 起核心业务

我的经验做法是:先按"权重 + 最大 KV Cache + 2 GB 框架开销 + 3 GB 其他模型"估算,如果结果超过显存的 90%,就把max_model_len降下来,而不是硬撑。把上下文从 32768 降到 8192,KV Cache 直接砍掉四分之三,用户体验的损失远小于频繁超时的损失。

2.2 推理引擎怎么选,三种形态各有各的战场

这一层的选择决定了整套中台的吞吐上限,我用下来大致是这么分的:

Ollama适合第一次跑通和单机开发。它的模型管理体验极好,一条命令拉模型、自动量化、自动卸载,缺点是调度策略偏保守,高并发下吞吐不如 vLLM,而且它的模型格式(GGUF 为主)在长上下文场景表现一般。用它做原型验证,一周内能出东西。

vLLM是当前生产环境的主流。核心优势是 PagedAttention 和连续批处理,同样硬件下并发吞吐能比朴素实现高一个数量级。它的 OpenAI 兼容接口开箱即用,--served-model-name这个参数一定要设,否则调用方要按你本地路径名去填模型名,非常别扭。prefix caching 在知识库问答这类"长系统提示词 + 短问题"的场景里提升特别明显,建议默认打开。

SGLang在多轮对话、Agent 场景下优势更大,因为它对前缀共享的复用更激进。如果你的业务是同一个系统提示词被成千上万次调用,值得试一试。

至于 llama.cpp 这类纯 CPU 方案,我的看法是:能跑,但别指望它扛生产。它的价值在于边缘设备和无 GPU 的验证环境,吞吐量用"每秒几个 Token"来衡量比较合适。

2.3 网络、存储与目录规划,先画好再动手

这部分最容易被忽略,但返工成本最高。我固定会做三件事:

第一,规划端口表并写进文档。容器化部署最容易出问题的就是端口冲突,尤其是默认 80、3000、8000 这几个。我的习惯是把 80 留给统一入口,编排平台 Web 走 3000,API 走 5001,推理服务从 8000 开始按实例递增,数据库和缓存不对宿主机暴露,只在内部网络里通信。

第二,规划目录并挂载到数据盘。模型文件动辄几十 GB,Docker 默认的数据目录在系统盘,很容易在下载第三个模型时把/var/lib/docker撑爆。我的做法是把模型、应用数据、日志、备份四类目录统一放到/data下,容器通过 volume 挂载进去,同时把 Docker 的>{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }

3. 从零把一套开源 AI 中台跑起来

3.1 基础环境:驱动、容器运行时、加速库三件套

我以 Ubuntu 22.04 加 NVIDIA 显卡为例走一遍。第一步装驱动,用系统包管理装比手动跑安装脚本稳,内核升级后不容易失效:

sudo apt update sudo apt install -y nvidia-driver-550-server sudo reboot nvidia-smi

看到显卡型号和驱动版本就说明驱动没问题。这里有个坑要提醒:nvidia-smi报"couldn't communicate with the NVIDIA driver",九成是内核更新后 DKMS 模块没重建,重装驱动或者sudo dkms autoinstall就能修,不用急着重装系统。

第二步装容器和 GPU 透传能力:

sudo apt install -y docker.io sudo systemctl enable --now docker # 添加 NVIDIA 容器运行时仓库并安装 sudo apt install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker

然后编辑/etc/docker/daemon.json,把 NVIDIA 设为默认运行时,这样启动容器时不用每次写--runtime:

{ "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "nvidia-container-runtime", "runtimeArgs": [] } }, "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }

验证命令很关键,跑通说明整条链路都通了:

docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

注意:推理引擎镜像里的 CUDA 版本、宿主驱动版本、PyTorch 版本三者必须兼容。一般来说驱动版本决定了支持的 CUDA 上限,容器里装的 CUDA 运行时不能超过这个上限。装之前先nvidia-smi看右上角那个 "CUDA Version",它是天花板,照着选镜像最省事。

第三步是模型下载。国内环境下直接用镜像源会稳定很多,ModelScope 上的模型覆盖面已经很全:

pip install modelscope export MODELSCOPE_CACHE=/data/models modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir /data/models/qwen2.5-7b

下载大模型一定要设缓存目录到数据盘,默认路径在用户主目录下,很容易把系统盘塞满。下载中断是常态,用支持断点续传的工具,别用简单的 curl。

3.2 推理层落地:vLLM 服务怎么起

模型下好之后,起一个 vLLM 服务:

docker run -d --name vllm-qwen \ --gpus '"device=0"' \ --shm-size 16g \ -v /data/models:/models \ -p 8000:8000 \ vllm/vllm-openai:latest \ --model /models/qwen2.5-7b \ --served-model-name qwen2.5-7b-instruct \ --max-model-len 8192 \ --gpu-memory-utilization 0.90 \ --enable-prefix-caching \ --tensor-parallel-size 1

几个参数值得展开讲。--shm-size必须给够,共享内存太小会在加载模型时直接被杀掉,报错信息还特别含糊,通常只写个 "Killed",新手很容易以为是内存不够,其实是共享内存。--gpu-memory-utilization设 0.9 是让它把 90% 显存用于权重和 KV Cache 的预分配,剩下 10% 留给 CUDA 上下文和碎片,设成 0.98 反而容易启动失败。--tensor-parallel-size要和显卡数匹配,单卡写 1,双卡写 2,写错了会直接报错退出。

启动后用两条命令验证:

curl http://127.0.0.1:8000/v1/models curl http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"qwen2.5-7b-instruct","messages":[{"role":"user","content":"用一句话介绍你自己"}]}'

提示:--served-model-name设的名字,就是调用方要填的模型名。如果你后面接了网关或者编排平台,这个名字要跟平台里配置的模型名完全一致,大小写和连字符都不能差,这是接入失败最常见的原因之一。

3.3 编排层落地:Dify 的部署与关键配置

编排平台我以 Dify 为例,它的部署形态比较典型,理解了它其他同类平台也大同小异。标准流程是拉代码、改环境变量、起容器:

git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env

.env里有几个必须改的项,我一个个说。SECRET_KEY一定要改成一个随机长字符串,它用于加密数据库里的敏感字段,用默认值等于把密钥公开。数据库和 Redis 的密码同样要改,如果这几个服务不对宿主机暴露端口,风险相对可控,但密码还是别偷懒。EXPOSE_NGINX_PORT决定 Web 入口端口,80 被占了就换成别的。向量库默认用的是内置的 Weaviate,数据量小的场景够用,但要换成 Milvus 或者 pgvector 也可以,改VECTOR_STORE变量并启用对应的 compose 片段即可。

docker compose up -d docker compose ps

起来之后访问 Web 端口,第一次会要求设置管理员账号。这时候别急着建应用,先把模型接进去:在模型供应商里选 OpenAI 兼容接口,Base URL填http://<推理服务IP>:8000/v1,模型名填qwen2.5-7b-instruct,密钥随便填一个非空字符串(vLLM 默认不校验)。填完点保存,如果能列出模型,说明通了。

如果平台和推理服务不在同一台机器,或者跨了 Docker 网络,容器的localhost指向的是自己,不是宿主机。这种时候要么用宿主机的内网 IP,要么用宿主机在 Docker 网桥里的地址(通常是 172.17.0.1),要么干脆把两个服务放进同一个自定义网络。这个坑我见过太多次了。

3.4 网关、知识库与可观测性

网关层的作用是统一密钥和路由。团队里五个人各自拿一把推理服务的密钥,等于没有管理。加一个网关,所有调用方拿到的是网关签发的令牌,模型切换、限流、额度统计都在网关做。配置无非是建渠道、填推理服务的地址和模型名、设限额,然后在业务侧把 Base URL 换成网关地址就行。

知识库这块,检索质量取决于三个环节:切分、向量化、重排。切分默认按固定长度切,中文场景建议按标点或段落切,长度 500 到 800 字比较均衡,太短丢上下文,太长检索精度下降。向量化模型选中文效果好的即可,注意它和推理大模型是两码事,嵌入选型不用追求参数规模。重排是提升命中率性价比最高的一步,加一个轻量重排模型,Top-3 命中率通常能明显改善。索引写入走的是异步队列,大批量导入时盯着队列积压情况,积压太多就调大 worker 数量。

可观测层建议一开始就搭,别等出问题再补。vLLM 自带/metrics端点,暴露了排队请求数、首 Token 延迟、生成吞吐等指标;Prometheus 定时抓取,Grafana 做看板。我重点关注三个指标:请求排队时长(反映容量是否够)、TTFT 首 Token 延迟(反映用户感知)、GPU 显存占用曲线(反映是否有泄漏)。社区有现成的 vLLM 面板可以直接导入,省掉自己画图的时间。日志用 Loki 或者简单的日志收集容器归集,重点看编排平台的错误日志和推理服务的异常退出。

3.5 端到端验证:把链路串一遍

部署完成的判断标准不是"容器都起来了",而是"一条完整请求走通了"。我的验证清单是这样的:

  1. 直接调推理服务/v1/chat/completions,能返回内容;
  2. 通过网关调同一个接口,返回内容一致,额度统计有变化;
  3. 在编排平台建一个最简单的对话应用,选好模型,能正常回答;
  4. 建一个知识库,上传一份测试文档,等索引完成,问一个只有这份文档里才有的问题,答案能引用到;
  5. 用 10 个并发压一轮,观察首 Token 延迟和错误率;
  6. 重启一次宿主机的 Docker 服务,确认所有容器能自动恢复。

第 6 条特别重要——很多人部署完就忘了加自启策略。容器启动命令里要带--restart unless-stopped,compose 文件里写restart: always,不然机器重启一次全套服务就没了。

4. 常见问题与排查技巧实录

4.1 启动失败类问题速查

现象大概率原因处理方式
容器启动后立即退出,无日志共享内存不足加--shm-size 16g
报 unknown runtime nvidia未配置默认运行时改 daemon.json 并重启 Docker
显存 OOM 但模型明明很小上下文过长或并发过高降max_model_len,降并发
端口被占用与已有服务冲突换端口或排查占用进程
数据库连接被拒绝依赖服务未就绪调整依赖顺序,加重试
接口返回 401密钥配置不一致核对网关与推理服务配置
模型列表为空Base URL 写成了 localhost改容器可达的地址
磁盘写满日志或模型缓存未限制加日志限制,迁移数据目录

4.2 性能类问题的排查思路

性能问题很少是单一原因,我一般按"显存 → 批处理 → IO → 网络"的顺序排查。

显存方面,如果gpu-memory-utilization设得很高但实际利用率上不去,说明请求量不够、批处理没攒起来,这不是配置问题而是负载问题。反过来,如果显存满了但吞吐很低,多半是 KV Cache 被长上下文占满,新请求只能排队。

批处理方面,vLLM 的连续批处理需要一定请求量才能体现价值。单用户单请求的场景下,它的优势发挥不出来,这时候延迟主要由模型本身决定。想提升单请求速度,可以试试开投机解码或者换更小的模型。

IO 方面,这一点很多人忽略。模型加载时如果从网络存储读,速度可能只有本地 NVMe 的十分之一,加载一个 15 GB 的模型要十几分钟甚至更久。另外,知识库索引写入频繁时磁盘 IO 会飙高,如果索引文件和模型文件在同一块盘上,会互相干扰。我的做法是把模型放一块 NVMe,索引和数据放另一块。

网络方面,跨节点调用推理服务时,如果中间走了公网或者跨了机房,首 Token 延迟会明显增加。同一内网内调用通常问题不大,但要确认 MTU 设置一致,否则大响应体可能出现分片异常。

4.3 几条不太好搜到的实操经验

第一,时间同步一定要配。我遇到过一次所有接口突然返回鉴权失败,排查了两个小时,最后发现是某台机器的时间漂移了几分钟,导致令牌校验失败。装个时间同步服务,sudo apt install chrony就完事,能省掉一次深夜加班。

第二,Ollama 的默认卸载策略要改。它默认 5 分钟不活动就把模型从显存卸载,生产环境下会导致请求忽快忽慢。把OLLAMA_KEEP_ALIVE设成-1或者一个很大的值,代价是显存一直占着。这个参数在开发环境很友好,在生产环境很坑。

第三,别把所有服务塞进一个 compose 文件。我在早期项目里这么干过,结果一次数据库升级把所有服务连带重启,业务停了半小时。后来改成按层拆分,推理层、编排层、监控层各自独立,升级互相不影响。

第四,模型名和路径一定要分离。用本地路径当模型名,一旦目录调整,所有调用方都得跟着改。用--served-model-name固定一个语义化的名字,路径随便换,调用方无感。

第五,监控指标只留十个以内。我一开始接了上百个指标,看板密密麻麻,出问题时反而找不到重点。后来精简到排队数、首 Token 延迟、吞吐、显存、错误率这几个,一眼就能判断健康状态。

5. 上线之后要处理的几件事

5.1 权限、配额与成本可见性

系统跑起来只是开始,真正决定它能不能长期活下去的是治理。我的做法是给每个调用方签发独立的密钥,在网关层设置日额度和并发上限。额度不是为了防止谁多用,而是为了让成本可见——月底能说清楚"哪个业务用了多少 Token、折算多少钱",这件事在向上汇报时非常有用。

配额设置要留缓冲。如果某个业务正常用量是每天 100 万 Token,额度设 120 万比较合适,设成刚好够用会导致偶发超限、业务中断。同时要监控超限次数,频繁超限说明额度需要调整,而不是业务方用得不对。

另外建议开启调用日志,但要设保留期限。全量日志存三个月没问题,存一年就是一笔不小的存储开销。敏感业务可以在日志层面做脱敏,提示词里的用户信息不建议原样落盘。

5.2 容量扩展与资源回收

扩容这件事没有想象中复杂。推理层是无状态的,加一个新实例、在网关里配成同一个模型的第二个渠道,就完成了横向扩展。前提是会话不要在实例上做本地绑定,否则用户第二次请求打到另一个实例会丢上下文。如果需要保持会话一致,用一致性哈希或粘性会话。

资源回收则是个长期活。我的清单是三件事:定期清理没在用的模型权重(一个 32B 模型占 20 GB 很常见);定期检查容器镜像,老版本镜像越积越多;定期审计密钥,把已经没人用的令牌删掉。这些事听起来琐碎,但半年不清理,磁盘告警一定会来。

5.3 版本升级与回滚路径

升级这套系统最怕的是"升完发现不兼容,想退回又退不回去"。我的习惯是升级前做三件事:备份编排平台的数据库和配置文件,记录当前所有镜像的完整版本标签(不要用 latest),确认新版本对环境变量的改动。

升级顺序建议从下往上:先升推理层,验证接口没问题;再升网关,验证路由和额度正常;最后升编排层,因为它依赖前两层的接口。每一步之间留出观察时间,看监控有没有异常。

回滚路径要提前准备好。用固定版本标签而不是 latest,回滚就是改回标签重启,十分钟内能完成。如果用了 latest,回滚时可能已经找不到之前那个镜像了。这一点在测试环境无所谓,在生产环境是硬要求。

我个人在实际操作中的体会是:这套系统最容易出问题的永远不是技术难点,而是那些"看起来不重要"的细节——共享内存、时间同步、日志限制、模型名一致性。把这几处基础工作做扎实,剩下的就是按部就班地接组件,一两天能出一套能用的东西;反过来,如果跳过容量规划和目录规划直接开干,后面返工的时间往往是部署本身的好几倍。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询