Coding From the Himalayas With an Offline AI Agent

TL;DR · AI 摘要
工程师可在无网络环境下通过本地AI代理(如OpenCode+Ollama+Qwen)完成编码任务,无需依赖云端模型。
核心要点
- OpenCode与Ollama结合可在本地运行Qwen模型,实现无网络编码
- 选择Qwen 3.5 9B模型可平衡性能与本地资源消耗
- 本地AI代理适合远程办公场景,如山区网络不稳定环境
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- 离线编码解决方案
- 核心组件
- OpenCode
- Ollama
- Qwen模型
- 部署流程
- 模型下载
- 网络断开
- 本地服务调用
- 适用场景
- 山区远程办公
- 航班/火车移动场景
金句 / Highlights
值得收藏与分享的关键句。
本地AI代理可在无网络时处理代码解释、测试排查等任务
OpenCode通过Ollama连接本地Qwen模型,实现离线编码
Qwen 3.5 9B在性能与资源消耗间取得平衡,适合本地部署
在喜马拉雅山区使用离线AI代理进行编码 —— 潜在空间
当我们谈论远程工作时,往往默认许多条件,尤其是稳定的网络和电力供应。但有时远程工作意味着在航班上、长途火车旅途中,或在几乎没有网络连接的地方尝试完成任务。
一年前我搬到了喜马拉雅山脚下。我喜欢这里宁静的生活环境,但这也伴随着独特的挑战,包括网络和电力中断。以前没有太多考虑的事情,现在都成为了规划工作的必要因素。
我在汤森路透担任首席工程师,大部分时间用于编码和审查同事的代码。编码代理已经是日常工作的重要组成部分,这让我好奇在没有网络连接的情况下,还能保持多少工作流程。
在喜马拉雅山脚下工作。我的工作空间照片。
如果你和我一样,既享受技术工作,又在那些网络不稳定但宁静的偏远地区找到内心的平静,那么这篇文章适合你。它也适合那些想知道编码代理是否能完全在本地笔记本电脑上运行(无需联网)的人。我尝试在本地笔记本电脑上运行编码代理,看看在没有网络的情况下究竟能完成多少工作。
离线状态下能做什么?
已经在本地笔记本电脑上的项目为我们提供了大量可操作的内容。我们可以让代理解释陌生的函数、调查失败的测试、重构一小段代码,或协助完成某个功能。当模型、项目依赖项和测试工具都本地可用时,这些任务都可以离线执行。下载新包或在网络上查找信息仍然需要网络连接。
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工作流;我们通过离线文件编辑和测试进行验证。
模型规模与内存占用
约下载体积
3.3–4.0 GB
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的测试范围已超出小型演示。研究预印本《编码代理中的支架效应》在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
括号内显示95%置信区间。作者指出,大多数通过率差异在统计学上并不显著。
研究还报告了OpenCode的token使用量显著高于Goose:每个解决任务的token数量约为Goose的40倍。这些测试使用了云API和不同的模型,因此无法预测本地Qwen3.5 9B的表现。
初始配置
在仍有网络连接时,请按照GitHub README中的完整配置指南操作。该指南涵盖工具安装、项目下载和OpenCode 1.19.4的安装。项目包含本地使用Qwen所需的示例、测试和配置。准备好后,请保持Terminal A在项目文件夹中打开。
在开始前,了解opencode.json的作用会有帮助。这是OpenCode的项目配置文件。在我们的配置中,model和small_model均选择Qwen3.5 9B,baseURL指向本地的Ollama服务http://127.0.0.1:11434/v1。仅启用了本地服务提供者。该配置还会在编辑文件或运行shell命令前进行确认,并禁用网络工具。完整配置请参见代码库。我们仍将在离线测试时断开网络连接。
我们将使用Terminal A运行OpenCode和测试。在Terminal B中启动Ollama并保持运行。此命令将模型服务保留在本地主机(同一台Mac内的地址),并禁用Ollama的云功能:
OLLAMA_HOST=127.0.0.1:11434 OLLAMA_NO_CLOUD=1 OLLAMA_CONTEXT_LENGTH=65536 ollama serve返回Terminal A,下载Qwen并等待下载完成。在断开网络连接前,我们将验证代理是否能正常响应:
ollama pull qwen3.5:9b从费用计算器开始
该示例包含五个费用项(含退款),正确总额应为25.50。在Terminal A中运行初始程序:
python3 expense_total.py初始程序输出8.00,即最后一个费用项的值。
赞助
您的赞助广告位在此
联系正在构建下一代AI的工程师团队
Latent Space被负责代理、模型和基础设施开发的团队使用。欢迎咨询赞助此广告位
该函数在每次迭代中都会覆盖其总和。在请代理修复之前,请先运行现有的测试用例。
python3 -m unittest -v有三个测试用例失败:十进制运算、退款处理和示例费用计算。空输入和单项目输入的测试已通过。
使用现有测试用例可以为代理提供明确的目标。同时,它也为我们提供了一个独立于解释的验证结果的方式。
在线状态下使用 OpenCode
在线时,直接从项目文件夹打开 OpenCode。--pure 参数会禁用外部插件。项目配置将主模型和辅助模型都指向 Ollama;之后断开网络连接就是实现离线运行的关键。
.tools/node_modules/.bin/opencode --pure确认已选择 Qwen3.5 9B 本地版本。在 OpenCode 中输入此诊断提示。
阅读 expense_total.py 并运行测试。在不修改任何文件的情况下解释错误所在。
OpenCode 接收到带有 Qwen3.5 9B 本地版本选择的诊断提示。
OpenCode 读取了源代码并搜索了测试用例。它最初建议使用 pytest,尽管该项目使用的是 Python 内置的 unittest。权限提示让我有机会在授权前检查命令。对于下一个任务,我会在提示中明确包含测试命令:python3 -m unittest -v。
代理找到测试用例并请求权限运行测试命令。
当本地环境响应后,退出 OpenCode。保持 Ollama 在终端 B 中运行。
/exit关闭网络连接
关闭 Wi-Fi 并断开以太网或手机热点连接(如果已连接)。本地服务仍可工作,因为请求会在 Mac 内部处理。
为连接性检查关闭了 Wi-Fi。
在终端 A 中检查 Ollama 的本地 API。
curl --noproxy '*' --fail http://127.0.0.1:11434/api/tagsOllama 仍然响应并列出已下载的 qwen3.5:9b 模型。
然后尝试访问外部地址。
curl --noproxy '*' --connect-timeout 5 --max-time 10 --head https://example.com外部请求失败,提示 Could not resolve host。
这些检查确认了捕获时的情况:本地服务响应正常,但外部查询失败。在执行编码任务时,保持所有外部连接断开。
离线修复错误
再次使用相同的直接命令在终端 A 中启动 OpenCode。
请代理修复错误。
在 expense_total.py 中修复错误,使现有测试通过。不要修改测试或安装任何内容。运行测试并解释你的修复方案。记录显示 Qwen 提出了一行代码修改,请求编辑权限并运行测试。修改幅度较小,因此易于检查。
total = Decimal(amount) # 修复前total += Decimal(amount) # 修复后记录的编辑和测试周期。Qwen 提出修复方案,请求批准后成功运行了五次测试。
代理完成操作后,在运行自己的检查前退出 OpenCode。
随后我们在终端 A 中自行运行了测试。
手动检查显示所有五项测试均通过。
保存的源代码包含 total += Decimal(amount),测试文件与初始版本完全一致。该修复方案现在可以累加每个金额。运行示例程序应返回 25.50。
两个更多编码任务可供尝试
我在配套项目中加入了两个更多练习:CSV 报告和日志分析器。我尚未完成它们的离线代理运行,因此上述结果来自费用示例。这些是使用相同设置需要尝试的下一个任务。
CSV 报告示例从一个未完成的函数开始。请 OpenCode 按产品分组,计算数量和收入,并生成可读报告。它包含示例数据和七个测试用例,涵盖分组、十进制运算、排序和空输入等场景。
CSV 报告:代码与实现说明
使用其 README 完成 examples/csv-report/csv_report.py 示例。保持测试用例不变,无需安装任何依赖。运行该示例的测试用例并解释你所做的修改。
日志分析器目前已能运行,但存在错误计数和选择最慢请求的缺陷。其七个测试用例同样覆盖了格式错误的行和空输入等场景。
日志分析器:代码与实现说明
使用其 README 修复 examples/log-analyzer/log_analyzer.py 示例。保持测试用例不变,无需安装任何依赖。运行其测试用例并解释你的修复方案。
每个实现说明都包含精确的测试命令和预期结果。使用相同的本地环境运行练习,然后检查修改内容和测试输出。
网络不可用时的应对策略
- 提前准备项目和模型。下载所有依赖并保存所需的文档到本地磁盘。我们的示例使用 Python 标准库,因此测试用例无需下载第三方包。
- 在联网时一次性启动完整环境。使用相同的命令、模型和配置进行离线尝试,确保所需的运行时组件已预先加载。
- 为代理提供明确的测试命令。即使示例使用 unittest,我们的初始建议仍是 pytest。清晰的测试命令可减少不必要的迂回操作。
- 保持任务聚焦并验证结果。每次只请求一个 bug 修复或小功能,审查代码差异并亲自运行测试。保留原始测试用例可确保结果验证的有效性。
- 注意内存压力。模型下载只是内存消耗的一部分,大上下文和其他打开的应用程序会进一步压缩模型可用内存空间。
- 记录需要帮助的尝试过程。有价值的实现说明应展示权限提示、重试和失败过程,以及最终通过的输出结果。
离线尝试的收获
关闭 Wi-Fi 后看到测试通过回答了我最初的疑问:我可以在无网络连接时使用编码代理读取本地文件、进行修改并运行检查。我仍然会亲自审查修改内容并运行原始测试用例。保持原始测试用例不变为我提供了一种有效的结果验证方式。
在断网或旅途中使用此设置时,我会从简单独立的任务开始。项目及其所有依赖必须在连接消失前已保存在笔记本电脑中。这个单行修复无法说明模型处理大型仓库或陌生框架的表现。CSV 报告是下一个有用的验证:它要求代理完成函数,因此需要检查的内容比单行修复更丰富。