
1. 从AI 只能看文本到AI 能替你点鼠标这个项目到底在解决什么做过 AI Agent 开发的人大概都有过这种憋屈时刻你让 Claude Code 或者 Codex 帮你查一个需要登录才能看的后台数据它要么告诉你我无法访问需要认证的页面要么给你一段 curl 命令让你自己去跑。你明明浏览器里已经登录得好好的Cookie 就躺在那儿可 AI 就是够不着。这个项目的核心思路说白了就是给 AI Agent 装一个油猴脚本式的浏览器扩展层。油猴Tampermonkey大家不陌生它能在你已登录的浏览器页面上注入脚本、操作 DOM、拦截请求。这个项目做的事情类似——让 Claude Code、Codex 这类命令行 AI 工具能够直接复用你浏览器里已经存在的登录态去访问那些需要认证的页面、调用那些需要 Cookie 的接口。它解决的不是AI 能不能上网的问题而是AI 能不能以你的身份上网的问题。这两者差别巨大。前者只需要一个 HTTP 客户端后者需要一整套会话桥接机制。适合谁来参考这篇内容如果你正在做 AI Agent 的工具链开发、在折腾浏览器自动化、或者单纯想让自己的 AI 助手能处理更多真实场景的任务这里面的设计思路和踩坑经验都值得一看。即便你只是好奇AI 怎么用我登录的浏览器读完也能有个清晰的认知。我先把结论摆在这儿这个项目的技术难点不在让 AI 发请求而在如何安全、可控、可撤销地把浏览器会话暴露给一个外部进程。后面几个章节我会把这个链条拆开讲。2. 浏览器登录态的本质Cookie、Session 与存储分区2.1 为什么不能简单复制 Cookie 就完事很多人第一反应是浏览器登录态不就是 Cookie 吗我把 Cookie 导出来给 AI 用不就行了理论上可行实操上坑极多。现代浏览器的登录态早已不是单一 Cookie 能概括的。以常见的几类认证为例认证类型存储位置直接复制 Cookie 是否够用传统 SessionCookieHttpOnly基本够用但 HttpOnly 无法被 JS 读取JWT TokenlocalStorage / sessionStorageCookie 里没有需要单独取OAuth 刷新令牌IndexedDB / 加密存储复制了也解不开绑定设备指纹设备指纹绑定多因素组合换环境直接失效你看光是登录态存在哪就有四五种情况。更麻烦的是 HttpOnly Cookie——浏览器故意不让 JavaScript 读取它这是安全设计。你从扩展里也读不到只能通过浏览器自身的请求携带。所以导出 Cookie这条路在真实场景里经常走不通。这也是为什么这个项目选择了一条更聪明的路不搬运登录态而是让请求本身发生在浏览器上下文里。2.2 浏览器扩展作为会话代理的天然优势浏览器扩展运行在浏览器的特权环境里它有几个关键能力可以调用chrome.cookiesAPI 读取包括 HttpOnly 在内的 Cookie在声明了对应权限的前提下可以通过chrome.webRequest或declarativeNetRequest拦截和修改请求可以在目标页面的上下文中执行脚本content script可以维持一个与外部进程通信的通道native messaging 或 WebSocket这四点组合起来就构成了一个完整的会话代理能力。AI Agent 不需要知道 Cookie 长什么样它只需要把我要访问这个 URL的意图告诉扩展扩展在浏览器里发起请求把结果回传。这个设计的精妙之处在于登录态始终留在浏览器里AI 拿到的只是请求结果。即使通信通道被截获攻击者也拿不到可复用的凭证。注意扩展的权限声明要尽可能最小化。只声明你真正需要访问的域名不要图省事用all_urls否则一旦扩展被滥用影响面会失控。2.3 存储分区Storage Partitioning带来的新麻烦近两年浏览器普遍推行了存储分区策略简单说就是同一个域名在不同顶级站点下作为第三方嵌入时Cookie 是隔离的。这对 AI Agent 意味着什么假设你的 AI 要访问api.example.com而这个接口的 Cookie 是在app.example.com页面里设置的。如果这两个域名的关系被浏览器判定为跨站那么你在扩展里读到的 Cookie 可能是不完整的。处理这个问题的常见做法是让扩展在目标站点的顶层页面上下文里发起请求而不是在扩展的 background 页面里发。因为 background 页面属于扩展自身的源很多站点的 Cookie 根本不会带上。我在实际调试中就遇到过同样的请求在 background 里发返回 401在 content script 里发就正常。排查了半天才意识到是分区策略在作祟。这个坑不踩一次很难记住。3. 通信桥的设计AI 进程与浏览器怎么对话3.1 三种桥接方案的取舍让外部 AI 进程和浏览器扩展通信主流有三条路Native Messaging浏览器官方支持的机制扩展通过标准输入输出与本地程序通信。优点是稳定、官方支持缺点是配置繁琐需要注册 manifest且只能由扩展主动发起连接。本地 WebSocket 服务扩展连一个本地起的 WebSocket 服务AI 进程也连这个服务由服务做中转。优点是灵活、双向、易调试缺点是需要额外维护一个本地服务进程。本地 HTTP 轮询扩展定时轮询本地 HTTP 接口取任务。优点是实现简单缺点是延迟高、实时性差。这个项目我推测采用的是 WebSocket 中转方案因为要支持 Claude Code、Codex 这类交互式工具实时性是刚需。轮询方案在AI 发一个请求等结果的场景下延迟会很难受。WebSocket 方案的一个关键设计点是消息协议。我建议至少定义这几类消息{ type: request, id: req-001, method: GET, url: https://target.example.com/api/data, headers: {}, body: null }{ type: response, id: req-001, status: 200, headers: {}, body: ... }用id做请求响应配对这样多个并发请求不会串。别小看这一点早期我用自增序号没做隔离结果两个请求的响应交叉了排查了很久。3.2 为什么要在浏览器侧做请求而不是转发 Cookie有人会问既然扩展能读到 Cookie为什么不干脆把 Cookie 发给 AI 进程让 AI 自己发请求三个理由HttpOnly Cookie 读不到前面说过这条路直接堵死一半场景。请求指纹很多站点会校验 User-Agent、TLS 指纹、请求头顺序等。AI 进程用普通 HTTP 客户端发出去的请求指纹和浏览器不一致容易被风控拦截。动态令牌有些接口的鉴权头是页面 JS 动态生成的比如带时间戳签名只有浏览器上下文里才能拿到正确的值。所以让请求在浏览器里发不只是方便而是唯一可行的方案在很多场景下。3.3 超时、重试与幂等性处理桥接层必须处理网络抖动。我的经验是请求超时设 30 秒超过就返回超时错误让 AI 侧决定是否重试重试只对幂等请求GET、HEAD自动进行POST 类请求交给 AI 判断每个请求带一个唯一 id浏览器侧维护一个已处理 id的短期缓存防止重复执行这个已处理缓存很关键。WebSocket 断线重连时如果消息重发没有去重机制就会导致同一个操作执行两次。我就吃过这个亏——AI 重试了一次下单请求结果下了两单。虽然是在测试环境但教训深刻。4. 权限边界与安全隔离别让 AI 拿到不该拿的东西4.1 白名单机制是底线这个项目最需要警惕的地方在于一旦 AI 能通过浏览器发任意请求它理论上就能以你的身份操作任何你登录过的站点。这是巨大的权限。所以白名单不是可选项是必选项。我的建议是三层白名单域名白名单只允许访问明确列出的域名路径白名单在域名基础上进一步限制路径前缀方法白名单默认只允许 GETPOST/PUT/DELETE 需要显式开启配置大概长这样{ allowedOrigins: [ { origin: https://internal.example.com, paths: [/api/read/*], methods: [GET] } ] }这样即使 AI 被提示注入攻击想让它去访问一个恶意地址也会被白名单挡住。4.2 敏感操作的二次确认对于写操作POST/PUT/DELETE我强烈建议加一道人工确认。实现方式可以是扩展弹一个通知用户点确认才放行或者 AI 侧在执行前打印操作详情等用户输入 y 确认别嫌麻烦。AI 幻觉是真实存在的它可能以为你要它删某个资源实际上你只是让它查一下。没有确认机制这种误操作直接生效。提示确认弹窗里要显示完整的请求方法、URL 和 body 摘要不要只显示是否允许操作否则用户根本不知道自己在确认什么。4.3 会话的可撤销性好的设计应该让用户随时能拔掉插头。具体来说扩展侧提供一个开关一键断开与 AI 进程的连接断开后所有进行中的请求立即取消重新连接需要用户主动操作不能自动重连这个不自动重连很重要。如果扩展在用户关闭后还偷偷重连那用户的安全感就没了。我见过一些工具为了体验流畅做成自动重连结果用户以为已经断开了实际上还在后台跑。5. 实战搭建从零跑通一条请求链路5.1 环境准备与最小验证假设你已经有一个能跑的浏览器扩展骨架接下来按这个顺序验证先写一个最简单的 content script在目标页面里fetch一个需要登录的接口确认能拿到数据。这一步验证的是浏览器上下文能访问登录态。再写 background 里的 WebSocket 客户端连上本地服务发一条 ping确认通道通。然后把两者接起来WebSocket 收到请求消息转发给 content script 执行结果回传。每一步都单独验证别一上来就全串起来。我见过太多人一次性写完出问题不知道是哪一层。5.2 消息路由的代码骨架浏览器侧的核心逻辑大概是这样// background.js const ws new WebSocket(ws://127.0.0.1:8765); ws.onmessage async (event) { const msg JSON.parse(event.data); if (msg.type ! request) return; const tab await findOrCreateTab(msg.url); const result await chrome.tabs.sendMessage(tab.id, { type: execute-fetch, payload: msg }); ws.send(JSON.stringify({ type: response, id: msg.id, ...result })); };content script 侧// content.js chrome.runtime.onMessage.addListener((msg, sender, sendResponse) { if (msg.type ! execute-fetch) return; const { method, url, headers, body } msg.payload; fetch(url, { method, headers, body, credentials: include }) .then(async (res) { const text await res.text(); sendResponse({ status: res.status, headers: Object.fromEntries(res.headers), body: text }); }) .catch((err) sendResponse({ error: err.message })); return true; // 保持消息通道开放 });注意credentials: include这是让 fetch 带上 Cookie 的关键。漏了这个参数请求就是匿名的。5.3 实测中遇到的三个意外意外一CORS 预检失败。有些接口对跨源请求会先发 OPTIONS 预检。如果 content script 所在的页面源和接口源不一致预检可能被拒。解决办法是让扩展在接口同源的页面里执行或者用declarativeNetRequest改写请求头绕过预检仅限你有权限的场景。意外二响应体太大导致 WebSocket 消息超限。默认 WebSocket 单条消息有大小限制遇到大响应会断。解决办法是分片传输或者把大响应先存到扩展的 storage 里只回传一个引用 id。意外三页面导航导致 content script 失效。如果目标页面在请求过程中发生了跳转比如登录过期跳登录页content script 会被卸载请求就悬空了。需要在 background 侧监听 tab 更新事件及时给 AI 侧返回错误。这三个坑我在不同项目里都踩过写出来希望能帮你省点时间。6. 让 Claude Code / Codex 真正用起来工具封装思路6.1 把桥接层包装成一个工具Claude Code 和 Codex 这类工具通常支持自定义工具tool或函数调用。你要做的是把通过浏览器发请求这个能力包装成一个工具让 AI 在需要时调用。工具的描述要写清楚这个工具能访问需要登录的页面参数是 method、url、headers、body返回的是状态码、响应头和响应体受白名单限制不在白名单内的请求会被拒绝描述写得越清楚AI 用得越准。我见过有人只写一句发 HTTP 请求结果 AI 在不需要登录的场景也调它白白绕了一圈。6.2 提示词里要交代的边界除了工具描述系统提示词里也要说明优先用普通 HTTP 工具只有明确需要登录态时才用浏览器桥接工具写操作前必须先向用户确认遇到 401/403 不要反复重试直接报告这些约束能显著降低误用率。AI 不会自己知道这个接口其实不需要登录你不说它就瞎试。6.3 一个完整的调用示例假设 AI 要查一个内部后台的用户列表用户帮我看看后台现在有多少活跃用户 AI 思考这需要访问内部后台需要登录态用浏览器桥接工具 AI 调用browser_fetch({ method: GET, url: https://internal.example.com/api/users/active }) 返回{ status: 200, body: {count: 1247} } AI 回复当前活跃用户 1247 人。整个链路里AI 完全不知道 Cookie 是什么它只是调了一个工具。这就是好的抽象——把复杂性藏在桥接层里。7. 这套方案不适合什么场景说了这么多优点也得说说它的边界。不适合无人值守的自动化。因为依赖你本地的浏览器和登录态如果浏览器关了、登录过期了整条链路就断了。它适合人在电脑前AI 辅助操作的场景不适合跑在服务器上的定时任务。不适合高并发。所有请求都挤在一个浏览器里发并发能力有限。如果你要批量抓取大量数据还是老老实实用带凭证的 HTTP 客户端。不适合跨设备。登录态绑定在特定浏览器实例上换台机器就得重新配。合规上要格外小心。用这套方案去访问的站点必须是你自己有权限访问的。拿它去绕过别人的访问控制那是另一回事了不在讨论范围内。我自己在实际使用中的体会是这套方案最大的价值不是能访问登录页面而是让 AI 的工作流不中断。以前 AI 遇到需要登录的步骤就得停下来让你手动操作现在它能自己走完体验上的提升是质变的。但前提是白名单和确认机制做到位否则便利和风险就是一念之间。最后分享一个小技巧调试阶段把桥接层的所有请求响应都打到本地日志文件里出问题时翻日志比在浏览器 DevTools 里翻 Network 面板快得多尤其是当请求是 AI 触发的时候你根本不知道它什么时候发的。日志里带上时间戳和请求 id排查效率能翻好几倍。