你坐在深夜的电脑前,屏幕上只有几行代码,却突然召唤出一个不知疲倦的“数字工人”——它观察、思考、行动、再观察、再思考……直到任务完美完成。这不是科幻电影,而是现实:一个名叫 **bu-agent-sdk** 的极简框架,用一个最朴素的 for-loop,就让大语言模型(LLM)变成了真正的“智能体”。没有繁杂的抽象层,没有华丽的“魔法”,只有赤裸裸的循环与工具调用。这正是它的魅力,也正是它想告诉我们的“苦涩教训”。

这张图就是整个框架的核心:一个永不停歇的循环。模型产生想法 → 调用工具 → 获得结果 → 再次思考 → 再调用……直到明确说出“我完成了”。简单,却深刻。
下面,让我们像探险一样,一步步走进这个“苦涩而甜蜜”的世界。
### 🔄 **代理的本质:只是一个for-loop的永恒舞步**
在AI智能体的世界里,人们常常被各种宏大的名词包围:规划器、记忆模块、反思机制、ReAct、Toolformer……但 bu-agent-sdk 的作者一针见血:**An agent is just a for-loop.**
想象一个勤劳的邮差,每天沿着固定路线送信:查看信箱(观察状态)→ 决定走哪条路(思考)→ 投递信件(调用工具)→ 再查看下一个信箱……如果没有明确的“今天工作结束”信号,他就会永远走下去。传统agent框架常常因为“没有工具可调用了”就强行停止,导致任务半途而废。而 bu-agent-sdk 的解决办法简单粗暴:让模型自己决定何时结束。
> **什么是AI智能体(Agent)?**
> 简单说,它是一个能自主完成复杂任务的AI系统。它不像ChatGPT那样只聊天,而是能“动手”:搜索网页、运行代码、操作浏览器、读写文件……最终给出完整答案。智能体真正的力量在于“行动—观察—思考”的循环,而不是一次性输出。
这个框架的哲学根基是著名的 **The Bitter Lesson**:过去70年AI研究的经验表明,越多依赖人类设计的巧妙结构,越容易被规模更大的模型+更多数据碾压。所有价值最终都集中在被强化学习(RL)打磨过的大模型上,而不是你写的几万行抽象代码。
### 🛠️ **几分钟上手:从零到活蹦乱跳的智能体**
安装极简:
```bash
uv sync
# 或者
uv add bu-agent-sdk
```
然后,最小可运行示例只有十几行:
```python
import asyncio
from bu_agent_sdk import Agent, tool, TaskComplete
from bu_agent_sdk.llm import ChatAnthropic
@tool("Add two numbers")
async def add(a: int, b: int) -> int:
return a + b
@tool("Signal task completion")
async def done(message: str) -> str:
raise TaskComplete(message)
agent = Agent(
llm=ChatAnthropic(model="claude-sonnet-4-20250514"),
tools=[add, done],
)
async def main():
result = await agent.query("What is 2 + 3?")
print(result) # 输出 "5"
asyncio.run(main())
```
看清楚了吗?代理收到问题后,会先思考是否需要调用工具。它发现需要计算,就调用 `add(2, 3)`,得到5,然后调用 `done("5")`,任务结束。整个过程就是循环中的几次工具调用。没有复杂的state machine,没有隐藏的控制流,只有透明的for-loop。
### ✅ **强制说“Done”:拒绝早退的艺术**
最容易出错的地方,就是代理“觉得自己没事可干了”就提前结束。很多人尝试“没有工具调用就停止”的策略,结果惨不忍睹——任务做到80%就戛然而止。
bu-agent-sdk 的解法优雅又暴力:提供一个显式的 `done` 工具,并且可以设置 `require_done_tool=True`,强制自主模式。模型必须主动调用 `done`,才能结束任务。
想象一个学生做作业,老师不喊“交卷”,他就一直坐在那儿发呆。加上 `done` 工具,就像老师说:“写完后必须举手说‘我完成了’”。这样模型会更认真地检查自己是否真的做完了所有步骤。
### 🧹 **短暂消息:让上下文窗口不再爆炸**
当工具返回大量数据(比如整个网页DOM+截图)时,上下文迅速爆炸,几轮下来就超出token限制。传统做法是硬性截断历史,导致模型失忆。
bu-agent-sdk 引入 **ephemeral messages**:你可以标记某些工具输出只保留最近N次:
```python
@tool("Get browser state", ephemeral=3)
async def get_state() -> str:
return massive_dom_and_screenshot
```
就像大脑的海马体,只把最近几次重要记忆保留在工作记忆中,旧的自动归档。这样既保持关键信息,又防止上下文雪崩。
### 🔌 **极简LLM适配:300行代码换来无限自由**
框架对每个LLM提供者的封装只有约300行,却实现了完全统一的接口:
```python
from bu_agent_sdk.llm import ChatAnthropic, ChatOpenAI, ChatGoogle
agent = Agent(llm=ChatAnthropic(...), tools=...)
# 轻松切换
agent = Agent(llm=ChatOpenAI(model="gpt-4o"), tools=...)
agent = Agent(llm=ChatGoogle(model="gemini-2.0-flash"), tools=...)
```
为什么这么薄?因为作者相信:模型已经足够强大,不需要你在中间加一堆“聪明”的包装。薄封装意味着你可以随时修改行为、插入日志、定制system prompt,而不会被厚重的框架卡死。
### 📦 **自动压缩:当上下文快炸时,聪明地总结**
接近token上限时,框架会自动触发总结机制(可配置阈值):
```python
from bu_agent_sdk.agent import CompactionConfig
agent = Agent(
...,
compaction=CompactionConfig(threshold_ratio=0.80),
)
```
就像一位老练的讲故事者,当听众注意力要散了,就快速回顾前情:“之前我们说到……”然后继续新内容。既保留关键情节,又腾出空间。
### 💉 **依赖注入:FastAPI式的类型安全魔法**
```python
from typing import Annotated
from bu_agent_sdk import Depends
def get_db(): return Database()
@tool("Query users")
async def get_user(id: int, db: Annotated[Database, Depends(get_db)]) -> str:
return await db.find(id)
```
这让工具可以优雅地获取数据库、浏览器实例、沙箱上下文等资源,完全类型安全,测试友好。作者把FastAPI的依赖注入系统直接搬了过来,熟悉的后端开发者几乎零学习成本。
### 🌊 **流式事件:实时偷看代理的内心戏**
```python
async for event in agent.query_stream("do something"):
match event:
case ToolCallEvent(tool=name, args=args):
print(f"Calling {name}")
case ToolResultEvent(tool=name, result=result):
print(f"{name} -> {result[:50]}")
case FinalResponseEvent(content=text):
print(f"Done: {text}")
```
你可以看到代理每一次“想调用哪个工具”“工具返回了什么”“最终答案来了”。这不仅适合构建交互式UI,也极有利于调试和监控。
### 💻 **百行实现Claude Code:沙箱里的编程神器**
文档中最精彩的部分,是用不到100行代码复刻了一个沙箱版“Claude Code”——让Claude在隔离的文件系统里读写运行代码。
核心工具只有几个:
- `bash`:执行shell命令
- `read` / `write`:读写文件(严格路径检查,防止逃逸)
- `glob`:查找文件
- `done`:任务完成
通过 `dependency_overrides` 注入沙箱上下文,所有文件操作都被限制在 `./sandbox` 目录。模型就像一个真正的程序员,在终端里敲命令、改文件、运行测试,最后说“搞定了”。
想象一下:你让它“实现一个Flask hello world”,它会先创建文件、写入代码、运行服务器、检查输出、修复bug……全程在沙箱里安全进行。这就是完整行动空间的威力。
### 📚 **更多示例,等你去挖掘**
仓库的 `examples/` 目录里还有:
- 完整的 `claude_code.py`(带grep、edit、todo等高级工具)
- `dependency_injection.py` 展示复杂依赖传递
每一个示例都短小精悍,却能直接扩展成生产级应用。
### ⚖️ **苦涩的真相:少即是多**
作者在结尾毫不留情地写道:
> Every abstraction is a liability. Every "helper" is a failure point.
模型已经经过了海量的强化学习,学会了使用电脑、写代码、浏览网页。它们不需要你用厚重的框架“保护”它们,而是需要:
- 完整的行动空间(丰富的工具)
- 一个干净的for-loop
- 明确的退出机制
- 聪明的上下文管理
**你构建得越少,它就工作得越好。**
这正是“苦涩的教训”:我们曾经花了无数精力设计精巧的结构,结果都被更大的模型+更多计算直接碾压。未来属于那些敢于“什么都不加”的人。
------
### 参考文献
1. bu-agent-sdk 官方文档与源码(核心参考资料)
2. The Bitter Lesson, Jeff Dean & Rich Sutton, 2019(框架哲学基础)
3. Anthropic Claude Code 逆向工程灵感来源
4. FastAPI 依赖注入系统(框架DI实现参考)
5. Browser Use 项目(https://browser-use.com)——框架诞生背景
这不仅仅是一个Python包,更是一场关于“如何与超级智能合作”的哲学宣言。它提醒我们:有时候,最强大的系统,正是最简单的那一个。
======
登录后可参与表态
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!