1. 别急着调参:先搞清楚你遇到的是哪种"卡顿"
上个月我把 Roo Code 接到本地 Qwen2.5-Coder 14B 上,第一反应是这组合根本没法用:发一句话,转圈二十秒才蹦出第一个字,后面的输出还断断续续,界面偶尔直接白屏。当时我差点把 Ollama 卸了换回云端 API,后来冷静下来,把"卡顿"这件事拆开一层层测,才发现真正的问题比我想象的复杂,也比我想象的简单。这篇就把整个排查和调优过程原原本本写出来,目标是让本地模型在 Roo Code 里恢复到接近原生速度——也就是直接敲终端问模型时的那种响应节奏。
1.1 卡顿其实分三层,别一上来就骂模型
很多人遇到卡顿就归结为"本地模型不行",但"卡顿"至少有三层来源,不区分清楚,调优就是瞎撞。
- 模型推理慢。这是算力问题,表现为每秒生成 token 数(tokens/s)低,遇到大段 prompt 时首 token 时间(TTFT)特别长。模型量化太大、显存没吃满、甚至模型根本没跑在 GPU 上,都会导致这一层慢。
- 接口往返慢。这是链路问题。Roo Code 每次请求都要重新组装对话历史、做 token 统计、走 HTTP 调用、再解析流式响应,任何一个环节拖沓都会放大延迟。而且它不像云端服务有服务端缓存,每一步都是全量重算。
- 界面渲染慢。这是本地 UI 问题。Roo Code 的聊天面板是 Webview 渲染的,历史消息一多,流式输出每来一个 token 都要刷新视图,帧率跟不上就会觉得"卡",甚至操作按钮都点不动。
区分方法很简单:绕开 Roo Code,先用终端或 curl 直接问同一个模型。如果直接用也慢,那问题在模型侧;如果直接用很快、进了 Roo Code 就慢,那问题在链路或 UI 侧。我见过太多人卡了一整天,最后发现模型直接调用快得很,纯属 Roo Code 的上下文管理出了问题。
1.2 先做一次"裸测",给模型速度划线
我每次调优之前必做的第一件事,是给模型建一个"裸测基准"。两条命令就够:
time ollama run qwen2.5-coder:14b "用 Python 写一个快速排序" ollama ps第一条测真实生成速度,第二条看模型当前跑在什么设备上。ollama ps输出里的 PROCESSOR 列,如果显示100% GPU,说明模型在显卡里跑,速度有保障;如果出现xx% CPU,说明显存放不下、部分层被挤回 CPU,速度会骤降。
想要更精确的 TTFT 数据,可以用 curl 测:
curl -s http://localhost:11434/api/chat \ -d '{"model":"qwen2.5-coder:14b","messages":[{"role":"user","content":"数一下从 1 到 100"}],"stream":true,"options":{"num_ctx":8192}}' \ -w "\nTTFT=%{time_starttransfer}s Total=%{time_total}s\n"我当时的裸测结果:TTFT 两秒以内,生成速度 30 tokens/s 上下。这说明机器本身没问题,后续在 Roo Code 里感受到的卡顿,十有八九是配置和用法问题。
1.3 我踩的第一个坑:上下文膨胀
裸测很快,回到 Roo Code 还是卡。后来我打开 Roo Code 里每轮请求的 token 统计,发现连续跑了十几个步骤之后,一次请求的 prompt 已经膨到四万 token 以上。Transformer 的 prefill 阶段是同步全量计算的,prompt 每多一万 token,首 token 时间就明显拉长。Roo Code 的机制决定了它每一步都会把系统提示词加完整历史重发给模型,历史越长,每一步越慢。
这个坑不是 Roo Code 独有的,而是"对话式编码助手 + 本地模型"组合的共同宿命。云端模型有服务端的 KV cache 和各种优化,几十万上下文也能扛,本地模型没这个待遇,每增加一段历史都是实打实的算力开销。想通这一点之后,我把调优分成了两条线:先把模型的裸速度跑上去,再把 Roo Code 每次请求的体积压下来。下面按这个顺序讲。
2. 模型侧调优:先让"裸速度"达标
2.1 量化版本和模型大小怎么选
本地模型要跑得动,第一步是选对量化格式。GGUF 量化里,Q4_K_M 和 Q5_K_M 是编码场景公认的性价比之选,显存占用小、质量损失不明显;Q8 质量略好但显存占用高不少;FP16 除非显存特别充裕,否则不要在编码场景用——同样的硬件,量化版本通常能快百分之二三十。
模型大小的选择直接看显存:8~12GB 显存用 7B/8B,16~24GB 用 14B,32B 级别的模型至少需要 24GB 显存还要配高速内存。Roo Code 干的是"读代码、定位问题、生成改动"这种复合任务,模型太小(比如 3B)会经常答非所问,反复返工反而更慢。我的经验是,至少 14B 才能流畅处理真实的仓库级任务,7B 只能用来做方案讨论和简单重构。
拉模型时别只写ollama pull qwen2.5-coder:14b就完事,显存紧张的话可以精确指定量化标签,比如qwen2.5-coder:14b-instruct-q4_K_M,避免拉到体积更大或与预期不符的版本。这一步省下来的显存,后面可以用来开更大的上下文窗口。
2.2 Ollama 的三个关键参数,改了就能见效
Ollama 有默认参数对 Roo Code 这种场景特别不友好,我列成一张表:
| 参数 | 默认行为 | 建议值 | 原因 |
|---|---|---|---|
| num_ctx | 2048 或 4096 | 8192~32768 | Roo Code 的请求轻松破千 token,窗口太小会静默截断上下文,模型直接"失忆" |
| keep_alive | 5 分钟 | -1 或 30m | 空闲 5 分钟后模型被卸载,下次请求要重新加载,冷启动卡十秒以上 |
| OLLAMA_NUM_PARALLEL | 按显存自动 | 1 | 单用户手动点发送不需要并发,避免为并行请求拆分 KV cache 拖慢首 token |
num_ctx的坑最隐蔽。默认 2048 的窗口装不下 Roo Code 的系统提示词加对话历史,超出部分被静默丢弃,模型就开始"忘事",你以为是它变笨了,其实是窗口太小。
修改方式有两种。一是写 Modelfile 生成一个带参数的模型别名:
FROM qwen2.5-coder:14b PARAMETER num_ctx 32768 PARAMETER temperature 0.2ollama create qwen2.5-coder-32k -f Modelfile ollama run qwen2.5-coder-32k二是设置环境变量OLLAMA_CONTEXT_LENGTH=32768后重启ollama serve,这会改变默认上下文长度。需要注意,上下文不是越大越好,prefill 时间随窗口长度近似线性增长,编码任务 16k~32k 完全够用,硬开到 128k 反而每一步都慢。
提示:Roo Code 设置里的 context window 一定要和 Ollama 的 num_ctx 对齐,否则 Roo Code 会在错误的时机触发历史压缩,信息丢得莫名其妙。
keep_alive建议直接设-1,让模型常驻显存。代价是显存一直被占着,但换来的是随时发消息都秒回。OLLAMA_NUM_PARALLEL设成 1,针对的就是"一个人手动点发送"的使用方式,没必要让模型同时处理一堆请求,那只会让单个请求变慢。
2.3 检查 GPU 卸载,别让模型偷偷跑 CPU
我见过很多"都按教程优化了还是卡"的情况,最后发现模型根本不在 GPU 上。ollama ps里 PROCESSOR 列如果显示100% CPU,那 14B 模型的生成速度可能只有个位数 tokens/s,怎么调 Roo Code 都没用。
Windows 上最常见的原因:显卡驱动没装好或版本太老。先跑nvidia-smi确认系统能识别 GPU;Apple Silicon 机器正常会走 Metal 加速;Linux 则要确认 Ollama 安装时带上了 CUDA runtime。
还有一类情况是显存不够。模型太大、上下文开太大,都会让 KV cache 占掉大量显存,导致部分层被挤回 CPU。这时候要么换更小量化,要么调低 num_ctx,要么换更小模型。别指望用OLLAMA_GPU_LAYERS=99硬塞,显存放不下时底层照样回退到 CPU,速度立刻掉一个量级。
2.4 进阶开关:Flash Attention 和 KV cache 量化
Ollama 0.5.7 之后支持两个能直接提速的环境变量:
OLLAMA_FLASH_ATTENTION=1:开启 Flash Attention,加速长 prompt 的 prefill,减少显存占用。OLLAMA_KV_CACHE_TYPE=q8_0:把 KV cache 量化到 8bit 精度,进一步省显存,有时反而因为"省出来的显存让更多层留在 GPU"而整体提速。
这两个变量要在启动 Ollama 之前设置好,改完重启服务生效。我的 12GB 显存机器上,这两个开关配合 32k 上下文,14B 模型能稳定跑满全 GPU,响应速度和显存占用都明显改善。老版本 Ollama 不识别这些变量,升级到最新版再试。
3. Roo Code 侧的配置:把"对话开销"降下来
3.1 API 端点和模型名的细节坑
Roo Code 接 Ollama 有两种接法:选 Ollama 提供商,base URL 填http://localhost:11434;或者选 OpenAI Compatible,base URL 填http://localhost:11434/v1。我实测下来,Ollama 版本较新时两种都能用,但 OpenAI Compatible 模式在 token 统计上更稳,Roo Code 能看到每轮请求的实际 usage 数据,诊断问题时方便很多。
如果你用的是 LM Studio,端口是 1234,填http://localhost:1234/v1,道理一样。
模型名必须和ollama list里的 tag 完全一致。Roo Code 有时会自动拉模型列表,但手动填的时候别只写qwen2.5-coder,要用qwen2.5-coder:14b-instruct-q4_K_M这种完整形式,否则可能匹配不到。请求超时也要检查,默认值对大模型的 prefill 阶段太短,我直接设成 300000 毫秒,避免跑大任务时被中途掐断。
3.2 上下文窗口、任务切分与规则文件
Roo Code 设置里的 context window 配置要和 Ollama 的 num_ctx 对齐。Roo Code 会在接近上限时自动压缩历史,如果两边数值对不上,压缩时机就会失控,有时上下文还没到一半就被压缩,关键信息凭空消失。
但说实话,最有效的手段不是调窗口,而是"及时开新会话"。我现在的做法是:把任务拆成功能点,做完一个就/newtask开新会话,上一个功能的代码先提交到 git,新任务只带需求和约束。这一个习惯比任何参数优化都管用,因为它是从源头把 prompt 体积压住,而不是等它膨胀了再去压缩。
另外,.clinerules不是写得越多越好。这些规则会作为系统提示词的一部分,每次请求都跟着发送,写一长串等于给自己增加 every-step 的 prefill 负担。我的规则文件控制在八行以内,只写项目级硬约束,比如"用 TypeScript""函数尽量短""改完必须跑测试"。
3.3 减少文件读入和渲染开销
Roo Code 在执行任务时会主动读文件,文件越多越大,prompt 越膨胀。日常项目里node_modules、dist、.git这些目录完全没必要让模型看。我在 VS Code 的设置里加了这几行:
"files.watcherExclude": { "**/.git/**": true, "**/node_modules/**": true, "**/dist/**": true }, "search.followSymlinks": false这组配置能减少 VS Code 的文件监听和搜索开销,Roo Code 读写文件时,整个编辑器的 UI 响应会顺很多。
超大文件是另一个隐形杀手。几百 KB 以上的文件,Roo Code 会截断读取,还会拖慢 token 统计和 Diff 渲染。平时注意把大文件拆成小模块,让模型的上下文花在真正重要的代码上,而不是浪费在一整段祖传配置里。
3.4 流式输出和权限确认的取舍
流式输出一定要开着,关了它你会觉得"发一条消息要等几十秒",体验直接回到远古时代。如果流式输出时打字都卡,那是 Webview 渲染压力大,试着折叠历史消息、减少同时打开的标签页,必要时重启 VS Code 窗口释放 Webview 内存。
权限确认也是吞时间的隐形大户。Roo Code 每执行一个写文件、跑命令的步骤都要等你点确认,人工反应时间经常比模型生成还长。我个人的做法是:把"读取文件"设为始终允许,"写文件"和"执行命令"保留确认。这样既保住安全性,又不会每一步都打断节奏。你要是追求极致的连贯性,可以把写文件也加入自动允许,但务必确认项目有 git 兜底。
4. 那些藏在"等待"里的隐形杀手
4.1 模型卸载与冷启动:时快时慢的真凶
Ollama 默认空闲 5 分钟就把模型从显存里卸掉。你喝杯水回来再发消息,Roo Code 会先等模型重新加载,一张 9GB 的模型从磁盘读进显存少说几秒,机械硬盘能到半分钟。这就是"有时候卡、有时候不卡"的典型原因,纯属冷启动。
OLLAMA_KEEP_ALIVE=-1能根治,代价是显存一直被占着。对一台专门用来跑本地模型的工作机来说,这个代价完全值得。设置方法是在启动 Ollama 前配置环境变量,Windows 可以在系统环境变量里加,macOS 和 Linux 可以写进启动脚本。
4.2 本地回环访问的偶发延迟
Roo Code 和 Ollama 都在本机,走 localhost 按理说没有网络延迟,但 Windows 下偶尔会出现首次连接卡五到十秒甚至超时的情况。这种多半是防火墙拦截规则或安全软件在检查本地回环流量导致的。
遇到这种症状,先在命令行跑:
curl http://localhost:11434/api/tags如果这条命令本身要等好几秒才返回,问题就出在系统网络层面,跟模型和 Roo Code 都没关系。处理方向是检查防火墙和安全软件里有没有屏蔽本机回环连接的规则,把 Ollama 监听的端口放行即可。另外我更推荐 Roo Code 和 Ollama 跑在同一台机器上,如果通过远程开发连到一台没有显卡的机器、再跨网络调用另一台机器的本地模型,延迟会明显叠加,怎么优化都救不回来。
4.3 磁盘 IO 与多模型并存的地雷
模型文件放在 SSD 上是底线。一张 9GB 的 Q4 量化模型,从 NVMe 加载到显存大概几秒,从机械硬盘能拉到半分钟以上。如果OLLAMA_MODELS目录还留在老硬盘上,每次冷启动都是煎熬。
多模型并存是另一个容易忽略的情况。有些人 Ollama 里装了一堆模型,来回切换测试,结果每个都占一部分显存,系统为了腾地方反复卸载重载,速度自然好不了。ollama ps随时能看到当前加载了哪些模型,养成"只保留一个主力模型常驻"的习惯很重要。
5. 实测对比:同一任务的三轮优化记录
5.1 测试环境与任务
怕空口无凭,我拿一个真实任务做了完整记录。环境是 Win11 + i7-13700 + RTX 4070 12GB + 32GB 内存,Ollama 0.6.x,模型 qwen2.5-coder:14b-instruct-q4_K_M,Roo Code 3.x。任务给一个现成的 Express 项目加 JWT 登录鉴权中间件,包含单元测试和说明文档。
我记录三个指标:首 token 时间(TTFT)、生成速度(tokens/s)、全程总耗时。全程总耗时包含 Roo Code 读文件、生成代码、写文件、跑测试的完整流程,而不仅仅是模型生成时间。
5.2 逐阶段调优的数据
按调整顺序记录如下:
| 阶段 | TTFT | 生成速度 | 全程耗时 | 备注 |
|---|---|---|---|---|
| 初始配置 | 20~30 秒 | 6~10 t/s | 约 8 分钟 | 上下文 40k+,中途超时一次 |
| 只调 Ollama 参数 | 4~6 秒 | 28~35 t/s | 约 3 分半 | num_ctx 32k,模型常驻,并行请求降为 1 |
| 加 Roo Code 配置 | 2~3 秒 | 35~40 t/s | 约 1 分 40 秒 | 新会话、精简规则、超时放宽 |
| 换使用习惯 | 1~2 秒 | 35~40 t/s | 约 1 分 10 秒 | 不再让模型通读全仓库 |
最值得琢磨的是第一阶段到第二阶段:模型完全没换,只改了 Ollama 的运行参数,TTFT 从二三十秒掉到四五秒,生成速度翻了四倍。这说明初始卡顿的大头根本不是"本地模型跑不动",而是显存没吃满、上下文失控、模型被反复卸载这些配置问题。
5.3 数据背后的结论
从数据能看出一个规律:优化次序比参数本身重要。先把模型裸速度测出来,再调 Ollama 的运行参数,最后才动 Roo Code 的配置和用法。如果一上来就怀疑 Roo Code 有 bug 或者想着直接换模型,方向就反了。
所谓"原生速度",其实是可以逼近的。Roo Code 本质上只是把请求拼好发给模型,任何额外延迟都来自请求体积、token 统计、UI 渲染和人工确认这几块。把这几块压到最小,本地模型在 Roo Code 里的响应节奏就和直接在终端问模型几乎一样了。
6. 提速之后要养成的使用习惯
6.1 及时开新会话,别让上下文无限膨胀
这条值得单独拿出来再说一遍。我见过很多人一个 Roo Code 会话跑了两三个小时不关,上下文早就超过模型窗口,每一步都在做超长 prefill,每一步都慢,最后得出结论"本地模型不行"。
其实只要把任务拆小,做完一个功能就开新会话,本地模型和云端模型的差距会小很多。Git 提交是天然的会话分隔点,每提交一次,就/newtask一次。别舍不得历史记录,代码已经进了 git,对话历史本身不值钱,模型的上限才值钱。
6.2 让不同模式各用各的模型
Roo Code 的 Plan 和 Build 模式可以分开指定模型。我现在 Plan 模式用 7B 小模型,速度快,出方案足够;Build 模式切回 14B 认真改代码。这样避免"只想让它列个步骤"时也要等大模型慢慢推理。
如果你硬要在 12GB 显存以下的机器上跑 32B 模型,我很诚实地劝一句:大概率会卡到你想放弃。本地模型最重要的不是"能跑",而是"跑得稳",性能边界外的尝试只会浪费调试时间。先把手头模型的性能吃满,再考虑加钱上硬件。
6.3 一张我每次排查都会过的检查清单
最后把整个排查过程压缩成一份清单,照着过一遍,基本能解决九成以上的卡顿问题:
ollama ps确认模型 100% 在 GPU,而不是 CPUollama run裸测,TTFT 超过 3 秒先查硬件和量化- Modelfile 或环境变量设置 num_ctx 16k~32k,别用默认 2k/4k
OLLAMA_KEEP_ALIVE=-1,模型常驻,杜绝冷启动OLLAMA_NUM_PARALLEL=1,单用户不需要并发- 升级 Ollama 后开启 Flash Attention 和 KV cache 量化
- Roo Code 的端点、模型名、超时设置逐一确认
.clinerules精简到八行以内- 每个功能点完成就
/newtask开新会话 - 模型文件放 SSD,别同时常驻多个模型
我个人在踩过这一轮坑之后的体会是:本地模型在 Roo Code 里卡不卡,七成取决于你怎么用它,三成才取决于硬件。先把请求体积和运行参数管好,你手里的 14B 很可能比你想象的快得多。等这些都调顺了,再考虑上更大的模型,那时候每换一次硬件升级,都能感觉到实打实的提升。