Day 16 / 共 20 天 · 第 4 周 平台/异步/生态

API controllers

平台对外的门面。今天读 controllers/(28 个):FastAPI 装配、主要端点、前端怎么通过 API 创建和运行智能体。

📍 你在整门课的位置 · 第 4 周 平台/异步/生态
第3周 工具/记忆/资源 D16 API 门面(外部入口) D17 Celery 异步 D18 GUI D19 部署 · D20 收官
L01

FastAPI 装配

🤔 前 15 天都在读"引擎",为什么现在突然跳到 API? 因为引擎再强,外面的人也够不着它。API 就是把前 15 天的一切能力(建 Agent、跑循环、装工具、传文件)包成"网线另一头能调的接口"。没有它,SuperAGI 只是一堆 Python 类,不是一个"平台"。
💡 一句话本质 controllers/ = 把内部能力翻译成 HTTP 端点的"翻译层"。它自己不干重活——只做四件事:收请求、校验、调 service/落库、返回(或入队)。main.py 则是"总装配",把 29 个路由拼成一个 app。
API 层就像生活中的餐厅前台:服务员(controller)只负责点单、传单、报进度,从不亲自下厨main.py 的 29 个 include_router 就是把凉菜档、热菜档、酒水档各自的菜单装订成一本总菜单。今天全程用这家"餐厅"来理解 API 层。

main.py:62 app = FastAPI():109-137include_router(共 29 处)把 30+ 控制器挂到不同前缀(/agents/agentexecutions/tools…)。用 fastapi-jwt-auth 做 JWT 登录、FastAPI-SQLAlchemy 中间件管 DB session。

main.py app = FastAPI() 总装配点 agent_router → /agents agent_execution → /agentexecutions tool / toolkit → /tools /toolkits resources → /resources …共 29 个 include_router 每个路由都: APIRouter + Pydantic 出入参 + JWT 鉴权 + DB session
include_router 把按功能拆分的 29 个路由聚合进同一个 FastAPI app——模块化装配,和 AutoGPT/OpenHands 一致。
读法:main.py 是装配点——把各功能模块的路由聚合到一个 FastAPI app,加 JWT 鉴权和 DB session 管理。几乎所有接口都 Depends(check_auth) 鉴权、通过 fastapi_sqlalchemy.db.session 访问数据库。和 AutoGPT/OpenHands 的 include_router 模块化装配一致。
L02

控制器分组

