共计 3191 个字符,预计需要花费 8 分钟才能阅读完成。
不少折腾家庭自建服务器或小型团队私有云的朋友,在 NAS 里塞入 RTX 3090 或者 4090 后,第一反应都是拉一个 Ollama 镜像,再挂个 Web 界面跑本地大模型。但当你真把它接入团队日常工作流、多标签页并发生成长文档,或者挂上自动化 Agent 做深度联网检索时,问题就接踵而至了:首字延迟飙升、上下文一长直接 OOM 爆显存挂掉、并发请求排队卡死。Ollama 开发体验极佳,但底层基于 llama.cpp 针对消费级单会话的默认调度,在多任务并发吞吐和长上下文管理上,远不如针对高并发场景优化的 vLLM。
上个月我把工作室存储与算力一体化 NAS(TrueNAS SCALE 底层,宿主机 Debian 12 内核,单卡 RTX 3090 24G + 64G DDR4 + ZFS NVMe 阵列)的核心推理链路彻底重构:vLLM 推理引擎 + Open WebUI 交互界面 + SearXNG 私有搜索引擎,跑 Qwen2.5-14B-Instruct-AWQ。整套配置连续压测了一个多月,并发吞吐提升了将近 3 倍,显存利用率极其稳健。今天把整套落地流程、关键配置参数以及我踩过的几个致命坑完整盘一遍。
一、架构设计:为什么舍弃默认方案?
在 NAS 这种“算力 + 存储”共存的环境下,必须在显存占用、内存带宽和并发响应之间做严格平衡:
- vLLM 做底层推理底座:PagedAttention 机制把显存碎片几乎压到了 0,且支持动态批处理(Continuous Batching)。多客户端并发请求时,它能根据显存块动态塞入计算,而不会像普通推理框架那样让线程硬排队。
- AWQ 4-bit 量化权重:相比原版 FP16,Qwen2.5-14B 在 AWQ 量化后显存占用直接从近 30GB 砍到 10GB 出头,给 KV Cache 预留出近 12GB 的充裕空间,足以支撑 32k 上下文的复杂多轮对话与文档召回。
- Open WebUI 与 SearXNG 内网闭环:Open WebUI 不仅原生兼容 OpenAI API 规范,还自带成熟的 RAG 模块与 Web Search 集成。搭配内网自建的 SearXNG,彻底杜绝数据外流,实现真正的本地隐私 Agent。
二、Docker Compose 全栈编排实战
在 NAS 上部署这一套,最忌讳东拼西凑几个孤立的容器。建议直接通过同一份 docker-compose.yml 编排,走独立的内部桥接网络,避免不必要的宿主机端口 NAT 损耗。
services:
# 1. 高性能 LLM 推理后端
vllm:
image: vllm/vllm-openai:latest
container_name: nas-vllm
runtime: nvidia
environment:
- HUGGING_FACE_HUB_TOKEN=your_hf_token_here
volumes:
- /mnt/storage/ai_models/cache:/root/.cache/huggingface
ports:
- "8000:8000"
ipc: host
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
command: >
--model Qwen/Qwen2.5-14B-Instruct-AWQ
--quantization awq
--dtype half
--gpu-memory-utilization 0.90
--max-model-len 16384
--enforce-eager
--served-model-name qwen2.5-14b
--port 8000
restart: unless-stopped
# 2. 本地私有元搜索引擎(供 Agent 联网使用)searxng:
image: searxng/searxng:latest
container_name: nas-searxng
volumes:
- ./searxng:/etc/searxng
environment:
- SEARXNG_BASE_URL=http://nas-searxng:8080/
restart: unless-stopped
# 3. Web 交互前端与 Agent 编排
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: nas-openwebui
volumes:
- ./open-webui-data:/app/backend/data
ports:
- "3000:8080"
environment:
- OPENAI_API_BASE_URL=http://vllm:8000/v1
- OPENAI_API_KEY=EMPTY
- ENABLE_RAG_WEB_SEARCH=True
- RAG_WEB_SEARCH_ENGINE=searxng
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=&format=json
restart: unless-stopped
三、三个硬核避坑细节(花了我两个通宵排查)
1. ipc: host 与共享内存崩溃
如果你在启动 vLLM 时发现容器频繁报 Bus error (core dumped) 或在长文本生成时直接无预警退出,90% 是因为 Docker 容器默认的/dev/shm(共享内存)只有 64MB。PyTorch 多进程张量传输需要大量共享内存,务必加上ipc: host,或者明确指定shm_size: 16g,直接使用宿主机的高速内存。
2. 显存参数 --gpu-memory-utilization 调优
很多人误以为这个参数设为 0.98 能压榨显存极限。但我在 24G 显存上实测,一旦拉到 0.95 以上,vLLM 在初始化 CUDA Graph 时就会由于瞬时显存申请失败直接抛出 CUDA OOM 错误。在 24G 显存单卡上,建议死守 0.88~0.90。给 CUDA Runtime 和底层系统预留至少 1.5G~2G 的呼吸空间,剩下的显存交给 PagedAttention 调度,才能保证 7 ×24 小时高负载不挂。
3. 为什么要加 --enforce-eager?
vLLM 默认会使用 CUDA Graph 来加速小 Batch Size 下的推理。但在 NAS 这种多合一服务器上,如果你后台偶尔还要跑 Plex/Jellyfin 转码,显存波动会导致 CUDA Graph 捕获失败,初始化极其缓慢(经常卡住 5 -10 分钟)。开启 --enforce-eager 虽然牺牲了约 5% 的极速吞吐,但能换来极高的启动速度、稳定性以及动态请求容忍度,非常适合自建生产环境。
四、实测吞吐表现与选型建议
在我的这台 Debian NAS 上,使用开源压测脚本进行并发模拟(输入提示词平均 500 tokens,输出目标 800 tokens):
- 单并发单任务响应:首字延迟(TTFT)约 180ms,生成速度约 42 tokens/s。打字机流式输出毫无肉眼可见的停顿感。
- 4 路并发混合请求:系统总吞吐达到 118 tokens/s。此时显存利用率稳定在 90%,没有出现任何一个请求超时的现象。相比之前 Ollama 排队响应模式,有效处理耗时缩短了近 60%。
- Agent 联网增强场景:当触发 SearXNG 检索 5 个外部网页并拼接进 Prompt 时(上下文暴涨至 8k tokens),vLLM 的 PagedAttention 在几百毫秒内完成预填充计算,依然保持了即时响应。
总结与结语
对于 NAS 技术玩家来说,把设备从单纯的“文件仓库”升级为“私有算力与知识中枢”是一件极具成就感的事。别再局限于开箱即用但性能受限的玩具方案,用 vLLM 打底构建容器内网闭环,不仅能彻底释放现代显卡的张量计算潜力,更能为你后续挂载私有知识库 RAG、搭建自动化工作流 Agent 提供真正生产级的稳定支撑。如果你手头也有一块空闲的大显存卡,不妨趁着周末把这套架构在 NAS 上跑起来。
===EOF===