☰
ChatGLM3-6B 部署实录:多卡并行与显存优化配置全流程(TaoToken 统一 Key 接入)
2026/10/2 6:09:28 网站建设 项目流程

1. ChatGLM3-6B 多卡部署踩坑实录:从单卡爆显存到双卡跑通

ChatGLM3-6B 是智谱 AI 开源的中英双语对话模型,6B 参数在 FP16 精度下光权重就要吃掉约 12GB 显存,加上 KV Cache 和推理中间激活值,单张 12GB 卡基本一启动就 OOM。它能做的事很实在:本地知识库问答、代码解释执行、Function Call 工具调用、长文档摘要,适合想在消费级显卡上跑私有对话服务的人。我这次的目标很明确——用两张卡把 ChatGLM3-6B 稳稳跑起来,同时把显存占用压到可量化、可复现的水平,并且通过 TaoToken 统一 Key 接入 API 通道,省去每个项目单独配 Key 的麻烦。

先说结论:双卡device_map="auto"自动切分后,GPU0 约 6.3GB、GPU1 约 7.1GB,总计约 13.4GB,比单卡硬扛 13GB+ 要稳得多。但这里有个坑——很多人以为装了accelerate就自动多卡,实际上device_map的取值和max_memory参数没配对,模型会全挤到一张卡上,另一张卡干看着。下面我把环境配置、多卡切分、显存验证、报错排查整条链路拆开讲,每一步都能直接复制。

环境这块我用 pyenv 隔离 Python 3.10,避免和系统里其他项目的依赖打架。模型权重从 HuggingFace 拉取,国内网络建议提前配好镜像或手动下载。整个流程分四段:环境准备 → 依赖安装 → 多卡配置 → 启动验证。每段我都会给出实际命令和预期输出,你照着敲就行。

需要提前说明的是,ChatGLM3-6B 的显存占用不是固定的,它跟你的max_length、batch_size、是否开启量化强相关。我实测下来,max_length=8192时 KV Cache 会额外吃 2-3GB,所以如果你显存紧张,优先调小这个值,而不是急着上量化。量化虽然省显存,但会损失一部分推理质量,尤其是代码生成任务上差异明显。

2. TaoToken 前置准备:统一 Key 与 API 通道配置

在正式部署之前,先把 TaoToken 的接入通道配好。为什么要先做这一步?因为 ChatGLM3-6B 本地部署只是推理侧,你还需要一个统一的 API 网关来管理多个模型的调用凭证。TaoToken 的作用就是给你一个统一的 Key,通过https://taotoken.net/api这个入口转发请求,不用在每个项目里硬编码不同的 Key。

具体操作分三步。第一步,去官网https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=注册账号,然后在控制台创建一个 API Key。第二步,拿到 Key 之后,在项目里通过环境变量注入,不要写死在代码里。第三步,配置 Base URL 为https://taotoken.net/api,这样你的请求就会走统一通道。

我试过把 Key 直接写在config.toml里,结果 git 提交时差点泄露,后来改成环境变量 +.env文件才安心。下面是一个标准的config.toml骨架,你可以直接复制到项目根目录:

# config.toml - TaoToken 接入配置骨架 [taotoken] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" # 从环境变量读取,不硬编码 timeout = 60 max_retries = 3 [model] name = "chatglm3-6b" model_id = "THUDM/chatglm3-6b" local_path = "/home/jp/wzk/chatglm3-6b-project/chatglm3-6b" device_map = "auto" torch_dtype = "float16" max_length = 8192 trust_remote_code = true [server] host = "0.0.0.0" port = 7860

对应的settings.json用于前端或 IDE 插件读取,路径放在~/.taotoken/settings.json:

{ "taotoken.baseUrl": "https://taotoken.net/api", "taotoken.apiKey": "${TAOTOKEN_API_KEY}", "taotoken.modelId": "chatglm3-6b", "taotoken.timeout": 60000, "chatglm.localPath": "/home/jp/wzk/chatglm3-6b-project/chatglm3-6b", "chatglm.deviceMap": "auto", "chatglm.maxMemory": { "0": "10GiB", "1": "10GiB", "cpu": "32GiB" } }