控制器前缀管什么
agent.py/agents智能体定义与调度
agent_execution.py/agentexecutions一次运行的生命周期
agent_execution_feed.py/agentexecutionfeedsGUI 拿实时进度
agent_execution_permission.py/agentexecutionpermissions人工审批
tool.py / toolkit.py/tools /toolkits工具 + 工具市场
resources.py/resources文件上传/读取
project.py / organisation.py/projects /organisations多租户层级
config.py/configs组织级配置
每个控制器一个 APIRouter(),用 Pydantic 的 *Out/*In 定义出入参。按功能拆分——清晰、易维护、不同团队管不同模块。
👶🏫 对话:为什么要拆成 28 个文件? 👶 小白:全写在一个 api.py 里不是更省事吗?
👨‍🏫 老师:28 个控制器加起来几千行。混在一个文件里,你改"审批"逻辑时得在几千行里翻找,还可能误伤"工具市场"的代码。
👶 小白:那拆开之后靠什么拼回去?
👨‍🏫 老师:就是 L01 的 include_router——各档口自己维护自己的菜单页,main.py 负责装订。改凉菜不会碰到热菜,这就是"按功能拆分"的全部动机。
用餐厅记住这张表 这张表就像餐厅里的各个档口/agents 是点菜窗口(定义要什么)、/agentexecutions 是下单出票口(发起一次制作)、/agentexecutionfeeds 是取餐进度屏、/agentexecutionpermissions 是"这道菜要加价,请顾客确认"的回访台。
L03

创建智能体

POST /agents/createcontrollers/agent.py:60 create_agent_with_config):

# 接收 AgentConfigInput(name/project_id/goal/constraints/tools/toolkits/model/max_iterations/...)
# ① 校验 project 和 tools(:89-97)
# ② Agent.create_agent_with_config 落库
# ③ 立刻建一条 AgentExecution(status='CREATED',:109)
# ④ 把 goal/tools/model 写进 AgentExecutionConfiguration
📝 输入 → 输出(最小例子) 前端 POST 一份 JSON:
{"name":"调研助手","project_id":1,"goal":["调研 AI 新闻并总结"],"tools":[3,7],"model":"gpt-4","max_iterations":15}
后端返回:{"id":42, "execution_id":88} —— 一次调用同时诞生了"智能体定义"(id=42) 和"第一次运行"(execution=88)。此刻 execution 的 status 还是 CREATED,尚未开跑(真正开跑要等 L04 入队)。
读法:"在 GUI 点 Create Agent"背后就是这个接口——同时创建"定义"(Agent+配置)和"第一次运行"(AgentExecution)。还有 /agents/schedule(创建并定时)、/get/project/{id}(列项目下智能体,标记 is_running/is_scheduled)、软删除。
L04

发起运行(入队)

POST /agentexecutions/addcontrollers/agent_execution.py:65)——发起运行的关键:

# 建 AgentExecution → status 改成 RUNNING → 关键一步(:148):
execute_agent.delay(db_agent_execution.id, datetime.now())   # 丢进 Celery 队列
# API 立即返回,不阻塞
📝 "秒回"到底是什么感觉 客户端 POST /agentexecutions/add几十毫秒就拿到 200 {"success":true}。此刻智能体一步都还没跑!它只是被写进 Redis 队列排队。真正的推理(可能几分钟)由后台 worker 慢慢做,客户端靠 L05 的轮询看进度。
对比:若同步执行,这个请求要挂 3~5 分钟才返回,浏览器早转圈超时了。
读法:.delay() 把运行任务推给 Celery(Day 17),API 秒回。真正的执行由后台 worker 领走(Day 05 追踪过)。PUT /update/{id}:322)用于暂停/继续——恢复时同样再 execute_agent.delay()
⚠️ 小白常误以为POST /agentexecutions/add 返回 200 = 智能体已经跑完了。其实:200 只代表"运行单已建好、已进队列"——此刻一步都没跑。跑没跑完要看 execution 的 status(轮询 Feed 才知道)。
API 层的核心职责 API 层不亲自跑智能体——它只负责"建记录、改状态、入队、返回"。把慢的执行推给 Celery,自己保持轻快响应。这是"接单/干活分离"(Day 01/04)在 API 层的落地。所有"发起/恢复运行"的接口最后都汇到 execute_agent.delay()——单一执行入口。
这就像餐厅前台接单:服务员在小票上记下你点的菜(建 AgentExecution)、把小票传进后厨的票夹(.delay() 入队)、马上回头招呼下一位顾客(秒回)——他绝不会自己进厨房炒菜,更不会让你站在收银台前等菜做完。
L05

Feed 与权限

  • /agentexecutionfeeds:GUI 轮询这里拿智能体每一步的 feed(思考/动作/结果),实现"实时展示"(Day 05)。
  • /agentexecutionpermissions:智能体配了需人工审批时,某步停在 WAITING_FOR_PERMISSION,用户在 GUI 批准/拒绝走这里。
为什么用轮询而非 WebSocket? SuperAGI 的 GUI 定期问后端"有新 feed 吗"(轮询),而非 AutoGPT/OpenHands 的 WebSocket 推送。轮询更简单(不用维护长连接),代价是有轮询间隔的延迟、和额外请求。对"看智能体思考流"这种秒级更新够用了。权限接口则实现 HITL——智能体停下等人点头(又见人工审批,五框架一致)。
还是那家餐厅:轮询 Feed 就像你隔几秒抬头看一眼取餐进度屏(自己看,而不是服务员逐条来报);权限接口则是服务员过来问"这道菜要另加 50 元,您确认吗?"——你不点头,后厨就停着不做。
L06

工具市场端点

toolkit.py/toolkits)提供整套市场交互:/marketplace/list/{page}(列市场工具)、/marketplace/details/marketplace/readme/get/install/{toolkit_name}(安装)、本地安装、更新检查。

这就是 Day 12 工具市场的 API 层——GUI 通过这些端点浏览、查看、安装工具包。resources.py/resources)则处理文件上传(POST /add/{agent_id},上传后触发后台 summarize_resource 任务,Day 14/17)。API 把 Day 12-14 的能力(工具市场、资源)暴露给前端。
L07

前端驱动链路

把 API 串成前端的完整操作链:

GUI → POST /agents/create        定义智能体(+ 自动建 Execution)
    → POST /agentexecutions/add   发起运行(execute_agent.delay 入队)
    → 轮询 GET /agentexecutionfeeds  看智能体一步步的进度
    → (需要时)POST /agentexecutionpermissions  批准/拒绝敏感动作
📝 第一人称之旅:现在你是一次"运行智能体"的请求 你从浏览器出发,身上带着 JWT 令牌和一个 agent_id
① 你敲开 POST /agentexecutions/add 的门,门口保安 check_auth 验了你的令牌;
② 服务员(controller)为你在 Postgres 里开了一张运行单(AgentExecution,status=RUNNING);
③ 他把单号写上小票,塞进 Redis 票夹(execute_agent.delay(88, now))——你的使命到此结束,带着 200 {"success":true} 回浏览器复命
④ 之后接力的是你的"兄弟请求们":每隔几秒一个 GET /agentexecutionfeeds 去看进度屏,直到看见 COMPLETED
注意:你(HTTP 请求)从头到尾没碰过 LLM——干活的是后厨(Day 17 的 Celery worker)。
读法:前端的每个功能都对应这些 API 端点。创建、运行、监控、审批——一条完整的用户操作链。结构规律:APIRouter + Pydantic 出入参 + JWT 鉴权 + DB session。这就是 GUI 和后端之间的完整接口契约。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • main.py 怎么装配 FastAPI app?鉴权/DB 怎么处理?
  • 主要控制器有哪些?/agents/create 做什么?
  • /agentexecutions/add 的关键一步(入队)?API 为什么不阻塞?
  • Feed 为什么用轮询?权限接口实现什么?
  • 前端驱动智能体的完整 API 链路?

✋ 动手

P=superagi
grep -n 'include_router' main.py | head
grep -n 'def create_agent_with_config' $P/controllers/agent.py
grep -n 'execute_agent.delay' $P/controllers/agent_execution.py
ls $P/controllers/ | head -28
明天预告 · Day 17Celery 异步执行——平台的核心!worker 怎么跑智能体循环、self-reschedule(自我重排)、Celery beat 定时调度、其它后台任务。
← Day 15 数据模型 Day 17 · Celery →