
1. 这个项目到底解决了什么痛点浏览器自动化这件事做过的人都懂。你写个脚本想让它帮你登录某个后台、抓点数据、自动填个表单结果第一步就卡住了——登录态。账号密码登录还好说遇到扫码登录、短信验证码、或者带二次验证的脚本直接歇菜。更别提有些系统压根不给你程序化登录的入口你只能老老实实手动点。传统的做法无非这么几种。一是用 Selenium 或者 Playwright 启动一个全新的浏览器实例然后想办法把登录流程也自动化掉。但登录流程本身往往是最难自动化的部分验证码、风控、设备指纹随便一个都能让你折腾半天。二是手动导出 Cookie 再注入到脚本里但 Cookie 有有效期过期了又得重新导而且有些站点的登录态不只在 Cookie 里还涉及 localStorage、sessionStorage、IndexedDB 等多个存储位置导起来非常麻烦。三是用一些浏览器扩展来桥接但扩展的权限和通信机制又有限制做复杂操作很别扭。腾讯这次开源的 BrowserSkill 项目思路就很直接既然你已经有一个登录好的浏览器摆在那里为什么不让 AI 直接用它呢不重新启动浏览器不重新登录不折腾 Cookie 导入导出直接连接到你已经开着的、已经登录好的 Chrome 浏览器上复用现有的登录态和会话让 AI 在这个浏览器里执行操作。这个思路听起来简单但真正落地需要解决几个关键问题。第一是怎么连接到已有的浏览器实例这涉及到 Chrome 的远程调试协议。第二是怎么让 AI 理解当前页面的状态并决定下一步操作这涉及到页面信息的提取和大模型的推理。第三是怎么保证操作的安全性和可控性不能让 AI 乱点乱填。BrowserSkill 这几个方面都做了处理下面我会逐一拆解。适合谁来参考这个项目呢如果你在做 AI Agent 相关的开发尤其是需要和真实网页交互的场景这个项目很有参考价值。如果你是个自动化测试工程师想看看怎么把 AI 引入到测试流程里也值得一看。哪怕你只是个对浏览器自动化感兴趣的开发者想了解怎么通过远程调试协议控制 Chrome这里面的实操细节也能给你不少启发。2. 核心架构与关键设计拆解2.1 为什么选择连接已有浏览器而不是新建实例这个设计决策是整个项目最核心的一点值得展开说。新建浏览器实例的方案比如 Playwright 默认的 launch 模式每次都是干干净净的环境没有登录态没有历史记录没有扩展。对于需要登录态的场景你必须在脚本里重新走一遍登录流程。而登录流程恰恰是最难自动化的部分因为各个网站的登录机制千差万别而且经常变。连接已有浏览器的方案本质上是把“登录”这个步骤交给人类来完成AI 只负责登录之后的操作。这个分工非常合理。人类擅长处理复杂的、需要判断的、一次性的任务比如扫码、输验证码、处理异常提示。AI 擅长重复性的、有明确规则的、大批量的操作比如填表单、点按钮、提取数据。各取所长整体效率最高。从技术实现上看连接已有浏览器需要 Chrome 以远程调试模式启动。具体来说就是在启动 Chrome 时加上--remote-debugging-port参数指定一个端口比如 9222。这样 Chrome 就会在本地监听这个端口接受通过 Chrome DevTools Protocol 发来的指令。BrowserSkill 就是通过这个协议和浏览器通信的。注意用远程调试模式启动 Chrome 时最好指定一个独立的用户数据目录不要用默认目录。因为如果 Chrome 已经在用默认目录运行了你再启动一个实例会冲突。指定独立目录的命令是--user-data-dir/path/to/your/profile。这个方案还有一个好处是你可以同时开多个浏览器窗口每个窗口登录不同的账号然后让 AI 分别操作。这在需要多账号操作的场景下非常实用。比如你管理着好几个店铺后台每个后台都要单独登录传统方案你得维护多套 Cookie现在只需要开多个窗口分别登录好AI 就能各操作各的。2.2 页面信息提取与 AI 决策的衔接连接上浏览器只是第一步更关键的是让 AI 知道当前页面上有什么应该做什么。BrowserSkill 在这方面的做法是通过 CDP 获取页面的 DOM 结构、可交互元素列表、以及每个元素的属性信息然后把这些信息整理成结构化的文本喂给大模型让大模型决定下一步操作。这里有个关键的设计取舍是给大模型看完整的 HTML还是看简化后的元素列表完整 HTML 的信息量大但噪音也多一个稍微复杂点的页面 HTML 就有几万行大模型的上下文窗口根本放不下。简化后的元素列表只保留可交互的元素比如按钮、输入框、链接、下拉菜单每个元素只保留必要的属性比如标签名、文本内容、位置、是否可见、是否可点击。这样信息量大幅减少大模型处理起来更快更准。但简化也有代价就是可能丢失一些上下文信息。比如一个按钮的文本是“提交”但页面上有好几个“提交”按钮分别属于不同的表单。如果只给大模型看按钮列表它可能分不清该点哪个。BrowserSkill 的解决办法是保留元素的层级关系和位置信息让大模型能根据上下文判断。比如“位于 id 为 login-form 的表单内的提交按钮”这样就明确多了。实际实现中页面信息的提取需要考虑几个细节。一是动态加载的内容有些页面是滚动加载或者异步渲染的你提取的时候可能还没加载完。二是 iframe 里的内容跨域 iframe 的内容通过 CDP 获取会有限制。三是 Shadow DOM 里的元素常规的 DOM 查询可能拿不到。这些边界情况都需要处理否则 AI 拿到的页面信息就是不完整的决策就会出错。2.3 操作执行的安全边界设计让 AI 直接操作你的浏览器这件事本身就让人有点不放心。万一 AI 理解错了点了个“删除”按钮怎么办万一它填错了数据提交了一个错误的表单怎么办BrowserSkill 在设计上考虑了这些风险做了几层防护。第一层是操作前的确认机制。对于高风险操作比如删除、提交、支付可以配置成需要人工确认后才执行。AI 先给出操作建议人类确认后再实际执行。这样既利用了 AI 的判断能力又保留了人类的最终控制权。第二层是操作范围的限制。可以配置 AI 只能操作特定域名下的页面或者只能操作特定类型的元素。比如只允许点击链接和填写输入框不允许点击按钮。这样即使 AI 判断失误也不会造成严重后果。第三层是操作日志和回滚机制。每一步操作都记录下来包括操作时间、操作类型、操作目标、操作前后的页面状态。如果发现操作有问题可以追溯原因也可以尝试回滚。当然网页操作的回滚不像数据库事务那么简单但至少日志能帮你快速定位问题。实操心得刚开始用的时候建议把确认机制开到最严格每一步操作都人工确认。跑一段时间观察 AI 的决策准确率如果稳定可靠再逐步放宽限制。不要一上来就全自动踩坑的概率很高。3. 从零搭建的完整实操流程3.1 环境准备与浏览器配置先说环境准备。你需要一台安装了 Chrome 的机器版本建议在 100 以上因为一些 CDP 的新特性在旧版本上不支持。操作系统 Windows、macOS、Linux 都可以BrowserSkill 本身是跨平台的。Node.js 环境也是必须的建议用 18 以上的 LTS 版本。第一步是配置 Chrome 以远程调试模式启动。最直接的方式是通过命令行启动# macOS 示例 /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ --remote-debugging-port9222 \ --user-data-dir/tmp/chrome-debug-profile # Windows 示例 C:\Program Files\Google\Chrome\Application\chrome.exe ^ --remote-debugging-port9222 ^ --user-data-dirC:\temp\chrome-debug-profile # Linux 示例 google-chrome \ --remote-debugging-port9222 \ --user-data-dir/tmp/chrome-debug-profile启动之后你可以在浏览器里访问http://localhost:9222/json/version如果能看到返回的 JSON 信息说明远程调试端口已经正常工作了。这个 JSON 里包含了浏览器版本、调试协议版本、WebSocket 调试地址等信息。接下来在这个浏览器里手动登录你需要操作的网站。登录完成后保持浏览器开着不要关闭。BrowserSkill 会连接到这个已经登录的浏览器实例复用当前的登录态。注意--user-data-dir指定的目录是独立的和你日常使用的 Chrome 配置是分开的。这意味着你在这个调试浏览器里登录的账号不会影响你日常浏览器里的登录状态。反过来也一样。这样做的好处是隔离坏处是你需要在这个调试浏览器里重新登录一次。但只需要登录一次后续只要不删除这个目录登录态就会一直保留。3.2 安装 BrowserSkill 并建立连接环境准备好之后安装 BrowserSkill。如果是 Node.js 项目直接通过 npm 安装npm install tencent/browserskill或者用 yarnyarn add tencent/browserskill安装完成后写一个最简单的连接测试脚本const { BrowserSkill } require(tencent/browserskill); async function main() { const skill new BrowserSkill({ debugPort: 9222, // 其他配置项 }); await skill.connect(); console.log(连接成功); // 获取当前打开的页面列表 const pages await skill.listPages(); console.log(当前页面:, pages); // 关闭连接 await skill.disconnect(); } main().catch(console.error);运行这个脚本如果能看到当前打开的页面列表说明连接已经建立成功了。如果报错最常见的原因是 Chrome 没有以远程调试模式启动或者端口号不对。检查一下 Chrome 启动命令里的--remote-debugging-port参数确保和脚本里配置的debugPort一致。连接建立之后你就可以通过 BrowserSkill 提供的 API 来操作页面了。基本的操作包括导航到指定 URL、获取页面元素列表、点击元素、填写输入框、提取文本内容、截图等。这些 API 的设计都比较直观上手很快。3.3 让 AI 接管操作的配置方法BrowserSkill 本身是一个浏览器操作库它提供了和浏览器交互的能力。要让 AI 来决策操作你需要把 BrowserSkill 和大模型结合起来。基本的流程是这样的通过 BrowserSkill 获取当前页面的可交互元素列表把元素列表和当前任务描述一起发给大模型大模型返回下一步应该执行的操作通过 BrowserSkill 执行这个操作重复 1-4 直到任务完成下面是一个简化的示例代码const { BrowserSkill } require(tencent/browserskill); const OpenAI require(openai); const openai new OpenAI({ apiKey: your-api-key }); async function runAgent(task, maxSteps 20) { const skill new BrowserSkill({ debugPort: 9222 }); await skill.connect(); const history []; for (let step 0; step maxSteps; step) { // 获取当前页面状态 const elements await skill.getInteractiveElements(); const pageInfo await skill.getPageInfo(); // 构造提示词 const prompt 当前页面: ${pageInfo.url} 页面标题: ${pageInfo.title} 可交互元素: ${elements.map((el, i) ${i}. [${el.tag}] ${el.text} (${el.selector})).join(\n)} 任务: ${task} 历史操作: ${history.join( - )} 请决定下一步操作返回 JSON 格式: {action: click|type|navigate|extract|done, target: 元素序号或选择器, value: 输入内容, reason: 决策理由} ; // 调用大模型 const response await openai.chat.completions.create({ model: gpt-4, messages: [{ role: user, content: prompt }], response_format: { type: json_object }, }); const decision JSON.parse(response.choices[0].message.content); console.log(步骤 ${step 1}:, decision); // 执行操作 if (decision.action done) { break; } else if (decision.action click) { await skill.click(decision.target); } else if (decision.action type) { await skill.type(decision.target, decision.value); } else if (decision.action navigate) { await skill.navigate(decision.value); } else if (decision.action extract) { const content await skill.extract(decision.target); console.log(提取内容:, content); } history.push(${decision.action}(${decision.target})); await skill.waitForStable(1000); } await skill.disconnect(); } runAgent(帮我登录后台并导出上个月的订单数据);这个示例展示了核心的循环逻辑。实际使用中你需要根据具体场景调整提示词、增加错误处理、优化元素提取的逻辑。比如元素列表太长的时候可以只保留当前视口内的元素或者按重要性排序后截取前 N 个。实操心得提示词的质量直接决定 AI 决策的准确率。我试过几种不同的提示词写法发现把“决策理由”也要求大模型输出能显著提高准确率。因为大模型在解释理由的过程中相当于做了一次自我检查能过滤掉一些明显不合理的决策。4. 实际场景中的问题排查与优化4.1 连接失败与端口冲突的排查连接失败是最常见的问题表现是脚本报错说连不上浏览器。排查思路按顺序来先确认 Chrome 是否以远程调试模式启动再确认端口是否被占用最后确认防火墙是否拦截。确认 Chrome 启动参数的方法在浏览器地址栏输入chrome://version/查看“命令行”那一行里面应该包含--remote-debugging-port9222。如果没有说明启动方式不对需要重新用命令行启动。端口被占用的情况也不少见。如果你之前启动过一个调试模式的 Chrome 没有正常关闭端口可能还被占用着。在终端里用lsof -i :9222macOS/Linux或者netstat -ano | findstr 9222Windows查看端口占用情况。如果被占用了要么关掉占用进程要么换一个端口。防火墙拦截的情况比较少见但如果你是在服务器上跑或者用了 Docker 容器就需要检查一下。远程调试端口默认只监听 localhost如果你需要从其他机器连接需要额外配置但出于安全考虑不建议这么做。还有一个容易忽略的问题是 Chrome 版本和 CDP 协议的兼容性。BrowserSkill 依赖 CDP 的一些特性如果 Chrome 版本太旧可能不支持。建议用最近一年内发布的 Chrome 版本。4.2 页面元素定位不准的解决思路AI 决策对了但操作执行失败最常见的原因是元素定位不准。比如 AI 说要点“提交”按钮但页面上有多个“提交”按钮脚本点错了。或者元素是动态生成的选择器每次都不一样。解决这个问题的思路有几个。一是给元素生成更精确的选择器不要只用标签名和文本要结合父元素的 id、class、层级关系。比如#login-form button.submit-btn就比button精确得多。二是给 AI 提供更多的元素属性信息比如元素的位置坐标、是否可见、是否可点击、关联的表单等。三是操作前先验证元素是否唯一如果不唯一让 AI 重新选择。还有一种情况是元素在 iframe 里。CDP 获取页面元素时默认只获取主框架的元素iframe 里的元素需要单独处理。BrowserSkill 提供了切换框架的 API你需要在操作前先切换到对应的 iframe。Shadow DOM 里的元素也是类似的问题。常规的document.querySelector拿不到 Shadow DOM 里的元素需要用shadowRoot.querySelector。BrowserSkill 在这方面做了封装但你需要确认目标元素确实在 Shadow DOM 里否则可能定位不到。4.3 操作超时与页面加载等待网页操作和本地操作最大的区别是网页操作有网络延迟和渲染延迟。你点了一个按钮页面不会立刻响应可能需要等几百毫秒到几秒。如果脚本不等直接执行下一步就会出错。BrowserSkill 提供了等待机制可以等待页面加载完成、等待特定元素出现、等待网络请求完成。但等待策略需要根据具体场景调整。等太短容易出错等太长效率低。我的经验是对于点击操作点击后等待 500 毫秒到 1 秒让页面有时间响应。对于导航操作等待页面 load 事件触发后再等 1 秒确保动态内容也加载完了。对于表单提交等待网络请求完成后再等 2 秒确保后端处理完了。还有一种情况是页面有动画效果元素在动画过程中位置会变这时候点击可能点不中。解决办法是等动画结束再操作或者用 JavaScript 直接触发点击事件绕过坐标点击。注意有些网站会检测自动化操作比如检测鼠标移动轨迹、点击间隔、页面可见性等。如果你的操作被检测到了可能会触发验证码或者直接封号。BrowserSkill 在这方面做了一些规避比如模拟真实的鼠标移动轨迹、随机化操作间隔。但这不是万能的对于风控严格的网站还是需要谨慎使用。4.4 常见问题速查表问题现象可能原因排查方法解决方案连接失败Chrome 未以调试模式启动访问localhost:9222/json/version用--remote-debugging-port参数重启 Chrome连接失败端口被占用lsof -i :9222查看占用关闭占用进程或换端口元素定位不到元素在 iframe 内检查元素是否在 iframe 中先切换到对应 iframe元素定位不到元素在 Shadow DOM 内检查元素的 shadowRoot用 Shadow DOM 查询方法点击无效元素被遮挡检查元素位置和层级滚动到元素可见或关闭遮挡层点击无效页面有动画观察页面是否有动画效果等动画结束再操作操作超时网络延迟大检查网络请求耗时增加等待时间或优化网络AI 决策错误页面信息不完整检查提取的元素列表增加元素属性或调整提示词AI 决策错误提示词不清晰检查提示词内容优化提示词增加约束条件被网站风控操作特征太明显观察是否触发验证码模拟真实操作特征降低频率5. 几个值得关注的扩展方向5.1 多标签页与多窗口的协同操作BrowserSkill 支持同时操作多个标签页和多个窗口。这在一些复杂场景下很有用。比如你需要在两个系统之间同步数据一个系统导出另一个系统导入。你可以开两个标签页分别登录两个系统然后让 AI 在一个标签页里提取数据在另一个标签页里填写数据。实现上BrowserSkill 提供了列出所有页面、切换当前页面、在新标签页打开链接等 API。你可以在任务描述里指定操作哪个页面或者在提示词里把多个页面的信息一起给 AI让 AI 决定操作顺序。多窗口的场景类似只是每个窗口是独立的浏览器实例有不同的调试端口。你需要为每个窗口创建一个 BrowserSkill 实例分别连接。这种场景适合需要完全隔离登录态的情况比如同时操作多个不同账号的后台。5.2 结合视觉能力处理复杂页面有些页面用 DOM 信息很难描述清楚比如 Canvas 绘制的图表、图片上的按钮、复杂的拖拽交互。这时候可以结合截图和视觉模型来处理。BrowserSkill 提供了截图 API你可以把截图发给支持视觉的大模型让大模型根据图像内容决定操作位置。这种方式的优点是直观大模型能看到页面的真实样子不受 DOM 结构的限制。缺点是速度慢每次决策都要传图片token 消耗也大。适合作为 DOM 方式的补充在 DOM 方式搞不定的场景下使用。实际操作中可以先用 DOM 方式尝试如果 AI 连续几次决策失败再切换到视觉方式。或者对于已知的复杂页面直接走视觉方式。5.3 任务编排与批量执行单个任务的自动化只是第一步更进一步是把多个任务编排起来批量执行。比如你每天需要从五个不同的后台导出数据然后汇总到一个表格里。你可以把这五个导出任务定义成五个步骤每个步骤对应一个网站的登录态和操作流程然后让 BrowserSkill 按顺序执行。任务编排的关键是状态管理。每个步骤执行完后需要保存状态以便下一步使用。比如第一步导出的文件路径第二步需要读取这个文件。BrowserSkill 本身不提供状态管理你需要在脚本层面实现比如用一个 JSON 文件记录每一步的执行结果。批量执行还需要考虑错误处理和重试。某个步骤失败了是跳过继续还是重试还是终止整个流程这些策略需要根据具体业务需求来定。我的建议是对于可恢复的错误比如网络超时自动重试三次对于不可恢复的错误比如登录态失效终止流程并通知人工处理。5.4 与现有自动化工具的对比选型市面上做浏览器自动化的工具不少Playwright、Puppeteer、Selenium 都是老牌选手。BrowserSkill 和它们的区别在哪简单说Playwright 和 Puppeteer 更偏向于“从零开始控制浏览器”适合做自动化测试和爬虫。BrowserSkill 更偏向于“接管已有浏览器”适合做需要登录态的 AI Agent 场景。如果你只是做自动化测试不需要登录态Playwright 可能更合适它的 API 更成熟社区更大。如果你需要复用已有的登录态或者需要让 AI 来决策操作BrowserSkill 的思路更对路。当然BrowserSkill 也可以和 Playwright 结合使用。比如用 Playwright 做页面操作用 BrowserSkill 做 AI 决策。两者通过 CDP 共享同一个浏览器实例各取所长。实操心得选型的时候不要只看功能列表要看实际场景。我试过用 Playwright 做需要登录态的自动化光是处理登录流程就花了两天而且很不稳定。换成 BrowserSkill 的连接已有浏览器方案后登录态的问题直接消失了开发效率高了很多。所以如果你的场景涉及登录态优先考虑连接已有浏览器的方案。6. 我在实际使用中踩过的坑第一个坑是 Chrome 自动更新。Chrome 默认会自动更新更新后可能会重启浏览器导致调试端口断开。解决办法是关闭 Chrome 的自动更新或者用固定版本的 Chrome。在 macOS 上可以用defaults write com.google.Chrome SUEnableAutomaticChecks -bool false关闭自动检查更新。第二个坑是用户数据目录的权限问题。如果你用--user-data-dir指定了一个目录但这个目录的权限不对Chrome 可能无法写入导致启动失败或者登录态无法保存。确保这个目录对当前用户可读写。第三个坑是页面加载完成的判断。load事件触发不代表页面完全加载完了很多页面是异步加载内容的。我一开始只等load事件结果经常在页面还没渲染完的时候就操作导致元素找不到。后来改成等load事件后再等一个固定的时间或者等特定元素出现问题就少多了。第四个坑是 AI 的“幻觉”。大模型有时候会编造不存在的元素或者操作比如页面上没有“导出”按钮但 AI 说要点“导出”。解决办法是在提示词里明确告诉 AI只能操作元素列表中存在的元素如果找不到合适的元素就返回“无法完成”。同时在执行操作前校验元素是否存在不存在就跳过并记录日志。第五个坑是登录态过期。有些网站的登录态有效期很短比如几小时就过期了。如果你的任务执行时间比较长中途登录态过期了后续操作就会失败。解决办法是定期检查登录态过期了就暂停任务等人工重新登录后再继续。或者在任务开始前先检查登录态确保有效再执行。这些坑说起来都是小事但实际遇到的时候很浪费时间。希望这些经验能帮你少走弯路。BrowserSkill 这个项目本身还在迭代中API 可能会有变化建议关注项目的更新日志及时了解新特性和变更。