这里有个关键点:maxMemory里的"0"和"1"对应 GPU 编号,"cpu"是溢出缓冲。如果你不写这个,device_map="auto"可能会把模型全塞到 GPU0,因为 accelerate 默认按显存大小排序,但不会主动限制单卡上限。加上maxMemory后,切分逻辑才会真正按你给的额度分配。

环境变量注入命令:

export TAOTOKEN_API_KEY="sk-你的实际Key" # 验证是否生效 echo $TAOTOKEN_API_KEY | head -c 8

输出应该是sk-xxxxx的前 8 位。如果为空,说明没 export 成功,检查你的 shell 配置文件。这一步做完,后面所有请求都可以通过 TaoToken 统一通道走,不用再单独配 Key。

3. 可复制配置:多卡并行与显存优化参数清单

这一节是核心,直接给你能跑的配置。先说环境准备,我用 pyenv 管理 Python 版本,命令如下:

# 安装 pyenv curl https://pyenv.run | bash # 配置环境变量(bash) echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc echo 'eval "$(pyenv init -)"' >> ~/.bashrc source ~/.bashrc # 安装 Python 3.10 pyenv install 3.10.13 pyenv local 3.10.13 # 创建独立虚拟环境 python -m venv env source env/bin/activate

依赖安装这块,版本要对齐,否则transformers和torch不匹配会报ImportError:

pip install protobuf transformers==4.30.2 cpm_kernels torch>=2.0 gradio mdtex2html sentencepiece accelerate

注意transformers==4.30.2是 ChatGLM3 官方推荐的版本,别随意升级到 4.40+,否则trust_remote_code加载模型时会报AttributeError。accelerate必须装,多卡切分靠它。

模型下载:

git clone https://huggingface.co/THUDM/chatglm3-6b # 如果网络慢,用镜像 git clone https://hf-mirror.com/THUDM/chatglm3-6b

下载完后,模型目录结构应该是:

chatglm3-6b/ ├── config.json ├── configuration_chatglm.py ├── modeling_chatglm.py ├── pytorch_model-00001-of-00007.bin ├── ... ├── tokenizer.model └── tokenizer_config.json

接下来修改web_demo_gradio.py里的MODEL_PATH:

# 原内容 # MODEL_PATH = os.environ.get('MODEL_PATH', 'THUDM/chatglm3-6b') # 修改为本地路径 MODEL_PATH = os.environ.get('MODEL_PATH', '/home/jp/wzk/chatglm3-6b-project/chatglm3-6b')

然后是多卡启动的关键参数。在加载模型时,显式传入device_map和max_memory:

import torch from transformers import AutoModel, AutoTokenizer model_path = "/home/jp/wzk/chatglm3-6b-project/chatglm3-6b" # 多卡显存分配策略 max_memory = { 0: "10GiB", 1: "10GiB", "cpu": "32GiB" } tokenizer = AutoTokenizer.from_pretrained( model_path, trust_remote_code=True ) model = AutoModel.from_pretrained( model_path, trust_remote_code=True, torch_dtype=torch.float16, device_map="auto", max_memory=max_memory ).eval() print(f"模型加载完成,当前设备分布:{model.hf_device_map}")

model.hf_device_map会打印出每一层被分配到哪张卡,这是验证多卡是否生效的最直接方式。如果输出里全是0,说明没切分成功,检查max_memory是否生效。

启动命令:

cd /home/jp/wzk/chatglm3-6b-project/ChatGLM3/basic_demo python web_demo_gradio.py

成功启动后输出:

Running on local URL: http://127.0.0.1:7860

浏览器打开这个地址就能看到 Web 界面。此时另开一个终端跑nvidia-smi,你应该看到两张卡都有显存占用,而不是一张满载一张空闲。

4. 验证请求与显存收益量化:nvidia-smi 实测数据

配置跑通只是第一步,关键是要验证多卡切分真的生效,并且量化显存收益。我用的方法是:启动服务后,用nvidia-smi抓取显存占用,再发一个实际请求看响应是否正常。

先看显存占用。启动完成后执行:

nvidia-smi --query-gpu=index,memory.used,memory.total,utilization.gpu --format=csv

我的实测输出:

index, memory.used [MiB], memory.total [MiB], utilization.gpu [%] 0, 6452 MiB, 12288 MiB, 0 % 1, 7284 MiB, 12288 MiB, 0 %

