Day 02 / 共 20 天 · 第 1 周 核心概念
Agent:自主智能体
第一个核心概念。今天读数据模型看清 Agent 到底是什么,并揭示 SuperAGI 最关键的"啊哈"点——它的自主循环不在代码里,而在数据库和消息队列里。
📍 你在整门课的位置 · 第 1 周 核心概念(D1-5)· 昨天看了全景,今天钻进第一个概念 Agent
D01 全景架构→
D02 Agent→
D03 工具→
D04 运行平台→
D05 完整旅程·
第2周 Agent执行·
第3周 工具/记忆/资源·
第4周 平台/异步/生态
L01
Agent 表极简
🤔 "Agent 智能体"听起来很高级,它在代码里到底是个啥?
很多人以为智能体是一段很聪明的、会自己思考的复杂代码。翻开源码前你可能预期看到一个几百行的
class Agent,里面全是决策逻辑。💡 一句话本质:Agent 只是数据库里几张表的记录,不是"聪明代码"
在 SuperAGI 里,Agent 不是一个装满逻辑的类,而是数据库里的一条身份记录 + 一堆配置行。"聪明"来自运行时反复调 LLM,而不是 Agent 类本身。所以读 Agent,就是读几张表的字段——今天全程都在看表结构。
贯穿今天的类比是"公司员工档案":Agent 表 = 员工工牌(只印工号、姓名、部门,稳定不变);配置 = 员工的档案袋(职责、权限,随时往里加纸);一次 Execution = 这名员工的一天出勤记录;Feed = 他的工作日志本。
贯穿今天的类比是"公司员工档案":Agent 表 = 员工工牌(只印工号、姓名、部门,稳定不变);配置 = 员工的档案袋(职责、权限,随时往里加纸);一次 Execution = 这名员工的一天出勤记录;Feed = 他的工作日志本。
看 Agent 模型(models/agent.py:20)——出乎意料地简单:
class Agent(DBBaseModel):
__tablename__ = 'agents'
id = Column(Integer, primary_key=True)
name = Column(String)
project_id = Column(Integer) # 归属哪个 Project
description = Column(String)
agent_workflow_id = Column(Integer) # 绑定一个工作流
is_deleted = Column(Boolean, default=False)
读法:Agent 表只存"身份 + 归属 + 绑哪个工作流",非常精简。它的目标、指令、工具、模型等都不在这张表里——拆到了
AgentConfiguration(L02)。为什么 Agent 表这么"空"?
因为一个 Agent 的"可变配置"(目标、工具、模型…)很多且经常增改。如果全塞进 Agent 表,字段会爆炸、加新配置要改表结构。SuperAGI 把"身份"(Agent 表,稳定)和"配置"(AgentConfiguration,多变)分开——身份表精简稳定,配置用灵活的 key-value 存。这是数据建模的"稳定/多变分离"。
L02
配置存 key-value(EAV 模式)
# models/agent_config.py:15
class AgentConfiguration(DBBaseModel):
__tablename__ = 'agent_configurations'
agent_id = Column(Integer)
key = Column(String) # 如 "goals" / "instructions" / "tools" / "model"
value = Column(Text)
读法:Agent 的目标、指令、约束、工具、模型全用"键值对"存——一个 Agent 有多行 AgentConfiguration,每行一个配置项。比如
key="goals", value="调研竞品定价"。📝 一个 Agent 在 agent_configurations 表里长这样(多行 key-value)
同一个
想给 Agent 加一个新配置项?再插一行就行,完全不用改表结构——这就是 EAV 的灵活之处。
agent_id=7 对应下面这几行:key=goals → value=["调研 3 家竞品定价"]key=instruction → value=["汇总成 csv 表格"]key=tools → value=[13, 21](工具 id 列表)key=model → value=gpt-4key=max_iterations → value=25想给 Agent 加一个新配置项?再插一行就行,完全不用改表结构——这就是 EAV 的灵活之处。
EAV(实体-属性-值)模式的取舍
这叫 EAV 模式——不给每种配置建一个列,而是用"key 列 + value 列"存任意配置。好处:加新配置项(比如
接着"员工档案"的类比:固定列建表 = 印死的工牌(想加一栏得重做整批工牌);EAV = 员工的档案袋(要加一项资质,塞张纸进去就行,档案袋结构不用动)。
resource_summary、last_resource_time)无需改表结构,加一行即可。坏处:查询不如固定列直接、value 都是文本要自己转类型。对"配置项种类多、常变"的场景,EAV 灵活性优先——SuperAGI 选了它。接着"员工档案"的类比:固定列建表 = 印死的工牌(想加一栏得重做整批工牌);EAV = 员工的档案袋(要加一项资质,塞张纸进去就行,档案袋结构不用动)。
L03
Execution:一次运行
Agent 是"定义",一次实际运行叫 AgentExecution(models/agent_execution.py:11)——一个 Agent 可以被跑很多次:
class AgentExecution(DBBaseModel):
status = Column(String) # CREATED/RUNNING/PAUSED/COMPLETED/TERMINATED
agent_id = Column(Integer)
num_of_calls = Column(Integer, default=0) # 调了几次 LLM
num_of_tokens = Column(Integer, default=0) # 消耗了多少 token
current_agent_step_id = Column(Integer) # ★ 当前走到工作流哪一步
读法:Execution 记录"这次运行的状态机 + 进度 + 用量"。关键是
current_agent_step_id——它指向"这次运行现在走到工作流的哪一步",把"运行"和"流程定义"关联起来。status 是运行状态机(L05)。Agent vs Execution 的区别(像"类"和"对象")
Agent = 定义("一个调研竞品的智能体")。Execution = 一次具体运行("周一那次调研"、"周二那次调研")。一个 Agent 定义可以产生多个 Execution,各自独立跑、各有状态和进度。这样能重复运行同一个 Agent、能定时跑、能同时跑多次——都靠 Execution 承载每次的独立状态。
L04
Feed:短期记忆
AgentExecutionFeed(models/agent_execution_feed.py:8)——运行过程中每一条 LLM 对话/工具响应存一行:
class AgentExecutionFeed(DBBaseModel):
agent_execution_id = Column(Integer)
feed = Column(Text)
role = Column(String) # system / user / assistant
feed_group_id = Column(String)
Feed = 智能体的"对话历史/短期记忆"
智能体每一步的思考、每次工具调用的结果,都作为一条 Feed 存下来(role 区分是谁说的)。下一轮循环时,框架把这些 Feed 读回来、拼成 LLM 的对话上下文——这就是智能体"记得自己之前干了什么"的机制。同时它也是 GUI 实时展示的数据源(你在界面上看到的"智能体思考流"就是 Feed)。Feed 一举三得:短期记忆、UI 展示、执行审计。(长期记忆则在向量库,Day 13。)
L05
循环在 DB 和队列里(最重要的"啊哈")
SuperAGI 的自主循环不是一个 while 循环!它是"数据库状态机 + Celery 任务链"。看 jobs/agent_executor.py:94:
# 执行完一步后,若没完成,就再排一个任务给自己(2秒后)
if agent_execution.status in ("COMPLETED", "WAITING_FOR_PERMISSION"):
return
superagi.worker.execute_agent.apply_async((agent_execution_id, datetime.now()), countdown=2)
左边"内存大 while"崩了就全丢;右边 SuperAGI 每步退出、把"下一步"重新入队,进度存 DB、对话存 Feed——所以能断点续跑、能多 worker 并发。
👶 小白 vs 👨🏫 老师:为什么不直接写个 while 循环?
👶 小白:智能体不就是"想一步→干一步→再想"吗?一个
👨🏫 老师:因为 while 循环活在一个进程的内存里。这个循环要跑几分钟到几小时,中间进程一崩(重启、OOM、部署),整局全丢,得从头再来。
👶 小白:那把进度存下来不就行?
👨🏫 老师:对!SuperAGI 就是把"下一步该干啥"存进 Redis 队列、把"走到第几步"存进 DB。于是循环不再依赖某个进程活着——任何一个 worker 都能接着跑下一步,还能同时开好几个 worker 分担。代价是"一步就退出、靠重排续跑"这套看起来绕的机制。
while True 循环到底不就完了,为什么搞得这么绕?👨🏫 老师:因为 while 循环活在一个进程的内存里。这个循环要跑几分钟到几小时,中间进程一崩(重启、OOM、部署),整局全丢,得从头再来。
👶 小白:那把进度存下来不就行?
👨🏫 老师:对!SuperAGI 就是把"下一步该干啥"存进 Redis 队列、把"走到第几步"存进 DB。于是循环不再依赖某个进程活着——任何一个 worker 都能接着跑下一步,还能同时开好几个 worker 分担。代价是"一步就退出、靠重排续跑"这套看起来绕的机制。
| 时刻 | 此刻发生什么 | status | current_step_id / num_of_calls |
|---|---|---|---|
| worker 第1次领取 | 跑迭代步:调 LLM 选工具、执行、写 Feed | RUNNING | step=12, calls=1 |
| 这步末尾 | 没完成 → apply_async(countdown=2) 排下一步 | RUNNING | step=13(已推进) |
| 2秒后 worker 第2次领取 | 跑 step=13,又一轮 LLM+工具 | RUNNING | step=13, calls=2 |
| 某次 LLM 调 finish | 宣布完成,不再重排 | COMPLETED | calls=8,循环结束 |
读法(单步走查表):盯着最后一列——进度全程写在 DB(step / calls)里,不在内存。所以"第1次""第2次"完全可以是不同的 worker 进程,甚至中间重启过,照样接着跑。
🤯 这是理解 SuperAGI 的关键
普通自主智能体是"进程里一个大 while 循环转到底"。SuperAGI 不是——它每执行一步(一次 LLM+工具)就退出,然后通过 Celery
apply_async 把"执行下一步"重新排进队列,2 秒后另一个(或同一个)worker 领走跑下一步。进度存在 DB 的 current_agent_step_id,对话存在 Feed。所以"循环"是"Celery 任务反复自我重新调度",状态全在数据库和 Redis 里,不在内存。好处:进程可以随时断、随时恢复(状态都持久化了)、能水平扩展多个 worker、崩溃不丢进度。理解了这点,两级 step、崩溃恢复、人工审批挂起就都顺理成章。👶 小白:循环靠队列反复重排、每次还 countdown=2 等 2 秒,那智能体岂不是很慢?
👨🏫 老师:几乎不影响。一步里"调 LLM + 执行工具"本身就要好几秒、甚至更久,2 秒的排队间隔相比之下微不足道。而这 2 秒换来的是可断点续跑、可多 worker 并发、崩溃不丢进度——用一点点延迟换一整套可运维性,非常划算。真嫌慢,这个 countdown 也能自己调小。
L06
max_iterations 熔断
自主循环怕失控,所以有 max_iterations 熔断(agent_executor.py:143 的 _check_for_max_iterations)——num_of_calls 超过上限就停。
又见"能循环处必配上限"
和 eino 的 MaxRunSteps、OpenHands/AutoGPT 的 max_iterations、CrewAI 的 max_iter 一模一样——凡是能自主循环的地方,必须配次数上限防失控烧钱。SuperAGI 用
💰 数字感受一下:GPT-4 级别一次调用大约几分到几毛钱。若没有上限、循环卡死打转,一个失控智能体一晚上跑几千次调用,就是几百上千块凭空烧掉——
num_of_calls(调 LLM 次数)计数,超 max_iterations 强制停。结束的其它出口:LLM 调用 finish 工具(自己宣布完成)、任务队列空、走到工作流的 COMPLETE 边。五个框架同一个铁律——这就是读多个源码的价值:看穿共性。💰 数字感受一下:GPT-4 级别一次调用大约几分到几毛钱。若没有上限、循环卡死打转,一个失控智能体一晚上跑几千次调用,就是几百上千块凭空烧掉——
max_iterations(默认几十次量级)就是那道保险丝。L07
三层租户
SuperAGI 是多租户平台,三层组织架构:
| 层级 | 模型 | 含义 |
|---|---|---|
| 顶层 | Organisation(organisation.py:7) | 租户(一个公司/团队) |
| 中层 | Project(project.py:5,含 organisation_id) | 项目 |
| 底层 | Agent(含 project_id) | 智能体 |
为什么要三层? 平台服务多个组织,每个组织有多个项目,每个项目有多个智能体。层级隔离保证"A 公司看不到 B 公司的智能体"——多租户 SaaS 的基本盘。所有模型都继承
DBBaseModel(base_model.py:10),统一提供 created_at/updated_at 和序列化方法(DRY)。L08
今日小结 + 动手
🧠 今天你应该能回答
- Agent 表为什么这么精简?配置为什么用 EAV key-value?
- Agent 和 Execution 的区别?(类 vs 对象)
- Feed 是什么?一举哪三得?
- SuperAGI 的循环为什么"在 DB 和队列里"?好处是什么?
- max_iterations 和其它框架有什么共性?
🗣️ 一句话复述今天
SuperAGI 的 Agent 就是"员工工牌 + 可加纸的档案袋",它的自主循环不在内存的 while 里,而是"进度记 DB、下一步排 Redis 队列、worker 一步步接力"——所以能断点续跑、能多开 worker、失控有 max_iterations 兜底。
✋ 动手
P=superagi
sed -n '20,40p' $P/models/agent.py
sed -n '11,40p' $P/models/agent_execution.py
sed -n '94,100p' $P/jobs/agent_executor.py # 循环 = 自我重排
grep -n '_check_for_max_iterations' $P/jobs/agent_executor.py
明天预告 · Day 03:第二个核心概念——工具 Tools:一个工具 = 名字 + 描述 + pydantic 参数 + _execute,看智能体的"手"怎么定义、怎么被调用。