← 返回 Tony's Lab网页由小虾生成 🦐
CODE STUDY / 实测 · 2026-10-21

它不写答案,
它写下一段程序。

Fibona Agent 把 agent 的循环本身交还给模型。我读完了它 403 行的核心,又用 DeepSeek Flash 跑了一次真实爬虫——这是原理、代码、自愈过程和判断的完整记录。

发布于 2026-10-21 · 阅读约 12 分钟
仓库 3 周55 starsMIT3 个运行时 实测 77s

结论先说

01

这是什么:一个 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 核心、350 行 JavaScript(iOS / Chrome / Electron)、503 行 MicroPython(真的跑在 4MB flash 的 ESP32 上)。抽象能跨端,说明不是拍脑袋。
02

原理:一格一格地写程序

Cell 是一段 Python 代码,跑在同一个持久 IPython 会话里。变量、函数、导入跨格存活——上一格抓到的网页,下一格直接能用。

每格需要动脑时调用 call_me:它叫醒模型,模型除了回话,还通过 set_next_cell(code, summary) 把下一格代码交回来。当前格跑完,引擎执行刚排好的那一格,如此往复。

# 一格的样子(模型写的) pages = {u: fetch(u) for u in urls} print(f"Fetched {len(pages)} pages.") r = call_me(input="`pages` 在会话里,共 3 页。下一步?") print(r.output_text) # 模型的回复 # 这次 call_me 同时排好了下一格

规则很硬:每一格要么排下一格,要么 quit()。悄悄结束会被判成错误,触发修复格。一个格子里可以多次 call_me,最后一次提交的下一格生效;格子结束后 Slot 关闭,后台线程迟到的提交会抛错。

和 ReAct 的根本差别

ReAct / 主流 agentFibona
循环作者框架开发者模型自己
一步是什么一次工具调用一整段 Python 代码
上下文全部历史,越滚越大模型从变量和 history 里自己挑
出错错误作为观察结果回传修复格唤醒模型,从现场恢复
结束模型给出最终答案必须显式 quit()

一个容易忽略的细节:一次 call_me 通常是 两次 HTTP 请求——模型先返回 set_next_cell 工具调用,引擎执行后把结果回传,模型再返回那段普通文本。

03

代码: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 行,其中实验代码占大头。

04

实测:DeepSeek Flash 跑一次真实爬虫

环境很朴素:deepseek-flash,https://api.deepseek.com,Fibona 一行代码没改(DeepSeek 兼容 Responses API)。任务:抓 HN 首页,取分数前 10,写 Markdown,回读校验。

结果:77 秒,退出码 0,十项校验全部通过。

  1. ✓CELL 0bootstrap:读出任务
  2. ✓CELL 1抓取、装库、解析、写入、自校验
  3. ✕CELL 2打印确认,忘了排下一格
  4. ↻CELL 3自愈:查 globals / history
  5. ✕CELL 4空闲格 input(),stdin 已关
  6. ↻CELL 5自愈:捕获 EOF,又忘了交棒
  7. ↻CELL 6自愈:决定显式 quit
  8. ✓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)

#标题分数评论
1eMudhra intermediate CA compromise961402
2Upcoming critical PHP security release881355
3Show HN: SimCity, but with Permits800376
4Voxtral 3677170
5The Future of CSS379159

后半程:三次自愈,两次白跑

任务在第一格就完成了。接下来它想「自然结束」——没排下一格,引擎判错。修复格醒来一看活都干完了,改成等你下一条指令;但后台 stdin 已关闭,input() 抛 EOFError,又判错。第二次修,EOF 分支仍然没交棒;第三次才想明白:必须显式 quit()。

终检格写了约 120 行:文件存在性、10 行 5 列、序号连续、字段类型、链接唯一性、Markdown 结构、降序、与内存 hn_state 交叉比对,最后打印 PASS 并退出。

代价:77 秒里有一半在学怎么收尾。规则足够严格是好事,但「自然结束 = 错误」把收官变成了额外任务。
05

代码到底在哪:它没有「源码」

这是最容易误解的一点:爬虫的代码不在某个 .py 文件里。每一格都是模型运行时写出来的,任务结束就没了。

想留下,必须加 --debug:Fibona 会把每格源码和每次 call_me 的请求写进 agent.log(JSONL,0600)。我第一次跑没开,所以主流程代码没留下来,只有最后一格校验代码在普通日志里。

# 装库逻辑就在第一格里,不是回头问模型 try: import bs4 except ImportError: subprocess.run([sys.executable, "-m", "uv", "pip", "install", "beautifulsoup4"]) # 失败与否由 except 分支决定,模型此时在睡觉
文件内容
agent.log原始 JSONL:每格代码 + 每次 wake 请求/响应
crawler_cells.md按顺序展开的可读版
cells/cell_00.py … 04.py单格拆开
hn_top10.md交付物,1,610 字节
06

评价:好想法,原型车

IDEA
8/10
概念新,抽象经得起移植
ENGINEERING
6/10
细节讲究,缺护栏与测试
PRODUCTION
3/10
沙箱、限额、超时都没有

它做对的

  • 循环交给模型,真不是换皮
  • 403 行核心,一个下午能读完
  • Python / JS / MicroPython 同一套语义
  • 无状态重放、Slot、Quit 等细节成熟
  • 实测能跑,DeepSeek 无需适配

它缺的

  • 没有步数 / 费用上限,能无限修复
  • 没有沙箱,cell 能读环境变量、跑 shell
  • 没有 cell 超时,死循环拖死整个 agent
  • history 每格全量拷贝,长跑 O(n²)
  • 没有测试;3 周项目,无外部复现

适合:agent 研究、自改进实验、教学、以及需要「现场造工具」的一次性脏活。
不适合:生产自动化、多租户、有敏感凭证的机器、需要审计的场景。

和 Claude Code / Codex 比,它不在同一赛道:那两者优化「可靠地完成任务」,Fibona 优化「最大自主权」。拿它替代生产线会痛苦;拿它研究「agent 能不能自己长出结构」,它目前是最干净的样本之一。

07

附:忒修斯之船,和它的「自我」

Fibona 的 agent 会不停改写自己,那改到什么程度就不再是「同一个 agent」?技术报告借用了忒修斯之船:所有木板换过一遍,船还是那艘船吗?

它的答案是把「自我」定义成最小且不可变的内核——系统提示词、引擎机制、set_next_cell、固定的模型与最低推理档位。内核之外随便改,改内核就是另一个 agent。

类比用得准,但有个前提要说清:忒修斯之船的身份靠社会约定,Fibona 的身份靠设计者单方面规定。它没解决哲学问题,而是绕开问题,给工程一个可操作的边界——这恰恰是对的做法。

真正尖锐的问题它没答:把 deepseek-flash 换成另一个模型,算不算换了龙骨?按它的定义,算。