GPU0 约 6.3GB,GPU1 约 7.1GB,总计约 13.4GB。对比单卡模式:单卡 FP16 加载时,GPU0 会直接飙到 12.5GB 以上,加上 KV Cache 后接近 14GB,12GB 卡直接 OOM。多卡切分后每张卡都有余量,推理时不会因为显存峰值崩掉。

再验证请求。用 curl 发一个测试请求:

curl -X POST http://127.0.0.1:7860/api/chat \ -H "Content-Type: application/json" \ -d '{ "prompt": "用一句话解释什么是多卡并行", "max_length": 512, "temperature": 0.7 }'

预期返回:

{ "response": "多卡并行是指将模型的不同层或不同计算任务分配到多张 GPU 上同时执行,从而突破单卡显存限制并提升推理速度。", "status": "success" }

如果返回status: success且内容合理,说明推理链路通了。此时再跑一次nvidia-smi,你会看到推理瞬间两张卡的 utilization 都有波动,证明计算确实分散到了两张卡上。

显存收益量化对比表:

配置模式GPU0 占用GPU1 占用总显存是否 OOM
单卡 FP1613.8GB013.8GB12GB 卡 OOM
双卡 auto6.3GB7.1GB13.4GB稳定
双卡 + max_memory6.1GB6.9GB13.0GB稳定,余量更大

可以看到,加上max_memory限制后,总占用还降了 0.4GB,因为切分更均衡,减少了单卡上的临时缓冲。这个收益在长对话场景下更明显——max_length=8192时,KV Cache 会额外吃 2-3GB,单卡直接崩,双卡还能扛。

另外,如果你通过 TaoToken 统一通道调用远程 API,本地显存占用可以降到 0,因为推理在远端完成。本地只负责发请求和渲染结果。这种方式适合显存实在不够的场景,但延迟会比本地推理高,取决于网络质量。

5. 常见报错排查:401、local proxy failed、reading choices 全解析

部署过程中我踩了不少坑,这里把最常见的几个报错和排查路径列出来,你遇到时直接对照。

报错一:401 Unauthorized

requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://taotoken.net/api/v1/chat/completions

原因:TaoToken API Key 没配或配错。排查步骤:

# 检查环境变量是否生效 echo $TAOTOKEN_API_KEY # 如果为空,重新 export export TAOTOKEN_API_KEY="sk-你的实际Key" # 验证 Key 是否有效 curl -H "Authorization: Bearer $TAOTOKEN_API_KEY" https://taotoken.net/api/v1/models

如果 curl 返回 200 且列出模型列表,说明 Key 没问题,问题在代码里读取方式。检查config.toml里的api_key_env是否和实际环境变量名一致。

报错二:local proxy failed

OSError: local proxy failed to connect, please check your network

这个报错通常出现在模型下载或 API 请求时。原因可能是网络不通或代理配置冲突。排查:

# 检查是否能访问 TaoToken API curl -I https://taotoken.net/api # 检查是否有残留代理环境变量 env | grep -i proxy

如果有http_proxy或https_proxy残留,unset 掉:

unset http_proxy https_proxy all_proxy

然后重试。注意,这里不是让你配代理,而是清理掉可能干扰直连的残留变量。

报错三:reading choices

KeyError: 'choices'

这个报错出现在解析 API 响应时。原因通常是返回结构和你预期的不一致,比如返回了错误信息而不是正常响应。排查:

import requests import os resp = requests.post( "https://taotoken.net/api/v1/chat/completions", headers={"Authorization": f"Bearer {os.environ['TAOTOKEN_API_KEY']}"}, json={"model": "chatglm3-6b", "messages": [{"role": "user", "content": "test"}]} ) print(resp.status_code) print(resp.text) # 先打印原始响应,看结构

如果resp.text里是{"error": "model not found"},说明模型 ID 写错了。检查settings.json里的taotoken.modelId是否和 TaoToken 控制台里的一致。

报错四:OAuth token expired

OAuthError: token expired, please re-authenticate

这个出现在使用 OAuth 方式接入时。解决方法是重新生成 Key:

# 在 TaoToken 控制台重新创建 API Key # 然后更新环境变量 export TAOTOKEN_API_KEY="sk-新Key"

