Browser Agent:共享 Chrome 运行时架构与接入手册
把真实 Chrome、固定 Profile、CDP 和恢复流程收敛为一个本地运行时;业务 Agent 只连接、创建页面并完成自己的任务。
本文目录 7 节 · 点击展开
把多个 Agent 都接到同一个 Chrome,并不等于让它们共享同一个任务。真正应该被共享的是运行时:一个可见的真实 Chrome、一个固定 Profile、一条固定 CDP 通道和一套可恢复的生命周期。每个业务任务仍只拥有自己的页面、选择器与结果。
先保证浏览器活着、可连接、可复用;再让 Agent 处理网页业务。
Browser Agent 把 Chrome 的启动与恢复从 Skill 中拿走。接入方只做两件事:调用 ensure,再连接 CDP。
- 01固定 Profile登录状态有唯一归属
- 02固定 CDP连接地址不再由项目各自分配
- 03独立 Page任务只关闭自己创建的页面
- 04显式边界默认串行,不把共享当作并发能力
先分清:谁管理运行时,谁完成网页任务
Browser Agent 不是采集器,也不是远程浏览器集群。它只在一台可执行本地命令的机器上管理 Chrome 进程、共享 Profile 和 CDP。业务 Skill 或 Python 项目负责进入网站、读取页面、提交表单或提取数据。
共享的是底座,不是页面控制权
把生命周期和业务逻辑拆开后,故障归属与关闭权限也随之清晰。
调用 ensure、连接 CDP、创建自己的 page,执行该网站的选择器和业务逻辑。
~/browser-agent/browser-agent提供 ensure、status、connect、disconnect、stop 等统一入口;页面命令会先确保浏览器可用。
保存登录状态与浏览器配置,并通过 http://127.0.0.1:19312 暴露调试连接。
这样可以消除常见的重复劳动:每个项目各自寻找 Chrome、各自创建临时 Profile、各自抢端口、连接失败后各自重启进程。只要业务脚本遵守“只关闭自己 Page”的规则,任务结束时就不会主动带走其他任务仍在复用的共享 Chrome。
固定约定是一份连接合同
这套工具的当前默认配置将运行时放在用户目录下,使用本机回环地址的 19312 端口。上游配置的 Chrome 可执行文件默认值是 macOS 的 Google Chrome 路径;若部署在其他系统,必须通过配置确认可执行文件路径,而不是照抄默认值。
让每个接入方说同一种语言
路径与端口是运行时边界;Profile 本身承载登录态,不能当作普通项目文件。
- 控制入口
~/browser-agent/browser-agent所有 Agent 与本地项目的统一命令入口。- 共享 Profile
~/browser-agent/chrome-profileCookie、本地存储和浏览器配置的持久化位置。- CDP 地址
http://127.0.0.1:19312Playwright 与命令行工具连接既有 Chrome 的回环地址。- 默认会话
browser-agentPlaywright CLI 的会话名;可临时覆盖,但仍连接同一 Profile。
如果要自定义路径、端口或会话名,先检查 config.env 中的 CHROME_BIN、CDP_PORT 与 BROWSER_AGENT_SESSION。修改后是否仍能启动和连接属于运行环境事实,需运行验证。
ensure 把“能否连接”收敛为一个状态机
业务代码不应该先猜 Chrome 是否已启动。它应当把判断交给 ensure:脚本先访问 /json/version,再根据共享 Profile 进程与端口状态决定复用、报错或恢复。
~/browser-agent/browser-agent ensure
复用优先;异常时先保护 Profile,再恢复 Chrome
这里的“恢复”只覆盖 Chrome 进程与 CDP 可用性,不验证某个网站是否仍处于登录状态。
ensure业务方不负责预检查。
/json/version端口可达并不自动代表 Profile 一定正确。
成立时不重复启动 Chrome。
先尝试正常结束;仍存在时脚本才会强制结束。
清理 SingletonLock、SingletonCookie、SingletonSocket。
等待 CDP 可访问后,接入方再连接。
这里有一个很重要的边界:ensure 解决的是“Chrome/CDP 是否可用”,不是“页面是否加载成功”“Cookie 是否过期”或“验证码是否已处理”。后几项仍要由业务任务观察并在需要时交给人处理。
接入顺序:保证运行时,再拥有自己的页面
外部 Python 项目最小接入步骤是:先运行 ensure,再以 CDP 附着到 Chrome;从已有 context 中新建页面;完成后只关闭该页面。下面的代码保留了连接与关闭边界,适合作为业务脚本的起点。
每个任务都从同一个入口进入,却只带走自己的 Page
CDP 连接附着的是已有 Chrome;它不应被业务任务当成私有浏览器来关闭。
- 1确保调用
browser-agent ensure。 - 2附着
connect_over_cdp()连接固定地址。 - 3隔离从既有 context 新建本任务的
page。 - 4收尾关闭该
page,保留 context、browser 与 Chrome。
import subprocess
from pathlib import Path
from playwright.sync_api import sync_playwright
browser_agent = Path.home() / "browser-agent" / "browser-agent"
subprocess.run([str(browser_agent), "ensure"], check=True)
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp(
"http://127.0.0.1:19312"
)
context = browser.contexts[0]
page = context.new_page()
try:
page.goto("https://example.com")
# 只写当前项目的网站业务逻辑。
finally:
page.close()
如果该运行时没有可用 context,或 CDP 协议与客户端版本不兼容,上面示例会失败;这是接入环境而非网页业务本身的问题,需运行验证后再决定如何处理。
复用登录态,不复用页面控制权
同一 Profile 让不同任务看见同一份登录状态。上游规则仍明确要求默认不要并发操作,并让不同任务各自创建页面;因此页面隔离只是最低限度的协作约定,不是多租户安全边界。
一份身份状态,多个独立任务页面
先识别什么被共享,才能避免把“新建页面”误当成账号或业务隔离。
它们由运行时维护,通常在任务结束后持续存在。
任务负责关闭自己的页面,并把结果写回自己的业务上下文。
context.close()、browser.close()、未授权的 stop这些动作会影响共享运行时与其他任务,应保留给明确授权的运维操作。
即使以不同 BROWSER_AGENT_SESSION 连接,它们依然控制同一 Profile;会话名不等于浏览器隔离。
验证码、扫码和账号安全验证不应尝试绕过。让用户在可见的 Chrome 中完成验证,再继续运行任务。对有写入、副作用或资金风险的网站,业务层还应自行设计确认、幂等和结果复核;Browser Agent 不替代这些控制。
日常命令:先看状态,再做可定位的动作
除了给 Python 接入,控制入口还封装了 Playwright CLI 的常用页面操作。它会在需要时附着到 CDP;其中 start 当前是 ensure 的别名,close 被显式拒绝,以避免误关共享 Chrome。
把“连上了”变成可检查的日常操作
页面已经跳转、刷新或弹窗变化后,应重新获取快照;旧引用不应继续假定有效。
browser-agent ensure保证共享 Chrome 与 CDP 可用。browser-agent status查看当前运行状态。browser-agent snapshot读取最新页面结构与引用。browser-agent click e12按最新快照中的引用执行操作。browser-agent fill e20 "文本"填写指定引用对应的输入区域。browser-agent screenshot保留页面可视证据。browser-agent disconnect只断开 CLI 会话,不关闭 Chrome。browser-agent stop仅在用户明确要求关闭共享浏览器时使用。snapshot、click、fill 中的引用值取决于当时的页面结构,示例里的 e12 与 e20 不是可跨页面复用的固定选择器。实际页面命令、登录状态和站点反馈均需运行验证。
出现故障时,按影响范围回到正确层级
不要用重启 Chrome 处理所有问题
先判断异常发生在运行时、连接、页面还是账号验证,再把动作限制在对应层级。
ensure若仍失败,检查端口占用、Chrome 可执行文件、Profile 权限和脚本输出。
这是网站或任务逻辑问题;不要仅因元素找不到就结束共享 Chrome。
登录状态保存在 Profile,但过期与安全验证仍是站点的业务边界。
不同 CLI 会话不提供页面或身份隔离;先完成当前任务再交接。