1596 字
8 分钟
为什么 AI Agent 总说「用 CloakBrowser」却偷偷调了 Playwright?—— 一次跨层排障与开源贡献

事情开始于一个简单的测试:「测试一下 cloakbrowser 能不能用。」

一个诡异的退化#

CloakHQ
/
cloakbrowser
Waiting for api.github.com...
00K
0K
0K
Waiting...

CloakBrowser 是一个防检测浏览器——它在 Chromium 源码层面打了 48 个 C++ 补丁,能通过 reCAPTCHA v3、Cloudflare Turnstile、FingerprintJS 等几乎所有 bot 检测。npm 安装后,API 长这样:

import { launch } from 'cloakbrowser';
const browser = await launch();

这是它 README 的第一行代码。

但 OpenCode 里的 agent 写了这个:

import { chromium } from 'playwright';
const browser = await chromium.launch({
  executablePath: '~/.cloakbrowser/chromium-.../chrome'
});

它把 cloakbrowser 当成了 Playwright 的 drop-in 二进制,而不是一个有自己 API 的包。 完全跳过了 cloakbrowser 自己的 launch() 函数,直接把它当原始 Chromium 喂给 Playwright。

第一步:我以为问题在 agent 身上#

我的第一反应很自然:「agent 没读文档。」

cloakbrowser 有 package.json,有 README,有 exports 字段。只要读了其中任何一个,都不会犯这个错。问题是 agent 没读——它看到 cloakbrowser info 输出一个二进制路径,就直接模式匹配到了 chromium.launch({executablePath})

这看起来是一个可以通过规则约束解决的问题。我花了相当的时间做了一个 docs-before-code skill,按照完整的 RED-GREEN-REFACTOR 方法论:

阶段测试结果
RED 基线agent 用 listr2 写代码(不读文档)暴露了「我知道这个库」的合理化
GREEN 验证agent 用 vitest 程序化 API(按 skill 规则)先查 vitest/node 子路径,再写代码 ✅
REFACTOR 压力agent 用 execa v9(2 分钟限制 + 旧记忆)发现 tagged template 新语法,避免写旧 API ✅

这个 skill 本身是有效的。它的 Gate Function(五个步骤:IDENTIFY → LOCATE → VERIFY → CONFIRM → 写代码)能在 agent 写 import 语句之前拦下它,强制它先去读 package.json 的 exports 字段和 README 的第一段代码。execa v9 的压力测试证明了这一点——即使 agent 的记忆里是 execa('cmd', [args]) 的旧 API,skill 也强迫它先查了文档,发现了 v9 的 tagged template 新语法。

但我很快就发现,cloakbrowser 的问题完全没有被解决。

第二步:发现 skill 完全没用#

我回去翻其他会话记录。三个不同的 session 里,用户明确说了「用 cloakbrowser」,agent 全都退化到了 Playwright MCP 工具。

其中一个 session 的转写特别刺眼:

User:  "设置界面和你说的不一样,你用 cloakbrowser 配置"
Agent: → 加载 dev-browser skill
Agent: → 加载 playwright skill
Agent: → 调用 playwright MCP 的 browser_navigate
Agent: → 完全没用 cloakbrowser

agent 根本没走到写 import 那一步。 它没有写 Node.js 脚本、没有 npm install、没有 import 语句。它直接调了 Playwright MCP 的 browser_navigatebrowser_click 这些现成的工具。

我花了两天写的 docs-before-code skill,在真实场景里一次都没触发过。不是它写错了,是它的触发条件(写 import 语句)和故障场景(MCP 工具选择)根本不在同一层。

这就好比你给司机装了一个「开车前检查后视镜」的提醒,但他连车都没上——他在车库门口就被导航系统指引到另一辆车上了。

第三步:追到 OMO 源码#

如果 agent 是在「工具选择」阶段被拐走的,那一定有什么东西在系统 prompt 里告诉它「浏览器任务必须用 Playwright」。

我开始翻系统配置。OpenCode 的 opencode.jsonc 里没有 Playwright MCP 配置。AGENTS.md 里也没有写死 Playwright。那这个偏好是哪里来的?

答案在 OMO(Oh-My-OpenCode)插件里。在其缓存安装目录 oh-my-openagent/dist/ 的源码中,我找到了这段:

var playwrightSkill = {
  name: "playwright",
  description: "MUST USE for any browser-related tasks. Browser automation via Playwright MCP ...",
};

“MUST USE for any browser-related tasks” —— 这是一条注入到 agent 系统 prompt 里的死命令。当用户说「用 cloakbrowser」时,agent 的语义解析是这样的:

"cloakbrowser" → 包含 "browser" → 这是 browser-related task → "MUST USE playwright"

系统级指令(skill description)的优先级比用户消息更高。用户的 cloakbrowser 被语义压缩成了 browser,然后被 MUST USE 抢占了。

进一步分析确认了 OMO 有一个 browser_automation_engine 配置项:

export const BrowserAutomationProviderSchema = z.enum([
  "playwright",
  "agent-browser",
  "dev-browser",
  "playwright-cli",
  // 没有 "cloakbrowser"
])

provider: BrowserAutomationProviderSchema.default("playwright")

可选值只有四个,默认是 playwright。cloakbrowser 不在选项里。

这意味着:即使用户完全不配置任何东西,agent 看到的系统 prompt 里也会有一行 playwright: MUST USE for any browser-related tasks。这不是 OMO 故意排斥 cloakbrowser——它只是还没被适配进去。

但这件事揭示了一个更深的问题:当框架有一个「强制指定工具」的机制时,不在名单里的工具根本就没有被正确使用的可能性。 无论你写多少 skill、优化多少 prompt,agent 都会被上游的「MUST USE」指令拖走。

修框架本身#

理解了根因之后,修复就很清晰了:把 cloakbrowser 加进 browser_automation_engine 的 provider 选项。

我 fork 了 OMO 仓库,在 feat/cloakbrowser-provider 分支上改了 4 个文件,总共 +126 行:

文件改动
src/config/schema/browser-automation.ts添加 "cloakbrowser" 到 provider enum
src/features/builtin-skills/skills/cloakbrowser.ts新建,119 行的 skill 模板,覆盖完整 API
src/features/builtin-skills/skills/index.ts导出 cloakbrowserSkill
src/features/builtin-skills/skills.tscreateBuiltinSkills 里添加 cloakbrowser 分支

新增的 cloakbrowser skill 包含了完整的 API 参考:三种启动方式(launchlaunchContextlaunchPersistentContext)、配置选项(headless、proxy、timezone、geoip、humanize)、CLI 工具、reCAPTCHA 优化技巧、与原生 Playwright 的关键差异。

合并后,用户只需在 oh-my-openagent.json 里加一行:

{ "browser_automation_engine": { "provider": "cloakbrowser" } }

agent 就不会再看到 playwright: MUST USE for any browser-related tasks,而是看到 cloakbrowser 的 skill,知道什么时候用它、怎么用它。

PR 已提交#

code-yeongyu
/
oh-my-openagent
Waiting for api.github.com...
00K
0K
0K
Waiting...

PR #4337:feat: add cloakbrowser as browser automation engine provider

  • TypeScript 类型检查:✅ 零错误
  • browser_automation_engine schema 测试:✅ 3/3 通过
  • 构建:✅ 成功

反思#

这件事最反直觉的地方在于:你以为是 agent 没读文档,最后发现是文档根本不在 agent 的视野里。

我花了两天写了一个精心测试过的 skill,它确实能解决它设计要解决的问题(agent 写 import 之前先查 API),但它对 cloakbrowser 的退化问题毫无作用——因为那个问题根本不在代码编写层。

docs-before-code 在工厂流水线的「组装」环节装了一个质检站,但我真正需要修的是「零件进料口」——工具选择那一层。错误不在 agent 怎么写代码,而在 agent 一开始就被给了错误的工具。

这也是一条给 AI agent 框架开发者的原则:如果你的框架有一个「强制指定工具」的机制,确保新工具能平等地接入它。 否则,你的框架就不是助推器,而是壁垒。

为什么 AI Agent 总说「用 CloakBrowser」却偷偷调了 Playwright?—— 一次跨层排障与开源贡献
https://lorenzofeng.top/posts/cloakbrowser-omo-pr/
作者
Lorenzo Feng
发布于
2026-05-24
许可协议
CC BY-NC-SA 4.0