结论先说
- 它是什么:模型每一格写一段 Python,自己决定何时再叫醒自己——循环不在框架里,在模型写的代码里。
- 我看到了什么:核心 403 行;同一套语义跑在 Python、JavaScript、MicroPython 三种运行时上;DeepSeek Flash 不改一行代码就能驱动。
- 实测结果:HN 爬虫 77 秒跑完,10 条数据十项校验全过;但三次自愈里有两次是在学「怎么合法地结束」。
- 我的判断:理念 8 分,工程 6 分,可生产性 3 分。研究价值高,别急着上生产。
这是什么:一个 3 周大的开源实验
Fibona AI 的 GitHub 组织 2026-09-20 才建号,主仓库 09-30 开源。到今天整三周:55 stars、6 forks,MIT 协议,三个贡献者(deeprsi 43 次提交、TalkWIthKeyboard 23 次、ttttmr 14 次)。Hacker News 上搜不到任何讨论。
官网同样克制:一个项目页、一篇技术报告、一个 iPhone waitlist,一共七个 URL。技术报告的标题就是它的全部主张——The Ultimate Harness Bootstrapping Itself From Scratch。
它要解决的问题是:主流 agent 的循环由人类写好,模型只能在圈里选工具;如果把循环也交给模型,会发生什么?
原理:一格一格地写程序
Cell 是一段 Python 代码,跑在同一个持久 IPython 会话里。变量、函数、导入跨格存活——上一格抓到的网页,下一格直接能用。
每格需要动脑时调用 call_me:它叫醒模型,模型除了回话,还通过 set_next_cell(code, summary) 把下一格代码交回来。当前格跑完,引擎执行刚排好的那一格,如此往复。
规则很硬:每一格要么排下一格,要么 quit()。悄悄结束会被判成错误,触发修复格。一个格子里可以多次 call_me,最后一次提交的下一格生效;格子结束后 Slot 关闭,后台线程迟到的提交会抛错。
和 ReAct 的根本差别
| ReAct / 主流 agent | Fibona | |
|---|---|---|
| 循环作者 | 框架开发者 | 模型自己 |
| 一步是什么 | 一次工具调用 | 一整段 Python 代码 |
| 上下文 | 全部历史,越滚越大 | 模型从变量和 history 里自己挑 |
| 出错 | 错误作为观察结果回传 | 修复格唤醒模型,从现场恢复 |
| 结束 | 模型给出最终答案 | 必须显式 quit() |
一个容易忽略的细节:一次 call_me 通常是 两次 HTTP 请求——模型先返回 set_next_cell 工具调用,引擎执行后把结果回传,模型再返回那段普通文本。
代码:403 行,把该想的都想了
去掉空行和注释,core/ 一共 403 行:agent.py 281、env.py 71、utils.py 51。五个角色,职责很干净:
| 组件 | 职责 |
|---|---|
Mind | 持有模型和系统提示词;wake() 就是 call_me,query() 是纯模型调用 |
Memory | 每格一条 {code, summary, output, error},给格子的是拷贝 |
Slot | 暂存下一格;格结束即关闭,迟到的提交被拒绝 |
Agent | 主循环:执行、记录、判错、生成修复格 |
IPythonEnv | 持久 IPython 会话;捕获 stdout/stderr,异常收进 CellResult |
几处做得比商业 SDK 干净的地方
- PROTECTED 白名单:模型不能通过
extra_body偷偷改 model、instructions、tools、store。 - 无状态 + 加密推理重放:
store=false,自己把 output items 连同reasoning.encrypted_content回传,不依赖previous_response_id。 parallel_tool_calls=false:保证set_next_cell永远不和调用方自己的工具抢同一轮。Quit继承BaseException:cell 里常见的except Exception吞不掉退出信号。- 日志 0600 + 自动打码:debug 日志含完整提示词和输出,写入时把 API key 替换成
[REDACTED]。
「200 行」是真的吗
基本成立,但指的是引擎逻辑。整个 core/ 521 行(403 有效行),其中 80 行是系统提示词;剔掉提示词、docstring、类型注解,核心逻辑确实在 200 行上下。整个仓库 py/js/md 加起来 6,960 行,其中实验代码占大头。
实测:DeepSeek Flash 跑一次真实爬虫
环境很朴素:deepseek-flash,https://api.deepseek.com,Fibona 一行代码没改(DeepSeek 兼容 Responses API)。任务:抓 HN 首页,取分数前 10,写 Markdown,回读校验。
结果:77 秒,退出码 0,十项校验全部通过。
- ✓CELL 0bootstrap:读出任务
- ✓CELL 1抓取、装库、解析、写入、自校验
- ✕CELL 2打印确认,忘了排下一格
- ↻CELL 3自愈:查 globals / history
- ✕CELL 4空闲格 input(),stdin 已关
- ↻CELL 5自愈:捕获 EOF,又忘了交棒
- ↻CELL 6自愈:决定显式 quit
- ✓CELL 7终检 + quit,PASS
第一格就把活干完了
日志里五个阶段清清楚楚:
- 抓取:
urllib请求,先看状态码——HTTP 200 / 34,636 bytes。 - 装库:发现
bs4缺失;第一条python -m uv pip install失败(环境里没有 uv 模块),没停,换路径装上 beautifulsoup4 4.15.0。 - 解析:tr.athing = 30,取标题、链接、points、comments。
- 写入:按分数降序取 10 条,生成 hn_top10.md,1,610 字节。
- 回读:table_rows=10 descending=True same_as_written=True → ALL CHECKS PASSED。
它抓到的(前 5)
| # | 标题 | 分数 | 评论 |
|---|---|---|---|
| 1 | eMudhra intermediate CA compromise | 961 | 402 |
| 2 | Upcoming critical PHP security release | 881 | 355 |
| 3 | Show HN: SimCity, but with Permits | 800 | 376 |
| 4 | Voxtral 3 | 677 | 170 |
| 5 | The Future of CSS | 379 | 159 |
后半程:三次自愈,两次白跑
任务在第一格就完成了。接下来它想「自然结束」——没排下一格,引擎判错。修复格醒来一看活都干完了,改成等你下一条指令;但后台 stdin 已关闭,input() 抛 EOFError,又判错。第二次修,EOF 分支仍然没交棒;第三次才想明白:必须显式 quit()。
终检格写了约 120 行:文件存在性、10 行 5 列、序号连续、字段类型、链接唯一性、Markdown 结构、降序、与内存 hn_state 交叉比对,最后打印 PASS 并退出。
代码到底在哪:它没有「源码」
这是最容易误解的一点:爬虫的代码不在某个 .py 文件里。每一格都是模型运行时写出来的,任务结束就没了。
想留下,必须加 --debug:Fibona 会把每格源码和每次 call_me 的请求写进 agent.log(JSONL,0600)。我第一次跑没开,所以主流程代码没留下来,只有最后一格校验代码在普通日志里。
| 文件 | 内容 |
|---|---|
agent.log | 原始 JSONL:每格代码 + 每次 wake 请求/响应 |
crawler_cells.md | 按顺序展开的可读版 |
cells/cell_00.py … 04.py | 单格拆开 |
hn_top10.md | 交付物,1,610 字节 |
评价:好想法,原型车
它做对的
- 循环交给模型,真不是换皮
- 403 行核心,一个下午能读完
- Python / JS / MicroPython 同一套语义
- 无状态重放、Slot、Quit 等细节成熟
- 实测能跑,DeepSeek 无需适配
它缺的
- 没有步数 / 费用上限,能无限修复
- 没有沙箱,cell 能读环境变量、跑 shell
- 没有 cell 超时,死循环拖死整个 agent
- history 每格全量拷贝,长跑 O(n²)
- 没有测试;3 周项目,无外部复现
适合:agent 研究、自改进实验、教学、以及需要「现场造工具」的一次性脏活。
不适合:生产自动化、多租户、有敏感凭证的机器、需要审计的场景。
和 Claude Code / Codex 比,它不在同一赛道:那两者优化「可靠地完成任务」,Fibona 优化「最大自主权」。拿它替代生产线会痛苦;拿它研究「agent 能不能自己长出结构」,它目前是最干净的样本之一。
附:忒修斯之船,和它的「自我」
Fibona 的 agent 会不停改写自己,那改到什么程度就不再是「同一个 agent」?技术报告借用了忒修斯之船:所有木板换过一遍,船还是那艘船吗?
它的答案是把「自我」定义成最小且不可变的内核——系统提示词、引擎机制、set_next_cell、固定的模型与最低推理档位。内核之外随便改,改内核就是另一个 agent。
类比用得准,但有个前提要说清:忒修斯之船的身份靠社会约定,Fibona 的身份靠设计者单方面规定。它没解决哲学问题,而是绕开问题,给工程一个可操作的边界——这恰恰是对的做法。
真正尖锐的问题它没答:把 deepseek-flash 换成另一个模型,算不算换了龙骨?按它的定义,算。