跳到正文

智能体框架的惨痛教训

不要包装大语言模型,也不要包装它的工具。

本文目录文章开头
部分图表可能显示不完整

The Bitter Lesson of Agent Harnesses

一个 SKILL.md 和一些 Python 辅助函数。LLM 拥有完全的自由。如果缺少什么,它就自己写。

学习文章图表

几个月前,我们写了 智能体框架的惨痛教训。论点是:不要用抽象层包裹 LLM。先给出最大化的动作空间,然后再加以限制。

我们仍然在包裹它的工具。

每一个 click()、type()、scroll() 辅助函数,都是你替模型决定它需要的抽象。每一个都是经过强化学习训练的模型必须绕开的约束。

为什么用原始 CDP文章图表

当我们构建 Browser Use 的第一个版本时,我们发布了数千行的元素提取器、DOM 索引器和点击包装器。

LLM 懂 CDP。它们是在数百万个 Page.navigate、DOM.querySelector、Runtime.evaluate 词元上训练出来的。

Framework stack vs Browser Harness stack: frozen at author-time vs shaped at runtime

CDP 是 Chrome 暴露的最低层级。直接把它交给模型:

  • 跨源 iframe。 直接附加到目标上,无需与任何框架抽象作斗争。
  • Shadow DOM。 像模型见过上万次那样遍历 shadowRoot.querySelectorAll。
  • 反机器人注入。 这是 Chrome 在和它自己对话。

我们错在哪里文章图表

几个月前,我们在这个博客上写了 更贴近底层:从 Playwright 转向 CDP。那篇文章的结论是:“我们的智能体不应该为了完成任务而必须了解 CDP Target 的种种细节。”

事实证明我们错了。

那篇文章列出了 Chrome 标签页可能崩溃的十种方式。我们构建了看门狗服务来捕捉每一种——标签页崩溃、target 分离、渲染进程内存耗尽、zygote 进程死亡、GPU 进程崩溃。每一种都有一个处理器。每个处理器都必须与 Chrome 的内部实现保持同步。

给 LLM 直接的 CDP 访问权限,以及编辑自身运行框架的能力,它就能自己处理所有这些。页面挂了、target 附加错了、Chrome 卡住了——智能体读取错误,重新附加到一个新的 target,然后重试。它不需要看门狗。它读过上万篇关于 Chrome 崩溃的帖子。它早就知道该怎么办。

我们试图隐藏的“CDP 的复杂性”并不是需要隐藏的东西。而是应该让模型看到的东西。

四个文件文章图表

这就是整个运行框架:

  • run.py(13 行)——运行预加载了辅助函数的普通 Python
  • helpers.py(192 行)——CDP 的薄封装,由智能体编辑
  • daemon.py(220 行)——保持 CDP websocket 连接存活
  • SKILL.md——告诉智能体如何使用上述内容

总共约 600 行。

Architecture: agent writes Python, run.py execs helpers, helpers speak CDP through daemon to Chrome

智能体编写 Python。Python 导入辅助函数。辅助函数与 CDP 对话。Chrome 照令行事。Chrome 之上的一切都是可重写的。

自愈循环文章图表

当缺少某个工具时,情况是这样的。

Self-heal timeline: agent wants to upload → upload_file() missing → agent edits the harness and writes it (helpers.py 192 → 199 lines, + upload_file()) → file uploaded

当缺少一个辅助函数时,智能体会做任何 Claude Code 用户都会做的事:grep helpers.py,添加函数,重新运行。

我们没有告诉它这样做。我们只是给了它 Claude Code 正常的 Read/Edit/Write 加上 CDP 访问权限。编码智能体本来就知道如何修复缺失的导入。

关键在于:智能体并不是从零开始编写新代码。它只是在编写那个缺失的函数,就像它在任何代码库中修复缺失的导入一样。

神奇时刻文章图表

上传。 我们忘了添加 upload_file()。任务进行到一半,智能体遇到了一个文件输入框,grep 了 helpers.py,什么也没找到,于是用原始的 DOM.setFileInputFiles 写了这个函数,并上传了文件。我们是在读 git diff 时才发现的。

分块上传。 写完 upload_file 之后,智能体尝试上传一个 12MB 的文件。CDP websocket 的负载上限约为 10MB。它撞上了限制,读取了错误信息,然后切换到了分块上传模式。

Gusto 日历集成。任务:将每位员工的生日添加到我们的共享日历中。需要导航到 Gusto 的员工标签页,从 DOM 中提取日期,然后创建 Google 日历事件。

Azure 管理员角色。Azure 的管理门户是 iframe 中层层嵌套的面板。原始 CDP 通过坐标级 Input.dispatchMouseEvent,在合成器层面穿透。

试一试文章图表

Claude Code 或 Codex 的设置提示词:

Set up https://github.com/browser-use/browser-harness for me.

第一个找到它失败任务(非验证码/双因素认证)的人将获得一台 Mac Mini。说真的。我已经尝试破解它一周了,但做不到。

仓库:github.com/browser-use/browser-harness

智能体框架的苦涩教训:你的辅助工具也是抽象。删掉它们。让智能体自己编写它需要的东西。

阅读显示设置

调整正文排版

当前浏览器记住选择,应用于文章正文。手机上正文宽度以屏幕可用空间为限。

图表完整性提示

普通文章遇到图表保存问题时显示提示。