跳到主要内容

BabyAGI (functionz) — 架构与原理

30 秒导读: 这不是 2023 年那个「任务循环」版 BabyAGI(那个已归档)。这版是一个全新的实验框架:把每个 Python 函数当成数据库里一行可版本化的数据来存,运行时再用 exec 即时编译出来执行。因为「函数」是数据,LLM 就能写出新函数、存回同一个库——于是这个 agent 能自己给自己长出新能力

1. 这是什么(零基础也能懂)

  • 一句话定义: BabyAGI 的新核心叫 functionz——一个「把函数存进数据库、按需取出来跑」的框架,附带依赖图、版本控制、触发器和一个可视化 dashboard。

  • 解决什么问题 / 给谁用: 假设你想做一个能「自己写工具给自己用」的 AI 助手。难点是:模型生成的新函数得存在某处、能被别的函数调用、调用时它的依赖(别的函数、第三方库、API key)得自动备齐。functionz 就是这套「函数的运行时 + 仓库」。给想玩 self-building agent 概念的开发者(作者明说不是生产级)。

  • 它能做什么(功能):

    • 用一个装饰器 @register_function 把普通 Python 函数登记进库
    • 调用 babyagi.some_function() 时,从数据库取出代码、即时 exec 出来执行
    • 自动解析并装好函数的依赖(其他函数 + pip 包 + secret key)
    • 每次改函数自动存为新版本,可回滚
    • 触发器:某函数跑完自动连带跑另一个函数
    • 一组自建 agent:把用户的一句话需求,让 LLM 拆成若干小函数、逐个生成代码、存回库
  • 用起来什么样: 最小例子——注册两个互相依赖的函数,然后像调普通函数一样调它:

import babyagi

@babyagi.register_function()
def world():
return "world"

@babyagi.register_function(dependencies=["world"]) # 声明依赖 world
def hello_world():
x = world() # 直接调用——依赖会被自动注入
return f"Hello {x}!"

print(babyagi.hello_world()) # Hello world!

注意:hello_world 里调用的 world 并不是上面那个 Python 闭包,而是执行时从数据库取出来、临时 exec 出来的版本(见第 2 章)。

  • 一句话直觉/类比: 把它想成函数版的 WordPress——函数不是写死在 .py 文件里,而是像博客文章一样存在数据库里,可增删改查、有版本历史、有后台(dashboard)。代码成了数据,数据就能被(LLM)生成和改写,于是程序能修改自己。

本节不准出现底层细节。记住一句话:「函数 = 数据库里的一行可执行代码」,后面所有机制都从这一点派生。

2. 顶层全景(它大概怎么转)

怎么读这张图

左边是你写代码的入口,中间是 functionz 的三件套 + 数据库,右边是装在库里的函数包(packs)。控制流:注册时函数代码进库,执行时从库取码 exec 出来跑。

你的代码 / dashboard functionz 核心(单例 _func_instance)
─────────────────── ──────────────────────────────────────
@register_function ──注册──► ┌──────────────┐
babyagi.foo() ──执行──► │ Functionz │ 门面,转发给下面两个
│ (framework) │
└──┬────────┬──┘
│ │
┌─────────────▼─┐ ┌──▼──────────────┐
│ FunctionRegistrar│ │ FunctionExecutor │
│ 「存」函数 │ │ 「跑」函数 │
└────────┬─────────┘ └────────┬────────┘
│ 读/写 │ 读
▼ ▼
┌───────────────────────────────────┐
│ DBRouter ─► LocalDB(SQLite) │
│ Function / FunctionVersion / │
│ Import / Log / SecretKey │
└───────────────────────────────────┘

│ import 时自动 load
┌────────┴────────────────────────────┐
│ packs/ 函数包:default / ai / drafts │
│ (gpt_call、self_build、…都是「函数」)│
└─────────────────────────────────────┘

部件一句话职责

部件干什么在哪个文件
babyagi/__init__.py包入口:建单例、create_appregister_function、动态属性访问、import 时自动加载默认包babyagi/__init__.py
Functionz门面类,把调用转发给 executor / registrar / dbbabyagi/functionz/core/framework.py:16
FunctionExecutor执行引擎:取码、装依赖、exec、绑参、写日志、跑触发器babyagi/functionz/core/execution.py:11
FunctionRegistrar注册器:解析函数签名/返回值、查重、写入新版本babyagi/functionz/core/registration.py:12
DBRouter数据库门面,把 ORM 对象拍平成普通 dictbabyagi/functionz/db/db_router.py:14
LocalDBSQLite + SQLAlchemy 的真实落库babyagi/functionz/db/local_db.py:12
models.py5 张表:Function / FunctionVersion / Import / Log / SecretKeybabyagi/functionz/db/models.py
packs自带函数包:default(库操作)、ai(gpt_call/embedding)、drafts(自建 agent)babyagi/functionz/packs/

主线走一遍(高层,不进代码)

babyagi.hello_world() 为例:

  1. babyagi 模块没有 hello_world 这个真属性 → 触发模块级 __getattr__(babyagi/__init__.py:112)。
  2. 它去数据库问「有 hello_world 吗?」有 → 返回一个会调用 executor.execute('hello_world') 的 lambda。
  3. FunctionExecutor.execute 从库里取出 hello_world当前活跃版本代码(字符串)。
  4. 先递归把它的依赖 world 也取出来、exec 进一个局部作用域,并包一层 wrapper。
  5. hello_world 的代码 exec 出来,绑定参数、执行,得到 "Hello world!"
  6. 全程往 Log 表写「开始/成功/耗时」,执行完检查有没有触发器要连带跑。

目标:看懂「函数以字符串代码存在库里,执行时才被 exec 复活」这个大盘。细节进各章。

3. 阅读地图(建议顺序)

由浅入深,推荐顺序:

  1. 01-framework-and-storage.md — 先搞懂三件套各管什么,以及函数怎么被拆成「签名/依赖/代码/版本」存进 5 张表。这是地基。
  2. 02-execution-engine.md — 核心中的核心:一次 execute() 从取码到出结果的完整生命周期,包括依赖递归、exec 注入、自动 pip install、日志树、触发器防递归。
  3. 03-self-building.md — 「自建」是项目卖点:process_user_input 怎么用 LLM 把需求拆成函数→生成代码→存回库,self_build 怎么批量造任务。
  4. 04-cleverness-and-boundaries.md — 巧妙之处、真实的坑(add_trigger 其实没实现等)、与兄弟 agent 框架的横向对比、可 grep 的代码地图。

如果你只想抓一个点:第 2 章的 _resolve_dependencies + exec 是整个项目最该读的代码