开源终端编码 Agent opencode 跑不动:按模型、认证、Windows、代理证书的顺序排查
本文基于 opencode 仓库 commit 7fe9938(2026-08-04)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/anomalyco/opencode 最新代码与文档为准。
**opencode 跑不动的时候,绝大多数人浪费时间的原因只有一个:从最上层的现象开始猜,而不是从最底层的链路开始查。**它的报错文案经常只反映最后一跳失败的那个环节,比如你看到的是模型不可用,真正断掉的却是代理没放行本地回环。把排查顺序固定成「连不上模型 → 认证失效 → Windows 上的路径与 WSL → 代理与证书」,一层查完再往下走,能省掉大半时间。
这篇只讲这条链路。站内已有几篇相邻的文章负责别的层面:Agent 失败分类 讲的是任务跑歪了怎么归因,Agent 框架调试 讲的是框架内部行为怎么看,API 超时与重试终端 讲的是请求层的超时策略;本篇不重复它们,只盯 opencode 这个具体项目的环境与链路故障。
一、动手之前:先知道它把东西放在哪
opencode 是个装在你机器上的 CLI,出问题时最有价值的信息不在终端刷过去的那几行红字里,而在它自己的落盘目录中。仓库文档 packages/web/src/content/docs/troubleshooting.mdx 明确写了两个位置:日志写到 ~/.local/share/opencode/log/,Windows 上是 %USERPROFILE%\.local\share\opencode\log;日志文件按时间戳命名,只保留最近 10 份。想看细节,用全局参数 --log-level 把级别调到 DEBUG,或者用 --print-logs 让日志直接打到终端上,这样你不用切窗口去翻文件。
同一份文档还说明了数据目录 ~/.local/share/opencode/ 下的结构:auth.json 存 API key 和 OAuth token,log/ 存日志,project/ 存会话与消息数据——如果当前目录在 Git 仓库里,会话落在 ./<project-slug>/storage/;不在 Git 仓库里,则落到 ./global/storage/。这一条在排查「上次的会话怎么找不回来了」时特别管用:你多半是在仓库外面启动的,会话被归到了全局那一档。
另外有个独立的缓存目录 ~/.cache/opencode。opencode 会按需动态安装各家的 provider 包并缓存在本地,这个设计让首次使用某个服务商时不必预装依赖,代价是缓存一旦过期或损坏,症状会伪装成 API 调用错误。
下面这张表把这次排查会碰到的几个组成部分对上仓库里的真实位置,方便你自己开仓核对:
| 组成部分 | 它负责什么 | 对应仓库位置 | 你什么时候会碰到它 |
|---|---|---|---|
| 故障排查文档 | 日志/存储/缓存路径、常见报错的处置 | packages/web/src/content/docs/troubleshooting.mdx | 任何一次「起不来」「报错看不懂」 |
| 网络文档 | 代理环境变量与自定义 CA 证书 | packages/web/src/content/docs/network.mdx | 公司网、抓包网关、自签证书环境 |
| Windows/WSL 文档 | WSL 里装与跑、跨系统访问文件 | packages/web/src/content/docs/windows-wsl.mdx | Windows 上性能差、文件访问异常 |
| CLI 参考 | 子命令、全局参数、环境变量清单 | packages/web/src/content/docs/cli.mdx | 想确认某个变量名到底叫什么 |
| 服务商配置 | baseURL、npm 等 provider 配置键 | packages/web/src/content/docs/providers.mdx | 接自建网关或兼容接口 |
| 权限模型 | allow/ask/deny 三态与 --auto | packages/web/src/content/docs/permissions.mdx | 决定它能不能自己执行命令、改文件 |
| Shell 选择逻辑 | Windows 上怎么找到 Git Bash | packages/core/src/shell.ts | Windows 上执行命令类工具失败 |
| 环境变量读取 | 把 OPENCODE_* 读进内部标志 | packages/core/src/flag/flag.ts | 你设了变量却像没生效 |
| 路径归一化 | 处理 Git Bash / MSYS2 的 /<drive>/ 路径 | packages/opencode/src/util/filesystem.ts | Windows 上路径解析对不上 |
顺带说一句规模感:这个仓库 packages/ 下有 32 个包,英文文档 packages/web/src/content/docs/ 有 36 份 mdx。你遇到的多数问题,文档里其实已经有对应的一页——难点是知道该翻哪一页。
二、第一关:连不上模型
这一关最容易被误判,因为它有三种长得不一样的报错,处置手段完全不同。
第一种是模型引用写错。文档里说得很直白:碰到 ProviderModelNotFoundError,你多半是在某个地方错误地引用了模型。opencode 的模型标识固定是 <providerId>/<modelId> 两段式,文档给的例子包括 openai/gpt-4.1、openrouter/google/gemini-2.5-flash、opencode/kimi-k2。注意第二个例子是三段——服务商 id 后面跟的是该服务商自己的模型路径,别按「一定是两段」的直觉去砍。想知道你手上到底能用哪些,跑 opencode models,它按 provider/model 的格式列出所有已配置服务商的模型;加上 provider id 可以过滤,比如 opencode models anthropic。模型列表是有缓存的,服务商上了新模型而你这边看不到,用 opencode models --refresh 刷新。
第二种是 ProviderInitError。文档的判断是:你的配置很可能无效或者已经损坏。处置分两步,先按服务商文档确认配置本身对不对,还不行就清掉存储目录(rm -rf ~/.local/share/opencode,Windows 上删 %USERPROFILE%\.local\share\opencode),然后在 TUI 里用 /connect 重新认证。这一步的代价要提前算清楚:那个目录里躺着 auth.json 和你所有的历史会话,删掉就没了,别在没备份的情况下当成第一手段。
第三种是 AI_APICallError。文档把它归到 provider 包过时上——因为包是动态下载并缓存的,缓存里那份可能跟服务商最新的参数和接口对不上。处置是清 ~/.cache/opencode(Windows 上是 %USERPROFILE%\.cache\opencode)后重启,让它重新拉一遍。这个操作比清存储目录安全得多,缓存丢了只是重下,不会带走你的会话和凭据,所以在链路排查里应该排在清存储之前。
对你意味着什么:看到模型相关报错,先分清是「名字写错」「配置坏了」还是「包旧了」,三者对应查配置、清存储、清缓存三种完全不同的动作。顺序上先做代价最小的那个。
三、第二关:认证失效
模型名和配置都对,下一步看凭据。opencode 的凭据管理集中在 opencode auth 这一组子命令上:opencode auth login 配置某个服务商的 API key,凭据写进 ~/.local/share/opencode/auth.json;opencode auth list(简写 opencode auth ls)列出已认证的服务商;opencode auth logout 把某个服务商从凭据文件里清掉。在 TUI 里,对应的交互式入口是 /connect 命令。
这里有个容易踩的机制:文档写明,opencode 启动时会从凭据文件加载服务商,同时也会读取环境里定义的 key,以及项目目录下 .env 文件里的 key。多来源意味着可能打架——你以为在用刚 login 的那把 key,实际生效的是环境里那把旧的。凭据类问题查不动的时候,先把这三处都列出来看一眼,而不是反复重新登录。
服务商各自还有优先级规则。以 Amazon Bedrock 为例,文档列的顺序是:先 bearer token(AWS_BEARER_TOKEN_BEDROCK 环境变量,或通过 /connect 拿到的 token),然后才是 AWS 凭据链(profile、access key、共享凭据、IAM 角色、Web Identity Token、实例元数据),并特意提醒 bearer token 会盖过包括已配置 profile 在内的所有方式。各家规则不同且会调整,以官方最新说明为准;你要养成的习惯是——认证有问题时先确认哪一层在生效。
文档给的认证故障处置也是三条,顺序不要乱:先用 /connect 重新认证,再确认 key 本身有效,最后确认你的网络允许连到该服务商的 API。第三条其实已经跨到后面两关了,这也是为什么排查顺序里认证要排在网络之前——认证问题能被网络问题伪装,反过来不成立。
顺带提醒一句安全边界:auth.json 是明文躺在你磁盘上的凭据集合,共享机器、共享容器镜像、往外发日志的时候都要意识到它的存在。密钥怎么分级、怎么轮换,可以看 API 密钥安全管理。
四、第三关:Windows 上的路径与 WSL
前两关排除了,问题还在,而你在 Windows 上——那大概率就是这一关。
opencode 能直接跑在 Windows 上,但仓库文档 windows-wsl.mdx 的立场是推荐用 WSL,给出的理由是文件系统性能更好、终端支持完整、跟它依赖的开发工具兼容性更好。troubleshooting.mdx 里也把「Windows 上性能慢、文件访问有问题、终端有问题」统一指向了 WSL 这一页。
技术上的根子在于 shell 与路径。opencode 在 Windows 上会去找 Git Bash,packages/core/src/shell.ts 里这段逻辑是可以直接读的:
export function gitbash() {
if (process.platform !== "win32") return
if (Flag.OPENCODE_GIT_BASH_PATH) return Flag.OPENCODE_GIT_BASH_PATH
const git = which("git")
if (!git) return
const file = path.join(git, "..", "..", "bin", "bash.exe")
if (stat(file)?.size) return file
}
它先看 OPENCODE_GIT_BASH_PATH(CLI 文档对这个变量的描述就是「Windows 上 Git Bash 可执行文件的路径」),没有则顺着 git 的位置往上推两级再进 bin/bash.exe。两种情况会出事:Git 是绿色版或装在非常规布局下,推不出来;或者 PATH 里根本没有 git。对症做法不是重装 opencode,而是显式把 OPENCODE_GIT_BASH_PATH 指对。
路径还有一层。packages/opencode/src/util/filesystem.ts 里的注释写明:不能直接依赖 path.resolve(),因为 git.exe 可能来自 Git Bash、Cygwin 或 MSYS2,这些路径要在边界上做转换。它们长成 /<drive>/... 的样子,跟 Windows 原生路径是两套写法。遇到「明明文件在,它说找不到」,先怀疑这条转换边界。
如果选择走 WSL,文档给的是完整链路:在 WSL 终端里安装并使用,Windows 上的盘符通过 /mnt/c/、/mnt/d/ 访问。文档同时给了一条更省事的建议——把仓库直接克隆或复制到 WSL 文件系统里(例如 ~/code/)再跑,体验最顺。想用桌面端配 WSL 里的服务端,做法是在 WSL 里起服务:
opencode serve --hostname 0.0.0.0 --port 4096
然后让桌面端连 http://localhost:4096;如果 localhost 不通,就用 WSL 侧 hostname -I 拿到的 IP 换成 http://<wsl-ip>:4096。这里有条硬要求别跳过:文档明确警告,用 --hostname 0.0.0.0 时要设置 OPENCODE_SERVER_PASSWORD 给服务端加保护。这不是形式主义——那个端口后面挂的是一个能在你机器上跑命令、改你代码的 Agent,绑到 0.0.0.0 等于把它暴露给同网段。同理,opencode web 也建议在 WSL 终端里跑而不是 PowerShell,理由同样是文件系统访问和终端集成。
还有一点会让人困惑:文档写明,走 WSL 之后你的配置和会话存在 WSL 环境里的 ~/.local/share/opencode/。所以 Windows 侧和 WSL 侧其实是两套数据,别到处找为什么会话对不上。Windows 上装同类终端工具时踩的坑高度相似,可以对照 Claude Code 的 Windows 安装 一起看 Windows 这套环境本身的坑。
五、第四关:代理与证书
到这一关,通常是公司网环境。network.mdx 这一页很短,但每一条都是坑位。
opencode 认标准代理环境变量,文档给的写法是:
export HTTPS_PROXY=https://proxy.example.com:8080
export HTTP_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1
第三行不是可选项。文档用了 caution 级别的提示:TUI 是跟一个本地 HTTP 服务通信的,你必须让这条连接绕过代理,否则会形成路由回环。这条正是本文开头说的那种典型误判——现象是「连不上模型」,根因在于本地回环被代理吃掉了。设了 HTTPS_PROXY 却忘了 NO_PROXY 的人非常多。
代理需要基本认证时,文档给的是把凭据放进 URL(形如 http://username:password@proxy.example.com:8080),同时提醒避免硬编码密码,用环境变量或安全的凭据存储。如果你们的代理要求的是 NTLM 或 Kerberos 这类更复杂的认证,文档的建议是转而使用一个支持该认证方式的 LLM 网关——也就是说这条路 opencode 自己不打算走完。
自定义 CA 的处置只有一行:
export NODE_EXTRA_CA_CERTS=/path/to/ca-cert.pem
文档说明它对代理连接和直连 API 都生效。企业里做 TLS 拦截的环境下,不设它的表现通常是握手阶段就断,报错跟额度、模型都没关系,别往回去查前两关。
六、边界与代价:这套顺序不管什么
把话说全,这条排查链路有明确的适用范围,越界了继续按它查就是浪费时间。
它不管模型答得好不好。Agent 把需求理解偏了、改出一堆没用的代码、在错误的方向上反复循环——这些是任务层问题,跟连不连得上无关,别指望清缓存能治。
它不管远端的额度与策略。各家服务商的额度、限流、可用模型范围规则不同且会调整,以官方最新说明为准。opencode 这边能做的是把请求发出去、把错误如实报出来。
它也不管你的权限配置合不合理。permissions.mdx 里的模型是三态的:allow 直接跑、ask 每次问你、deny 直接拦;还有一个 --auto 模式,会自动批准所有未被明确 deny 的请求。这是个必须自己拿主意的取舍:全开 allow 或者常年挂 --auto,换来的是不被打断,代价是这个 Agent 可以在你机器上执行任意 shell 命令、直接改你的工作区文件。误删、误改、把半成品覆盖掉,都是这个配置下的正常后果而不是 bug。同理,编码 Agent 的工作方式就是把代码内容发给模型服务商——私有仓库、含密钥的配置文件、客户数据,一旦进了上下文就出了你的边界。这两件事没有任何排查技巧能补救,只能靠事前的权限与目录约束。相关的取舍可以对照 Agent 最小权限设计。
还有一类问题它明确交给了别处:桌面端的插件冲突、缓存损坏、服务端地址配错,走的是另一套处置(禁插件、清缓存、清默认服务端地址);Linux 上的复制粘贴要靠系统里装了 xclip、xsel 或 wl-clipboard 才行,这是外部依赖不是它的功能缺失。
七、上手与避坑清单
先清缓存再清存储。 会踩是因为两条命令长得像,一个是 ~/.cache/opencode,一个是 ~/.local/share/opencode。后者装着 auth.json 和全部历史会话,删了不可逆。避法:把「清缓存」当常规操作,「清存储」当最后手段,动手前先把 auth.json 拷一份到别处。
模型名按 <providerId>/<modelId> 写,且不要想当然砍成两段。 会踩是因为不同服务商的 modelId 本身可能带路径分隔。避法:不手写,跑一次 opencode models 把真实标识复制过来。
设代理必设 NO_PROXY。 会踩是因为 TUI 与本地服务之间那条连接是隐形的,你不会想到它也要走代理判定。避法:HTTPS_PROXY 和 NO_PROXY=localhost,127.0.0.1 永远成对出现,写进你的 shell 配置。
Windows 上先确认 Git Bash 找得到。 会踩是因为它靠 which("git") 往上推两级去猜 bash.exe,绿色版 Git 或非常规安装布局会推空。避法:显式设 OPENCODE_GIT_BASH_PATH,别让它猜。
服务端绑 0.0.0.0 必配 OPENCODE_SERVER_PASSWORD。 会踩是因为为了让桌面端连上 WSL 里的服务,--hostname 0.0.0.0 是文档给的标准做法,密码那一步很容易顺手跳过。避法:把变量和命令写在同一行一起执行,让它们物理上不可分离。
怀疑是插件的时候,用全局参数 --pure 起一次。 会踩是因为插件出问题的表现是行为古怪而不是明确报错,很难往那边想。CLI 文档对 --pure 的描述就是「不加载外部插件运行」,跑一次就能二分掉一大块可能性。桌面端那边的对应做法是把配置里的 plugin 键清空:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [],
}
顺带把插件这件事的边界说清楚:插件和 MCP server 都是你自己引进来的第三方代码,跑在你本机、能接触到会话上下文和当前工作区,多接一个就是多信任一份来源。它出问题的表现不止是崩溃,也可能是安静地读走它本不该读的东西。所以装之前先确认来源可查、改动可读,排查完别顺手把一堆试过的插件长期挂在配置里;同理,MCP server 连的是哪台机器、拿走了什么,也该在接入时就问清楚,而不是等出事再回头查日志。
别把配置目录和数据目录搞混。 会踩是因为两者路径风格接近:全局配置在 ~/.config/opencode/opencode.jsonc(早期安装可能在 ~/.local/share/opencode/opencode.jsonc),插件目录是 ~/.config/opencode/plugins/ 和项目里的 .opencode/plugins/。避法:改配置前先确认你编辑的是哪一个文件在生效。
收束:一份可以照抄的自检顺序
下次它跑不动,从上往下走,不要跳:
- 加
--log-level DEBUG --print-logs重跑一次,先拿到真实错误,而不是终端上那一行摘要。 - 看错误属于哪一类:模型名不对(查
opencode models)、配置坏了(ProviderInitError)、provider 包旧了(AI_APICallError,清~/.cache/opencode)。 - 用
opencode auth ls确认凭据在,并排查环境变量、项目.env、auth.json三处是否打架。 - 在 Windows 上,确认 Git Bash 路径解析正常;反复出问题就整体挪到 WSL 里跑,仓库放在 WSL 文件系统内。
- 在公司网里,确认
HTTPS_PROXY与NO_PROXY成对,自签 CA 环境补上NODE_EXTRA_CA_CERTS。 - 还是不行,用
--pure排除插件,再去仓库的 issue 里搜同类现象。
想继续往下挖的话,接下来该读的是仓库里这三份:packages/web/src/content/docs/cli.mdx(环境变量与子命令的完整清单,很多「有没有开关」的疑问在这里能一次问完)、packages/web/src/content/docs/providers.mdx(自建网关与兼容接口的 baseURL、npm 写法)、packages/web/src/content/docs/permissions.mdx(在放开自动执行之前,先把 deny 名单想清楚)。
本篇属于一个把开源AI 编程 Agent 项目 opencode逐层拆开讲的系列,整体地图见 opencode 是什么:终端里的开源 AI 编程 Agent 全景地图;沿着这条线往下,还可以看 opencode 的诊断与格式化两条线:语言服务器怎么报错、格式化器何时跑 和 opencode 安装上手:开源终端编码 Agent 的装法与避坑。