> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 智能体框架的苦涩教训
- URL: https://www.hubwiz.com/blog/the-bitter-lessons-of-agent-frameworks/
- Published: 2026-05-12T03:13:39.000Z
- Updated: 2026-10-13T16:10:10.000Z
- Description: 所有价值都在经过RL训练的模型中，而不是你那10,000行抽象代码。
- Author: admin
- Tags: AGENT, #Import 2026-10-14 14:41

一个agent其实就是一个消息的for循环。agent唯一应该拥有的状态就是：一直运行直到模型停止调用工具。你不需要agent框架。你不需要任何其他东西。它只是一个工具调用的for循环。

我们最早的Browser Use agents有几千行的抽象代码。它们能工作——直到我们尝试修改任何东西。每次实验都在和框架对抗。agents失败不是因为模型笨，而是因为我们自己笨。

坚持看到最后，我会给你展示构建Claude Code有多容易。

## 1、为什么抽象会破坏学习

抽象的问题在于：它们冻结了对智能应该如何工作的假设。而RL会打破这些假设。

每次你在模型行为周围添加一个“聪明”的包装器——规划模块、验证层、输出解析器——你就是在编码你认为模型应该做什么。但模型是在数百万个例子上训练的。它见过比你能预见到的多得多的模式。你的抽象变成了约束，阻止模型使用它所学到的东西。

机器学习研究中的**Bitter Lesson**（苦涩教训）很清楚：利用计算的通用方法每次都能击败手工打造的人类知识。agent框架只是这个错误最新的一个例子。

## 2、99%的工作在模型内部

