作者实测用 OpenCode 与本地 Qwen3.5 9B 在断网状态下完成代码修复
Coding From the Himalayas With an Offline AI Agent
作者在喜马拉雅山麓断网环境下,用 OpenCode 连接 Ollama 本地运行的 Qwen3.5 9B,成功让代理读取本地文件、修复 expense_total.py 中的累加 bug 并通过全部五项测试。
AI 全文翻译,未经原作者审校;可切换原文对照。

当我们谈论远程办公时,很多东西都被我们视为理所当然,尤其是可靠的网络和电力。但有时,远程办公意味着要在航班上、长途火车上,或者网络信号微弱甚至没有网络的地方完成工作。
一年前我搬到了喜马拉雅山麓。我喜欢这里宁静的生活,但它也带来了自身的挑战,包括断网和断电。以前我不太在意的事情,现在成了我规划工作的一部分。
我在 Thomson Reuters 担任首席工程师,大部分时间都在写代码和审查队友的代码。编码代理已经是我日常工作流的重要组成部分,这让我很好奇我的工作流中有多少能在离线状态下继续使用。

在喜马拉雅山麓工作。我的工作空间照片。
如果你像我一样,既喜欢与技术打交道,又能在网络并不总是配合的安静偏远之地找到内心的平静,那么这篇文章就是为你写的。它也适合任何曾想过编码代理能否完全在笔记本电脑上运行、断开互联网的情况下运行的人。我尝试在笔记本电脑上本地运行一个编码代理,看看离线状态下实际能完成多少工作。
我们离线时能做什么?
你笔记本电脑上已有的项目给了我们足够的发挥空间。我们可以让代理解释一个不熟悉的函数、排查一个失败的测试、重构一小段代码,或者帮助完成一个功能。当模型、项目依赖和测试工具都在本地可用时,这些任务可以离线运行。下载新包或在网上查找资料仍然需要网络连接。
OpenCode 的定位
OpenCode 是一个开源编码代理,可以与你的项目协同工作。你给它一个任务,它可以读取文件、提出修改建议并运行测试套件等命令。在我们的配置中,它的权限提示让我们在允许命令和修改之前先进行审查。
我选择 OpenCode 是因为它让我能在终端中保持这种工作流,同时连接到运行在我自己笔记本电脑上的模型。Ollama 负责运行模型;OpenCode 负责与项目交互。

我 Mac 上的 OpenCode,已选择 Qwen3.5 9B 作为本地模型。
开放权重模型(包括 Qwen)让这一切成为可能:它们的权重——用于生成响应的学习参数——可以下载并在本地运行。当 Ollama 在同一台笔记本电脑上运行 Qwen 时,OpenCode 可以将其请求发送到本地服务。我们先下载所有内容,然后断开互联网进行编码任务。
如果你更喜欢有引导的编辑工作流,Aider 是另一个选择;它同样支持 Ollama。在整个演示过程中我们都使用 OpenCode,以确保配置和结果保持一致。

