
最近不少朋友都在从云端 API 往本地模型迁移Roo Code 接 Ollama 或 LM Studio 慢慢成了标配。但很多人试完第一反应是卡真卡比云端 API 还卡。命令发出去半天不见反应输出像打字机慢放跑一个小任务像在放 PPT几次工具调用之后干脆超时最后只能骂一句“本地模型就是不行”又灰溜溜换回云端。说实话我一开始也是这样被折磨了一周之后才慢慢把速度救了回来。现在同样的本地模型在 Roo Code 里的响应速度虽然比不上顶级云端接口那种“瞬时回话”但已经非常接近原生手感日常写代码、跑小任务完全不会让人觉得在迁就它。这篇就把我整个排查、优化、调参的过程完整写出来包括卡顿到底卡在哪一环、Ollama 和 LM Studio 分别要怎么调、Roo Code 侧的哪些设置最影响体感以及我踩过的几个比较隐蔽的坑。不管你是刚装上 Roo Code 接本地模型的新手还是已经被卡到想砸键盘的老手这篇的实操步骤都能直接照着抄。1. 卡顿并不全是模型的锅先拆开“调用链路”看瓶颈在哪1.1 一次请求从发出到显示要经过哪几道门先说一个我踩过的最大的认知偏差一看卡顿就觉得是“模型太弱算不过来”。但实际上 Roo Code 这类 AI 编程助手和聊天工具完全不同它不是一个“你问一句它答一句”的简单交互而是一个复杂的编排循环。真正的调用链路是这样的你输入一条指令后Roo Code 会先去收集工作区上下文——包括当前打开的文件内容、目录结构、终端输出、之前多轮对话的历史记录、模型返回过的工具调用结果然后把这些统统组装成一段长 Prompt发送到模型 API。模型拿到 Prompt 后要先做 prefill预填充也就是把这一整段输入从头到尾扫一遍然后才开始逐字生成。生成出的 token 流会被前端实时渲染到界面上Roo Code 同时还要不断解析输出里有没有“工具调用”指令——如果有它就去读文件、执行命令、搜代码再把结果塞回去发起下一轮请求。这整条链路里任何一环慢一点你感受到的都是“卡”。组装 Prompt 本身很快毫秒级基本可以忽略。请求传输在本地也很快除非你把 Ollama 挂在了远程机器上走网络传输。模型推理是大头从几百毫秒到几十秒都可能是优化的主要战场。工具执行也很容易被忽略如果 Roo Code 执行了一个超长的终端命令或者往 prompt 里塞进了上万行的文件内容下一个请求的 prefill 就会直接爆炸。所以遇到卡顿第一步不是去换模型而是先判断“卡在哪道门”。1.2 本地模型“慢”的三个真实来源第一是 prefill 太慢。Roo Code 的 prompt 很容易越积越长几千甚至上万 token 都是常态。模型必须先处理完所有输入 token 才能输出第一个字而 prefill 是纯计算密集的活输入越多就越慢。这就是为什么你感觉“命令发出去了半天才开始回复”——你等的不是生成速度而是预填充速度。第二是上下文膨胀导致的 KV cache 压力。上下文越长模型需要为每个 token 维护一组缓存占用的显存就越多。显存一旦不够用Ollama / LM Studio 会把部分计算回退到 CPU速度断崖式下跌。更糟的是Roo Code 如果不主动清理历史每轮请求都会把之前的整个对话带上十几轮工具调用之后 prompt 动辄一两万 token越到后面越卡。第三是流式渲染和工具调用循环带来的额外开销。Roo Code 的界面是基于 Webview 的收到 token 要实时渲染。如果机器性能本身就紧张或者 Roo Code 版本有 UI 性能问题模型明明已经在往回吐结果界面上却半天不刷新你的体感就是“卡死了”。搞清楚这三点后优化的优先级就出来了先优化模型服务端的推理效率和常驻状态再优化 Roo Code 侧的上下文和 prompt 策略最后处理工具执行和系统资源问题。顺序不能反否则都是隔靴搔痒。2. 模型服务端是最大的优化杠杆Ollama 和 LM Studio 的实测调参2.1 先正确地测量别靠感觉调参在动手调参数之前先做一件事建立一个可复现的基准。所谓“卡”是主观的但 tokens/s 和首字延迟是客观的。如果你用 Ollama直接在终端里跑ollama run qwen2.5-coder:32b-instruct-q4_K_M然后在交互界面里输入一段固定文本观察返回信息里的 eval rate 和 total duration。或者用 API 方式测curl http://localhost:11434/api/generate -d { model: qwen2.5-coder:32b-instruct-q4_K_M, prompt: 写一个冒泡排序的 Python 实现, stream: false }看返回 JSON 里的 eval_count、eval_duration算出每秒生成 token 数。如果命令行里就已经只有 5 token/s那 Roo Code 界面再怎么优化都没用锅就在模型服务和硬件上。还要注意两个速度指标分开看prefill 速度处理输入的速度和 decode 速度生成的速率。Roo Code 的请求总是输入远大于输出所以体感上的“等待首字时间”主要取决于 prefill。很多人在 Ollama 里看到的 eval rate 很高但进 Roo Code 还是卡就是因为输入 token 太多prefill 吃掉了大量时间。这一步能帮你明确到底是“生成慢”还是“吃输入慢”。2.2 Ollama 的性能参数与推荐配置Ollama 里最容易被忽视、同时也是影响最大的参数是 num_ctx上下文长度。Ollama 默认的上下文只有 2048 或 4096但 Roo Code 这类工具会按照自己配置里的 max_tokens 去请求更大上下文。当请求的上下文超过 num_ctx 时Ollama 会按请求参数自动调整导致 KV cache 瞬间膨胀显存被拉满推理速度下降。更恶心的是如果每次请求的上下文长度不一致KV cache 会被反复重新分配出现周期性的卡顿峰值。一个稳妥的做法是为模型单独创建一个 Modelfile把上下文固定下来FROM qwen2.5-coder:32b-instruct-q4_K_M # 固定上下文长度避免 KV cache 跟着请求乱跳 PARAMETER num_ctx 16384 # 让尽量多层跑在 GPU 上 PARAMETER num_gpu 35 # 代码生成任务的温度建议调低 PARAMETER temperature 0.2 PARAMETER top_p 0.9 # 模型空闲后常驻内存避免冷加载 PARAMETER keep_alive 30m然后ollama create qwen2.5-coder-ctx16k -f Modelfile ollama run qwen2.5-coder-ctx16k再到 Roo Code 的模型配置里把 API 地址填成http://localhost:11434/v1模型名填qwen2.5-coder-ctx16k。这样上下文稳定在 16KKV cache 分配一次到位不会频繁重建。另一个非常重要的环境变量是OLLAMA_KEEP_ALIVE。Ollama 默认在模型空闲一段时间后把模型从内存里卸载下次请求又重新加载。32B 的模型从磁盘加载到显存要十几秒甚至更久这段时间 Roo Code 界面上就是一片空白。设成 30 分钟或更长export OLLAMA_KEEP_ALIVE30m ollama serve注意这个变量是给服务端进程设置的不是在 Modelfile 里设。如果是在 Windows 上的服务需要在系统环境变量里配置然后重启 Ollama。另外推荐开启 flash attention 和 KV cache 量化。新版 Ollama 默认开启 flash attention如果你在 Mac 上跑可以显式设置export OLLAMA_FLASH_ATTENTION1KV cache 量化在 Modelfile 里加PARAMETER num_ctx 16384 PARAMETER kv_cache_quant f16这里的思路是KV cache 是长上下文的显存大户能省一点是一点。省下来的显存可以留给更大的 batch 或更长的上下文换来的速度提升非常可观。代价是极小程度的精度损失对于代码生成这种任务基本无感。2.3 LM Studio 的引擎设置与上下文管理如果你用的是 LM Studio对应要调整的内容差别不大但操作入口在界面上。首先是 GPU Offload。打开模型加载界面切换引擎到 GPU并确认层数已经在显卡上加载。LM Studio 会显示有多少层 offload 到 GPU比如 “33/33 layers offloaded” 才是理想状态。如果你看到 “0/33 layers offloaded”那就是完全跑在 CPU 上生成速度上不去这是最容易犯的错误。其次是 Context Length。LM Studio 默认会尝试根据显存自动扩展上下文长度这个自动扩展逻辑会导致运行时的缓存频繁调整卡顿感非常明显。手动把它设成一个固定值比如 16384 或 8192别让它自动填满显存。再就是 Cache 选项把 Flash Attention 和 KV Cache Quantization 打开。LM Studio 里可以分别开启这两个选项开启后长上下文场景的延迟会有肉眼可见的下降。LM Studio 还有一个很实用的功能是 Prompt 前缀缓存。Roo Code 每轮请求里系统提示词和前面的对话历史基本不变前缀缓存能让这些部分只计算一次。开启后连续多轮对话的响应会明显变快。Ollama 里对应的是“prompt cache”而且是默认行为但要求模型常驻内存才能生效——你看keep_alive 又绕回来了。这里我特别想强调一句话服务端调优的核心目标不是把生成速度从 30 token/s 提到 100 token/s而是保证两件事——模型常驻不反复冷加载和上下文稳定不频繁重建 KV cache。这两点做好比单纯追求数值上的更快更有意义。因为 Roo Code 的交互模式里一个任务可能触发十几次模型请求每一次都要在毫秒级内从“待命状态”接活而不是从“冷启动状态”现场搬砖。3. Roo Code 侧的配置Prompt 策略、上下文压缩与模型选择3.1 先看懂 Roo Code 在模型配置页里的“隐藏开关”服务端调好之后接下来看 Roo Code 侧。在配置模型时我踩过几个直接影响卡顿感受的开关。第一是 API 端点和模型名。填 Ollama 用http://localhost:11434/v1LM Studio 用http://localhost:1234/v1。确认连接是通的之后再看是否开启了流式输出Stream。如果你关掉了流式输出Roo Code 会等模型把整个响应全部生成完才一次性刷新界面。生成长度 2000 token 时你就要干瞪眼等 30 秒这期间界面毫无反馈那就是彻头彻尾的“卡死”体验。所以流式输出必须保持开启这是底线。第二是 Max Tokens。很多教程会让你把它拉得很高比如 65536理由是“让模型一次把整个文件写完”。但这是个坑。Max Tokens 越高模型接口那边要预留的 KV cache 空间就越大同时任何一个小请求都可能被服务端按长任务来调度。本地模型本来就资源有限你设置超大的 Max Tokens 等于让 Ollama 每次请求都背着巨大的缓存压力跑。更合理的是先从 8192 开始某些确实需要长输出的任务再临时调高到 16384。我实测下来绝大多数代码修改任务 4096 都够用真正需要一口气出 1 万 token 的场景非常少见。第三是模型选择。Roo Code 支持根据任务类型配置不同的模型。如果你只有一个大模型比如 32B那所有请求都走它简单读文件、执行命令这种轻量操作也用重炮自然慢。Roo Code 的 Auto Switch 功能可以配置简单任务用 7B 小模型复杂任务切到 32B 大模型。这相当于给你配了两个档位小请求轻踩油门大任务才地板油整体响应速度会明显好起来。3.2 用自定义指令和任务拆解控制“废话率”本地模型的指令遵循能力通常比云端大模型弱这是客观事实。问题在于很多人把对接 GPT-4o 或 Claude 的那套低约束指令习惯带了过来让本地模型自由发挥结果它非常容易把一分钟能做完的事拖成十分钟——大量解释思路、复述需求、自我总结经验这些全都算在生成时间里。在 Roo Code 的设置里有一项 Custom Instructions自定义指令把它当成给本地模型立的规矩。我建议至少加入这样几条不要解释除非被明确要求。不要复述用户需求直接执行。输出代码时只输出代码块不要附带“以下是实现”。工具调用前不要输出过渡句和语气词。推理过程用内部思维不输出到对话里。这几条能直接把模型每次生成的 token 数砍掉 30% 甚至更多体感上就是“说话利索了”。另外一个同样关键的动作是任务拆解。Roo Code 执行复杂需求时如果你一下子把完整需求丢给它它会读一堆文件、规划一个巨大的 todoList然后开始埋头苦干。问题是上下文越滚越大模型很快就“迷失”了。本地模型的注意力窗口虽然是够用的但长任务下它会出现重复、漏步、前后不一致。我在实践中发现把大任务拆成多个小任务逐次对话效果远好于一次大而全第一轮“先分析项目目录结构列出关键文件和入口点不要写代码。”第二轮“基于上面的分析给出一个实现方案的步骤列表每个步骤不超过一句话。”第三轮“按方案第 1 步实现核心函数保持简单。”每一轮 prompt 更短、prefill 更快模型也不容易在长上下文里“犯迷糊”。缺点是你要手动多操作几次但换来的流畅度和正确率完全值得。3.3 上下文管理你能做的最直接、最有效的优化这是我要重点讲的部分。Roo Code 的卡顿主要原因其实不是模型推理速度而是上下文膨胀。默认情况下每次请求都会带上完整对话历史一个任务执行了 5 次工具调用之后单次请求的 prompt 就可能超过 1 万 token。上下文一长prefill 就慢显存就紧张KV cache 就开始作妖——一系列问题全都跟着来了。保持流畅的操作习惯是一是适时使用 clamp/compress 或直接新开任务。Roo Code 有压缩对话的功能把历史摘要化减少后续请求的 token 数量。但压缩并不完全无损重要细节可能被丢掉。更好的做法是当任务完成一个关键里程碑后直接开一个新任务把当前项目状态、已做改动、待办事项、下一步计划用几行文字写进去然后从新对话继续。这样上下文永远是干净的模型不会背着上个阶段沉重的记忆干活。二是控制文件读取范围。Roo Code 在分析代码时会把文件内容塞进上下文如果你让它读取一个几千行的文件几千 token 就搭进去了。更别提它有时候一口气读多个文件。办法是主动约束它明确让它“只读 app.py 第 1-200 行”或用自定义命令封装“只查看某个函数定义”。对于大型 monorepo目录树本身也可能有几万个条目一定要通过配置忽略列表把 node_modules、dist、build、.git 这些目录排除掉否则光目录结构就可能撑爆上下文。三是保持工作区干净。Roo Code 会根据当前工作区状态收集信息如果你开着几十个未保存的文件和标签页很多内容会被一并算进上下文。我只保留当前任务相关的文件其他全部关掉实测能显著降低单轮请求的 token 数量。这一点我反复踩坑后最深的体会就是本地模型最忌讳“把所有东西都丢给它”。云端模型上下文大、有钱兜底你可以不在乎 token本地模型每一个 token 都是真金白银的显存和计算开销。prompt 从 2K 涨到 8K首字延迟几乎翻倍地涨。一旦你学会了“给模型做减法”你会明显感受到本地模型像是换了一个。4. 实测中的卡顿排查链路一个从“每次等 20 秒”到“秒回”的真实案例4.1 排查前先收集三类证据光讲理论容易飘分享一个我自己遇到过的非常典型的案例。当时我在 Roo Code 里用 Ollama 跑 qwen2.5-coder:32b刚开始很流畅用了两天后突然每个请求都要等 20 秒左右才开始有反应偶尔直接超时。我的第一反应也和大家一样觉得是模型“越用越笨”。但冷静之后我开始按证据排查。第一类证据是 Ollama 服务日志。在前台跑ollama serve每次请求都会打印一行日志里面有 prompt tokens、eval count、total duration 等指标。通过这些数据能看出每次请求的输入 token 是不是在持续膨胀以及 prefill 花了多少时间。第二类证据是资源占用。在 Windows 上打开任务管理器Linux 上用nvidia-smiMac 上用活动监视器。重点看 GPU 利用率、显存占用、内存占用。如果你发现 GPU 利用率接近 100% 且显存打满那是模型真的算不过来如果 GPU 利用率很低而内存占用接近上限那大概率是上下文分配问题如果显存已经溢出推理就会回退到 CPU速度断崖式下跌。第三类证据是隔离复现。不经过 Roo Code直接用 curl 向 Ollama 发一个和它近似的请求测原生 API 的延迟。如果原生 API 就很慢说明问题在服务端配置和模型本身如果原生 API 很快但是 Roo Code 里慢那问题出在 Roo Code 端——要么是 prompt 太大要么是 UI 渲染阻塞。4.2 逐步定位从服务端、到扩展、到系统资源我的排查结果是日志显示每次请求的 prompt token 数高达 18K。我的模型配置上下文是 32K也就是说模型每一轮都要 prefill 这 18K 的输入在 32B 模型上这本身就要好几秒。再加上我的显卡是 RTX 409024GB 显存32B 模型的 Q4 量化权重约 20GBKV cache 占掉剩余空间正好卡在边缘。一旦上下文稍微波动KV cache 就被迫重新分配日志里能看到相关记录。然后我做了两个隔离实验第一个实验清空 Roo Code 的对话历史新开一个空任务只发一句“你好”。首字延迟立刻降到 1 秒以内。这说明服务端本身不慢。第二个实验在同一个任务里连续多聊几轮不做任何清理首字延迟从 1 秒涨到 3 秒、5 秒最终又回到十几秒。到这里结论已经非常清楚了这个“卡顿”根本不是模型性能问题而是上下文管理失控加上显存告急的双重结果。4.3 最后的修复动作与效果对比修复动作分三步第一步把 Roo Code 的上下文策略改成“每完成一个关键阶段就 manual clamp / 新开任务”彻底改变“一路拖到底”的工作习惯。第二步把 Ollama 的 num_ctx 从 32K 固定为 16K同时通过 Modelfile 设置 keep_alive让模型常驻。第三步开启 KV cache 量化把 KV cache 的显存占用压下来给系统留出余量。改完之后的对比非常直观场景优化前优化后空项目首字延迟约 1 秒约 0.3 秒10 轮对话后续任务首字15~20 秒2~3 秒长文件修改请求经常超时10 秒内完成显存占用峰值 23.8GB频繁溢出稳定 19GB 左右这个案例最大的价值在于验证了一个判断本地模型卡顿大概率不是模型不行而是你把太多了不必要的东西塞给了它。优化说到底就三句话——控制上下文、保持常驻、稳住显存。5. 其他容易被忽略的坑文件读取、扩展冲突与硬件选择5.1 大文件读取别让 Roo Code 把整个仓库读进去POST 请求的 token 数膨胀很多时候不是对话历史造成的而是文件读取习惯造成的。Roo Code 拿到你让它“修改某模块”的指令后为了解上下文会把相关文件、当前文件、目录结构甚至文件搜索结果都丢进 prompt。如果你没做任何限制它可能把一个 5000 行的文件整个读进去那就是四五千 token几个文件一叠加prompt 立刻过万。我的建议是养成两个习惯一是在 .clinerules 或 Roo Code 设置里明确排除不需要的目录比如node_modules、dist、build、.git、__pycache__光这一项就能把目录树和文件监听的开销降下来。二是让 Roo Code 在处理大文件时先“查看文件结构”而不是整个读入。你可以用自定义命令封装一个操作让它先输出文件的行数和所有函数/类名然后按需读取具体片段。这样模型始终只需要处理小范围文本上下文压力骤减。5.2 扩展冲突和 UI 渲染的卡顿另一种特别冤枉的卡顿来自 Roo Code 的 UI 渲染层。特征非常明显模型日志已经显示生成完了但界面过了很久才把字显示出来或者界面半天无响应但 CPU 占用很高。如果你在 VS Code 里装了太多重型扩展尤其是代码格式化、自动补全、Emmet、文件监听相关的插件它们在 Roo Code 流式渲染 token 的时候会来抢主线程资源。一次生成任务里Roo Code 不仅要渲染几百个 token还要和其他扩展抢占 UI 进程效果就是整个编辑器卡成 PPT。解决方案调试 Roo Code 时先把不必要的扩展禁用掉特别是自动格式化类的。同时检查 VS Code 的files.watcherExclude设置把大型目录排除掉。最后记得把 Roo Code 和 VS Code 都升级到较新版本——历史上有几个版本的 Webview 存在性能问题升级后卡顿会明显缓解。5.3 硬件选型的一点经验硬件上的建议也很直白。运行本地模型时最重要的不是 GPU 有多少个核心、频率有多高而是内存带宽。模型参数要从内存搬到计算单元带宽决定了这个过程的上限。Apple Silicon 的统一内存架构在这一点上很有优势M 系列芯片跑 14B/32B 量化模型的体验往往比不少中端显卡笔记本更流畅。NVIDIA 用户则要优先保显存大小因为模型权重和 KV cache 都要住在显存里。不同显存规模的合理选择大概是这样的显存容量适合的模型规格建议上下文8GB7B~14B Q4 量化8K 以内16GB14B~32B Q4 量化16K 上下32GB32B 及以上可以尝试 32K但仍需克制注意一个反面教训不是显存越大就越流畅。内存带宽不够的情况下显存再大模型也会因为搬运速度慢而卡。所以如果你考虑为本地模型升级硬件先查内存带宽参数再决定要不要买大显存卡。6. 优化后的进阶思路向量检索、多模型分工与请求编排如果前面几点都做到位了Roo Code 调用本地模型已经相当流畅那接下来还能进一步“榨干”这套流程的价值。一是把向量数据库当成记忆外挂。Roo Code 本身不内置检索能力但你可以通过自定义命令把项目历史决策、常用代码片段、踩坑记录做成一个本地向量索引。每次需要时检索出最相关的几段文本注入 prompt而不是把整个项目塞进去。我自己在实践中是拿 Ollama 的 embedding 模型生成向量用本地向量库存起来效果很稳。每次注入只有几百 token但模型能准确回答“这个项目里支付模块之前为什么这么写”这类问题上下文压力比每次全量塞文档小了一个量级。二是多模型分工策略。Roo Code 的 Auto Switch 功能可以根据任务类型自动切换模型。我的配置是读文件、执行终端命令、简单代码补全走 7B 小模型架构分析、复杂代码生成、重构走 32B 大模型。这样可以避免所有请求都动用重火力。你需要注意设置好触发条件否则频繁切换带来的开销反而得不偿失。实测中最稳的方案是让它在同一个任务内保持模型一致只在任务类型明显变化时切换。三是可以搭一个本地的请求编排层。你的 Ollama / LM Studio 都对外提供 OpenAI 兼容接口你可以用一些轻量工具去作统一入口做请求路由、失败重试和日志审计。好处是排错更容易也能对高频工具调用做一定程度的合并减少模型往返次数。但代价是多了一层维护成本。我建议先把基础链路跑顺确认问题不在自身后再考虑引入这一层。最后额外提醒一句不要盲目照搬别人的配置。上下文长度、模型量化等级、keep_alive 时间这些参数的合理值强烈依赖你的硬件和实际任务负载。看到别人 32B 模型流畅不代表你的 8GB 显存机器也能复现。先把自己手里的模型、上下文、资源占用三个数字摸清楚再根据本文的思路逐步调整速度是可以一点一点找回的。本地模型流畅后的体验确实比云端 API 更踏实不烧钱、不泄漏代码、没有网络延迟值得你把那套配置正式稳定下来。