![](https://www.hubwiz.com/blog/content/images/2026/05/image-161.png)

事情是这样的：99%的工作是在模型自身内部完成的。我们不需要在它周围套一个高度抽象的框架。

现在的Claude Code可以直接编写AppleScript。它需要某个冷门Spotify播放器的信息？它不需要一个Spotify的computer-use工具。它只是在macOS上写AppleScript。它有完美的上下文。它在这方面训练得很好。

你不需要提前预见每一个用例。模型已经知道了。

## 3、关键洞见

这引出了一个重要结论：

> agent框架失败不是因为模型弱，而是因为它们的行为空间不完整。

与其提前定义每一个可能的动作，不如从相反的假设开始：模型几乎什么都能做。然后再加以限制。

给LLM尽可能多的自由，然后基于评估进行“vibe-restrict”（氛围限制）。

## 4、为什么我们把一切都扔掉了

Browser Use的第一个版本是一个经典的agent框架：一个被复杂消息管理器包裹的模型，里面有很多旨在控制行为的抽象。它能工作，但扩展起来很痛苦。每一次实验都在和框架对抗。添加新能力感觉就像在违背Bitter Lesson。（公平地说，模型从去年以来已经变得好多了）

所以我们后退一步，问了一个更根本的问题：

> LLM实际上被训练得极其擅长什么——以及随着模型变得更好，什么会保持不变？

我们扔掉了整个agent，从零开始。为了理解“最小化”真正意味着什么，我们逆向工程了Claude Code和Gemini CLI。向他们致敬，他们创造了真正优秀且大多简洁的原语。虽然它们内部很复杂，但底层理念很简单：

> 不要过度指定智能——让模型去推理。

## 5、BU Agent：实际应用

我们把这个理念构建进了BU Agent——一个为Browser Use提供动力的极简agent框架。

我们没有暴露一小套脆弱的“click / type / scroll”原语，而是让BU Agent给模型提供对浏览器原始控制面的访问。

核心是：能够发出纯Chrome DevTools Protocol (CDP)指令的能力。实际上，模型几乎可以在浏览器中做任何事情。

在此之上：浏览器扩展API。它们让某些用CDP单独做起来尴尬或不可能的任务变得 trivial——比如访问活动窗口或处理带权限的浏览器状态。

CDP和扩展API各自都有盲点。但结合在一起，它们形成了一个几乎完整的行为空间。

当模型拥有这种自由时，重要的事情发生了。如果一种方法失败，它会绕过去。如果一个工具坏了，它会找到另一条路径。

只要原则上一切皆有可能，LLM就极其擅长在飞行中自我修复。

## 6、反转

![](https://www.hubwiz.com/blog/content/images/2026/05/image-162.png)

所以BU Agent是基于一个简单的反转构建的：

> 从最大能力开始，然后再限制。

给模型一个人类在浏览器中能做的任何事情的自由。只有在这之后才叠加安全、结构和约束。

这正是让系统能随着更好模型一起扩展而不是对抗它们的原因。

## 7、我讨厌其他所有LLM框架

真的。它们实现LLM对象的方式让人痛苦。

所以我写了自己的。超级简单的方式来调用。就这么简单——支持Anthropic、OpenAI和Google。根据我们的遥测数据，这些占了95%的用例。

![](https://www.hubwiz.com/blog/content/images/2026/05/image-163.png)

```
pythonclass ChatAnthropic:
    async def ainvoke(self, messages, tools) -> ChatCompletion: ...

class ChatOpenAI:
    async def ainvoke(self, messages, tools) -> ChatCompletion: ...

class ChatGoogle:
    async def ainvoke(self, messages, tools) -> ChatCompletion: ...
```

同样的接口。对缓存、序列化、提供商 quirks 有完全控制。没有魔法。没有意外。

自己做缓存和实现消息要容易得多。完全模型无关。你不会被锁定在一个提供商。你自己决定。

## 8、临时消息（Ephemeral messages）

我们为浏览器agents需要的一个有趣东西：如果你请求浏览器状态，它非常庞大。DOM快照、截图、元素索引——每次请求很容易50KB+。

如果没有临时消息，会发生什么：经过10次浏览器交互后，你的上下文里就有500KB的状态。20次后就到了1MB。模型开始失去连贯性。它忘记了原始任务。它会幻觉已经不存在的元素。最终你达到上下文限制，整个东西崩溃。

所以我引入了临时消息。

```
@tool("Get browser state", ephemeral=3)  # Keep last 3 only
async def get_state() -> str:
    return massive_dom_and_screenshot
```

如果你定义某个工具调用了X次，它就会移除所有之前的输出。会稍微破坏一点缓存。但这是一个非常好的权衡——LLM反正无法真正处理海量上下文。模型只需要最近的状态；旧的浏览器快照只是噪声。

## 9、for-loop行不通（直到你修复它）

![](https://www.hubwiz.com/blog/content/images/2026/05/image-164.png)

天真的做法——当模型返回没有工具调用时就停止——效果不好。agents会过早结束。尤其是当它们缺少某些上下文时。你想要一个跟进，但如果你用这种API，就不可能。

最好的修复方式是**done tool**。

```
@tool('Signal that the current task is complete.')
async def done(message: str) -> str:
    raise TaskComplete(message)
```

当模型输出一个done工具调用时，agent就终止。这迫使它显式完成，而不是隐式的“我猜我们做完了？”

我们有两种模式：

- CLI模式：当LLM返回没有工具调用时停止（快速交互）
- 自主模式：仅在显式done()调用时停止

Claude Code就是这么做的。Gemini CLI也是这么做的。现在你知道它为什么存在了。

## 10、但你需要可靠的基础设施

是的。for-loop很简单。让它可靠却不容易：

- 指数退避的重试
- 速率限制处理
- 连接恢复
- 上下文压缩
- Token跟踪

这是运维。已经解决的问题。必要——但不要把它和agent本身混淆。

## 11、苦涩的真相

每一个抽象都是负债。每 一个“helper”都是故障点。

模型已经变好了。真的很好。它们在computer use、coding、browsing上经过了RL训练。它们不需要你的护栏。它们需要的是：

![](https://www.hubwiz.com/blog/content/images/2026/05/image-165.png)

苦涩的教训：你构建得越少，它工作得越好。

我们正在把这个开源为[agent-sdk](https://github.com/browser-use/agent-sdk?ref=hubwiz.com)。

如果你想，你可以在生产环境中使用它，但最好只是把上下文粘贴到Claude Code里，用你正在编码的任何语言自己做一个。仓库里也包含了一个Claude Code重新实现的例子。

总之，这就是我们在构建bu.app时学到的东西。去试试吧。它很棒！！

---

原文链接：[The Bitter Lesson of Agent Frameworks](https://x.com/gregpr07/status/2012052139384979773?ref=hubwiz.com)

汇智网翻译整理，转载请标明出处

> **这是「Agent / MCP」专题的一部分。**完整地图见：[Agent / MCP / 自动化完全指南](https://www.hubwiz.com/blog/agent-stack/)