apache/burr · 上手攻略
- 仓库:apache/burr
- 链接:https://github.com/apache/burr
- 分类:Stateful Agent 框架 / 状态机 / LLM 应用编排
- 作者:spark
- 更新:2026-07-20
是什么
Apache Burr(incubating)是一个 Python 状态机框架,用来构建"会做决策的应用"——chatbot、agent、simulation、人机协作工具。它把应用建模成一张 state machine(状态机/流程图):
- 节点(action):一个 Python 函数,读/写 state 中的某些字段。
- 边(transition):声明从一个 action 到下一个 action 的可能路径,路径条件由函数返回值决定。
- state:一个命名空间,存所有跨步骤需要共享的数据(聊天历史、中间结果、用户上下文)。
- persister:可插拔的状态持久化后端(SQLite/Postgres/Redis/...),让流程可恢复、可幂等。
- telemetry:每次执行的 trace + 状态快照,送入 Burr 自带 UI 做实时可视化。
Burr 的关键设计哲学是 "框架无关":它不规定你必须用哪个 LLM SDK、哪个 vector DB、哪个 agent 范式。它只负责把"调用顺序、状态持久化、可观测性、人机协作"这四件事组织好,业务侧随便接 LangChain / LlamaIndex / 直接调 OpenAI API / 完全不用 LLM 都可以。
起源同样是 DAGWorks 公司,跟 Hamilton 同源(Hamilton DAG 是无环的,Burr 是带循环的,最早 Burr 就是 Hamilton 的 harness),现已进入 Apache 孵化器。License:Apache-2.0。
解决什么问题
LLM 应用进入生产时,团队通常会被几个老问题反复折腾:
- chatbot 上下文管理:每轮对话要拼历史,历史太长会丢消息、历史错乱会导致幻觉。手动维护一个 list 容易爆。
- agent 决策不可见:ReAct / tool-use agent 内部跳了几步、为什么走 A 不走 B,出问题只能盯日志。
- 生产可恢复性:长任务跑到一半服务挂了,重启后状态没了,用户得从头来。
- 人机协作难嵌入:审批、确认、回调等环节跟 LLM agent 混在一起时,代码迅速变成意大利面。
- 评测和回放困难:想重跑某次用户对话、对比 prompt 改动前后效果,没有统一的 state snapshot。
Burr 用状态机把这五件事一并解决:
- 显式建模"哪一步做什么",transition 条件把决策逻辑写在图上。
- state 是 typed 的(基于 pydantic),所有写入受 schema 约束。
- persister 让你随时
.run(...)中断、.load_state(...)恢复。 - UI 实时展示状态机的执行轨迹 + state 变化 + 时延。
- 因为每一步 state 都可持久化,回放和评估天然简单。
它和 Hamilton 的关系是:Hamilton 管 DAG(无环),Burr 管状态机(可循环)。README 自己说:"Originally Apache Burr was built as a harness to handle state between executions of Apache Hamilton DAGs."
快速安装
pip install "apache-burr[start]"
[start] 会一起装上 UI 服务、Streamlit 集成和常用持久化后端。用 poetry 装的话参考官方 getting_started/install/ 文档。
装完启动 UI:
burr
浏览器自动打开 Burr telemetry UI(自带示例数据可点开看,"Demos" 侧栏选 chatbot 可以跟一个 demo 聊,需要 OPENAI_API_KEY,没设也能看 trace)。
核心用法
1) Hello-world:单次计数
git clone https://github.com/apache/burr
cd burr/examples/hello-world-counter
python application.py
终端跑计数器的同时,UI 里能看到对应 trace。
2) 最小 chatbot(README 直接给的官方例子)
from burr.core import action, State, ApplicationBuilder
@action(reads=[], writes=["prompt", "chat_history"])
def human_input(state: State, prompt: str) -> State:
chat_item = {"role": "user", "content": prompt}
return state.update(prompt=prompt).append(chat_history=chat_item)
@action(reads=["chat_history"], writes=["response", "chat_history"])
def ai_response(state: State) -> State:
response = _query_llm(state["chat_history"]) # 换成你自己的 OpenAI / Anthropic 调用
chat_item = {"role": "system", "content": response}
return state.update(response=response).append(chat_history=chat_item)
app = (
ApplicationBuilder()
.with_actions(human_input, ai_response)
.with_transitions(
("human_input", "ai_response"),
("ai_response", "human_input"),
)
.with_state(chat_history=[])
.with_entrypoint("human_input")
.build()
)
*_, state = app.run(halt_after=["ai_response"], inputs={"prompt": "Who was Aaron Burr, sir?"})
print("answer:", app.state["response"])
要点:
reads/writes显式声明每个 action 操作 state 的字段,pydantic 校验。with_transitions声明图。halt_after=["ai_response"]跑到指定节点就停;可以传inputs注入初始参数。_query_llm自由实现,Burr 不关心你怎么调 LLM。
3) 持久化 + 恢复(生产必学)
from burr.core import ApplicationBuilder
from burr.core.persistence import SQLitePersister
persister = SQLitePersister(db_path="./burr.db", table_name="chat_state")
app = (
ApplicationBuilder()
.with_actions(human_input, ai_response)
.with_transitions(...)
.with_state(chat_history=[])
.with_entrypoint("human_input")
.with_state_persister(persister)
.with_identifiers(app_id="chat-42") # 不同对话用不同 app_id 隔离
.build()
)
# 执行
app.run(halt_after=["ai_response"], inputs={"prompt": "hi"}, app_id="chat-42")
# 之后从断点恢复
state = persister.load(app_id="chat-42")
persister 选项还包括 Postgres / Redis / SQLAlchemy 通用后端,生产选 Postgres。
4) 跟 FastAPI 集成(生产部署)
Burr 的设计目标之一是"fastapi integration"已在 roadmap,开发中。社区已有的做法是:在 FastAPI handler 里直接 app.run(...),把 app_id 绑定到 session_id,每次请求带着 app_id 来就能续上前面的状态。
5) 接 LLM 框架(LangChain / LlamaIndex / Hamilton)
Burr 故意保持"框架无关",_query_llm 里可以:
- 直接
openai.OpenAI().chat.completions.create(...) - 调 LangChain LCEL chain
- 跑一个 LlamaIndex agent
- 把整个 Hamilton DAG 当成一个 action 的内部逻辑
官方 README 的对比表里专门强调:"Burr 不在意你怎么用 LLM"。
6) 用 UI 看 trace
启动 burr 之后访问 UI,能看到:
- 每个 action 的执行顺序(高亮当前节点)
- state 在每一步的 diff(哪些字段被改了)
- 每步耗时
- persister 中的状态条目(按 app_id 索引)
调试 agent 决策时这个 UI 是杀手锏——比盯 print 直观 10 倍。
典型适用场景
- 多轮 chatbot:人类输入 ↔ LLM 回复循环,需要维护 chat_history。
- RAG with 审批:retrieval → 生成 → 人工 review → 改写 → 再生成,循环结构天然适合状态机。
- 长流程 agent:研究类 / 数据分析类 agent,跑 10+ 步,中途要可恢复。
- simulation / 决策演练:金融反欺诈、风控规则演练、人机协作训练,Burr 的"非 LLM 也能用"特性正好。
- 评估与回放:录下 app_id 序列化的 state,跑评测时再回放,对比 prompt/model 改动效果。
坑与注意
- 状态机思维有学习成本:从"写函数"转到"画图 + transition 条件"需要适应,团队第一周会慢。
reads/writes漏写会导致 bug:state 字段如果不在 writes 里声明,Burr 会拒绝运行;这是 feature,但调试时容易踩。- pydantic 模型要维护:state 字段加一个就要更新 pydantic schema,否则反序列化失败。
- persister 不是银弹:高频状态写入会让 DB 压力飙升,Burr 默认在 transition 边界持久化,可以调粒度但要小心一致性。
- UI 用 Electron:跟 Burr UI 共生,第一次启动可能稍慢;关掉 demo 数据可以加快。
- FastAPI 官方集成还在 roadmap:生产部署要自己写胶水,参考
examples/下的 web 例子。 - 小任务过度工程:如果只是"用户问一句、模型答一句"的极简 chatbot,用 LangChain LCEL 一行代码更省事,Burr 的价值在复杂度上升后才显现。
与同类对比
README 自带的对比表:
| 工具 | 显式状态机 | 框架无关 | 异步事件编排 | 内置 web 服务 | 自带 UI | 支持非 LLM |
|---|---|---|---|---|---|---|
| Apache Burr | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| LangGraph | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Temporal | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ |
| LangChain | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Superagent | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Apache Hamilton | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ |
差异点:
- vs LangGraph:同样基于图,但 LangGraph 锁 LangChain 生态;Burr 完全无关,可以包任何东西。
- vs Temporal:Temporal 是分布式 workflow 引擎,重在事件编排;Burr 轻量,单进程为主,专注于"应用内状态管理"。
- vs Apache Hamilton:Hamilton 是无环 DAG,Burr 是带循环的状态机——刚好互补。
- vs LangChain LCEL:Burr 范式更显式、可观测性更强,但学习曲线更陡。
一句话推荐
如果你正在写"多步骤 + 状态需要持久 + 出问题要可回放 + 团队要看见 trace"的 LLM 应用,Burr 比 LangGraph / LangChain LCEL 更值得;如果只是单轮问答,直接调 OpenAI SDK 反而最干净。
不确定处
- "FastAPI integration + hosted deployment" 在 README 中明确列为 roadmap 项目,未来版本可能内置;目前要自己写集成。
- 文中 persister 选项(SQLite/Postgres/Redis/SQLAlchemy)来自 README 列表,具体接口签名以
burr.core.persistence文档为准;高频场景建议先压测。 - Burr 与 Hamilton 的协作模式("Burr 作为 Hamilton 的 harness")在 README 中提及但未给出完整 example,建议直接看
examples/目录里的 ml-training 等案例。 - "Burr Cloud" 是商业版本(waitlist 状态),self-host 能力完全开源,但企业级 SLA 与多租户能力要等商业版。
- 用户引言(Reddit / TaskHuman / Provectus 等)属社区反馈,不构成生产可靠性背书。