opencode 技能加载全挂背后,竟是不用系统的ripgrep

花了整整一下午跟 opencode 的 skill 工具死磕,各种改配置、查文档、翻源码,甚至怀疑自己是不是写了个假技能。结果呢?原因离谱得令人发笑------opencode 没有自带 rg,而我的网络又下不了。

本文完整记录这次排查全过程,包括走过的弯路、踩过的坑、最终的修复,以及对 opencode 生态的一些思考。希望这些经验能帮你节省半天时间,不要再踩同一个坑。

一、背景:我在做什么?为什么需要这些技能?

先交代一下背景,否则这个问题可能显得有些抽象。

最近我在搭建一套跨平台自动化工具链,核心场景是这样的:

场景一:WSL2 环境要调 Windows 的能力

我的主开发环境是 WSL2(Ubuntu 26.04),但有些任务必须在 Windows 端执行------比如操作 Windows 注册表、管理 Windows 服务、调用 PowerShell 特有的 cmdlet。直接在 WSL 里 powershell.exe 跨进程调用虽然可行,但不够优雅,返回结果处理也很麻烦。

于是我写了一个 win-shell-selfskill 技能 ,通过 MCP(Model Context Protocol)通道,让 opencode 可以直接调用 Windows 端的 cmdpowershell,输出自动转回给 LLM 上下文。

场景二:文档知识库的自动化管理

还有一个 anythingllm-knowledge-embed 技能,自动把本地文档(.md/.txt/.pdf/.docx)上传到自托管的 AnythingLLM(跑在 localhost:3001),并嵌入到指定工作区。这样可以构建自己的私有知识库,让 LLM 基于我自己的文档回答问题。

场景三:Windows 脚本编码修复

还写了个 bat-encoding-fixer 技能,专门解决 Windows .bat/.cmd 文件的中文乱码问题。Windows 批处理文件的编码问题是老大难,这个技能可以自动检测编码、处理换行符,让脚本在不同环境下都能正常运行。

三个技能都写好了,SKILL.md 格式也没问题,信心满满准备测试。

然后------全军覆没

二、现象:技能全部罢工,grep 也跟着摆烂

那天照常在 WSL2 的 opencode 里操作,先测试 skill() 工具:

javascript 复制代码
skill("win-shell-selfskill")

结果------

什么都没有。

没有技能加载提示,没有报错信息,没有超时等待,什么都没有发生。就像调用了一个 void 函数,往黑洞里扔了一块石头,连个回声都没有。

换一个技能试试:

javascript 复制代码
skill("anythingllm-knowledge-embed")

还是一样,静默得可怕。

"是不是技能文件路径写错了?"我这么想着,改了几次路径,依旧没有效果。

顺手试了下 grepglob

scss 复制代码
grep("pattern", "*.js")  // 没有结果
glob("**/*.ts")           // 没有结果

这两个工具也一起挂了。同一时间内,技能加载、内容搜索、文件发现三大核心功能全线瘫痪。

翻日志文件,发现了一条反复刷的存在感很强的错误:

复制代码
ripgrep execution failed

第一反应:这不就是少了个 ripgrep(rg)吗?Linux 下一行命令就能解决:

bash 复制代码
sudo apt install ripgrep

装好了,rg --version 也正常输出版本号。重启 opencode,再试------

还是挂。

三、排查之路:从怀疑技能到怀疑系统

既然 apt install ripgrep 没用,那问题可能不在 ripgrep 本身。我开始系统性地排查:

尝试 1:检查技能文件格式

也许我的 SKILL.md 写错了?

打开技能文件,检查 frontmatter:

yaml 复制代码
---
name: win-shell-selfskill
description: 通过 win-shell MCP 通道调用 Windows 端命令
license: MIT
---

## 技能说明
...

格式完全正确。换成另一个技能,依旧无法加载。排除技能定义问题。

尝试 2:检查文件权限

技能文件权限有问题?ls -l 检查一下:

css 复制代码
-rw-r--r-- 1 admin admin ... SKILL.md

权限正常,可读可写。排除权限问题。

尝试 3:检查 opencode 版本

opencode 版本过旧导致的 bug?查看版本:

bash 复制代码
opencode --version
# 输出正常,版本最新

排除版本问题。

尝试 4:检查 WSL 环境配置

WSL 环境本身有问题?检查 PATH、环境变量、权限:

bash 复制代码
echo $PATH  # 正常
which opencode  # 正常

环境配置完全没问题。排除 WSL 配置问题。

尝试 5:检查 opencode 日志

这个关键。打开日志文件(~/.local/share/opencode/log/opencode.log),开始逐行分析。

日志里有这么几行关键内容:

bash 复制代码
timestamp=2026-09-09T... level=INFO message="downloading ripgrep" url=https://github.com/BurntSushi/ripgrep/releases/download/15.1.0/ripgrep-15.1.0-x86_64-unknown-linux-musl.tar.gz

