一、先看一个只有模型和工具的报销助手
第一版内部报销助手很容易做出来:给模型一段说明,再提供“读发票”“查制度”“写回报销系统”三个函数。 用户上传发票,模型查到制度,算出金额没有超标,demo 看起来已经会工作。
第二个同事开始使用时,麻烦才出现:两个人的历史混在一起;模型准备写回高额报销,却没有主管确认; 浏览器刷新后看不到执行到哪一步;服务重启后又把同一张发票写了一次。模型会判断,工具也能执行, 但这个产品仍然没有一套稳定的运行方法。
二、Agent 框架是什么
Agent 框架,就是把“让模型反复判断、调用工具并把任务安全做完”所需的公共运行责任, 变成可复用组件和规则。它不替模型思考,也不替业务决定报销政策;它负责让思考和动作能够连续、 可控、可记录地发生。
先不要记框架名,只看报销助手逐渐需要的六类责任:
- 推进任务:模型回答后要不要调用工具,工具返回后要不要继续问模型。
- 执行工具:把模型提出的参数校验好,再调用文件、数据库或远端服务。
- 保存进度:记住用户、消息、工具结果和当前任务状态,让下一轮能接着做。
- 拦住风险:只读查询可以直接做,高额写入要暂停并等待主管确认。
- 控制流程:查发票、查制度可以并行,写回系统必须等前面完成。
- 接入产品:把进度发给网页,为多人隔离会话,并在中断后恢复。
后文会把它们叫作 model loop、tool runtime、state ledger、permission gate、workflow graph 和 service plane。 现在只需要先理解它们各自解决的麻烦,不必背英文名。
三、一张报销单怎样走完
- 产品入口收到用户、发票和本次报销编号,找到这个用户自己的会话。
- 运行时把当前问题、必要历史和可用工具交给模型;模型决定先读发票。
- 工具层校验文件参数并返回金额,运行时把结果记到账本,再让模型查制度。
- 如果金额超过门槛,权限关口暂停写入,前端显示“等待主管确认”。
- 确认通过后,流程层才允许写回报销系统,并记录外部操作结果。
- 最终回答、工具结果和任务状态被保存;刷新页面或服务重启后仍能恢复。
这六步就是本系列反复使用的主线。不同框架的差别,不只是有没有某个类,而是谁接住其中哪些步骤, 又把哪些步骤留给应用自己实现。
3.1 先给这次运行一个不会丢的身份
为了不让六类责任变成六组名词,后文都跟踪同一条记录:报销运行 E-1042。
它不是整段聊天记录,而是应用用来回答“现在做到哪里、下一步能不能做、失败后从哪里接”的任务账本。
模型、工具、审批页和 ERP 看到的字段并不相同,但它们都通过这个身份回到同一件事。
{
"expense_run_id": "E-1042",
"applicant": "alice",
"invoice_ref": "INV-77",
"amount": null,
"policy_result": null,
"pending_action": null,
"approval": "not_required_yet",
"idempotency_key": "expense:E-1042:commit",
"erp_receipt": null,
"status": "submitted"
}
第一次读发票后,工具层只把 amount 改成 12800;制度检查再把
policy_result 改成“需主管审批”。权限关口不会直接写 ERP,而是先保存
pending_action=write_expense 和恢复键,把状态推进到
waiting_approval。主管批准会创建一次新的运行,但新运行仍引用
E-1042 和原幂等键;只有 ERP 返回 ERP-778 后,状态才变成
completed。
| 阶段 | 改变记录的 owner | 新增的事实 | 中断后从哪里接 |
|---|---|---|---|
submitted |
产品入口 | 用户、发票引用、任务身份 | 按 E-1042 重新装载会话 |
evaluated |
工具层与流程层 | 金额和制度结论 | 从已保存结果继续,不必让模型猜测 |
waiting_approval |
权限关口 | 待执行动作、审批摘要、恢复键 | 批准事件重新关联原任务和待执行动作 |
completed |
应用与 ERP | 幂等写入回执 ERP-778 |
回执证明已经写过,重试不得重复入账 |
这也解释了三个容易混淆的“看见”:账本可以保存完整工具结果,模型下一轮只看到投影后的必要部分, 审批页则只看到金额、理由和待执行动作。保存了,不等于模型看到了;模型看到了,也不等于有权执行。
阅读契约。 这篇先不做排行榜,也不先问哪个框架更火。我们只问一件事: 当 agent 从 demo 走向产品,模型循环、工具调用、状态记录、权限、人机确认和服务化入口, 分别由谁负责?这个“谁负责”,就是后面反复出现的 runtime owner。
本文把几个常见框架放到同一张地图上: AgentScope、 Pi、 Google ADK Python、 Agno、 AutoGen、 CrewAI、 Eino、 tRPC-Agent-Go,旁边也会把 OpenAI Agents SDK 作为一个轻量但重要的参照。这里不做性能排名,只建立后续源码阅读的坐标。
证据边界。 框架定位来自项目 README、官方文档和公开源码。源码链接固定到当前公开快照; 文中“运行主线”“owner”“服务平面”“状态账本”是工程归纳,用来比较公开可见的抽象边界, 不推断闭源控制台、云服务或模型 provider 内部实现。
换成更直白的话,这篇只回答五个问题:
- Agent 框架是什么,它比“模型加几个工具”多解决了什么?
- 一个 agent 应用要进产品,至少要接住哪六类责任?
- Pi、AgentScope、ADK、Agno、AutoGen、CrewAI、Eino、tRPC-Agent-Go 分别把重心放在哪里?
- 为什么不能只用“多 agent”或功能数量判断框架?
- 后续十二篇应该按什么顺序阅读?
后面会反复用到四个词。先把它们钉在同一层,能避免把“磁盘里有记录”“模型看到了记录”和 “框架拥有这份记录”误读成同一件事:
| 本文术语 | 在这个系列里的含义 | 不等于什么 |
|---|---|---|
| Owner | 为一项责任定义输入输出、状态更新点、失败边界和应用交接的位置。 | 不只是目录名,也不一定是一个类。 |
| Ledger | 用于恢复、审计或继续运行的结构化记录,可能是消息、事件、entry 或 session state。 | 不自动等于下一轮模型输入。 |
| Model-visible view | 一次模型调用前,从 ledger、summary、memory 和当前输入投影出的可见上下文。 | 不是 durable history 的完整副本。 |
| Gate | 可以改变执行路径的决定点,例如 allow、deny、pause、route 或 resume。 | 不只是一个布尔校验函数。 |
四、把六步抽象成 runtime owner
学一个框架时,我们很自然会先看目录和类名:Agent、Tool、Workflow、
Memory。这当然有用,但还不够。真正决定工程成本的是:这些类背后有没有一个稳定的责任归属。
比如工具调用不是只有“函数能不能被调用”,还包括 schema 从哪里来、错误怎么返回、是否需要审批、结果怎样进入下一轮上下文。
所以我把 runtime owner 翻译成一个更朴素的问题:这层麻烦最后归谁管? 如果归框架管,应用代码就能少写一批 glue code;如果不归框架管,开发者就要自己拼状态、事件、权限和恢复逻辑。
可以把后面几篇都压成同一条形状级 trace。它不是某个框架的真实结构体,而是读源码时要追的状态变化:
报销运行 E-1042:“读取 INV-77 并提交报销”
-> model loop:生成本轮 run id,投影当前问题与必要历史
-> tool runtime:把 read_invoice 转成 schema 校验过的 tool call
-> permission gate:判断这次调用是只读、需确认,还是直接拒绝
-> state ledger:写入金额、tool_call_id、result 和 pending_action
-> workflow graph:资料齐全但金额超门槛,路由到主管审批
-> service plane:只向前端投影审批摘要,并保存 resume key
-> application:批准后用 expense:E-1042:commit 写 ERP,保存 ERP-778
后面读每个框架时,我会反复问这条 trace 的同一个问题:哪个对象接住了输入,哪个 gate 改变了路径, 哪条记录让下一轮还能继续。如果一篇文章只能说出“这里有 Agent / Tool / Memory 类”,但说不清这条 trace 怎么走, 说明它还没有真的解释 runtime owner。
| 责任层 | 它替你管什么 | 没人管时会怎样 |
|---|---|---|
| Model loop | 把一次任务推进成多轮模型调用、工具调用和最终回答。 | 应用层到处写 while loop,停止条件、重试和流式事件很快散掉。 |
| Tool runtime | 注册工具、生成 schema、执行工具、流式返回结果。 | 工具像普通函数,缺少统一错误、并发、MCP 和结果压缩边界。 |
| State ledger | 保存消息、事件、summary、memory、session 和可恢复记录。 | UI 看到的历史、模型看到的上下文和磁盘记录互相漂移。 |
| Permission gate | 在读写文件、执行命令、外部工具和人机确认之间建立副作用刹车。 | 模型一旦产生 tool call,应用只能全信或全挡。 |
| Workflow graph | 把确定性步骤、路由、fan-out/fan-in、循环和 agent 节点组合起来。 | 复杂业务只能塞进 prompt 或散落在应用 callback 里。 |
| Service plane | 处理多租户、多会话、调度、SSE/WebSocket、观测和控制台。 | demo 可以跑,本地脚本可以跑,但很难变成多人使用的产品。 |
五、同一张地图上看几个框架
下面这张表也不要当成优劣排名。它只是在回答:如果你第一次打开源码,应该优先看哪条主线。 有的框架最该先看 workflow graph,有的最该先看多 agent 消息 runtime,有的最该先看服务化控制平面。 先找主线,后面的类名和函数名才不会散落成互不相连的名词。
| 框架 | 最强 owner | 更适合先问的问题 | 第一眼证据 |
|---|---|---|---|
| AgentScope | 事件化 agent runtime、权限、workspace、服务化 session。 | 一个 reply_stream 怎样变成模型事件、工具事件和可恢复状态? |
Agent、EventType、PermissionEngine。 |
| Pi | 最小 coding agent harness:provider adapter、agent loop、事件、工具批次与 append-only session tree。 | 当 core 不内置 plan、sub-agent、MCP 和权限弹窗时,哪些运行责任仍必须稳定? | README 把模型接入、agent loop、coding harness 和终端 UI 拆成四层 package。 |
| ADK Python | Agent + graph-based workflow runtime。 | 什么时候用 agent 自主推进,什么时候把步骤显式放进 workflow? | README 把 Agent 和 Workflow 放在 quick start 里。 |
| Agno | agent platform:API、storage、tracing、scheduling、RBAC、control plane。 | 当 agent 要进产品,哪些平台能力不该由业务代码临时拼? | README 明确说它用于 build, run, manage agent platforms。 |
| AutoGen | 多 agent 对话、AgentChat、Core、Extensions 分层。 | 多 agent 编排的抽象如何从实验范式演进到企业 runtime? | README 已标注 maintenance mode,并指向 Microsoft Agent Framework。 |
| CrewAI | Crews 与 Flows:角色协作 + 事件驱动业务流。 | 任务适合交给角色协作,还是应该由确定性 flow 控制? | README 同时强调 Crews 和 Flows。 |
| Eino | Go 风格 component、compose graph 与 ADK。 | 在 Go 服务里,agent 能不能只是可组合组件图的一部分? | README 把 Components、ADK、Composition 放在同一层描述。 |
| tRPC-Agent-Go | Go agent 的 Runner、GraphAgent、tools、skills、artifact、server 与长上下文 runtime。 | 一个 Go agent 上线后,谁拥有运行边界、确定性流程、工具副作用、协议出口和长会话状态? | README 把 agent、graph、tools、session/memory、skills、A2A/AG-UI/MCP 放进同一套 Go-native stack。 |
旁边还有一个很有用的参照: OpenAI Agents SDK 把 Agent、tools、handoffs、guardrails、sessions、tracing 和 Realtime 放成核心概念。 它提醒我们:轻量框架并不等于没有 runtime,它只是把很多 owner 做得更窄、更贴近模型和应用边界。
六、为什么不把“多 agent”放在第一位
多 agent 很显眼,因为它容易演示:一个 planner,一个 researcher,一个 coder,再加一个 reviewer。 但源码阅读时,如果先看角色名,容易把协作误解成 prompt 模板。更关键的问题是: agent 之间的交接是不是普通 tool call,是否有独立 session,是否共享 memory, 子任务的权限是否继承,结果如何回到父任务,失败是否能恢复。
还是回到报销助手的例子。你当然可以拆出“票据识别 agent”“制度检查 agent”“审批沟通 agent”。 但真正难的不是起三个名字,而是决定:票据识别的结果谁保存,制度检查失败后谁重试, 审批沟通能不能直接写系统,用户中途关闭页面后下一次从哪里继续。没有这些边界,多 agent 只是多个 prompt。
在 E-1042 里,更稳妥的做法是让三个子任务都只把结果写回父记录:
票据识别补金额,制度检查补政策结论,审批沟通补批准或拒绝。它们都不能直接触发 ERP 写入;
只有拥有幂等键和完整前置条件的父流程可以提交。这样“多 agent”改变的是分析分工,而不是副作用的最终 owner。
AutoGen 的价值正在这里:它让社区很早就把多 agent 对话、team、handoff 和工具化 agent 当成一等抽象来实验。 但它的当前 README 已经明确写出 maintenance mode,并建议新项目转向 Microsoft Agent Framework。 所以这个系列读 AutoGen 时,会把它放在“抽象演进与迁移”位置,而不是把它包装成新项目的默认起点。
Pi 给出另一种修正:不是每个常见能力都应该进入 core。它把 provider、agent loop、tool batch、事件、 append-only session tree 和 compaction 做成稳定主线,却把 plan mode、sub-agent、MCP、远程工具和权限交互留给扩展。 这让我们能区分“运行时必须保证的机制”和“产品可以选择的策略”。
CrewAI、Eino 和 tRPC-Agent-Go 则代表三种不同修正。CrewAI 把协作角色和业务 flow 分开, 让“谁自主协作”和“谁确定性路由”不混在一起。Eino 更 Go:先定义 component 和 compose, 再把 agent patterns 放到可组合图里。tRPC-Agent-Go 继续往服务端 runtime 走,追问 Runner、GraphAgent、 tools、Skills、artifact、server plane,以及 session summary、long-term memory 和 hidden-history recall 分别由谁拥有。
七、后续怎么读:先定最小 core,再展开完整 runtime
第二篇先读 Pi,不是因为它比其他框架更重要,而是因为它把 core 的边界画得很清楚。 provider adapter、agent loop、tool result、event 和 session 必须稳定;plan、sub-agent、MCP 和具体权限策略可以留给扩展。 读者先知道“不能再少什么”,后面才能分辨框架新接走了哪些责任。
| 阅读站点 | 这一站先回答什么 | 为下一站留下什么 |
|---|---|---|
| 第二篇:Pi | 一个最小 agent harness 怎样连接模型、工具、事件和可恢复会话? | 最小 core 进入真实产品后,谁负责权限、暂停和服务化? |
| 第三篇:AgentScope | reply_stream 怎样把结构化账本、typed event、权限关口和 provider adapter 串成完整 runtime? |
workspace、storage 与 service session 装到一起后,Agent 的真实工作现场由谁拥有? |
| 第四篇:Agent 工作现场 | Coding / General 与 Local / Cloud 为什么是两条坐标,Session、Workspace、Artifact、Memory 又分别保存什么? | 这些 owner 跨越进程、服务与客户端边界时,应该用哪种协议? |
| 第五篇:Agent 协议 | MCP、A2A、AG-UI 和 ACP 分别连接工具、远程 agent、前端和编辑器的哪条边界? | 后面读框架的 protocol 支持时,不再把它们当成同一类 feature。 |
这四站构成系列的基础课:Pi 定 core,AgentScope 展开 runtime,工作现场篇分清部署与状态 owner,协议篇再把 runtime 放到系统边界上。 接下来看 ADK 的 workflow runtime、Agno 的平台化运行面、AutoGen 到 Microsoft Agent Framework 的迁移、 CrewAI 的 Crews/Flows、Eino 的 Go composition 和 tRPC-Agent-Go 的长上下文账本,就不会只是看 API 名称, 而是在比较 owner 的取舍。
读后续文章时可以带着一个检查问题:如果把这层从框架里拿掉,应用代码要自己补哪些状态、事件、权限和恢复逻辑? 这个问题比“框架支持多少工具”更接近真实工程成本。
八、先记住这张决策表
| 你的压力 | 优先比较的 owner | 可能先读的框架 |
|---|---|---|
| 想快速写一个可工具调用的单 agent。 | Model loop、tool schema、sessions。 | OpenAI Agents SDK、Pi、AgentScope、ADK。 |
| 业务流程本身有确定性步骤和分支。 | Workflow graph、state transition、human gate。 | ADK、CrewAI Flows、Eino compose。 |
| agent 要进入多人产品或内部平台。 | Service plane、storage、RBAC、tracing、scheduler。 | Agno、AgentScope service。 |
| 重点是多 agent 协作和委派。 | Handoff、team protocol、session isolation、result routing。 | AgentScope team、CrewAI Crews、AutoGen / Microsoft Agent Framework。 |
| 系统已经在 Go 服务里,想少引入 Python runtime。 | Component composition、stream、callback、tool interface、long-context ledger。 | Eino、tRPC-Agent-Go。 |
8.1 选中框架之后,还要通过采用门
以报销产品为例,框架在 README 里出现 Session、Workflow 或 Approval,只能说明“有候选能力”,
不能说明已经接住生产责任。团队还应固定四个验收场景:Alice 与 Bob 的记录不会串线;审批等待期间重启服务仍能回到
E-1042;重复提交同一幂等键只产生一个 ERP 回执;审计记录能还原谁在何时批准了什么。
某项能力缺失时只有两个诚实选择:由应用明确拥有并测试它,或者淘汰这个候选框架。 因此这里要一直分开三件事:框架产出了运行结果,验收用例验证了恢复与副作用边界, 产品负责人最后才采用这套实现。类名、demo 和一次成功运行都不能跳过中间两步。
下一篇先进入 Pi。我们不会从 package 列表开始,而是跟一次“改代码并跑测试”的任务: 模型怎样反复提出工具调用,事件怎样报告进度,原始会话怎样留在 JSONL 树中, 以及上下文过长时为什么是“重新投影”而不是“删掉历史”。