BaseAgent 接口集成 Agent。框架负责任务加载、CLI 解析、工作目录和结果保存,你只需实现 run_task() 并注册即可。
现有 Agent 的接入方式
1. browser-use — Python SDK 直接调用
接口:直接import browser_use Python 包,在进程内异步运行。
2. Skyvern — Python SDK + 内嵌服务
接口:import skyvern,需要本地 PostgreSQL 做认证,支持本地和云端两种模式。
3. Agent-TARS / Claude Code — CLI 子进程
接口:调用 CLI 工具,完全黑盒。接入模式
| 模式 | 适用场景 | 典型例子 |
|---|---|---|
| SDK | Agent 以 Python 库的形式分发 | browser-use、Skyvern |
| API | Agent 暴露 HTTP 接口 | OpenAI CUA、Anthropic Computer Use |
| CLI | Agent 以二进制或 npm 包分发 | Agent-TARS、Claude Code |
接入步骤
1. 实现 Agent
新建browseruse_bench/agents/my_agent.py,唯一必须实现的方法是 run_task()。
使用 BaseAgent 辅助方法读取配置,不要手动解析 agent_config:
| 辅助方法 | 读取的配置键 | 环境变量回退 |
|---|---|---|
self.build_task_prompt(task_info) | task_text + url | — |
self.get_system_prompt(agent_config) | system_prompt | 类默认值 |
self.get_model_id(agent_config) | model_id → model | — |
self.get_timeout(agent_config, default=300) | timeout_seconds → timeout → TIMEOUT | — |
self.get_max_steps(agent_config, default=40) | max_steps → max_turns → max_iterations | — |
self.get_api_key(agent_config, env_var="X") | api_key | os.getenv("X") |
self.get_base_url(agent_config, env_var="X") | base_url | os.getenv("X") |
self.save_screenshot(b64, index, dir) | — | 返回 bool |
- SDK
- API
- CLI
在进程内直接调用 Python 库。异步 SDK 使用
asyncio.run()(假设运行器是同步上下文;如从异步上下文调用,请使用 nest_asyncio)。重依赖包在 run_task 或 prepare() 钩子内懒加载。完整的带错误处理的可复制模板,请在 Claude Code 中使用
custom-agent-creator skill。2. 注册模块
在browseruse_bench/agents/__init__.py 添加一行导入:
3. 注册配置
在根目录config.yaml 的 agents 下添加:
configs/agent_registry.yaml 中添加元数据:
4. 冒烟测试
第三方 SDK 接入常见问题
这一节只覆盖大多数读者都会遇到的接入坑。更底层的实现选择,比如“应该优先包一层 SDK 的 inference engine, 还是直接去 patch 第三方包”,会刻意保留在custom-agent-creator skill 中,而不会在这里展开成单独的用户文档章节。
1. SDK 可能自带模型白名单
有些 SDK 文档上写“支持 OpenAI / Gemini”,但实际初始化时只接受少数固定模型名。这时不要把这个限制直接暴露给 browseruse-bench 用户。 更稳妥的做法是:
- SDK 初始化时使用一个 provider 原生支持的 bootstrap 模型
- 初始化完成后,把 SDK 内部的推理 client / engine 替换成你自己的封装
- 真正执行推理时再使用
config.yaml中配置的model_id/api_key/base_url
- 项目实际运行时配置中的较新模型 ID,或非默认的
model_id - 自定义网关
- OpenAI-compatible 模型
2. 配置字段语义要保留,环境变量值可以复用
如果项目里已经统一走一套内部代理,不代表 YAML 里所有 provider 都要共用同一组字段名。 推荐做法:OPENAIprofile 继续使用api_key/base_urlOPENAI_COMPATIBLEprofile 继续使用openai_compatible_api_key/openai_compatible_api_base- 但这些字段的值可以都引用同一组环境变量,例如
$OPENAI_API_KEY/$OPENAI_BASE_URL
3. 只从环境变量读取凭证的 SDK,要做窄范围注入
有些 SDK 不接受显式传参,只会从环境变量里读取 API Key。这种情况下:
- 在 agent 内部临时设置环境变量
- 只设置当前 provider 需要的那几个变量
- 在
finally里恢复原值
4. 第三方 SDK 往往假设运行目录已经存在
很多 SDK 会直接往以下目录写文件,但不会先mkdir:
screenshots/dom/playwright_traces/accessibility/
- 在 SDK 启动后立刻创建这些目录
- 如果 SDK 在每一步都会生成文件,必要时在每次回调前再次确保目录存在
5. 截图/trace 丢失时不要让整个任务直接失败
有些 SDK 即使截图保存失败,也还会把不存在的文件路径继续传给后续推理流程。这时如果你不做保护,就会在读取文件时直接
FileNotFoundError。
更好的处理方式是:
- 在把图片路径传入模型前先检查文件是否存在
- 如果不存在,退化成无图/纯文本请求
- 保留日志,让任务尽量继续执行
6. 先检查 resolved config,再怀疑 SDK
很多“模型不支持”或“provider 没接好”的报错,最终根因只是配置 typo。排错顺序建议是:
- 先打印/检查最终 resolved 的
model_type、model_id、api_key来源、base_url - 再确认传到 SDK 初始化层的 bootstrap 模型是什么
- 最后再看真正推理层使用的模型和网关
- 配置拼写错误
- provider 路由错误
- SDK 初始化白名单限制
- 真实网关请求错误
7. 模型名和 provider 路由不是一回事
不要因为模型名看起来像某个 provider,就默认它一定该走那个 provider 的链路。 一个很常见的坑是:- 配的模型名属于
gemini-*这类 Gemini 系列命名模式 - 用户实际想走的是内部统一的 OpenAI-compatible 网关
- 但路由器根据模型名自动推断成了
Vertex或Google Gemini
- 把 provider 路由当成显式配置,而不是隐式推断
- 必要时强制指定 provider,不要完全依赖自动识别
- 如果请求本来就该走 OpenAI-compatible 网关,即使模型名像 Gemini,也要显式走 OpenAI-compatible 路径
- 对 LiteLLM 来说,这通常意味着显式设置
custom_llm_provider="openai",而不是只靠模型名推断
- 缺少
vertexai之类的依赖 - Google / Gemini API key 无效
- 请求绕过了你本来想走的统一网关
8. 如果日志每条都出现两遍,先检查 SDK 自己的 logger
有些 SDK 会自己挂一个终端StreamHandler,同时又把日志继续向 root logger 传播。
这样同一条日志就会在 benchmark 输出里出现两遍,但实际上 agent 并没有真的执行两次。
常见修法是:
- 检查 SDK logger 上挂了哪些 handler
- 视情况关闭
propagate - 去掉重复的
StreamHandler,但保留 file handler(如果你还想保留 SDK 自己的文件日志)
9. provider 依赖要和真实路由路径匹配
有些依赖报错是因为真正要走的 provider 路径缺了包,也有些报错是因为请求其实走的是另一条路, 却额外装了一堆不相关的 provider 依赖。 常见有两种情况:- 如果你真的走的是直连 Gemini / Vertex 的多模态路径,运行时可能需要额外安装
Pillow、vertexai或其他 Google SDK 依赖 - 如果请求本来就是走 OpenAI-compatible 网关,不要只因为模型名长得像
gemini-*,就额外安装 Gemini / Vertex 专属依赖
- 先确认真实的 provider 路由路径
- 只为那条实际路径安装需要的依赖
- 如果模型实际走的是 OpenAI-compatible 网关,就显式固定到 OpenAI-compatible 路径,避免引入 不相关的 provider SDK 依赖
- 运行时缺少
PIL/vertexai之类的导入错误 - 环境里塞进大量根本不会被用到的 provider 依赖
参考:AgentResult
AgentResult 设置了 extra="forbid" — 任何未知字段都会抛出 ValidationError。必填字段:
| 字段 | 类型 | 说明 |
|---|---|---|
task_id | str | 必须与 task_info["task_id"] 一致 |
timestamp | datetime | datetime.now(UTC) |
env_status | "success" | "failed" | 环境(浏览器/服务)是否正常? |
agent_done | "done" | "timeout" | "max_steps" | "error" | Agent 如何结束的? |
metrics | AgentMetrics | AgentMetrics(end_to_end_ms=..., steps=...) |
agent_success(bool | None)记录 Agent 自报的执行结果 — 仅在 agent_done == "done" 时设置,否则必须为 None。
可选但推荐:answer(str)— Agent 的最终答案字符串,评估器用此字段打分。
参考:输入参数与工作目录
task_info 从 benchmark 数据集加载。标准字段:task_id、task_text、url、prompt(可选)。
agent_config 来自根目录 config.yaml 中 agents.<agent>.models[active_model] 的配置。框架在运行时会注入 timeout_seconds。
task_workspace 是每个任务的输出目录(<output_dir>/tasks/<task_id>/)。框架会在此写入 result.json,你可以在同目录保存截图、日志或其他产物。
参考:浏览器后端(SDK 和 CLI Agent)
使用open_browser_session() 而非硬编码 Chrome:
browseruse_bench/browsers/providers/,不要放在 agent 模块中。cleanup 失败必须记录日志并容忍,不能覆盖任务执行的原始错误。