
在离线内网里把一套能对话、能检索、能接业务系统的 AI 能力跑起来这件事我从零到一做过几轮踩的坑比想象中多得多。开源 AI 中台部署运行这个题目听起来像是装几个容器就完事实际上它横跨了驱动、容器运行时、推理引擎、编排平台、向量检索、网关、监控七个层面每一层都有自己的脾气。有硬件只有一张 4090 的个人开发者也有预算充足、机房里摆着八卡整机的团队两类人遇到的问题完全不一样但底层的判断逻辑是共通的。我写这篇东西的目标很明确把开源 AI 中台从一句口号翻译成一张能执行的清单——它由哪些组件拼成、为什么要这么分层、显存到底怎么算、配置文件里哪几个参数改错就会翻车、报错信息背后真正的含义是什么。适合正在做技术选型的架构同学也适合第一次接触大模型部署、想在家用机器上跑通一套完整链路的工程师。代码我会尽量给全至于硬件你按自己的卡对号入座就行。1. 先把AI 中台这件事说清楚别一上来就 docker run1.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 降到 8192KV 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 走 3000API 走 5001推理服务从 8000 开始按实例递增数据库和缓存不对宿主机暴露只在内部网络里通信。第二规划目录并挂载到数据盘。模型文件动辄几十 GBDocker 默认的数据目录在系统盘很容易在下载第三个模型时把/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报couldnt 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 --runtimedocker 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 device0 \ --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 端到端验证把链路串一遍部署完成的判断标准不是容器都起来了而是一条完整请求走通了。我的验证清单是这样的直接调推理服务/v1/chat/completions能返回内容通过网关调同一个接口返回内容一致额度统计有变化在编排平台建一个最简单的对话应用选好模型能正常回答建一个知识库上传一份测试文档等索引完成问一个只有这份文档里才有的问题答案能引用到用 10 个并发压一轮观察首 Token 延迟和错误率重启一次宿主机的 Docker 服务确认所有容器能自动恢复。第 6 条特别重要——很多人部署完就忘了加自启策略。容器启动命令里要带--restart unless-stoppedcompose 文件里写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回滚时可能已经找不到之前那个镜像了。这一点在测试环境无所谓在生产环境是硬要求。我个人在实际操作中的体会是这套系统最容易出问题的永远不是技术难点而是那些看起来不重要的细节——共享内存、时间同步、日志限制、模型名一致性。把这几处基础工作做扎实剩下的就是按部就班地接组件一两天能出一套能用的东西反过来如果跳过容量规划和目录规划直接开干后面返工的时间往往是部署本身的好几倍。