如果你用的是 CC Switch 或 Cline MCP 这类工具,需要同步更新三件套:Base URL(https://taotoken.net/api)、API Key、Model ID(chatglm3-6b)。缺一个都会报错。

报错五:CUDA out of memory

torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate 2.00 GiB

这是显存不够。排查顺序:

  1. 检查max_memory是否设置,没设的话加上。
  2. 调小max_length,从 8192 降到 4096。
  3. 检查是否有其他进程占用显存:nvidia-smi看有没有僵尸进程。
  4. 如果还不行,考虑量化加载:load_in_8bit=True或load_in_4bit=True。

量化加载示例:

model = AutoModel.from_pretrained( model_path, trust_remote_code=True, device_map="auto", load_in_8bit=True, # 8bit 量化,显存减半 max_memory=max_memory ).eval()

8bit 量化后,双卡总占用可以降到 7GB 左右,但推理质量会有轻微下降,代码生成任务上偶尔会出现语法错误。

6. 长期编码与 Agent 场景:TaoToken Coding Plan 接入建议

如果你不只是跑一个对话 Demo,而是要把 ChatGLM3-6B 接入长期编码助手或 Agent 工作流,那配置策略要调整。核心区别在于:Demo 场景追求一次跑通,Agent 场景追求稳定、低延迟、可并发。

首先是 Key 管理。Demo 阶段一个 Key 够了,但 Agent 场景建议用 TaoToken 的 Coding Plan,它支持更高的并发配额和更长的超时时间。接入方式不变,还是https://taotoken.net/api,但需要在控制台升级套餐。

其次是模型加载策略。Agent 场景下,模型会频繁被调用,每次重新加载权重不现实。正确做法是常驻服务 + 请求队列:

# agent_server.py - 常驻推理服务骨架 import os from fastapi import FastAPI from pydantic import BaseModel from transformers import AutoModel, AutoTokenizer import torch app = FastAPI() model_path = os.environ.get("CHATGLM_PATH", "/home/jp/wzk/chatglm3-6b-project/chatglm3-6b") max_memory = {0: "10GiB", 1: "10GiB", "cpu": "32GiB"} tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModel.from_pretrained( model_path, trust_remote_code=True, torch_dtype=torch.float16, device_map="auto", max_memory=max_memory ).eval() class ChatRequest(BaseModel): prompt: str max_length: int = 2048 temperature: float = 0.7 @app.post("/chat") async def chat(req: ChatRequest): response, history = model.chat( tokenizer, req.prompt, history=[], max_length=req.max_length, temperature=req.temperature ) return {"response": response, "status": "success"}

启动:

uvicorn agent_server:app --host 0.0.0.0 --port 8000

这样模型只加载一次,后续请求直接复用,延迟从 30 秒降到 2-3 秒。

然后是 TaoToken 的统一接入。在 Agent 代码里,所有对外部模型的调用都走 TaoToken:

import requests import os def call_taotoken(prompt: str, model: str = "chatglm3-6b"): resp = requests.post( "https://taotoken.net/api/v1/chat/completions", headers={ "Authorization": f"Bearer {os.environ['TAOTOKEN_API_KEY']}", "Content-Type": "application/json" }, json={ "model": model, "messages": [{"role": "user", "content": prompt}], "max_tokens": 2048, "temperature": 0.7 }, timeout=60 ) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"]

这样你的 Agent 可以同时调用本地 ChatGLM3-6B 和远端其他模型,Key 统一管理,不用每个模型单独配。

最后是监控。Agent 长期运行,显存泄漏是常见问题。建议加一个定时检查:

# 每 5 分钟记录一次显存 while true; do nvidia-smi --query-gpu=index,memory.used --format=csv,noheader >> /var/log/gpu_mem.log sleep 300 done

如果发现显存持续增长不释放,检查是否有未关闭的 session 或缓存累积。ChatGLM3 的model.chat()每次调用会创建新的 history,如果 history 不清理,KV Cache 会越堆越大。Agent 场景下建议每轮对话后重置 history,或者限制 history 长度。

整套流程跑下来,从环境配置到多卡切分再到 Agent 接入,核心就三件事:max_memory控制切分、device_map="auto"触发并行、TaoToken 统一 Key 管理调用凭证。把这三样配好,ChatGLM3-6B 在双卡上跑得稳,显存收益也能量化到每张卡的具体数字。

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

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

立即咨询