这说明 opencode 正在尝试从 GitHub 下载 ripgrep。但是,下载之后应该有的后续日志都没有

  • 没有 downloaded ripgrep successfully
  • 没有 extracted ripgrep to path
  • 没有 ripgrep installed

只看到开始下载,没有看到结束。

往下翻,果然看到了错误:

复制代码
ripgrep execution failed

这个错误在每次调用 grep/glob/skill 时都会出现。

四、真相:opencode 根本不用系统的 rg

通过源码分析,我终于发现了最坑爹的地方。

opencode 没有捆绑 ripgrep,但它需要 ripgrep 来做文件检索。它的设计思路是:

  1. 首次启动时,检查私有缓存目录是否有 rg;
  2. 没有的话,从 GitHub Releases 下载一个;
  3. 下载完成后,解压到缓存目录;
  4. 后续启动时,直接用缓存目录里的 rg。

关键问题是:这个私有缓存目录是什么?

答案是:

javascript 复制代码
~/.cache/opencode/bin/rg

这个路径就是 opencode 的"命脉"。它对 rg 的态度是这样的:

  1. 优先级 1 :去 ~/.cache/opencode/bin/rg 找找看?
  2. 优先级 2:没有?那去 GitHub 下载一个放这里。
  3. 优先级 3:下载失败了?......那就不找了。报错。

重点来了:即使你的系统里早就装好了 rg(比如通过 apt install ripgrep),opencode 完全无视。 它只认自己私有缓存目录里的那个。既然你用,为什么不默认安装!

这意味着:除非那个 ~/.cache/opencode/bin/rg 文件存在且可执行,否则 skillgrepglob 三个内置工具全线报废。

为什么这个设计会出问题?

这个设计背后的思路可能是:确保所有用户用的 ripgrep 版本一致,避免版本差异导致的行为差异。 这对于工具稳定性确实有好处。

但它忽略了两个现实情况:

  1. GitHub 在某些地区无法直接访问(比如中国大陆),下载会静默失败;
  2. opencode 不回退到系统 PATH 里的 rg,即使用户已经手动安装了 ripgrep,它也不认。

于是就出现了"系统有 rg,opencode 愣是不用"的尴尬局面。

五、为什么会下不了?网络环境的关键

为什么我的环境下载失败了?

因为我这台机器的网络环境是中国大陆

测试了一下网络:

bash 复制代码
# 百度------正常
curl https://www.baidu.com
# HTTP/1.1 200 OK

# GitHub------超时
curl https://github.com
# curl: (7) Failed to connect to github.com port 443: Connection timed out

百度随随便便访问,GitHub 根本连不上。

opencode 首次启动时尝试下载 rg:

bash 复制代码
url=https://github.com/BurntSushi/ripgrep/releases/download/15.1.0/ripgrep-15.1.0-x86_64-unknown-linux-musl.tar.gz

GitHub 连不上,下载静默失败。缓存目录里什么都没落下来,rg 的状态从始至终都是"不存在"。

skill 工具每次被调用,都会因为找不到 rg 而报 ripgrep execution failed

最讽刺的是: 错误信息明明写着"ripgrep execution failed",给人一种"rg 有但执行出错了"的错觉。实际上根本就是rg 压根不存在

后来翻日志,发现 opencode 在每次启动时都会打一行 downloading ripgrep,但下载完成后应该有的 downloaded / extracted / installed 日志永远没有出现------下载无声无息地失败了,而且 opencode 还把失败状态缓存了,同一进程内不会再重试。只有重启才能重新触发下载,但在我的网络环境下,重试的结果永远一样。

离线环境呢?

想象一下,如果一台机器完全离线(没有网络访问能力),opencode 第一次启动时会尝试下载 rg → 失败 → 所有依赖 rg 的工具全部不可用。整个工具链直接废掉。

这种情况在企业内网、涉密环境、离线开发环境中完全可能发生。

六、修复:借 Windows 的手,把 rg 塞进正确的位置

既然 WSL 下不了 GitHub,那就绕个弯------用 Windows 宿主机的网络下载

我这边的环境正好配了 win-shell MCP 通道(通过 opencode 的 win-shell_run_cmd / win-shell_run_powershell 工具直接操作 Windows 端)。于是我这么搞:

第一步:让 Windows 下载 ripgrep

通过 win-shell_run_powershell 让 Windows 端的 PowerShell 下载 ripgrep-15.1.0-x86_64-unknown-linux-musl.tar.gz(注意是 Linux 版本,因为 rg 是要放到 WSL 里跑的),存到 Windows 临时目录:

sql 复制代码
C:\Users\Administrator\AppData\Local\Temp\ripgrep-15.1.0-x86_64-unknown-linux-musl.tar.gz

Windows 端能直连 GitHub,下载顺利完成。

下载命令(PowerShell):

powershell 复制代码
Invoke-WebRequest -Uri "https://github.com/BurntSushi/ripgrep/releases/download/15.1.0/ripgrep-15.1.0-x86_64-unknown-linux-musl.tar.gz" -OutFile "C:\Users\Administrator\AppData\Local\Temp\ripgrep-15.1.0-x86_64-unknown-linux-musl.tar.gz"

