Skip to content
格物致知
返回

OpenCode glob command failed 排查实录:当 AI Agent 帮你 Debug 自己的工具链

在内网部署 OpenCode + oh-my-opencode 多模型 Agent 编排系统的过程中,我反复遇到一个恼人的错误:glob command failed。每当 Agent 尝试搜索文件时,就会报错退出。

最有趣的是——最终帮我定位根因的,正是运行在这套系统上的 Kimi K2.5 模型自己。

排查过程

第一步:报错

使用 OpenCode 在 Ubuntu 24.04 服务器上执行任务时,Agent 调用 glob 工具搜索文件频繁失败:

Error: /usr/bin/grep: invalid max count

环境信息:

第二步:怀疑 ripgrep 未安装

报错显示用的是 /usr/bin/grep 而不是 rg。初步判断是系统没装 ripgrep,于是安装了 ripgrep:

apt install ripgrep

安装后确认 which rg 返回 /usr/bin/rg,版本正常。

第三步:退出当前 opencode,问题依旧

退出了当前 OpenCode 进程后重新启动,结果问题依旧。这说明安装 ripgrep 并没有解决问题——或者说,某些东西阻止了 OpenCode 使用已安装的 rg

第四步:让 Kimi K2.5 自行排查

这时候我做了一件反直觉的事:直接问正在使用的 Kimi K2.5 模型,让它分析自己为什么调用 glob 会失败。

我问它:“你之前多次报 glob command failed,请具体告诉我是什么原因?你调用什么东西失败了?”

模型的反应很诚实。它直接读取了 oh-my-opencode 的编译产物:

/root/.cache/opencode/node_modules/oh-my-opencode/dist/index.js

这才是关键——oh-my-opencode 插件覆盖了 OpenCode 原生的 glob 工具,有一套自己的实现,包含一个 resolveGrepCli() 检测函数。

第五步:杀掉所有 opencode 进程,问题解决

在 Kimi 的分析指引下,我意识到之前只是退出了当前的 opencode 进程,但 OpenCode 在后台还有其他进程在运行(如 server 进程、后台任务进程等)。这些后台进程中缓存的 cachedCli 变量仍然指向 grep

# 杀掉所有 opencode 相关进程
pkill -f opencode

# 重新启动
opencode

问题彻底解决。

根因分析

错误的调查方向:OpenCode 原生源码

在 Kimi 定位到问题之前,我还走了一段弯路——去看 OpenCode 的原生源码。克隆了 OpenCode 仓库,在 packages/opencode/src/tool/glob.ts 找到了原生实现。它 100% 使用 ripgrep,永远不会调用系统 grep。误诊了。

真正的罪魁祸首:oh-my-opencode 的检测逻辑

Kimi K2.5 在 oh-my-opencode 的编译产物中找到了 resolveGrepCli() 函数(约第 67735 行),其检测链如下:

1. getOpenCodeBundledRg()     → OpenCode 自带的 rg
2. findExecutable("rg")       → 用 spawnSync 找系统 rg
3. getInstalledRipgrepPath()  → OpenCode 下载的 rg
4. findExecutable("grep")     → 回退到系统 grep  ← 最终走到这里

为什么 rg 明明存在但检测失败?

findExecutable("rg") 内部使用了 spawnSync 来验证可执行文件。但 OpenCode 运行在 Bun 运行时环境中,Bun 的 spawnSync 行为与 Node.js 有微妙差异。这导致即使 /usr/bin/rg 存在且可执行,检测函数仍然返回失败,最终回退到系统 grep

为什么回退到 grep 后会报错?

oh-my-opencode 把 rg 特有的参数(如 --max-count)传给了 grep,参数格式不兼容 → invalid max count

cachedCli:为什么退出当前进程没用?

var cachedCli = null;  // 第 67718 行

这个全局缓存变量是问题反复出现的关键。一旦首次检测回退到了 grepcachedCli 就被设为 grep,之后整个进程生命周期都不会再尝试检测 rg

更关键的是:OpenCode 不是单进程应用。即使你在 TUI 里退出了当前会话,后台的 server 进程可能仍然在运行,这些进程里的 cachedCli 仍然缓存着错误的 grep。只有 pkill -f opencode 杀掉所有关联进程,才能彻底清除缓存。

解决方案

方案 1:杀掉所有进程并重启(✅ 实测生效)

# 注意:不是退出当前 opencode,而是杀掉所有相关进程
pkill -f opencode

# 重新启动
opencode

**这就是最终生效的方案。**关键在于 pkill -f opencode(杀掉所有),而不是仅仅在 TUI 里按 q 退出(只退当前)。

方案 2:确保 Bun 环境能找到 rg(预防复发)

如果重启后问题反复出现,说明 Bun 运行时的 PATH 环境有问题:

PATH="/usr/bin:$PATH" opencode

或创建软链:

ln -sf /usr/bin/rg /usr/local/bin/rg

方案 3:硬编码 rg 路径(终极手段)

直接修改 oh-my-opencode 的编译产物,搜索 resolveGrepCli,在函数开头插入:

return { cli: "/usr/bin/rg", type: "rg" };

注意:oh-my-opencode 更新后会被覆盖。

方案 4:禁用 glob 工具

opencode.json 里禁掉 glob,模型会自动改用 bash + find

{
  "tools": {
    "glob": false
  }
}

经验总结

  1. 退出 ≠ 杀掉所有进程 — OpenCode 有后台 server 进程,仅退出 TUI 不会清除后台进程的内存缓存。遇到”明明重启了还不行”的情况,想想是不是有后台进程在作祟。

  2. 插件会覆盖原生工具 — oh-my-opencode 有自己的 glob/grep 实现,bug 可能不在 OpenCode 本身。排查时要分清调用的是哪一层的代码。

  3. 全局缓存是定时炸弹cachedCli 这种模式让问题变得间歇性、难以重现。首次检测失败就会”感染”整个进程树。

  4. 让 AI 自省很有效 — 与其从外部猜测 AI Agent 为什么失败,不如直接让它去读自己的工具链源码。Kimi K2.5 几分钟就从 oh-my-opencode 的编译产物里找到了我花半天在 OpenCode 原生源码里没找到的真正 bug。

这或许就是 Agent 时代 debug 的新范式:让 Agent 自己去理解自己为什么出错。


分享文章:

上一篇
全栈 UI 框架为什么不支持 OpenAPI?
下一篇
多模型 Agent 编排实战:一次提示词背后的 50 次 AI 协作