跳到主要内容

第 4 章:巧妙之处、边界与代码地图

收尾章:先讲值得带走的设计精华,再诚实列出真实的坑(包括一个没实现的函数),最后给横向对比和可 grep 的代码地图。

4.1 巧妙之处(可借鉴的技术)

(1) 「函数即数据」+ 版本化:让程序能改自己

把函数体抽成字符串存库(registration.py:24)、用 is_active 位做版本切换(local_db.py:98),是整个项目的支点。因为代码变成了可增删改查的数据,LLM 生成的新代码才能无缝成为系统的一部分——这是 self-building 能成立的根本前提。

(2) 模块级 __getattr__ 门面糖

babyagi.anything() / func.anything() 自动去库里找同名函数执行(__init__.py:112framework.py:26)。用户感觉在调普通 Python 函数,实则每次都从数据库取码 exec。用语言机制把「数据库查询」伪装成「属性访问」,极大降低了使用心智负担。

(3) 运行即装依赖:生成的函数能立刻跑

依赖(第三方库)在执行时缺了就当场 pip install(execution.py:15),依赖函数递归 exec 进同一作用域(execution.py:37)。这让 LLM 刚生成、声明了 imports=["requests"] 的新函数无需任何手动安装步骤就能首次运行。

(4) 调用劫持 + 防环:统一的依赖装配与日志

依赖函数被包成 wrapper 回调 execute()(execution.py:50),使整棵调用树都享有依赖装配和日志;visited(依赖环)和 executed_functions(触发器递归)两道防线(execution.py:37:221)防住了自引用结构的死循环。

(5) 触发器实现「自我维护」闭环

ai_description_generator 声明 triggers=["function_added_or_updated"](ai_functions.py:32):每当有函数被加/改,自动用 LLM 补描述。新生成的函数会被系统自动「整理归档」,这是 self-building 系统保持可检索的关键。

4.2 边界与局限(诚实)

★ 真实的坑:add_trigger 根本没实现

add_trigger_wrapper(default_functions.py:111)→ func.add_trigger(framework.py:108)→ db.add_trigger(db_router.py:289)→ 最终调 self.db.add_trigger(...),但 LocalDB 里压根没有 add_trigger 方法(grep local_db.py 命中 0 次)。所以运行时调用 add_trigger_wrapper 会抛 AttributeError

实际可用的触发器只能通过注册时的 triggers=[...] 字段声明(存进 FunctionVersion.triggers JSON,由 get_triggers_for_function 读取,db_router.py:293)。这是文档/API 与实现脱节的典型 draft 缺陷。

exec 无沙箱:任意代码执行

执行引擎对函数代码直接 exec(code, local_scope)(execution.py:122),且会自动 pip install 任意包名(execution.py:19)。库里的代码(尤其 LLM 生成的)以完整进程权限运行,没有任何隔离。配合「LLM 写代码存库」,这是明显的安全面——作者也明说非生产用途

「第一个函数即入口」的强假设

process_user_input 默认 function_breakdown[0] 是入口(code_writing_functions.py:528)。LLM 拆解顺序一旦不把主函数放第一个,就会调错函数。

draft pack 的无限重试

check_existing_functions / break_down_task 等用 while True 解析 LLM 输出(code_writing_functions.py:69 等),LLM 持续返回坏 JSON 会卡死。只有 self_build.pygenerate_queries 用了有上限重试。

输出参数靠静态猜测

parse_function_parameters 只扫第一个 return、按 AST 节点类型猜类型(registration.py:64),复杂返回一律 Any,且只看第一个 return 语句——参数元数据不可全信。

单进程单库,无并发设计

全局一个 _func_instance + 一个 SQLite 文件(funztionz.db),scoped_session(local_db.py:16)。没有面向多 worker/高并发的设计,定位是单机实验。

4.3 横向对比(同 shelf 兄弟项目)

维度BabyAGI (functionz)经典 ReAct/工具型 agent多 agent 编排框架
核心抽象函数即数据库行,运行时 exec工具是固定注册的 Python 回调agent + 消息/角色
能否自造能力:LLM 写新函数存回库一般不能(工具集预定义)一般不能
能力持久化持久(进 SQLite,跨会话留存)进程内,重启即失多为进程内
版本/回滚内建(FunctionVersion + is_active)
安全隔离(裸 exec + 自动 pip)取决于工具实现取决于实现
成熟度实验 / draft多为成熟库多为成熟库

一句话定位: 兄弟项目大多在「用固定工具集把任务做好」,BabyAGI 赌的是另一条路——让 agent 持久地、可版本化地往自己身上加工具。代价是牺牲了安全隔离和工程成熟度。

注:本表对「兄弟项目」的描述是该类框架的一般取舍,具体子库以各自 doc 为准。

4.4 代码地图(导航索引)

按符号名可 grep 定位,行号 as-of fa8930eb:

主题文件路径符号名
包入口 / 单例 / 动态属性babyagi/__init__.py_func_instancecreate_appregister_function__getattr__
门面类 / 接好三件套babyagi/functionz/core/framework.pyFunctionzFunctionz.__init__Functionz.__getattr__
执行引擎主流程babyagi/functionz/core/execution.pyFunctionExecutor.execute
依赖递归装配babyagi/functionz/core/execution.py_resolve_dependencies_create_function_wrapper
自动 pip 安装babyagi/functionz/core/execution.py_install_external_dependency
触发器执行 + 防递归babyagi/functionz/core/execution.py_execute_triggered_functions_prepare_trigger_arguments
注册:抽代码 + AST 解析babyagi/functionz/core/registration.pyregister_functionparse_function_parameters
注册查重babyagi/functionz/core/registration.pyfunction_has_no_changes
ORM 5 张表babyagi/functionz/db/models.pyFunctionFunctionVersionImportLogSecretKey
版本化落库babyagi/functionz/db/local_db.pyLocalDB.add_or_update_function
ORM 拍平成 dictbabyagi/functionz/db/db_router.pyDBRouter.get_functionget_all_functions
触发器读取(注意 add_trigger 缺失)babyagi/functionz/db/db_router.pyget_triggers_for_functionadd_trigger(调用了不存在的 LocalDB.add_trigger)
密钥加密babyagi/functionz/db/models.pySecretKey.valueget_or_create_key
库操作函数包babyagi/functionz/packs/default/default_functions.pyadd_new_functionexecute_function_wrapperfunction_added_or_updated
LLM 调用 / 向量检索babyagi/functionz/packs/default/ai_functions.pygpt_callfind_similar_functionai_description_generator
函数调用式 chatbabyagi/functionz/packs/default/function_calling_chat.pychat_with_functions
自建主流程babyagi/functionz/packs/drafts/code_writing_functions.pyprocess_user_inputbreak_down_taskcreate_functiongenerate_function_code
批量自建babyagi/functionz/packs/drafts/self_build.pyself_buildgenerate_queries

4.5 一句话收束

BabyAGI(functionz)把一个大胆的想法做成了能跑的最小原型:把函数当数据存、运行时 exec 复活、让 LLM 写新函数存回同一个库,于是 agent 能持久地、可版本化地给自己加能力。它在「自我扩展」这条轴上走得很前,但用裸 exec、无沙箱、draft 级容错换来这份简洁——正如作者所言,这是用来启发讨论的实验,不是生产系统