1. 先想清楚:本地部署大模型到底解决什么问题
把 DeepSeek 这类开源权重拉到自己机器上,再接进 VS Code,本质上不是"装个软件"那么简单,而是在给自己搭一套私有化的推理基础设施。我在过去一年多的时间里,陆陆续续在四台不同配置的机器上折腾过这条链路——从只有集成显卡的老笔记本,到 4090 独显的台式机,再到一台纯 CPU 的小主机——踩过的坑几乎覆盖了所有新手会遇到的场景。这套方案能提供三样东西:数据不出本机、调用不花钱、响应不排队。但它同时也要你付出三样代价:显存要够、速度会慢、配置得自己调。所以这篇内容不是劝你一定要上本地,而是把账算清楚,让你知道自己在做什么。
先说清楚这篇适合谁看。第一类是有代码补全和对话需求、但公司网络策略严格、代码不能外发的开发者;第二类是经常在断网环境、出差路上、或者网络质量极差的地方写东西的人;第三类纯粹是技术好奇,想搞清楚大模型推理到底是怎么回事。如果你只是想偶尔问几个问题,云端服务明显更省事,这篇文章对你价值不大。但如果你每天要在编辑器里和 AI 交互几十次,本地部署带来的边际体验提升会非常明显——延迟从几百毫秒降到几十毫秒,那种"顺手"的感觉是完全不一样的。
前 100 字里我把核心词都摆出来了:本地部署、DeepSeek、VS Code、大模型。接下来我按真实搭建顺序拆,从算硬件账开始,到装运行时、拉模型、起服务、配插件、排故障,一步一步来。每一步我都会说明为什么这么做,以及不这么做会出什么问题——这比单纯给你一份命令行清单有用得多。
1.1 三类真实诉求,对应三种完全不同的方案
我在帮别人配置的过程中发现,大家嘴上说的都是"我想本地跑大模型",但实际诉求差别极大,配错方向就是白折腾。第一类是代码补全,需求特征是"低延迟、短输出、高频次",你敲三个字符它就得出结果,超过 300 毫秒的等待就会打断心流。这类需求对模型能力要求其实不高,1.5B 到 7B 的代码专用模型完全够用,但对手感和显存占用极其敏感。第二类是对话式问答,比如让它解释一段老代码、帮我写个正则、梳理一个报错的可能原因,这类需求可以接受 2 到 10 秒的首字延迟,但要求上下文够长、理解能力够强,7B 起步、14B 到 32B 体验会好很多。第三类是长文档处理,比如把一份几百页的规范塞进去做检索问答,这类需求真正的瓶颈不是模型参数量,而是上下文窗口和显存。
这三种诉求对应的配置策略完全不同。补全型追求的是"小模型 + 短上下文 + 常驻显存",我一般会配一个 1.5B 到 3B 的模型专门干这个,把 num_ctx 压到 2048 甚至 1024,让它一直待在显存里不卸载。对话型追求的是"中大模型 + 8K 以上上下文 + 可接受的首字延迟",7B 的 Q4 量化是很稳的起点。长文档型则要考虑是否用 CPU 加内存来兜底,因为显存是真的不够用。很多人一上来就想用最大的模型干所有事,结果就是补全卡顿、对话也慢,两头不讨好。我的建议是分开配:小模型管补全,中模型管对话,需要重活的时候再临时切换。
还有一类容易忽略的诉求是隐私合规。有些团队的代码资产、客户资料、内部文档明确不允许上传到外部服务,这时候本地的价值不在于性能,而在于"能用一个比没有强的模型"。这种情况下,7B 量化模型跑出来的质量哪怕只有云端旗舰的六成,也是从 0 到 1 的差别。我见过不少团队卡在这一步,最后干脆放弃了 AI 辅助,其实完全没必要——本地跑个中等模型,日常的样板代码、单元测试、注释补全,体验已经相当能打了。
1.2 硬件账本:显存到底要多少,量化档位怎么选
这是最多人问的问题,也是最多人算错的地方。显存占用不是"模型文件多大就占多少",它由三部分组成:权重本身、KV Cache、运行时开销。权重部分好算,看量化等级:Q4_K_M 大约每个参数 0.55 到 0.6 字节,Q5_K_M 大约 0.7 字节,Q8_0 大约 1.05 字节,FP16 是 2 字节。所以一个 7B 模型用 Q4_K_M 量化,文件大概 4.1 到 4.5GB;14B 大概 8.5GB;32B 大概 19GB;70B 大概 40GB。这个数字你下载的时候就能看到,不难。
难算的是 KV Cache。它的公式是:2 × 层数 × KV头数 × 头维度 × 序列长度 × 每元素字节数。以常见的 7B 模型为例,32 层、GQA 下 8 个 KV 头、头维度 128、FP16 存储,那么每个 token 每层的 KV 占用是2 × 8 × 128 × 2 = 4096字节,也就是 4KB;乘上 32 层就是每 token 128KB;8K 上下文就是128KB × 8192 ≈ 1GB。这个量级在小模型上还能忍,但如果你把上下文开到 32K,光 KV Cache 就要 4GB,直接翻倍。很多人配了 8GB 显存跑 7B,模型占 4.5GB,剩下 3.5GB 本来看起来够,结果上下文一开大就爆显存,根源就在这里。
我把常见配置的账算成一张表,方便你直接对照:
| 模型规模 | Q4_K_M 权重 | 8K 上下文 KV Cache | 建议显存 | 实际体验 |
|---|---|---|---|---|
| 1.5B 到 3B | 1.0 到 1.8GB | 约 0.3GB | 4GB 起 | 补全飞快,对话能力有限 |
| 7B 到 8B | 4.1 到 4.9GB | 约 1.0GB | 8GB 舒适 | 日常对话、补全都能干 |
| 14B | 8.5 到 9.0GB | 约 1.5GB | 12GB 舒适 | 理解能力明显上一个台阶 |
| 32B | 18 到 20GB | 约 3.0GB | 24GB 舒适 | 接近可用的复杂推理 |
| 70B | 39 到 42GB | 约 5.0GB | 48GB 以上或双卡 | 本地天花板,但很吃资源 |
表里"建议显存"这一列我留了余量,因为运行时本身要占几百 MB,而且操作系统和显示输出也要吃掉一部分。Windows 上尤其明显,独显如果还接着显示器,实际可用显存往往比标称少 0.5 到 1GB。我的经验是:算出来的总需求再往上留 15% 到 20% 的余量,否则很容易在某个上下文突然变长的时刻崩溃。
再补充一个常被忽略的点:内存也要够。模型加载的时候会先读进内存再传到显存,如果内存不够,加载过程会极慢甚至失败。粗略标准是内存至少要是模型文件大小的 1.5 倍。跑 32B 的 Q4 模型,16GB 内存会很吃力,32GB 是起步线。如果是纯 CPU 推理,那内存就是唯一的"显存",32B 的 Q4 至少要 32GB 内存才能跑起来,而且速度会降到每秒两三个 token,只能做离线批处理,不适合交互。
1.3 四条技术路线的横向对比,别一上来就选最难的
本地跑模型现在有四条主流路线,我按上手难度和适用场景排一下。第一条是 Ollama,一条命令装完、一条命令拉模型、一条命令起服务,默认就带 OpenAI 兼容接口,绝大多数 VS Code 插件直接就能连。它是我的默认推荐,90% 的人用这个就够了。第二条是 llama.cpp 原生,需要自己编译或者下预编译包,手动指定参数量化文件、层数卸载、线程数,灵活度最高,适合想榨干性能或者做嵌入式部署的人。第三条是带图形界面的桌面客户端,加载模型点几下鼠标就行,适合完全不想碰命令行的人,但可配置项少,接编辑器时容易卡在端口和接口格式上。第四条是 vLLM 这类面向吞吐的服务框架,主打并发和批处理,单机单用户场景属于杀鸡用牛刀,而且对显存要求更严格,装起来也麻烦。
我为什么默认推 Ollama?因为它把最容易出错的部分都封好了:模型下载、量化选择、显存与内存的自动分层、服务进程管理。你不需要懂 GGUF 格式,也不需要手动算--n-gpu-layers该设多少,它会自己判断。而且它的 API 同时提供原生接口和 OpenAI 兼容接口,前者功能更全(比如能拿模型的加载状态),后者兼容性更好(插件基本都认)。代价是它的默认参数偏保守,上下文长度默认不长,并发数也低,需要手动调——这就是后面第 3 章要重点讲的部分。
llama.cpp 原生路线我建议在你已经跑通 Ollama、并且明确知道自己的瓶颈在哪之后再去碰。它的价值在于精细控制:你可以指定把多少层放到 GPU、多少层留在 CPU,可以在显存刚好不够的时候做混合推理,可以用不同的线程数匹配你的 CPU 核心。我实测过同一台机器上同一个模型,llama.cpp 手动调优后比默认配置快 20% 到 30%,但这个优化过程要花一两个小时反复试。对绝大多数人来说,这个时间花得不值。
2. 环境准备:把地基打牢再动手
动手之前先把前置条件检查一遍,能省掉后面一大半的莫名其妙的问题。我见过太多人卡在"命令敲了没反应""插件一直转圈"这种状态,最后发现是驱动太老、或者端口被别的程序占了、或者系统盘空间不够导致模型下载失败。这些检查花不了五分钟,但能避免你后面花两小时抓瞎。这一章我把检查项、安装步骤、模型管理三件事按顺序讲清楚,每一步都说明它在验证什么。
需要强调的是,安装顺序很重要:先装显卡驱动,再装推理运行时,最后拉模型。顺序反了会出现运行时识别不到 GPU、只能用 CPU 跑的情况,而 CPU 跑 7B 模型的速度大概只有 GPU 的十分之一,体验天差地别。另外建议把模型目录放在空间充足的盘上,默认位置往往在系统盘,一个 32B 模型就能吃掉 20GB,几个模型下来系统盘就红了。
2.1 前置检查清单:五分钟排掉八成隐患
第一项检查是显卡驱动和可用显存。N 卡用户直接跑nvidia-smi,看两个数:显存总量和当前占用。如果命令不存在,说明驱动没装或者版本太老,去官网下最新的装上。A 卡和核显用户情况复杂一些,不同运行时的支持程度差异很大,建议先确认你打算用的运行时是否支持你的平台,别装完了才发现用不了。Mac 用户相对省心,统一内存架构下显存和内存是一体的,M 系列芯片的推理效率相当不错,但要注意内存是共享的,开太多程序会互相抢。
第二项检查是磁盘空间和目录规划。我会单独建一个目录放模型,比如统一放在一个专门的数据盘下,然后通过环境变量把运行时的模型路径指过去。这么做的好处是备份、迁移、清理都很方便,不会和系统文件混在一起。检查一下目标盘至少留出你要跑的模型体积三倍的空间——模型文件、加载时的临时缓存、以及未来可能加的模型,都要算进去。
第三项检查是端口占用。本地推理服务默认走11434(Ollama)或8080(llama.cpp 常见默认值),先确认这些端口没被别的程序占着。Linux 和 macOS 上用lsof -i :11434,Windows 上用netstat -ano | findstr 11434。如果已经被占用,要么改服务端口,要么把占用程序停掉,别硬扛,插件配置里的端口和服务端口对不上是最常见的连接失败原因。
第四项是网络和代理设置。模型文件动辄几个 GB,下载速度直接决定你的耐心消耗。如果公司网络有限速或者需要走内网源,提前准备好镜像地址或者离线导入方案。离线场景下可以先在能联网的机器上把模型拉好,再整个目录拷过去,Ollama 的模型目录结构是自包含的,拷过去改个环境变量就能用。
提示:检查清单里最容易被跳过的是驱动版本。有些老驱动能跑起来,但会缺失某些算子支持,表现为推理结果乱码或者直接报错退出。如果遇到这类诡异问题,第一件事就是更新驱动。
2.2 推理运行时安装:三条命令搞定基础环境
以 Ollama 为例,Linux 和 macOS 上是官方脚本一行装完,Windows 是下载安装包双击。装完之后它一般会自动注册成系统服务并开机自启,这一点很重要——意味着你不需要每次手动serve,后台常驻一个进程在监听端口。验证安装是否成功,直接跑版本查询命令看输出,如果能看到版本号,说明二进制装好了;再跑一次服务状态查询,如果能看到服务在监听,说明后台进程起来了。
装完之后第一件事是配环境变量,这是很多人忽略但影响巨大的环节。默认配置下,服务只监听本机回环地址、上下文长度偏小、并发数为 1、空闲一段时间就卸载模型。这几个默认值在单人轻度使用下没问题,但你一旦要接编辑器、频繁调用、还要开大上下文,就必须调整。Linux 上通过 systemd 的 override 机制改,macOS 上用 launchctl 设置,Windows 上在系统环境变量里加。改完要重启服务才生效,这一步别忘。
关键的几个环境变量我列一下,都是实测有明确收益的:
| 变量名 | 作用 | 推荐值 | 说明 |
|---|---|---|---|
OLLAMA_HOST | 监听地址与端口 | 127.0.0.1:11434 | 只本机用就别开0.0.0.0 |
OLLAMA_NUM_PARALLEL | 同时处理的请求数 | 2 | 补全和对话同时用时设 2 |
OLLAMA_MAX_LOADED_MODELS | 同时驻留的模型数 | 2 | 配合双模型分工使用 |
OLLAMA_KEEP_ALIVE | 模型空闲后保留时长 | 30m | 避免频繁加载卸载 |
OLLAMA_FLASH_ATTENTION | 启用注意力优化 | 1 | 支持时能降显存提速 |
OLLAMA_KV_CACHE_TYPE | KV Cache 量化类型 | q8_0 | 能省一半 KV 显存 |
OLLAMA_KEEP_ALIVE这个参数值得单独说。默认值往往是 5 分钟,意味着你不敲代码五分钟之后模型就被卸载了,下次调用要重新加载,7B 模型冷启动大概 3 到 8 秒,14B 要 10 秒以上。这个延迟落在编辑器里体感极差,你会觉得"这插件怎么老是转圈"。设成 30 分钟或者更长,模型就一直待在显存里,响应稳定在几百毫秒。代价是显存长期被占着,如果你还要打游戏或者跑别的 GPU 任务,那就调回短一点,或者用完手动卸载。
OLLAMA_KV_CACHE_TYPE=q8_0也是我强烈建议开的。它把 KV Cache 从 FP16 量化到 8 位,显存占用直接减半,而实测对输出质量的影响几乎察觉不到。对于 8GB 显存跑 7B 这种"刚好卡线"的配置,这个开关往往就是"能开 8K 上下文"和"只能开 4K"的区别。
2.3 模型拉取与目录管理:别让模型文件变成垃圾场
模型管理这块我吃过亏。一开始什么都往下拉,7B、14B、32B、各种量化档位、各种微调版本,半年下来模型目录塞了一百多 GB,每次列出来都看花眼,而且根本记不清哪个是干什么用的。后来我定了个规矩:只保留三个模型——一个 1.5B 到 3B 的代码补全专用小模型、一个 7B 到 14B 的通用对话模型、一个按需临时拉的"重活"模型。前两个长期驻留,第三个用完就删。
拉取的时候一定要带明确的标签,别只写模型名。不带标签会默认拉最新版本,而最新版本可能是个很大的量化档位,或者干脆不适合你的硬件。我一般会先查一下有哪些可用标签,看清楚参数量和量化等级再决定。参数量看名字里的数字,量化等级看后缀,Q4_K_M 是性价比甜点,Q5_K_M 质量略好但体积大 20%,Q8_0 质量接近无损但体积翻倍。除非你的显存非常充裕,否则不建议上 Q8。
还有一个实用技巧:模型的量化档位不是越高越好,而是要和你的硬件匹配。如果你的显存刚好在临界点,Q4_K_M 能全量放显存里跑,Q5 就得分层到 CPU,那 Q4 的实际体验会远好于 Q5——因为分层推理的速度损失可能有 3 到 5 倍,而 Q4 到 Q5 的质量提升大概只有几个百分点。判断标准很简单:先拉 Q4,跑起来看显存占用,如果还有 2GB 以上余量,再试试 Q5;如果没有余量,就老老实实待在 Q4。
模型文件下载完之后,建议做一次完整性验证。虽然下载工具有校验机制,但偶尔会因为磁盘问题或者中断续传出错,表现为加载时报格式错误。验证方式很简单,直接跑一次最小推理,能正常输出就说明文件没问题。这一步花 10 秒,能避免你在配置插件的时候怀疑人生。
3. 把模型变成服务:本地接口的搭建与验证
模型下载完只是有了"原料",要让它能被 VS Code 用起来,还得把它变成一个持续监听的服务。这一层很多人理解得不清楚,以为"装了 Ollama 就能用了",其实中间隔着一个 HTTP 服务。编辑器插件的工作方式是发 HTTP 请求到某个地址,服务收到请求、调度模型推理、把结果流式返回。所以你要保证三件事:服务在跑、地址对得上、接口格式匹配。这三件事任何一个出问题,插件就只会转圈或者报连接错误。
这一章我会把服务启动、参数定制、接口验证三块讲透。其中参数定制是最容易被跳过、但对体验影响最大的部分——默认的上下文长度往往只有 2K 到 4K,你贴一段稍长的代码进去就会被截断,模型表现得像"记性很差"。而接口验证是排障的基础,学会用命令行直接打接口,你就能快速判断问题出在服务端还是客户端,排障效率能提升好几倍。
3.1 一条命令拉起服务,但要理解它在后台做了什么
启动服务的基础命令很简单,敲下去看到监听日志就说明起来了。但我想让你理解它背后的三件事,因为这决定了你后面怎么调。第一,它启动了一个 HTTP 服务器,默认监听本机的一个固定端口,所有推理请求都通过这个端口进来。第二,它维护一个模型池,收到请求时先看模型在不在池子里,在就直接用,不在就加载——这就是为什么第一次调用特别慢。第三,它会根据你的硬件自动决定把多少层放到 GPU,剩余部分放内存,这个决策是启发式的,不总是最优,遇到明显的性能问题可能需要手动干预。
服务起来之后,先做一个连通性测试:查一下模型列表接口,看返回的 JSON 里有没有你刚拉的那个模型。这一步验证了两件事——服务在监听,且能读到模型目录。如果列表是空的,说明模型目录配置错了,或者模型没拉成功。这一步看起来简单,但我见过很多人跳过它直接去配插件,结果在插件里折腾一小时才发现服务根本没起来。
关于要不要开远程访问,我的建议是能不开就不开。默认只监听本机回环地址,这是安全的默认值。如果你确实需要局域网内其他设备访问(比如台式机跑模型、笔记本连过去用),才改成监听所有地址,并且一定要配合防火墙规则限制来源。这类服务没有任何认证机制,一旦暴露在公开网络上,等于把你的机器变成一个任人调用的推理端点,风险和收益完全不对等。
3.2 Modelfile 定制:上下文长度才是真正的体验分水岭
这是我在这条链路上花时间最多、收益也最大的部分。默认参数的模型用起来总有一种"笨笨的"感觉——你让它改一个函数,它改着改着就把前面的代码忘了;你贴进去三个文件让它对比,它只记得最后一个。这不是模型能力问题,是上下文长度被截断了。默认上下文往往只有 2K 到 4K token,换算成代码大概就是一两百行,稍微复杂点的文件就装不下。
定制方式是用 Modelfile 定义一个派生模型。基本结构是这样的:
FROM deepseek-r1:7b PARAMETER num_ctx 16384 PARAMETER temperature 0.2 PARAMETER top_p 0.9 PARAMETER repeat_penalty 1.1 PARAMETER num_predict 2048 SYSTEM """ 你是一个严谨的编程助手。回答时优先给出可直接运行的代码, 避免不必要的解释。不确定的地方明确说明不确定,不要编造 API。 """num_ctx是核心,它决定上下文窗口大小。设成 16384 意味着能装下大约 800 到 1200 行代码(取决于代码密度)。但要注意,这个值直接决定 KV Cache 大小,前面算过 8K 上下文 7B 模型约 1GB,16K 就是 2GB。所以设多大要看你的显存余量,不要盲目拉满,显存不够会导致推理直接失败或者疯狂换页,速度掉到不可用。
temperature对代码场景我一般设 0.1 到 0.3。补全和改代码需要确定性,温度高了它会给你一些"有创意但跑不通"的写法。repeat_penalty设 1.1 左右能缓解重复输出,但设太高会让它不敢用重复的变量名,反而奇怪。num_predict是单次最大输出长度,设 2048 够用,设太大在遇到失控输出时会白等很久。
SYSTEM提示词这块值得认真写。我用下来最有效的三条约束是:要求给可运行代码、要求不确定时明说、要求不要重复我的问题。第三条听起来很傻,但很多模型默认会先复述一遍你的需求再回答,白白浪费几百个 token 的生成时间,在编辑器里这个延迟体感很明显。
建好 Modelfile 之后用创建命令生成派生模型,起个带版本号的名字方便回滚,比如local-coder:v1。以后调参数就新建一个 v2,别覆盖 v1,出问题能立刻切回去。这个习惯救过我一次——某次调num_ctx调过头导致显存溢出,直接切回 v1 就恢复了,不用重新排查。
3.3 接口连通性验证:学会用命令行直接打
这一步是分水岭。会用命令行打接口的人,排障时间大概是不会的人的十分之一。因为你可以明确知道:服务端返回了什么、延迟多少、是不是流式、错误信息是什么。而只在插件里点按钮的人,永远只能看到一个"请求失败",然后开始瞎猜。
先测原生接口,查模型列表:
curl -s http://127.0.0.1:11434/api/tags | head -c 500能看到 JSON 里的模型名和大小就说明服务和模型目录都正常。再测一次实际推理,用原生生成接口:
curl -s http://127.0.0.1:11434/api/generate -d '{ "model": "local-coder:v1", "prompt": "用一句话解释什么是闭包", "stream": false }'如果这一步能返回内容,服务端就彻底没问题了。接着测 OpenAI 兼容接口,因为大部分插件走的是这个:
curl -s http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "local-coder:v1", "messages": [{"role": "user", "content": "说一句你好"}], "stream": false }'注意这里的路径是/v1/chat/completions,模型名要用你本地实际存在的名字。这一步失败但上一步成功,说明是接口格式或模型名映射的问题,插件里配的apiBase要写到端口为止,不要自己拼/v1——有些插件会自动补,重复拼就 404 了。这个坑我踩过,配了半天一直 404,最后发现是地址多写了一段。
再补一个测延迟的小技巧:加-w "\n总耗时: %{time_total}s\n"到 curl 命令末尾,能直接看到整次请求花了多久。冷启动和热启动的差距会吓你一跳,这也是为什么我强调要把KEEP_ALIVE调长。
3.4 端口规划与多服务共存
当你同时跑补全模型和对话模型时,会面临一个选择:是一个服务加载两个模型,还是起两个服务各管一个。我倾向于前者,因为一个服务内部会做模型调度,切换成本低。但如果你用的是不同的运行时(比如补全用轻量方案、对话用主方案),那就得规划端口,避免冲突。
我的端口规划习惯是这样:主服务占11434,备用或实验性服务占11435、11436,往上递增。每个端口对应一个明确的用途,写在笔记里。这样半年后回来看,一眼就知道哪个是干什么的。千万不要随手改端口然后不记录,下次排障时会浪费大量时间在"到底哪个端口是对的"上。
另外提一句并发。默认并发数是 1,意味着补全请求和对话请求会排队。你在编辑器里打字触发补全的同时,如果对话窗口正在生成回复,补全就会卡住,体感很差。把并发数设成 2 能解决这个问题,但要注意显存——两个请求同时跑,KV Cache 是翻倍的。7B 模型 8K 上下文,单请求 KV 约 1GB,双并发就是 2GB,加上权重 4.5GB,8GB 显存就很紧张了。这种情况我会把补全模型的上下文压到 2K,把省下来的显存让给对话模型。
4. VS Code 接入:让编辑器真正用起来
前端接入这块,插件生态变化很快,我不打算推荐某一个具体插件,而是讲清楚两类插件的本质区别和配置的通用逻辑,这样不管以后用什么插件,你都能自己看明白配置文件在写什么。这一点很重要,因为我见过太多人只会复制别人的配置,一旦模型名或者端口变了就完全不知道改哪里。
两类插件的区别是根本性的。补全型插件在你不主动触发的时候也会工作——你打字,它预测下一段,这类插件对延迟极度敏感,必须用小模型、短上下文、常驻显存。对话型插件需要你主动发起,可以接受几秒等待,但要能读多个文件、理解项目结构,需要大模型、长上下文。很多插件两类功能都有,但配置里是分开的两套模型设置,一定要分别配,别指望一个模型全包。
4.1 配置文件的通用结构:读懂它比复制它有用
大多数现代编辑器 AI 插件的配置文件都是 YAML 或 JSON,结构大同小异:一个models数组,每项描述一个模型的连接方式;一个context数组,描述要把哪些信息塞进提示词;还有一些全局选项控制界面行为。看懂这个结构,你就能自己改。
关键字段通常包括:provider(说明用哪种协议对接,选本地运行时对应的那个)、model(本地实际的模型名,必须和服务里列出的一致)、apiBase(服务地址,写到端口)、roles(这个模型承担什么角色,是 chat、edit 还是 autocomplete)、以及一组推理参数。这里最容易错的是model字段——服务里的模型名可能带 tag,比如local-coder:v1,你写成local-coder就找不到。另一个易错点是apiBase末尾要不要带斜杠、要不要带/v1,不同插件行为不同,建议先用最小配置跑通再加东西。
roles这个字段值得单独说。它决定了插件在什么场景下调用这个模型。如果你把一个模型同时标成chat和autocomplete,那补全和对话会抢同一个模型实例,配合并发数为 1 的服务,就会出现互相阻塞。正确做法是补全模型只标autocomplete,对话模型只标chat和edit,让它们各司其职。
4.2 一份可以直接抄的配置模板
下面这份配置是我目前在用的结构,两个模型分工,参数经过实测调整。你可以直接拿去改模型名和端口:
name: local-setup version: 1.0.0 schema: v1 models: - name: 本地对话 provider: ollama model: local-coder:v1 apiBase: http://127.0.0.1:11434 roles: - chat - edit defaultCompletionOptions: contextLength: 16384 maxTokens: 2048 temperature: 0.2 topP: 0.9 - name: 本地补全 provider: ollama model: tiny-coder:latest apiBase: http://127.0.0.1:11434 roles: - autocomplete defaultCompletionOptions: contextLength: 2048 maxTokens: 128 temperature: 0.05 topP: 0.8 context: - provider: code - provider: diff - provider: terminal - provider: problems - provider: folder几个参数的选择理由我说明一下。对话模型的contextLength设 16384,是因为要能同时装下当前文件、相关文件和对话历史;maxTokens设 2048,够生成一个完整函数;temperature0.2,代码场景要确定性。补全模型这边激进得多:contextLength只给 2048,因为补全只需要看光标附近的代码;maxTokens只给 128,因为补全本来就是短输出,给多了反而会让模型"想太多";temperature压到 0.05,几乎完全确定,保证同样的上下文给出同样的补全,不然你会觉得它在乱抖。
context那段决定了插件会往提示词里塞什么。code是当前文件的相关片段,diff是未提交的改动,terminal是终端输出,problems是编辑器报的错。这几个里我建议必备code和problems——后者特别有用,你把光标放在报错行上提问,插件会自动带上错误信息,回答准确率高很多。codebase这类全项目索引的选项要谨慎开,它会在后台建索引,占 CPU 和磁盘,小项目反而不划算。
4.3 参数调优:三个立竿见影的调整
配置跑通之后,如果体验还是不够好,先调这三个参数,收益最明显。
第一是补全的防抖延迟。大多数补全插件有个"停止输入多久后才触发"的设置,默认值往往偏短,导致你每敲一个字符就发一次请求,服务端排队排到爆。我一般设 300 到 500 毫秒,也就是你停手思考的那一下才触发。这个调整能让补全的命中率和响应速度同时提升,因为请求量下来了,每个请求都能及时得到处理。
第二是超时时间。默认超时常常只有 10 到 20 秒,但你第一次调用要加载模型,或者上下文特别长的时候,很容易超时。设成 60 秒比较稳妥。同时要注意,有些插件把"首字超时"和"总超时"分开设置,前者管多久没开始返回就放弃,后者管整个请求。首字超时设太短会误杀冷启动,设太长又会在服务真挂掉的时候让你干等,30 秒左右是个平衡点。
第三是上下文的组织策略。如果插件支持选"带上哪些文件",别贪多。塞五个文件进去,每个都被截断,效果远不如塞一个完整文件加一个相关片段。我实操下来的经验是:上下文总长度控制在模型窗口的 70% 以内,留出空间给模型生成,也留出余量防止溢出。塞满 100% 会导致生成阶段被强行截断,输出在半句话上戛然而止。
4.4 双模型分工的实操价值
单独说一下双模型配置为什么值得折腾。我最初的配置是单模型全包,结果就是:用 7B 做补全,每次触发要 800 毫秒到 1.5 秒,打字体验极差;用 1.5B 做对话,问复杂点的问题它就开始胡说。两头都不满意。
拆成两个之后,体验是质变。补全用 1.5B 到 3B 的模型,contextLength压到 2048,实测首 token 延迟能到 100 到 200 毫秒,快到你几乎感觉不到等待,它就已经把后半行补出来了。对话用 7B 到 14B,可以慢慢想,回答质量也够看。显存上,小模型占 1.5GB 左右,大模型占 5 到 9GB,8GB 显存刚好卡在能跑小模型加 7B 模型 Q4 的边缘,12GB 就从容很多。
这里有个工程上的小技巧:把补全模型的KEEP_ALIVE设得比对话模型长。因为补全调用频次高但单次很短,卸载后重新加载的代价特别明显;对话调用频次低,偶尔冷启动可以接受。如果服务支持按模型设置的话,就分开设;不支持的话,全局设一个偏长的值,接受显存常驻。
5. 排障实录:那些让人抓狂的瞬间
排障这部分我按"症状"来组织,而不是按"原因",因为实际出问题的时候,你手里只有症状。我在笔记里记了二十多条,挑最高频的几类展开。每一类我会给出判断路径:先验证什么、再验证什么、怎么快速定位。这套方法让我现在遇到新问题基本能在十分钟内定位,而不是像最开始那样重装系统级别的折腾。
核心思路是一条:从服务端往客户端排,不要反过来。先用 curl 确认服务端能正常推理,再确认网络能通,最后才去查插件配置。反过来做的话,你会在插件的一堆配置项里迷失,而真正的问题可能只是服务没起来。
5.1 速度问题:从每秒几个 token 到流畅交互
症状一:首字延迟极长,要等十几秒才开始出字。这几乎一定是冷启动——模型不在显存里,正在加载。验证方法很简单,连续发两次同样的请求,如果第二次明显快,就是冷启动。解法是调长KEEP_ALIVE,或者干脆保持一个常驻请求定期唤醒。
症状二:出字速度只有每秒一两个 token,像蜗牛。这说明模型在 CPU 上跑,或者大量层被卸载到 CPU。用nvidia-smi看推理时 GPU 利用率,如果显存占用很低但 CPU 占用很高,那就是没吃到 GPU。原因可能是驱动不匹配、运行时不认识你的显卡、或者模型太大显存放不下。前两个更新驱动和运行时,第三个要换更小的量化档位。
症状三:跑着跑着突然变慢,之前很快。这通常是显存溢出触发换页,或者系统在压缩内存。检查一下是不是同时开了浏览器、IDE、其他吃显存的程序。我遇到过一次是浏览器开了几十个标签页,显存被吃了 1.5GB,导致模型被迫分层。关掉之后立刻恢复。
症状四:多请求同时来的时候全部卡住。并发数设的是 1,请求在排队。调大NUM_PARALLEL,但要算好显存账。如果显存不够,更好的方案是把补全请求的上下文压小,让两个请求的总占用落在显存范围内。
5.2 连接问题:插件连不上服务的五种可能
第一种,服务没起来。最常见。用curl打一下模型列表接口,没响应就是服务问题。重启服务,看日志里有没有报错。
第二种,端口不对。服务监听的是 11434,插件里写的是 8080,或者反过来。核对一下,这是纯粗心问题但发生频率极高。
第三种,地址格式不对。apiBase写成了带/v1的完整路径,插件自己又补了一次,变成/v1/v1/chat/completions。解法是先只写到端口,跑不通再试着补路径,别一次写全。
第四种,模型名不匹配。插件里写deepseek,服务里的实际名字是local-coder:v1。用列表接口查准确名字,一个字一个字对。冒号、横杠、版本号都不能错。
第五种,网络策略拦截。某些环境会把本地回环地址之外的请求拦掉,或者有安全软件在监控本地端口。这种情况下curl也会失败,需要看系统日志。
注意:排连接问题时,先把插件的日志级别调到最详细。很多插件默认不打印请求详情,你只能看到"失败",开了详细日志就能看到完整的 URL 和错误码,问题往往一眼就看出来了。
5.3 输出质量问题:不是模型不行,是喂得不对
症状:回答总是很短,说一半就没了。检查maxTokens和num_predict,可能设得太小。另外检查是不是上下文塞太满导致生成空间被挤占。
症状:回答开始胡编 API,函数名都是假的。这种情况模型能力确实不够,7B 在冷门库上容易编。解法有两个:换更大的模型,或者在提示词里明确要求"只使用上下文中出现过的 API"。后者的效果比想象中好,因为模型有很强的指令跟随倾向。
症状:同样的输入,输出质量忽高忽低。温度设太高了。代码场景压到 0.1 到 0.2,还有一点随机性但不会乱来。
症状:改代码改着改着把原来的逻辑删了。上下文不够,模型看不到完整文件。把contextLength调大,或者缩小喂进去的文件范围,只给相关部分。宁可给它一个完整的小文件,也别给五个被截断的大文件。
症状:中文回答里夹杂英文术语,看着别扭。系统提示词里明确语言要求。"用中文回答,代码和专有名词保留英文",这一句能解决大部分问题。
5.4 常见问题速查表
| 症状 | 最可能原因 | 快速验证 | 处理 |
|---|---|---|---|
| 首次调用等十几秒 | 模型冷启动 | 连发两次对比 | 调长KEEP_ALIVE |
| 每秒只有 1 到 2 token | 跑在 CPU 上 | 看 GPU 利用率 | 换小量化档或修驱动 |
| 插件一直转圈 | 服务未启动或端口错 | curl 打接口 | 核对端口和地址 |
| 请求返回 404 | 地址路径重复拼接 | 看插件日志的完整 URL | 只写到端口 |
| 找不到模型 | 模型名带 tag 未写全 | 查模型列表接口 | 补全 tag |
| 显存溢出报错 | 上下文开太大 | 看显存峰值 | 降num_ctx或开 KV 量化 |
| 输出突然截断 | maxTokens太小 | 看输出结尾 | 增大生成上限 |
| 补全和对话互相卡 | 并发数为 1 | 同时触发观察 | 调大并发或压小上下文 |
| 输出重复啰嗦 | 重复惩罚过低 | 观察重复模式 | repeat_penalty调到 1.1 |
| 加载模型报格式错误 | 下载不完整 | 重新校验文件 | 删除重拉 |
这张表我建议存下来。实际出问题的时候按行扫一遍,比从零开始想要快得多。
6. 长期维护与个人心得
这条路跑通之后不是就完事了,日常维护比搭建更考验耐心。模型会更新、插件会升级、系统会变动,某天忽然就用不了了是常态。我的做法是把所有配置都放在一个固定目录里,用版本控制管起来,每次改动都留记录。这样出问题的时候能快速回滚,也能清楚知道上次改了什么。
另外一个心得是不要频繁追新。新模型出来就想试是人之常情,但每次都重新调参数、重新适配,时间成本很高。我现在只在新模型明显解决了我当前痛点的时候才换,比如上下文窗口翻倍、或者某个能力明显提升。日常用着顺手的配置,就让它稳定跑着。
6.1 我踩过的几个印象深刻的坑
第一个坑是以为装完就能用。第一次搭的时候装完运行时,拉了个 7B 模型,兴冲冲去配插件,结果一直连不上。折腾了四十分钟才发现服务根本没启动——安装程序只装了二进制,没注册成服务,得手动起。这个教训让我养成了"每次都先用 curl 验证"的习惯。
第二个坑是上下文长度没改。用默认配置跑了两周,一直觉得"本地模型果然不行,连个稍微长点的函数都改不好"。后来偶然看了一眼配置,发现上下文只有 2K。改到 16K 之后完全是两个模型。这件事让我意识到,很多"模型不行"的判断,其实是配置不到位。
第三个坑是双模型抢显存。配了两个模型之后,补全和对话同时用,频繁报显存不足。原因是两个模型都按默认参数加载,加起来超过显存。后来把补全模型的上下文压到 2K、量化档位降到 Q4,就稳了。教训是:多模型共存时,显存要按"总峰值"算,不是按单个算。
第四个坑是盲目上大模型。有一阵子非要跑 32B,结果量化档位被迫降到 Q3,质量反而不如 14B 的 Q4,速度还慢一倍。这件事让我明白:参数量和量化档位是个乘积关系,不是单调递增。在显存固定的前提下,找一个平衡点比追最大参数量重要得多。
6.2 日常维护的几条实用建议
把配置目录纳入版本控制。模型文件太大不适合进版本库,但 Modelfile、插件配置、环境变量脚本都可以。我建了个私有的小仓库,每次改配置就提交一次,commit message 写清楚改了什么、为什么改。半年后回头看,能清楚知道自己当初的参数是怎么试出来的。
定期清理不用的模型。每个模型几个 G,攒着攒着磁盘就红了。我一般每月清一次,超过一个月没用过的就删掉,需要的时候再拉。删之前记一下名字,别删完忘了原来用的是哪个。
留意显存泄露。长时间运行之后,偶尔会出现显存占用只增不减的情况,最后新模型加载不进来。这时候重启服务就能解决。如果你发现跑了几天之后开始变慢,先重启一次再排查其他原因。
给需要长期使用的模型打固定 tag。别用latest这种会变的标签,用v1、v2这种明确的版本号。上游更新了模型文件之后,latest会指向新版本,你的体验可能一夜之间变化,而固定 tag 不会。这个习惯能避免很多"明明什么都没改怎么就不一样了"的困惑。
最后分享一个小技巧。我会给每个常用的模型写一行简短的用途备注,放在一个文本文件里,比如"小模型:补全,2K 上下文,常驻""主模型:对话,16K,Q4,温度 0.2"。听起来很土,但当你有了五个模型、三个服务、若干份插件配置之后,这份备注能省下大量回忆时间。本地部署这件事,靠的不是一次性的技术能力,而是长期把配置管清楚的习惯。
我个人在实际操作中的体会是,这条链路真正的门槛不在技术,而在预期管理。本地 7B 模型的质量确实比不上云端旗舰,但它稳定、免费、数据不外流,在你每天高频使用编辑器辅助这个场景里,综合体验未必更差。把参数调对、把分工配好、把排障方法学会,它能成为一个相当可靠的日常工具。反过来,如果指望它一次配好就完美运行,那大概率会失望。慢慢调,边用边改,这才是本地部署的正常节奏。