第二步:WSL 端解压并放到正确位置

在 WSL 里,把 Windows 临时目录里的压缩包解压:

bash 复制代码
# 进入 WSL,解压压缩包
tar -xzf /mnt/c/Users/Administrator/AppData/Local/Temp/ripgrep-*.tar.gz

解压后会得到一个目录,名字类似 ripgrep-15.1.0-x86_64-unknown-linux-musl/,里面就有我们要的 rg 二进制文件。

把它复制到 opencode 期望的路径:

bash 复制代码
# 创建目录(如果不存在)
mkdir -p ~/.cache/opencode/bin

# 复制 rg 二进制
cp ripgrep-15.1.0-x86_64-unknown-linux-musl/rg ~/.cache/opencode/bin/rg

# 加上执行权限
chmod 755 ~/.cache/opencode/bin/rg

第三步:重启 opencode

这步很关键。opencode 启动时会检测 ~/.cache/opencode/bin/rg 是否存在,如果存在就跳过下载流程,直接启用。

验证修复效果

bash 复制代码
# 确认 rg 可用
~/.cache/opencode/bin/rg --version
# 输出:ripgrep 15.1.0 - Simpler grep. Fast.

测试技能加载:

javascript 复制代码
skill("win-shell-selfskill")

成功了! 技能正常加载,所有内容都被注入到 LLM 上下文。

再测试另外两个技能:

javascript 复制代码
skill("anythingllm-knowledge-embed")  // ✅ 成功
skill("bat-encoding-fixer")            // ✅ 成功

grepglob 也同步恢复正常:

javascript 复制代码
grep("pattern", "*.js")  // ✅ 正常返回结果
glob("**/*.ts")           // ✅ 正常返回文件列表

从"全线瘫痪"到"全部修好",只差这一个文件。

七、为什么会这样?一句话总结

opencode 的 skill/grep/glob 三个工具都依赖 ripgrep 做文件检索,但 opencode 既不捆绑 rg,也不会回退到系统 PATH 里的 rg 。一旦 ~/.cache/opencode/bin/rg 不存在(下载失败 / 未下载),这三个工具就全部报废。而在中国大陆网络环境下,GitHub 下载几乎必定静默失败。

这是一个环境依赖 + 设计缺陷 + 网络受限的三重叠加。

从 opencode 的角度看

opencode 的设计初衷是好的:确保 ripgrep 版本一致性,避免系统差异导致的行为不一致。但它忽略了几个现实问题:

  1. GitHub 并不是全球可访问的,在很多地区会被墙;
  2. 离线环境完全不可用,没有网络就等于工具链断裂;
  3. 手动安装的系统 ripgrep 没有被识别,增加了用户的困惑;
  4. 失败状态被缓存,同一进程内不会自动重试,需要重启。

从用户的角度看

用户期望的行为是:

  1. opencode 启动时自动检测依赖,缺少时报清晰的错误(而不是静默失败);
  2. 优先使用系统已安装的 ripgrep(如果有的话),没有的话再尝试下载;
  3. 下载失败时给出明确的提示("无法连接 GitHub,请手动安装 ripgrep"),而不是让用户一直猜;
  4. 提供离线安装包或捆绑版本,让离线环境也能用。

八、一句话总结

opencode 技能加载失败的根因,往往不是技能本身的问题,而是 ripgrep 这个隐藏依赖出了问题。记住一个关键路径:

javascript 复制代码
~/.cache/opencode/bin/rg

这个路径里的 rg 存在且可执行,opencode 的技能、grep、glob 就能正常工作;不存在,它们就全部报废。

遇到问题,先查这个路径,再查网络环境,最后手动放置 rg,重启 opencode。搞定。


记录时间:2026-09-09 · 环境:WSL2 Ubuntu 26.04 + Windows 11 宿主机

相关推荐
j7~1 小时前
【Linux网络加餐(二)】《进程组,会话,控制终端,作业控制和守护进程》---详解
linux·运维·服务器·守护进程·会话·进程组·控制终端
天道jimmy1 小时前
VulnHub 系列:Prime,1
linux·运维·服务器
xiaoye-duck2 小时前
《Linux 网络编程》深入传输层 UDP 协议原理:端口、报文、缓冲区与内核源码解析
linux·网络·udp
好评1242 小时前
【Linux】数据链路层
linux·运维·网络
CC城子3 小时前
EtherNet/IP I/O 丢包排查(linux系统)
linux·单片机·tcp/ip·ethernetip
新时代牛马3 小时前
Linux 信号处理完整篇:从sigaction、掩码到内核发送与可重入排障
linux·运维·信号处理
程序员梅雨3 小时前
Linux & Shell 实用干货
linux·运维·服务器·后端·面试·php
吴声子夜歌3 小时前
编写Shell脚本——自顶向下设计
linux·运维·shell
M78佐菲4 小时前
HTML学习笔记
linux·笔记·学习·tcp/ip·html