本地多模型统一工作台:LiteLLM 网关两行配置搞定 DeepSeek、Qwen、GLM 路由
1. 为什么要把三个大模型塞进同一个工作台先说说我自己的情况。手头一台 4090 的机器24G 显存平时写代码、查资料、做点小工具DeepSeek、Qwen、GLM 这三个模型我都在用。DeepSeek 强在推理和代码Qwen 的中文理解和多模态能力很扎实GLM 在某些工具调用和结构化输出场景下响应特别干脆。问题是我一开始是三个终端窗口来回切每个模型一套启动脚本、一套端口、一套 API 格式用起来跟打地鼠一样。后来我琢磨着能不能搞一个统一的入口把这三个模型都挂上去前端只认一个地址后端根据请求自动路由到对应的模型。折腾了一个周末最后发现核心改动其实就两行配置——一行是模型注册表一行是路由规则。剩下的都是环境准备和参数调优的体力活。这篇文章就是把我整个搭建过程拆开来讲。从为什么要做这件事、选什么方案、怎么配、踩了哪些坑到最终跑通后的实际体验全部摊开说。如果你手头也有多个模型想统一管理或者单纯想搞一个自己的 AI 工作台这篇应该能帮你省掉不少试错时间。注意本文涉及的所有模型部署和调用均基于本地或自有服务器的合规使用场景不涉及任何第三方服务的非授权接入。2. 整体方案设计与选型思路2.1 为什么不用现成的聚合平台市面上确实有一些模型聚合平台注册就能用但我不太想走这条路。原因有三个第一数据要经过第三方我平时处理的一些代码和文档不想往外传第二免费额度有限用起来束手束脚第三也是最重要的我想搞清楚底层到底是怎么跑的而不是黑盒调用。自己搭的好处是模型权重在自己手里推理过程可控API 格式自己定想加什么模型就加什么模型。坏处也明显——环境配置、显存管理、并发处理全得自己来。2.2 核心架构一个网关 三个推理后端我最终的架构是这样的推理层三个模型各自独立跑在自己的推理框架上DeepSeek 用 vLLM 部署Qwen 用 vLLM 或者 Ollama 都行GLM 我用的是官方提供的推理接口封装。每个模型监听不同的本地端口。网关层一个轻量的 API 网关对外暴露统一的 OpenAI 兼容接口。网关内部维护一张模型映射表收到请求后根据model字段转发到对应的后端端口。前端层任何支持自定义 API 地址的客户端都能接比如 VS Code 插件、Chatbox、Open WebUI 等。这个架构的关键在于网关层。它不需要很复杂核心功能就两个请求转发和模型路由。我试过用 Nginx 做反向代理也试过用 FastAPI 自己写一个简单的路由服务最后选了一个折中方案——用 LiteLLM 做代理层因为它原生支持多模型路由而且配置极其简单。2.3 那两行配置到底改了什么标题里说的“只改了两行配置”具体是指 LiteLLM 的配置文件里的两个地方第一行是模型列表的注册。在config.yaml的model_list下面把三个模型的名称、后端地址、API Key本地部署随便填一个都列进去。这一行决定了网关知道有哪些模型可用。第二行是路由策略。在router_settings里指定routing_strategy我选的是simple-shuffle意思是根据请求里的模型名称直接转发不做负载均衡。如果你想让同一个模型名对应多个后端实例可以改成least-busy或者latency-based-routing。就这两处。剩下的都是环境变量和启动参数的事。3. 环境准备与模型部署实操3.1 硬件与基础环境确认我的机器配置是Intel i9-13900K64G DDR5 内存RTX 4090 24G 显存2TB NVMe 固态。操作系统是 Ubuntu 22.04CUDA 版本 12.1Python 3.10。这里有个坑要先说三个模型如果同时加载到显存里24G 是绝对不够的。DeepSeek 的 7B 量化版本大概占 6-8GQwen 的 7B 量化版本差不多GLM 的 6B 版本也要 5-6G。三个加起来接近 20G再加上推理框架本身的开销和 KV Cache很容易爆显存。我的解决方案是不同时加载。用的时候按需启动或者用 CPU 卸载部分层。但这样切换很麻烦所以后来我改成了一种更实用的方式——DeepSeek 和 Qwen 常驻GLM 按需启动。因为前两个我用得最频繁GLM 主要在处理特定格式的任务时才用。提示如果你显存更小比如 12G 或 16G建议只常驻一个模型其他模型用 Ollama 的按需加载模式或者直接走 CPU 推理速度会慢很多但能用。3.2 DeepSeek 的 vLLM 部署DeepSeek 我选的是 7B 的指令微调版本用 vLLM 部署。vLLM 的好处是吞吐量高支持 PagedAttention显存利用率比 HuggingFace 的默认推理好很多。安装 vLLM 的命令如下pip install vllm启动命令python -m vllm.entrypoints.openai.api_server \ --model /path/to/deepseek-model \ --served-model-name deepseek-7b \ --port 8001 \ --max-model-len 8192 \ --gpu-memory-utilization 0.45 \ --dtype auto这里有几个参数需要解释。--max-model-len控制上下文窗口大小我设成 8192因为再大显存扛不住。--gpu-memory-utilization设成 0.45意思是让 vLLM 最多用 45% 的显存给后面的 Qwen 留空间。--dtype auto让框架自动选择精度一般会选 float16。启动后DeepSeek 的 OpenAI 兼容接口就在http://localhost:8001/v1上了。你可以用 curl 测试一下curl http://localhost:8001/v1/models如果返回模型列表说明部署成功。3.3 Qwen 的部署与参数调整Qwen 我用的是 7B 的 chat 版本同样用 vLLM 部署端口换成 8002。启动命令和 DeepSeek 类似但有几个参数不一样python -m vllm.entrypoints.openai.api_server \ --model /path/to/qwen-model \ --served-model-name qwen-7b \ --port 8002 \ --max-model-len 16384 \ --gpu-memory-utilization 0.40 \ --dtype auto \ --trust-remote-codeQwen 的上下文窗口我设成了 16384因为它的长文本处理能力确实不错而且我经常用它来读长文档。--trust-remote-code是因为 Qwen 的模型定义里有一些自定义代码不加这个参数会报错。这里有个细节Qwen 的 tokenizer 对中文的处理和 DeepSeek 不太一样。如果你发现同样的中文输入Qwen 的 token 数明显比 DeepSeek 多那是正常的因为两者的词表不同。做成本估算的时候要注意这一点。3.4 GLM 的接入方式GLM 的情况稍微特殊一点。我用的不是完整的本地部署而是官方提供的推理 SDK 封装成本地服务。原因是我手头的 GLM 版本对显存的要求比较刁钻直接上 vLLM 会和其他模型抢资源。我的做法是用 FastAPI 写了一个薄薄的包装层把 GLM 的推理接口转成 OpenAI 兼容格式监听 8003 端口。核心代码大概长这样from fastapi import FastAPI from pydantic import BaseModel import uvicorn app FastAPI() class ChatRequest(BaseModel): model: str messages: list temperature: float 0.7 app.post(/v1/chat/completions) async def chat(req: ChatRequest): # 调用 GLM 的推理接口 result glm_inference(req.messages, req.temperature) return { choices: [{message: {role: assistant, content: result}}] } if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8003)这个包装层很薄但足够用。关键是它把 GLM 的输出格式统一成了 OpenAI 的格式这样网关层就不需要为 GLM 做特殊处理。4. 网关配置那两行核心改动4.1 LiteLLM 的安装与基础配置LiteLLM 是一个开源的 LLM 代理工具支持 100 多个模型的统一接口。安装很简单pip install litellm[proxy]安装完成后创建一个配置文件config.yaml。这个文件就是整个工作台的核心。4.2 第一行改动模型注册表在config.yaml里model_list部分就是第一行核心改动所在model_list: - model_name: deepseek litellm_params: model: openai/deepseek-7b api_base: http://localhost:8001/v1 api_key: sk-local - model_name: qwen litellm_params: model: openai/qwen-7b api_base: http://localhost:8002/v1 api_key: sk-local - model_name: glm litellm_params: model: openai/glm-6b api_base: http://localhost:8003/v1 api_key: sk-local这段配置的意思是对外暴露三个模型名称——deepseek、qwen、glm。当客户端请求modeldeepseek时LiteLLM 会把请求转发到http://localhost:8001/v1以此类推。api_key填sk-local是因为本地部署的 vLLM 默认不校验 Key但 LiteLLM 要求这个字段不能为空所以随便填一个就行。4.3 第二行改动路由策略router_settings部分是第二行核心改动router_settings: routing_strategy: simple-shuffle num_retries: 2 timeout: 300routing_strategy我选的是simple-shuffle。这个策略的逻辑是根据请求里的model字段直接找到对应的后端不做额外的负载均衡。如果你有多个同名的后端实例它会随机选一个。num_retries: 2表示如果某个后端请求失败自动重试两次。timeout: 300是超时时间设成 300 秒是因为有些长文本推理确实需要这么久。4.4 启动网关与验证配置文件写好后启动 LiteLLMlitellm --config config.yaml --port 4000网关启动后对外暴露的地址是http://localhost:4000。你可以用 curl 测试curl http://localhost:4000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: deepseek, messages: [{role: user, content: 你好}] }如果返回正常的对话结果说明网关配置成功。把model字段换成qwen或glm就能调用对应的模型。5. 前端接入与日常使用技巧5.1 VS Code 插件的配置我平时写代码用 VS Code所以第一个接入的就是 VS Code 的 AI 插件。大部分插件都支持自定义 API 地址以 Continue 为例在config.json里这样配{ models: [ { title: DeepSeek, provider: openai, model: deepseek, apiBase: http://localhost:4000/v1, apiKey: sk-local }, { title: Qwen, provider: openai, model: qwen, apiBase: http://localhost:4000/v1, apiKey: sk-local } ] }这样在插件里就能随时切换模型。写代码的时候用 DeepSeek读文档的时候切 Qwen需要结构化输出的时候切 GLM。5.2 Chatbox 与 Open WebUI 的接入Chatbox 的配置更简单在设置里选择“自定义 OpenAI API”地址填http://localhost:4000/v1Key 填sk-local然后在模型列表里手动输入deepseek、qwen、glm三个名称就行。Open WebUI 稍微麻烦一点需要在管理面板里添加连接地址同样是http://localhost:4000/v1。但 Open WebUI 有个好处它支持模型分组和预设提示词你可以给每个模型配不同的系统提示词用起来更顺手。5.3 日常使用中的模型切换策略用了一段时间后我总结出了一套切换策略代码生成和调试优先用 DeepSeek它的代码补全和错误定位能力最强。中文长文档理解和总结用 Qwen它的中文 tokenizer 效率更高同样的文档消耗的 token 更少。结构化输出和工具调用用 GLM它的 JSON 模式输出特别稳定很少出现格式错误。通用对话和头脑风暴随便哪个都行我一般用 Qwen因为响应速度最快。这套策略不是固定的你可以根据自己的实际体验调整。关键是先把三个模型都跑通然后在使用中慢慢找到各自的甜点区。6. 常见问题与排查实录6.1 显存不足导致模型加载失败这是最常见的问题。症状是 vLLM 启动时报CUDA out of memory或者模型加载到一半就崩了。排查思路先用nvidia-smi看当前显存占用。如果已经有其他模型在跑先算一下剩余显存够不够。DeepSeek 7B 的 float16 权重大概占 14G量化到 int8 大概 7Gint4 大概 4G。加上 KV Cache 和框架开销int8 版本至少需要 10G 可用显存。解决方法降低--gpu-memory-utilization或者换用量化版本或者把部分层卸载到 CPU。vLLM 支持--cpu-offload-gb参数可以把指定大小的显存压力转移到内存。6.2 网关转发超时症状是客户端请求很久没响应最后报 timeout。可能的原因有三个后端模型推理太慢、网关超时设置太短、网络问题。排查步骤先用 curl 直接请求后端端口看响应时间。如果后端本身就慢那是模型或硬件的问题。如果后端响应正常但网关超时就调大router_settings里的timeout值。我一开始设的 60 秒后来发现处理长文档时经常超改成 300 秒后就再没出过问题。6.3 模型名称不匹配症状是网关返回model not found错误。这通常是因为客户端请求的model字段和config.yaml里注册的model_name不一致。排查方法检查客户端配置里的模型名称确保和model_list里的model_name完全一致。注意大小写敏感DeepSeek和deepseek是不同的。6.4 中文乱码或输出异常这个问题比较隐蔽。有时候模型返回的内容里夹杂着乱码或者中文标点变成了英文标点。原因通常是 tokenizer 配置不对或者推理框架的编码设置有问题。解决方法检查 vLLM 启动时是否加载了正确的 tokenizer。对于 Qwen一定要加--trust-remote-code。对于 DeepSeek确认模型目录下的tokenizer_config.json里的chat_template是否正确。6.5 常见问题速查表问题现象可能原因解决方法CUDA out of memory显存不足降低 gpu-memory-utilization用量化版本请求超时网关 timeout 太短调大 router_settings.timeoutmodel not found模型名称不匹配检查客户端和配置文件的 model_name中文乱码tokenizer 配置错误检查 tokenizer_config.json加 trust-remote-code响应速度慢模型太大或并发太高换小模型或限制并发数网关启动失败端口被占用换端口或 kill 占用进程7. 性能调优与进阶玩法7.1 并发请求的处理LiteLLM 默认是异步处理的但后端 vLLM 的并发能力有限。如果你同时发多个请求可能会排队。vLLM 有一个--max-num-seqs参数控制同时处理的最大请求数。默认是 256对于 24G 显存的机器来说太大了我一般设成 8 到 16。另外LiteLLM 的router_settings里可以加allowed_fails和cooldown_time当某个后端连续失败时自动冷却避免一直往坏掉的后端发请求。7.2 用缓存加速重复请求如果你经常问同样的问题可以开启 LiteLLM 的缓存功能。在config.yaml里加litellm_settings: cache: true cache_params: type: local ttl: 3600这样相同的请求在 1 小时内会直接返回缓存结果不走模型推理。对于调试和测试场景特别有用。7.3 模型别名与版本管理如果你同时部署了同一个模型的多个版本可以用别名来区分。比如- model_name: deepseek-v2 litellm_params: model: openai/deepseek-7b-v2 api_base: http://localhost:8004/v1这样客户端可以明确指定用哪个版本方便做 A/B 测试。7.4 监控与日志LiteLLM 支持把请求日志写到文件或数据库。我在config.yaml里加了litellm_settings: set_verbose: true json_logs: true这样每次请求的模型、耗时、token 数都会记录在日志里。定期看一下日志能发现很多性能问题。比如某个模型的平均响应时间突然变长可能是显存碎片化了需要重启。8. 我踩过的坑与实操心得第一个坑是 vLLM 的版本兼容性。我一开始用的 vLLM 0.4.x部署 Qwen 时报了一堆 tokenizer 相关的错误。后来升级到 0.5.x 才解决。所以如果你遇到奇怪的报错先检查版本。第二个坑是端口冲突。8001、8002、8003 这三个端口我用了没多久就发现和别的服务撞了。后来改成了 18001、18002、18003世界清净了。建议一开始就用不常用的高位端口。第三个坑是模型切换时的显存碎片。vLLM 在加载和卸载模型时显存不会完全释放跑久了会出现“明明显存够但就是加载不了”的情况。我的解决办法是写了一个定时重启脚本每天凌晨自动重启所有推理服务。第四个坑是 LiteLLM 的配置文件格式。YAML 对缩进极其敏感多一个空格少一个空格都会导致解析失败。我建议用 VS Code 的 YAML 插件它会实时检查格式。最后分享一个实用技巧如果你不确定某个模型是否真的在正常工作可以用一个简单的测试脚本定期跑一下import requests models [deepseek, qwen, glm] for m in models: resp requests.post( http://localhost:4000/v1/chat/completions, json{model: m, messages: [{role: user, content: 11?}]} ) print(m, resp.json()[choices][0][message][content])这个脚本跑一遍三个模型的状态就一目了然了。我把它设成了每小时执行一次有问题能第一时间发现。这套工作台我用了大半年稳定性还不错。核心就是那两行配置剩下的都是围绕它做的环境准备和调优。如果你也想搞一个自己的多模型工作台建议先从两个模型开始跑通了再加第三个。一步到位容易出问题而且排查起来很麻烦。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →