memory_search 突然变弱?一次 WSL 9p 协议 Bug 引发的血案
qmd 进程因 EIO 崩溃,OpenClaw 自动 fallback 到本地小模型——排查全过程复盘

memory_search 突然变弱?一次 WSL 9p 协议 Bug 引发的血案
本文更新于 2026-07-04。原始排查记录归档于 2026-05-17。
前言:一场悄无声息的降级
2026 年 5 月 16 日至 17 日,oc-engineer agent 的 memory_search 功能出现了一个诡异的现象——语义搜索质量突然大幅下降,但没有任何人主动修改过配置。
Gateway 日志里满是 unable to open database file 的错误,系统自动 fallback 到了内置的本地引擎(sentence-transformers/all-MiniLM-L6-v2)。这意味着原本强大的向量搜索 + reranking 被降级为本地小模型,搜索精度直线下降。
这就像你突然发现手机导航变慢了——功能还在,但体验已经天差地别。
错误链路还原:从 EIO 到全链路崩溃
问题的完整链条比想象中复杂得多:
1. Gateway 启动 → 触发 qmd session-start sync
2. qmd 递归扫描配置的 22 个 collection 路径
3. 扫描到 /mnt/g/.../AI/05-智能体 目录时
4. WSL 9p 协议层 scandir() 返回 EIO (I/O error)
5. qmd 进程以 exit code 1 crash
6. OpenClaw 捕获错误,报 "unable to open database file"
7. memory_search 自动 fallback 到 builtin 本地引擎
8. 搜索质量从 qmd 向量搜索降级为本地小模型关键点在于:真正的根因根本不是数据库文件本身有问题。而是 WSL 的 9p 协议层在扫描特定目录时触发了 I/O 错误,导致 qmd 进程崩溃。

为什么这么难排查?
如果你亲自参与过这次排查,就会知道它有多折磨人。我们尝试了整整六种方案,每一种都看似合理却全部失败:
| 尝试方案 | 预期结果 | 实际结果 | 教训 |
|---|---|---|---|
| 在 qmd paths 加 ignorePatterns | 跳过问题目录 | 配置校验失败,非 qmd schema | 不要瞎加不支持的字段 |
| umount/remount /mnt/g | 刷新 9p 缓存 | Protocol not available | WSL 内核 9p 是内建的 |
| chkdsk G: /f | 修复文件系统 | 无问题 | 问题不在 Windows 文件系统层 |
| 目录剪切到桌面再粘贴回 | 重建目录元数据 | inode 不变,EIO 依旧 | WSL 9p 缓存了旧句柄 |
| wsl –shutdown 重启 | 清除所有缓存 | 问题依旧 | 9p 缓存在 WSL VM 内部 |
| 修改 qmd index.yml 加 exclude | 排除问题目录 | qmd 不支持 exclude 字段 | 先查 schema 再修改 |
每一种方案的失败都指向同一个事实:问题不在用户空间,而在 WSL 内核层的 9p 协议实现中。
问题目录的技术特征
为了确认根因,我们对问题目录做了一系列技术检查:
| 检查项 | 结果 | 含义 |
|---|---|---|
| Windows chkdsk G: /f | 无问题 | NTFS 文件系统层完好 |
| WSL ls 目录 | 能列出文件名,exit code 2 | readdir 返回 EIO |
| WSL stat 目录内文件 | 全部正常 | 文件本身可访问 |
| WSL mkdir/rmdir 子目录 | 正常 | 目录写权限正常 |
| WSL inode 号 | 重启前后不变 | 9p 缓存了旧句柄 |
| WSL 重启 (wsl –shutdown) | 问题依旧 | 缓存在 WSL VM 内核层 |
这些检查结果勾勒出了一个清晰的画像:Windows 侧的文件系统完好无损,问题出在 WSL 与 Windows 之间的 9p 协议层。
真正有效的修复步骤
在排除了所有错误方向之后,最终的修复方案出奇地简单:
- 在 Windows 资源管理器中将
05-智能体目录剪切到桌面再粘贴回原位置(并重命名为05-agent 智能体) - 执行
wsl --shutdown完全重启 WSL - 手动修复被污染的 openclaw.json 配置(移除之前瞎加的 ignorePatterns 字段)
- 执行
openclaw gateway restart重启 gateway - 验证
openclaw config validate通过
重启后,memory_search 恢复正常,qmd provider 正常工作,不再 fallback 到 builtin。

根因深度分析
WSL 9p 协议层 Bug
WSL 的 9p 协议是 Linux 内核与 Windows 文件系统之间的桥梁。某些目录状态变化(删除子目录、权限变更、元数据修改等)会导致 9p server 在 readdir 系统调用时返回 EIO,即使 Windows 侧目录元数据完好无损。
这是一个 WSL2 内核与 Windows 9p server 之间的协议层问题,用户空间无法修复。
OpenClaw 错误处理过于激进
qmd session-start sync 失败后,OpenClaw 直接报 "unable to open database file",这个错误信息具有严重误导性,让排查方向偏离到数据库文件本身,而不是 qmd 进程 crash 的真正原因。
qmd + WSL + Windows 9p 是不稳定组合
qmd 依赖递归扫描文件系统建立索引,而 WSL 的 9p 协议在目录元数据缓存方面存在已知限制,两者结合容易触发 EIO 错误。
生产环境建议
基于这次排查的经验,我给出三个递进式的解决方案:
方案 A(强烈推荐):迁移到 WSL 原生文件系统
将 Obsidian vault 迁移到 WSL 原生文件系统(如 ~/obsidian-vault),完全避免 9p 协议层问题。性能更好,稳定性更高。
方案 B(妥协方案):改回 builtin 引擎
如果必须使用 Windows 盘挂载,将 memory.backend 改回 "builtin",牺牲搜索质量换取稳定性。builtin 引擎不依赖外部进程,不会触发 session-start sync。
方案 C(监控方案):添加 EIO 错误检测
如果坚持用 qmd + 9p 组合,添加监控脚本检测 qmd session-start 日志中的 EIO 错误,发现后立即告警并定位问题目录。
经验教训
这次排查给我上了好几课:
第一,优先验证数据库本身。 一开始就应该用 sqlite3 直接打开所有相关数据库文件验证完整性和权限,而不是绕弯子查目录权限、9p 缓存、文件系统损坏等外围问题。
第二,9p 缓存无法在用户空间清除。 WSL 的 9p 缓存在内核/VM 层,wsl --shutdown 不一定能刷新,需要完全重启 WSL VM 或等待微软修复内核 bug。
第三,不要瞎改配置。 添加不支持的 schema 字段(如 ignorePatterns)只会污染配置文件,增加后续修复成本。修改配置前必须先查 schema 定义。
第四,错误日志要完整捕获。 Gateway 日志会被新日志快速冲刷,关键错误要在出现时立即捕获保存,否则后续排查缺乏依据。
第五,session 上下文限制要注意。 排查期间 oc-engineer 子会话 cb2b3da0 因输入超过 131072 tokens 而 failed,长会话需要定期归档或重置上下文。
后续行动
- 检查其他 21 个 collection 路径是否存在类似 EIO 风险(特别是
/mnt/g/和/mnt/j/挂载路径) - 评估将 AI vault 迁移到 WSL 原生文件系统的工作量和风险
- 在 OpenClaw GitHub 社区反馈 qmd session-start 错误信息不够明确的问题
- 建立定期归档机制,避免子会话上下文超过 131072 tokens 上限
归档自 agent-ops 与风哥的排查会话 | Session: 50712bc2-bcf3-4ac8-b715-eedc7f8a08ca | 原始归档时间:2026-05-17 18:02
–全文完–

梦行志
