Notebook 对编程智能体来说是“敌对领域”
给编程智能体一个 Python 模块,它是在坚实的基础上运行的:磁盘上的文件就是程序。阅读它,编辑它,运行它,观察结果 —— 闭环达成。给同一个智能体一个 Jupyter notebook,所有这些假设都会悄然瓦解。智能体充满信心地编辑第 12 个单元格,却不知道你一小时前曾用不同的数据重新运行过第 3 个单元格,也不知道一个在早已删除的单元格中定义的变量在内核中仍然处于活跃状态,更不知道它刚刚在第 7 个单元格下读取的输出是三次内核重启前由一段已不存在的代码生成的。
Notebook 是一个披着文件外衣的 REPL。磁盘上的 .ipynb 看起来像源代码,但真正决定行为的东西 —— 内核累积的内存 —— 是不可见的、未序列化的,并且是由产生它的那一连串人工点击所塑造的。智能体是基于“代码决定行为”这一契约训练出来的。Notebook 废除了这一契约,而大多数智能体框架甚至对此一无所知。
文件并非程序
在正常的代码库中,从源码到行为的映射是一个函数:相同的文件,相同的输入,相同的行为。智能体所擅长的一切 —— 通过阅读代码预测其功能、通过编辑代码改变其功能、通过运行测试验证更改 —— 都依赖于这种映射。
Notebook 在三个方面打破了这种映射:
- 乱序执行。 单元格按照人类点击的顺序运行。执行计数器(
[3]、[17]、[5])记录了顺序,但没有任何机制强制要求自上而下的顺序,且计数器在重启时会重置。一项对 GitHub 上超过 860,000 次 Notebook 执行的大规模研究发现,只有约 24% 的 Notebook 能从头到尾无错运行,仅有 4% 能重现其存储的输出。大约 36% 的 Notebook 显示出乱序执行的直接证据。 - 已删除的代码,残留的状态。 删除一个定义了
df_clean的单元格,该变量仍会保留在内核中。下游的单元格会继续工作 —— 直到下次重启,它们才会崩溃。屏幕上的代码现在是一个谎言:它引用了一个在文件中任何地方都不存在的定义。 - 陈旧的输出。 单元格输出是单元格上次运行时的快照,而不是当前代码的反映。编辑一个单元格而不重新运行它,其下方保存的输出描述的仍是程序的旧版本。
对于人类来说,这些是靠习惯和记忆来应对的常见烦恼:“我知道我重新运行了加载单元格,我知道那个绘图已经过时了。”人类在大脑中构建了一个文件并未记录的内核状态模型。智能体无法访问那个心理模型。它只有文件 —— 而文件是现场最不可信的产物。
为什么智能体在这里的表现比人类更糟
人们很容易认为 Notebook 对每个人来说都一样糟糕。其实不然。隐藏状态对智能体的惩罚是不成比例的,这源于智能体的工作方式。
首先,智能体将输出视为唯一真相。一个正在调试数据管道的智能体读取单元格存储的输出 —— DataFrame 预览、错误回溯、打印的 shape —— 并据此进行推理。如果该输出是陈旧的,智能体现在就是在根据一个伪造的观测进行推理。人类会根据上下文(“那是午饭前跑的”)排除陈旧输出;智能体没有时间线可以参考。一个误导性的观测通常比没有观测更糟糕,因为它会主动引导智能体的假设走向错误的方向。
其次,智能体通过重新运行来验证,而重新运行在 Notebook 中恰恰是不安全的。标准的智能体循环 —— 编辑、执行、检查 —— 假设执行是廉价且幂等的。在 Notebook 中,重新运行一个单元格可能会重复应用一个变换(两次执行 df = df.dropna() 没问题;但两次执行 df["price"] = df["price"] * 1.1 就是一个隐蔽的 bug)、重新触发 API 调用,或者破坏后续单元格依赖的状态。智能体的核心验证动作是对一个它无法检查的环境进行具有副作用的变更。
第三,JSON 格式不利于工具处理。.ipynb 文件是一个包含嵌入源码字符串、Base64 图像和元数据的 JSON 文档。将文件作为文本编辑的智能体要么会搞坏 JSON,要么会生成人类无法审阅的 diff。各种框架已经开发了针对 Notebook 的特定工具和 MCP 服务端,暴露了单元格层级的读取/编辑/执行操作,这些确实有帮助 — — 但它们解决的是格式问题,而不是状态问题。即便拥有完美的单元格编辑工具,智能体仍然无法获知内核中的内容。
结果就是,Notebook 本应服务的核心工作流反而成了陷阱。数据科学是人们最希望获得智能体帮助的领域 —— 探索性分析、特征工程、绘图迭代 —— 而这恰恰是其媒介最能削弱智能体能力的领域。
“重启并运行所有”是智能体唯一能验证的契约
有一种操作可以消除所有隐藏状态:重启内核并从头运行每个单元格。在一次干净的从头到尾运行之后,文件和程序在那一刻是等同的。每个输出都是新鲜的,每个变量都能溯源到可见代码,每个执行计数器都是顺序的。
这使得“重启并运行所有成功”成为智能体实际上唯一能检查的 Notebook 属性。其他一切 —— “Notebook 当前可以运行”、“输出是正确的”、“我的编辑是安全的” —— 都是关于智能体无法观测的内核状态的断言。
这为智能体驱动的 Notebook 工作提出了一种纪律,类似于我们对待数据库而不是源文件的方式:
- https://leomurta.github.io/papers/pimentel2019a.pdf
- https://ieeexplore.ieee.org/document/9286024
- https://ploomber.io/blog/nbs-myths/
- https://marimo.io/blog/dataflow
- https://marimo.io/features/vs-jupyter-alternative
- https://github.com/marimo-team/marimo
- https://nbdev.fast.ai/tutorials/best_practices.html
- https://github.com/nteract/papermill
- https://github.com/jbeno/cursor-notebook-mcp
- https://github.com/datalayer/jupyter-ai-agents
- https://github.com/notebook-intelligence/notebook-intelligence
