
前阵子我把 Roo Code 接到本地模型上原本图的是离线、省钱、不用盯着各家 API 的余额页面。结果半天没到就开始怀疑人生一句“帮我给这个函数补个类型注解”转圈时间够我冲杯挂耳咖啡。群里一问发现这不是个例——不少人用 Roo Code 接 Ollama 或 LM Studio 之后都有一种诡异体验明明是本地跑的模型响应却比云端还慢UI 还时不时冻结几秒跟“原生速度”完全不沾边。这篇文章是我从那种状态里爬出来的完整记录。我会先把 Roo Code 调用本地模型的链路拆开讲清楚卡顿到底发生在哪一段然后分别从模型服务端和 Roo Code 两侧给你能直接照抄的参数最后放一份实测记录告诉你如何把它从“卡到不想用”优化成接近原生速度的手感。适合所有用 Roo Code 调本地模型但被延迟折磨的人也适合刚接触本地模型、想搞清楚它为什么忽快忽慢的朋友。1. 卡顿的真相先搞清楚慢在模型本身还是链路第一课最重要别一上来就换模型也别上来就调量化。我见过太多人从 7B 换到 13B、从 Q4 换到 Q8结果问题原封不动还在那。因为 Roo Code 调本地模型的链路比你想象的长得多VS Code 扩展 → HTTP/SSE 请求 → 本地推理服务Ollama / LM Studio→ llama.cpp 内核 → GPU/CPU 推理 → 流式返回 → Roo UI 渲染 → 下一个工具调用循环。Roo Code 不是普通聊天窗口。它每执行一个操作大概率会发起多轮 tool call。每轮 tool call 都要敲一次服务端而且携带的上下文是在慢慢累积的。一次请求里真正耗时的不只是逐 token 生成decode首 token 延迟往往由 prefill 决定。prefill 就是把 prompt 里所有 token 做一次前向计算产出 KV cache。对 3 万 token 的上下文来说prefill 就是一次 3 万 token 的批处理模型再快这一下也要好几秒到几十秒。所以我的判断标准很简单工具调用环节从发出到看到第一个文字超过 5 秒就别再纠结 decode 速度先把链路想办法减短。有人可能觉得“5 秒不是挺正常吗”真不是。你可以实际测一下7B Q4 模型在 RTX 4060 级别显卡上解码速度通常能到 50-80 token/s一个 200 token 的回复只要 3 秒左右。如果它转圈十几秒你再怎么调生成参数都没用瓶颈在 prefill 和请求体长度这些“看不见的地方”。1.1 先用 curl 给服务端掐表把变量分离出来第一步我建议绕开 Roo Code直接拿本地推理服务的 OpenAI 兼容端点做一次计时。Ollama 默认端口 11434LM Studio 是 1234两者都提供/v1/chat/completions。我用的是这条命令curl -N -s -o /dev/null \ -w 首字节时间: %{time_starttransfer}s\n总耗时: %{time_total}s\n \ http://localhost:11434/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen2.5-coder:7b, messages: [ {role: user, content: 写一个Python函数返回列表众数带注释} ], stream: true }首字节时间基本等于“首 token 前等待”总耗时是流式响应完整收尾的时间。如果这个 curl 简单请求很快但 Roo Code 还是卡那至少有七成概率问题出在 Roo 这一侧——比如请求体过大、思考预算太高、流式没开。如果 curl 本身就慢那就去检查服务端参数、显存和量化。想更严谨一点可以把 Roo Code 实际发出的请求体导出来在 VS Code 的开发控制台或日志里找到那次 chat/completions 请求把 messages 原封不动做成 JSON 再 curl 一次。这样测出来的首字节时间就非常接近你在 Roo 里体感的延迟定位也最准。1.2 模型自检确认硬件和量化没有拖后腿还有一个两秒钟的检查直接在终端跑ollama run qwen2.5-coder:7b print hello。如果 CLI 都慢吞吞说明模型本身或者加载就有问题先别怪 Roo。这时候配合看ollama ps能直接看到模型跑在 GPU 还是 CPU 上ollama ps7B Q4_K_M 整体也就 4-5GB正常应该全部驻留在显存。如果显示 100% CPU 推理那不管谁调用都会卡先把这关过了再说。2. 服务端参数优化同一个模型快慢能差三倍服务端参数是“卡顿重灾区”。同一台电脑、同一个模型参数配错和配对体感差距能有三倍。下面挑影响最大的几项说。2.1 显存、量化与 GPU offload 的取舍GPU offload 是头号关键。Ollama 可以通过环境变量或 Modelfile 控制卸载层数LM Studio 则直接在模型加载面板里拉 GPU offload 滑块。原则永远是一句话显存能放得下就尽量全部卸载到 GPU。7B Q4_K_M 大约占 4.7GB再算上 KV cache 和系统占用8GB 显卡可以放心跑6GB 显卡也能试但要留意上下文长度别开太大。量化等级也要会权衡。Q4_K_M 通常是代码场景的甜点体积小、速度快、质量损失在代码生成任务里基本可接受。Q8_0 质量略好但要多占一两 GB 显存。显存富裕时用 Q8_0 没问题显存紧张时我会劝你老老实实 Q4_K_M别为了那点质量提升换来换页掉速。至于 FP16本地推理根本没有必要。2.2 上下文长度与 KV cache隐形杀手这应该是全文最容易被忽略的点。本地模型最怕大上下文。很多人刚接触时都喜欢把 context 开到 32k 甚至 128k觉得“窗口越大越能处理复杂任务”。但代价是实打实的同样的模型16k 和 32k 上下文的 prefill 时间近乎翻倍KV cache 占用也翻倍。一旦超显存KV cache 就要溢出到内存带宽断崖式下跌表现就是“前几轮还行越往后越卡”。我建议本地模型先设 14k-16k 左右代码任务完全够用。如果你跑的是 32B 大模型8k 到 10k 已经能覆盖绝大多数多文件任务。窗口再大本地模型能力跟不上窗口的收益其实发挥不出来反而变成纯延迟。另一个低成本的改动是 keep_alive。Ollama 默认会在空闲几分钟后把模型卸载。Roo Code 任务中间经常思考个几十秒模型被卸载下一次请求又要重新加载两秒到十秒钟就这么白白没了。设长一点OLLAMA_KEEP_ALIVE20m ollama serve或者在请求里带 keep_alive 参数让模型常驻。LM Studio 用户直接把 Keep model loaded in memory 打开就行。2.3 停止词与输出约束别让模型把多余 token 吐完本地模型在 tool call 场景里特别容易“嘴碎”明明结果已经输出完还继续补充两句废话导致 Roo 一直在等完整响应结束。这里有几个处理办法保证 Roo 传入的 stop 参数完整到达本地服务不要在中间网关里被删掉对不支持原生 function calling 的模型让 Roo Code 走纯文本工具调用格式避免模型输出结构错乱后被重试在服务端限制 max_tokens / num_predict比如单次生成限制 2048。这样即使模型失控也不至于生成几千个 token 才停。2.4 环境变量速查表下面这几个是ollama serve场景里影响延迟最多的环境变量建议直接照抄参数默认建议原因OLLAMA_NUM_PARALLEL11Roo 请求本身是串行并行帮不上忙反而可能让服务端多预留 KV cacheOLLAMA_MAX_LOADED_MODELS11多个模型频繁切换会有冷启动加载延迟OLLAMA_KEEP_ALIVE5m20m 或更长防止任务思考间隙被卸载模型context length模型默认16384 左右过大时 prefill 和 KV cache 成本线性上升如果你版本较老没有OLLAMA_CONTEXT_LENGTH这个变量那就在 Modelfile 里写PARAMETER num_ctx 16384效果一样。3. Roo Code 侧配置默认值不是给本地模型准备的服务端扫平之后 Roo 还是卡那问题多数在 Roo Code 自己的配置。我踩过的经典坑有三个个个都能让延迟翻倍。3.1 思考预算Thinking Budget先降下来Roo Code 有一个 Thinking Budget控制模型在执行工具调用前要先生成多少思考 token。对云端大模型这个预算能显著提升任务正确率但对本地模型每个 thinking token 都是实打实的延迟。默认档位在本地跑起来等于每次请求前面先生成几百个思考 tokenprefill 和 decode 双倍花钱。我建议直接调到 Low 或 Off。做法是在 Roo 的 Provider 配置面板里找 thinking 相关选项如果你版本里叫别的名字搜“thinking”也能搜到。以我的实测光是这一步就能把单轮延迟砍掉 30% 左右。当然代价是复杂任务偶尔会“思考不足”导致规划变差这个需要用一段时间找到自己的平衡点。3.2 流式响应别关掉否则看起来就是卡死有个场景特别有欺骗性请求其实没卡模型也在正常生成但 Roo 面板半天不动最后一次性刷出一大段。这多半是流式响应没开。流式开启后每个 token 生成完立刻推到 Roo 面板并实时渲染关闭时则要等完整响应结束才显示中间全程空白。从用户视角看那就是“卡死”。去 Roo 设置里确认 stream / streaming 为开启状态。这一步不改前面所有调优都会白费因为你根本看不到实时进度心理体感会放大十倍。3.3 上下文爆炸别让 Roo 反复读整个文件这是 Roo 场景特有的“慢”。普通聊天窗口每次请求只带当前问题Roo 的 tool call 会把整个会话历史全部发过去。如果任务过程中你反复让 Roo 读一个 2000 行文件每轮请求随便就能到 15k token后面会越来越重。缓解手段读文件时明确行号范围读取 src/utils.ts 的 100 到 200 行先把大文件的目录结构扫一遍再按需读小块单个任务尽量聚焦别让一个任务里累积了几十个 tool call长会话启用 Auto Compact或者手动触发上下文压缩。上下文压缩值得多说一句。Roo Code 会在会话上下文接近上限时自动压缩但如果你没开它会一直把旧历史原样带着。每轮都让模型重新 prefill 一遍几万 token不卡才怪。3.4 工具调用格式不匹配本地模型可能根本没在“干活”还有一个更阴间的坑本地模型不认识 Roo 发的严格 function calling 数据输出了一段看着正常但结构不对的文本。Roo 解析不到工具调用就开始等待、重试、再等待表现就是转圈、转圈、再转圈。解决办法有两个方向。一是换一个工具调用能力更强的模型比如 Qwen 系列、Llama 3.x二是让 Roo Code 走纯文本工具调用格式。后者通常不会把 OpenAI 风格 JSON 硬塞给模型而是用标签或 XML 格式告诉模型“你现在要调用工具”。对本地模型来说这种格式更好理解失败重试少了卡顿自然就散了。4. 实测记录从 20 秒到 2 秒的关键调整下面是我自己一套完整实测环境供参考Windows 11RTX 2080 Ti 11GBOllama 跑 qwen2.5-coder:7b Q4_K_MRoo Code 通过 OpenAI 兼容端点接本地服务。任务内容是让 Roo 修复一个中型项目的测试文件涉及反复读取文件、跑 pytest、改代码。4.1 优化前的基线刚开始几乎是默认配置上下文 32kThinking Budget 默认 Medium没确认流式是否开启任务里还频繁让 Roo 读完整文件。结果单次 tool call 平均 15-20 秒整个任务跑了将近 10 分钟体感跟“老年打字机”一样。我截了其中一条请求messages 总 token 数到了 26kprefill 占了 8-9 秒decode 一个 200 token 左右的回复又要 4-5 秒加起来就是 13 秒以上。这里最扎心的是模型本身解码速度并不慢慢的是 prefill 庞大的历史上下文。4.2 逐项调整与效果我没有一次性全部改掉而是按顺序一项项来先把上下文窗口降到 16k同时把OLLAMA_KEEP_ALIVE设成 20m。请求的 prefill 降低约 40%。把 Thinking Budget 改为 Low。每轮请求少了几百个思考 token延迟立刻再降。确认流式响应开启。UI 体感变化最明显不再是“半天空白后一次性喷出”。指令改成“读取 src/xxx_test.py 的 120-260 行”不再让 Roo 读全文。请求体显著瘦身。任务进行到 8 轮之后手动触发一次上下文压缩。最终结果单次 tool call 从 15 秒降到 2-4 秒首 token 时间从 8-9 秒降到 0.4-1.6 秒整个任务时间从 10 分钟压到 3 分钟左右。对于 7B 本地模型这已经非常接近“原生速度”的手感了。这里我想强调一句我没有换模型、没有换量化、没有加显存只是把没必要的开销一个个砍掉。所谓原生速度不是模型被超频而是链路减法做到位。4.3 为什么不建议一次改多个变量很多人调优喜欢“全改一遍”然后发现确实变快了但不知道是哪一步起效。下次再出问题依旧抓瞎。我的做法是改一个变量 → 用 curl 复测 → 记录首字节时间和总耗时 → 改下一个。你可以自己建一张表类似修改项首字节前值首字节后值总耗时后值结论上下文降到 16k8.9s4.8s7sprefill 明显改善Thinking Budget Low4.8s2.1s4sthinking token 减少有效流式开启2.1s1.2s3.5sUI 体感变化最大局部读文件1.2s0.6s2.2s请求体瘦身有用上下文压缩0.6s0.4s1.8s长会话必须维护这个表是我用来判断瓶颈的“病历本”。以后如果某天又开始卡我会先猜是不是上下文又膨胀了而不是从头摸一遍。5. 避坑清单与硬件补充有些“卡顿”根本不是优化参数能解决的调试到最后你会发现有一部分卡顿来自参数之外的坑。这些坑不解决再好的参数也白搭。5.1 Windows 下的推理后端没选对LM Studio 在 Windows 上比较坑的一点是默认推理引擎可能是 CPU 版。你需要进模型加载面板手动把 Engine 切到 CUDAN 卡或 VulkanA 卡 / Intel 核显。一个肉眼可见的检查方法跑任务时打开任务管理器看 GPU 利用率。如果 GPU 一直是 0%说明模型根本没在显卡上跑这时候哪怕 7B 也能慢到让人怀疑人生。5.2 显存不够导致换页比慢更隐蔽显存溢出后llama.cpp 会把部分层放到内存每次前向计算都要跨 PCIe 传输速度断崖式下降。更讨厌的是它不像“完全 CPU 推理”那么快暴露而是表现为“偶尔卡一下”特别容易被误判成工具调用问题。遇到这种参数调不出奇迹只能换个更激进的量化比如 Q4_K_M缩小上下文窗口因为 KV cache 会随上下文线性膨胀实在不行就换更小的模型7B 换 3B/4B 损失一点能力但流畅度完全不同。5.3 中间网关、并发和重试的连环坑有人喜欢在 Ollama 前面再套一层本地 API 网关统一管理 API Key、统计调用量之类。网关如果只是透传还好一旦自作聪明加了重试、缓存、改写响应体延迟立刻翻倍。我的建议很简单Roo Code 的 base URL 直接指向本地推理服务中间不要放任何不必要的东西。并发也要提一嘴。Ollama 支持并发请求但 Roo Code 的任务是按轮执行的天然串行并发没有意义。把OLLAMA_NUM_PARALLEL1保持默认能避免服务端为了并行预留更多 KV cache 而挤占显存。如果 Roo 自己频繁重试大概率是工具调用格式不兼容或超时设置太短去服务端日志看结尾输出比在 UI 里死等重试有用得多。5.4 我最后留下的检查单每次有人问我“Roo Code 调本地模型卡怎么办”我就把这个清单丢过去上下文长度降到 16k 或更低模型常驻没有被频繁卸载加载GPU 利用率正常不是 CPU 在死扛Roo 的流式响应已开启Thinking Budget 选了 Low 或 Off读文件用行号范围或局部内容不读全文会话超过 10 轮就做上下文压缩中间没有多余的 API 网关 / 转发层把这些过一遍本地模型的延迟基本就到头了。剩下的差异来自模型本身的能力边界比如某些复杂工具偶尔判断错、格式偶尔不规范。那是质量问题不是速度问题别和延迟混在一起调。最后说点题外话。我后来也试过 32B 大模型确实更聪明但如果不控制上下文和 tool-call 格式照样卡到怀疑人生。反过来把 7B 优化到两三秒一轮之后处理日常重构、写测试、改配置已经非常顺手。我个人体会是别执着于“一步到位上大模型”先把 7B 或 14B 的链路磨爽你收获的体感提升比直接换模型大得多。如果你在 Roo 里还挂了本地 embedding 做语义记忆那又是一套独立的优化思路留到下次再聊。希望这篇踩坑记录能帮你少喝几杯等着转圈的咖啡。