ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

6GB显存跑双本地模型:OOM避坑与GGUF量化部署实录

6GB显存跑双本地模型:OOM避坑与GGUF量化部署实录 先说个背景。我手里这台机器是前几年的游戏本显卡正好 6GB 显存平时写代码、跑点小模型还算够用但最近想在本地同时跑两个决策相关的小模型——一个我习惯叫 Kev一个叫 Laya——就有点尴尬。Kev 是偏对话和多步推理的Laya 更偏向结构化决策输出两个加起来如果都塞显存里光是权重就要 5GB 往上再算上推理缓存基本就是要顶爆的节奏。这文章就是我花一晚上从下载模型到调试推理、再到解决各种 OOM 和速度问题的完整翻车记录适合手里只有 6GB 级别入门卡、又想跑两个本地模型的读者参考。这篇记录最后是用 DeepSeek 帮我顺了一遍笔记和截图整理出来的实际折腾的过程远没有文字看起来这么顺畅。先说清楚一个前提我这里的“决策模型”不是什么神秘的东西就是相对通用聊天模型更偏任务型推理的那类开源模型——你给它一个问题它不光要给出结论还要把决策依据、可选方案、风险点按结构化方式列出来。Kev 是群里朋友推荐的 7B 量级模型擅长多步推理和对话Laya 则是个 3B 左右的小模型专门优化过工具调用和固定格式输出适合干“从几个选项里挑最优”这类活。两个模型的侧重点不同所以要一起跑。1. 先把需求和账算明白6GB 显存到底能不能塞下两个模型1.1 为什么是 Kev 和 Laya而不是只跑一个大模型我一开始也想过干脆只跑一个更大参数的模型把“对话”和“决策”都包了。但这带来两个问题第一7B 以上模型在 6GB 显存上只能做重度量化效果打折明显第二来回切换对话场景和结构化决策场景上下文容易被污染——刚才还在闲聊突然让它输出一份规范决策报告格式和语气很容易飘。Kev 和 Laya 分开各干各的一个负责把问题聊透一个负责把决策结果结构化两边互不干扰。其实这也是社区里常见的“双模型”玩法一个模型当“大脑”负责理解和推理另一个模型当“执行器”负责输出固定格式、调用工具、拆解任务。Laya 就是那个执行器角色。这类配合思路跟很多 Agent 框架里的“规划模型 执行模型”是一样的只是我这里没有用重框架而是直接让两个模型跑在本地。1.2 显存账本权重、KV Cache 和运行开销显存占用不能光看模型文件大小实际推理时大头是“模型权重 KV Cache 运行时 buffer”。量化后的 GGUF 文件在磁盘上是多大加载后权重基本就是多大KV Cache 则跟上下文长度强相关通常会额外吃掉几百 MB 到 1GB 多再加上 CUDA context、计算图临时缓冲区之类杂七杂八加起来得有 500MB 到 1GB 的预留。我按当时手头模型的情况粗略算了一笔账。Kev 的 7B Q4_K_M 量化版约 4.2GBLaya 的 3B Q4_K_M 约 2.0GB两个权重加起来 6.2GB——已经超过 6GB 了。即便把其中某个再压低到 Q3 量化也只能勉强塞下权重完全没有 KV Cache 的空间。所以结论很明确想在 6GB 显存里同时驻留两个模型不可行必须有一个模型住在内存里、按需调度。1.3 部署工具选型为什么我选了 llama.cpp 系而不是 vLLM很多人一上来就想上 vLLM实测下来在 6GB 这个量级不太合适。vLLM 的 Continuous Batching 和 PagedAttention 是好东西但它的显存管理本身就有不小开销而且对 6GB 这种小容量卡很不宽容经常在启动阶段就报显存不足。相比之下llama.cpp 系的 llama-server 和 Ollama底层都走了 GGUF 量化 CPU/GPU 分层 offload 的路线显存不够时可以自动把一部分层放到内存这对小显存卡才是真友好。我最终选了 Ollama 当主入口因为它把模型管理、并发请求、上下文处理都封装好了日常用起来省心。但 Laya 我没有直接挂在 Ollama 里跑常驻服务而是单独用 llama-server 按需启动这样两个模型的进程隔离得更干净切换时也不会互相抢占显存。后面小节会细说这个方案。2. 动手前的准备工作模型下载、量化选择和显存精算2.1 硬件环境与基础依赖清单先说我这台机器的具体配置CPU 是 8 核 16 线程内存 32GB显卡 6GB 显存系统是 Linux。32GB 内存很关键因为后面必须有一个模型住在内存里16GB 内存会比较紧张但也不是完全不能跑只是上下文开不了太大。系统里需要准备的东西不多Ollama或者 llama.cpp 源码编译出来的 llama-server、git、aria2 或 wget 这类下载工具。如果你打算直接用 llama.cpp记得编译时加上 CUDA 支持命令大概是cmake -B build -DGGML_CUDAON这一步别省否则模型全靠 CPU 跑速度会慢到怀疑人生。2.2 GGUF 量化格式怎么选Q4_K_M 是性价比甜点位关于 Kev 和 Laya 的下载我是从 Hugging Face 和 ModelScope 这类模型仓库里找的 GGUF 文件。GGUF 就是 llama.cpp 系的量化格式文件名里通常带 Q2、Q4、Q5、Q8 之类的字样表示比特数。Q4_K_M 是我个人最常用的档位因为它在体积和效果之间比较平衡——比 Q8 小一半左右但困惑度差距通常在 0.1 以内肉眼基本分不出来。Q3 及以下体积更小但模型有时候会开始胡言乱语决策类任务尤其明显Q8 体积太大6GB 显存下没必要。需要注意的一点是同名模型的 GGUF 也可能有不同版本下载的时候先看文件的 SHA256 校验值模型仓库页面一般会给出官方哈希。我第一次下载 Kev 时就没校验结果跑起来效果奇差后来发现是下载中断留下的不完整文件。后面翻了半天日志才反应过来尴尬。2.3 显存和内存预算的精算过程建模思路指向一个可复用的公式推理总占用 ≈ 模型权重大小 KV Cache 大小 运行开销约 0.51GBKV Cache 具体多大取决于模型的层数、注意力头数和上下文长度。粗略估算时7B 模型开 4K 上下文KV Cache 大概 300600MB3B 模型同样开 4K 上下文大概 100300MB。不同实现有差异但量级差不多。那么 6GB 显存的分配方案就出来了项目计划显存占用说明Kev 权重Q4_K_M约 4.2GB全部层放 GPUKev 的 KV Cache4K 上下文约 0.5GB根据上下文动态调整运行开销与 CUDA buffer约 0.8GB底部红线Laya 权重0GB放内存按需启动合计约 5.5GB给 GPU 底部留 0.5GB 余量Laya 走内存方案时它的推理速度会慢不少但 3B 模型半精度或 Q4 量化后对内存带宽要求并不高实测下来每秒能出 510 个 token因为它输出的决策文本普遍不长等个几十秒完全能接受。2.4 模型下载和文件校验的实操命令拉模型我用的是 Hugging Face CLI如果你的网络访问这些仓库不畅用 ModelScope 的镜像或者相关社区源也一样重点是把文件大小和哈希验一遍。参考命令# 下载示例模型名按你实际要拉的替换 hf download kev-org/Kev-7B-GGUF Kev-7B-Q4_K_M.gguf --local-dir ./models/kev hf download laya-org/Laya-3B-GGUF Laya-3B-Q4_K_M.gguf --local-dir ./models/laya # 校验哈希 sha256sum ./models/kev/Kev-7B-Q4_K_M.gguf sha256sum ./models/laya/Laya-3B-Q4_K_M.gguf哈希一定要跟仓库官方给出的值一致不一致就重新下载。我不止一次因为下载中断产生“残废模型”然后花大量时间去怀疑自己的量化参数最后才发现是文件本身的问题。3. 实操过程记录把 Kev 和 Laya 装进 6GB 显存的每一步3.1 先跑通 Kev还算顺利的第一小时我先把 Kev 放进 Ollama因为 Ollama 对 GGUF 的支持最省心。导入方式有两种如果模型已经在仓库里直接ollama pull kev就行如果是我这种手动下载的 GGUF需要先写一个 Modelfile再用ollama create导入。参考做法# Modelfile 示例 FROM ./models/kev/Kev-7B-Q4_K_M.gguf TEMPLATE {{- if .Messages }} {{- range .Messages }} {{- if eq .Role user }}|im_start|user {{ .Content }}|im_end| {{- else if eq .Role assistant }}|im_start|assistant {{ .Content }}|im_end| {{- end }} {{- end }} |im_start|assistant {{- else }} |im_start|assistant {{- end }} PARAMETER temperature 0.7 PARAMETER num_ctx 4096然后ollama create kev -f Modelfile用ollama run kev 写一个三段推理验证一下确认它能正常输出。接着准备做显存占用测试。Kev 挂在 GPU 上的推理速度很满意7B 模型 Q4 量化后在我的 6GB 卡上大约每秒 1218 个 token生成一段 300 字的分析也就半分钟左右。ollama 默认会尽量把层全塞进显存如果塞不下会自动把部分层放到内存不过我特意把 Kev 设为全部层都跑 GPU让它保持最佳性能——它是我这边的“主模型”。3.2 再啃 Laya结构化输出带来的第一个坑Laya 的部署方式和 Kev 不太一样。它的用途是决策输出通常需要严格的 JSON 格式所以我不希望它常驻内存、一直占着显存而是想用的时候再启动用完就关。我选择了 llama-server 直接跑 GGUFllama-server -m ./models/laya/Laya-3B-Q4_K_M.gguf \ --host 127.0.0.1 --port 8001 \ --n-gpu-layers 0 \ --ctx-size 4096 \ --temp 0.1 --top-k 40 --top-p 0.9 \ --jinja这里有一个关键参数--n-gpu-layers 0也就是说 Laya 所有层都在 CPU/内存里跑完全不占显存。这样 Kev 才能稳稳地住在 6GB 显存里。Laya 只是 3B 模型纯 CPU 推理速度也在可接受范围内。如果想让 Laya 快一点可以试--n-gpu-layers 10之类的值把一部分层放 GPU但这会挤占 Kev 的显存空间所以我在最终方案里让它全走内存。Laya 这边我踩了一个典型坑决策模型对温度参数极其敏感。我第一次没有设置temp 0.1直接用 Ollama 默认的 0.8 去跑结果模型输出的 JSON 文档里频繁出现空字段、重复键甚至自己编造根本不存在的选项。后来把温度降到 0.1top_p 设为 0.9输出立刻稳定下来。这算是我这次折腾中收获最大的一条经验。3.3 两个模型同时“装进”6GB 显存的三种姿势我实际尝试过三种共存方案都有各自的取舍。方案一两个模型都全量驻留 GPU理论上最美好实际完全不可行。Kev 权重 4.2GBLaya 权重 2GB加起来 6.2GB还没算 KV Cache 和运行开销就已经超了。我尝试把 Laya 换成 Q3 量化勉强压到 1.5GB 左右但启动 Laya 的瞬间 Kev 就 OOM 崩溃了。6GB 真的不是一个可以随便挥霍的空间。方案二主模型全驻留 GPU副模型全驻留内存最终采用Kev 常驻 Ollama 服务全部 32 层放 GPU上下文限制在 4KLaya 用 llama-server 按需启动全部层在内存里端口 8001。需要调用 Laya 的决策能力时我命令行里发一个带问题描述、选项列表和约束条件的请求等服务返回结构化结果后再关闭 Laya 进程。这个方案从显存分配上彻底避开了冲突Kev 的推理体验跟单模型时完全一致。方案三两个模型都做部分 GPU offload这个方案适合“两个模型都想保住一定性能”的场景比如 Kev 放 24 层 GPU、Laya 放 10 层 GPU另一个 8 层的 Kev 放内存共用。但实际测下来非常容易失衡稍微并发几个请求就会出现性能骤降。所以我最终没有采用适合有大内存但显存不够的机器尝试。三种方案的核心取舍Kev 是高频使用的主模型必须保证速度Laya 是低频使用的决策工具慢一点没关系。这跟做缓存系统的思路是一样的——热的放快存储冷的放慢存储。3.4 统一接口让 Kev 和 Laya 能被其他工具调用两个模型装好之后要能真正用到工作流里接口统一很重要。Ollama 自带 OpenAI 兼容接口默认地址是http://127.0.0.1:11434/v1llama-server 也可以加--api参数直接提供兼容接口所以 Kev 和 Laya 对上层调用方来说就是两个不同端口的 OpenAI 服务。我在本地写了一个简单的调用脚本把 Kev 当作“分析大脑”Laya 当作“决策执行器”先让 Kev 解析用户请求并拆解出候选方案再把候选方案发给 Laya 让它输出标准化的决策报告。示意图没有画文字逻辑其实很简单核心就是# 伪代码示例Kev 负责拆解Laya 负责结构化决策 import requests def ask_kev(prompt): r requests.post(http://127.0.0.1:11434/v1/chat/completions, json{model: kev, messages: [{role: user, content: prompt}]}) return r.json()[choices][0][message][content] def ask_laya(prompt): r requests.post(http://127.0.0.1:8001/v1/chat/completions, json{model: laya, messages: [{role: user, content: prompt}]}) return r.json()[choices][0][message][content]这样做的价值在于两个模型跑在本地不上传隐私数据也不依赖外部 API。延迟上Laya 首次冷启动加载会比较慢主要原因是它每次都要从磁盘重新读权重到内存里。我的解决办法是一个常驻的 wrapper 服务启动时预加载 Laya 模型到内存调用方直接发请求省掉反复冷启动的时间代价是多占约 2GB 系统内存。4. 翻车实录这一晚我踩过的典型坑4.1 坑一一开跑就 OOM日志直接劝退第一次尝试“两个模型都驻留”时我在同时加载 Kev 和 Laya 后马上收到了 CUDA 内存不足的错误日志里明确写着类似CUDA out of memory或not enough memory。我当时的第一反应是降低上下文但后来发现真正的核心问题是显存里塞了两个模型权重。解决思路是前面讲的方案二Laya 走内存。排查 OOM 时有个技巧值得分享先用nvidia-smi看显存占用看看是不是被浏览器或其他进程占了再用ollama ps看当前加载的模型大小能很快判断是权重超了还是缓存超了。4.2 坑二模型加载成功但推理像老牛拉车Laya 纯 CPU 推理的早期版本我忘了限制--threads参数结果系统里所有进程都在抢 CPU 资源Kev 的推理速度也被拖垮了。后来我在 llama-server 启动命令里加了--threads 8并限制 Laya 进程的 CPU 亲和性Kev 才恢复原来的速度。如果你用的是 Ollama 管理两个模型可以用OLLAMA_NUM_PARALLEL和OLLAMA_MAX_LOADED_MODELS环境变量限制并发模型数避免 Ollama 自作主张把两个模型都塞显存里。4.3 坑三上下文一长就开始胡言乱语Laya 在 4096 上下文跑满之后会出现内容重复、JSON 格式错乱的问题。起初我以为是模型本身不行后来用--ctx-size 2048限制后发现情况明显改善。其实很多小模型在长上下文下的注意力分布不稳定与其追求长上下文不如优先保证输出质量。决策类任务通常不需要特别长的上下文支撑输入内容整理干净比开 8K 上下文更有效。4.4 坑四下载的模型文件损坏排查了半天才发现前面提到过我下载 Kev 的 GGUF 文件不完整模型效果很差。这种问题的隐蔽性在于模型可以启动、可以生成内容只是输出的质量明显不如预期非常容易让人误以为量化等级选错了。后来我把文件哈希和仓库页面的官方值一对比才发现文件大小差了几百 MB。血的教训任何模型文件下载后先校验 SHA256再进部署环节。4.5 坑五两个服务的端口冲突Ollama 默认占用 11434llama-server 默认占用 8080听起来不冲突但我当时给 Laya 设置的端口和另一个本地服务撞了。排查方式很简单ss -tlnp | grep 8001看端口被谁占着然后换端口。这不算是特别重大的问题但在深夜连续出错时这种小问题最容易逼疯人。4.6 常见问题速查表现象可能原因排查方向解决方案启动即报 CUDA OOM两个模型同时驻留 GPU用 nvidia-smi 查显存占用副模型改为全内存或按需加载模型速度极慢CPU offload 层数过多 / 线程受限观察 CPU 和 GPU 负载分布调高主模型 GPU 层数限制线程数长上下文后输出混乱KV Cache 溢出或模型长文本不稳定检查上下文长度设置降低 ctx-size 或清理输入冗余输出 JSON 格式不规范温度参数过高 / 模板错误查看原始输出和模板渲染结果温度降到 0.1~0.3检查模板模型生成内容质量差文件损坏或量化等级过低核对 SHA256 哈希重下文件或改用 Q4_K_M 及以上服务端口冲突端口被占用ss -tlnp 查看占用换端口或停掉占用进程首次请求等待过久副模型冷启动加载查看加载日志预加载模型并保持进程常驻5. 结尾给想在 6GB 显存上折腾两个模型的人几句实在话坦白说折腾这一晚上的最大收获不是“6GB 也能跑两个模型”这种成就感而是明白了怎么管理有限资源。6GB 显存就是一个很小的房间你不能把两个大沙发都搬进去最好的方式是一张床放房间里另一张折叠床需要时再支起来。对应到模型部署上就是“一个主力模型常驻 GPU一个辅助模型常驻内存”。这个思路放到任何小显存、低资源的场景都适用。我个人在实际操作中的体会是确定模型分工比调速度更重要。先想清楚哪个模型你是天天用、每秒都在等的哪个模型只是偶尔调一下、几秒钟的延迟也能接受的然后再分配资源。Kev 和 Laya 这个组合里Kev 是主力Laya 是辅助所以 Kev 占 GPU、Laya 住内存是明确且理性的选择。如果反过来用体验会差很多。最后再分享一个小技巧如果你也要像我这样一边跑两个本地模型一边写使用记录可以把两头的事情交给不同工具处理。模型负责干模型该干的活文档整理这种重复性工作我当时是让 DeepSeek 帮忙把零散的截图和日志整理成连贯记录的。这种组合使用的思路本质上也是在做资源的最优分配——把人的注意力留在真正需要判断的地方效率会高很多。
返回列表