OpenCode 处理项目文件,并将模型请求发送到同一台笔记本电脑上的 Ollama。Ollama 在本地运行 Qwen。
选择开源模型
Qwen 有多种尺寸。我想要一个能在本地运行、同时也能使用代理工具的模型。作为参考,以下是 Qwen 的模型卡中报告的两种 Qwen 尺寸和另一种开放权重选项的已发布结果。
LiveCodeBench v6 在编程问题上测试代码生成能力。BFCL-V4 评估函数调用能力,当模型需要选择工具并给出正确参数时,这一点很重要。两项测试都是分数越高越好。
模型 | LiveCodeBench v6 | BFCL-V4 |
|---|---|---|
Qwen3.5 4B | 55.8 | 50.3 |
Qwen3.5 9B(此处使用) | 65.6 | 66.1 |
gpt-oss-20b | 74.6 | 未报告 |
上表分数报告自 Qwen 的模型卡片,并非来自这台笔记本的实测。“未报告”表示来源未提供该分数。
本教程使用的是 Qwen3.5 9B。与 4B 版本相比,它已发布的编码和工具调用结果更强,因此是一个有用的起点。该表并未测量笔记本速度或整个 OpenCode 工作流;我们的离线文件编辑和测试才是这方面的检验。
模型大小与内存
模型 | 大约下载量 |
Qwen3.5 4B | 3.3–4.0 GB |
Qwen3.5 9B(此处使用) | 6.6–7.6 GB |
Qwen3.5 27B | 17–20 GB |
Ollama 列出了所有可用大小;下载量因运行时格式而异。
下载大小并不等于内存需求。Voltti 为 6.6 GB 的 Qwen3.5 9B 构建预留了 12–16 GB 内存。我们 64k token 的 OpenCode 配置可能需要更多,所以要为上下文和其他应用留出空间。
OpenCode 在基准测试中的表现
OpenCode 也在小型演示之外接受了测试。研究预印本 The Scaffold Effect in Coding Agents 使用两个云端模型,在 50 个 Terminal-Bench Pro 任务上比较了 OpenCode、Goose 和 OpenHands-SDK。以下是表 2 中报告的通过率。
编码智能体 | Qwen3.6 Plus | MiniMax M2.5 |
Goose | 48% [34–62%] | 38% [24–52%] |
OpenCode | 50% [36–64%] | 46% [32–60%] |
OpenHands-SDK | 50% [36–64%] | 46% [32–60%] |
括号内为 95% 置信区间。作者提醒,大多数通过率差异在统计上并不显著。
该研究还报告 OpenCode 的 token 消耗明显更高:每个已解决任务的 token 用量约为 Goose 的 40 倍。这些运行使用的是云端 API,且模型与我们的不同,因此无法预测本地 Qwen3.5 9B 的表现。
初始设置
在还能访问互联网时,按照 GitHub README 中的完整设置进行操作。它涵盖了安装工具、下载项目以及安装 OpenCode 1.19.4。该项目包含在本地使用 Qwen 所需的示例、测试和配置。完成后,让终端 A 保持在项目文件夹中打开。
开始之前,先了解 opencode.json 的作用会很有帮助。这是 OpenCode 的项目配置。在我们的文件中,model 和 small_model 都选择 Qwen3.5 9B,baseURL 指向 Ollama 的 http://127.0.0.1:11434/v1。只启用了本地 provider。它还会在编辑文件或运行 shell 命令前询问,并禁用了网络工具。完整配置在仓库中。我们仍会断开网络进行离线测试。
我们将使用终端 A 运行 OpenCode 和我们的测试。在终端 B 中启动 Ollama 并让它保持运行。该命令将模型服务保留在 localhost(同一台 Mac 内部的地址)上,并禁用 Ollama 的云功能。
OLLAMA_HOST=127.0.0.1:11434 OLLAMA_NO_CLOUD=1 OLLAMA_CONTEXT_LENGTH=65536 ollama serve回到终端 A,下载 Qwen 并等待下载完成。在断开互联网之前,我们会先检查智能体是否能响应。
ollama pull qwen3.5:9b从一个费用计算器开始
示例添加了五笔费用,其中包含一笔退款。正确总计为 25.50。在终端 A 中运行起始程序。
python3 expense_total.py
起始程序打印出 8.00,即最后一笔费用的值。
该函数在每次迭代时都会替换它的总计。在让智能体修复它之前,先运行现有的测试。
python3 -m unittest -v
有三个用例失败:小数运算、退款和示例费用。空输入和单项输入已经通过。
使用现有测试为智能体提供了一个具体目标。它也让我们能够独立于智能体的解释来检查结果。
联网时尝试 OpenCode
联网时,直接从项目文件夹打开 OpenCode。--pure 选项会禁用外部插件。项目配置将主模型和辅助模型都指向 Ollama;之后断开网络才能使运行处于离线状态。
.tools/node_modules/.bin/opencode --pure确认已选择 Qwen3.5 9B local。在 OpenCode 中输入这个诊断提示。
阅读 expense_total.py 并运行测试。在不编辑任何文件的情况下解释这个 bug。

OpenCode 在选中 Qwen3.5 9B local 的情况下接收到了诊断提示。
OpenCode 读取了源代码并搜索了测试。它最初提议使用 pytest,尽管这个项目使用的是 Python 内置的 unittest。权限提示让我有机会在允许之前检查该命令。对于下一个任务,我会在提示中包含确切的测试命令:python3 -m unittest -v。

智能体找到测试并请求运行测试命令的权限。
本地设置响应后,退出 OpenCode。让 Ollama 在终端 B 中继续运行。
/exit关闭互联网
关闭 Wi-Fi,并断开以太网或手机网络共享(如果已连接)。由于请求停留在 Mac 内部,localhost 仍然可用。

已关闭 Wi-Fi 以进行连通性检查。
在终端 A 中,检查 Ollama 的本地 API。
curl --noproxy '*' --fail http://127.0.0.1:11434/api/tags
Ollama 仍然响应,并列出了已下载的 qwen3.5:9b 模型。
然后尝试一个外部地址。
curl --noproxy '*' --connect-timeout 5 --max-time 10 --head https://example.com
外部请求失败,报错 Could not resolve host。
这些检查确定了录制时的情况:本地服务有响应,而外部查询失败。在运行编码任务期间,请保持所有外部连接断开。
离线修复 bug
在终端 A 中使用相同的直接命令再次启动 OpenCode。
.tools/node_modules/.bin/opencode --pure让智能体修复这个 bug。
Fix the bug in expense_total.py so the existing tests pass. Don't change the tests or install anything. Run the tests and explain your fix.录制显示 Qwen 提议了一行更改,请求编辑权限并运行测试。改动很小,因此很容易检查。
total = Decimal(amount) # beforetotal += Decimal(amount) # after
已录制的编辑和测试循环。Qwen 提议修复方案,请求批准并成功运行了五个测试。
智能体完成后,在运行你自己的检查之前退出 OpenCode。
/exit然后我们在终端 A 中自己运行了测试。
python3 -m unittest -v
手动检查显示全部五个测试通过。
保存的源代码包含 total += Decimal(amount),测试文件与起始文件相比没有变化。修复后现在会累加每个金额。运行示例程序应返回 25.50。
另外两个可以尝试的编码任务
我在配套项目中包含了另外两个练习:一份 CSV 报告和一个日志分析器。我还没有完成它们的离线智能体运行,因此上面显示的结果来自费用示例。这些是使用相同设置接下来要尝试的任务。
CSV 报告示例以一个未完成的函数开头。让 OpenCode 按产品对行进行分组,计算数量和收入,并生成一份易读的报告。它包含示例数据和七个测试,涵盖分组、小数运算、排序和空输入。
参照其 README 完成 examples/csv-report/csv_report.py。保持测试不变,不要安装任何东西。运行此示例的测试,并说明你做了哪些改动。
日志分析器已经可以运行,但在错误计数和选择最慢请求方面存在 bug。它的七个测试还覆盖了格式错误的行和空输入。
参照其 README 修复 examples/log-analyzer/log_analyzer.py。保持测试不变,不要安装任何东西。运行它的测试,并说明你的修复。
每份讲解都包含确切的测试命令和预期结果。用相同的本地环境运行这些练习,然后检查改动和测试输出。
当网络不可用时什么有帮助
既准备好项目,也准备好模型。 下载它的依赖,并把你需要的文档保存在磁盘上。我们的示例使用 Python 标准库,因此它们的测试不需要下载软件包。
在线时先完整运行一次设置。 离线尝试时使用相同的命令、模型和配置,这样所需的运行时组件就已经可用了。
把项目的测试命令交给智能体。 我们的智能体最初提议使用 pytest,尽管这个示例使用的是 unittest。明确的测试命令可以减少不必要的绕路。
保持任务聚焦并检查结果。 要求修复一个 bug 或添加一个小功能,审查 diff,并自己运行测试。保留原始测试,这样通过的结果仍然在检查预期行为。
留意内存压力。 下载模型只是内存开销的一部分。庞大的上下文和其他打开的应用会减少模型可用的空间。
也要记录那些需要帮助的尝试。 一份有用的讲解应当展示权限提示、重试和失败,以及最终通过的输出。
我从这次离线尝试中学到了什么
关掉 Wi-Fi 后看到测试通过,回答了我最初的问题:我可以在没有互联网连接的情况下,使用编码智能体读取本地文件、做出修改并运行检查。我仍然审查了编辑内容,并自己运行了原始测试。保持这些测试不变,为我提供了一种检查结果的有用方式。
在断网或旅途中使用这套环境时,我会从小而自包含的任务开始。在连接消失之前,笔记本电脑上必须已经准备好项目及其所需的一切。这个一行修复无法告诉我模型在处理大型代码库或陌生框架时表现如何。CSV 报告是下一个有用的检查:它要求智能体完成一个函数,因此需要检查的内容比一行修复更多。
来源:Latent Space · latent.space