盲松鼠理论:fchollet 一个比喻,终结了你对 Agent 的所有幻觉
本文最后更新于 2026-05-19,文章内容可能已经过时。
盲松鼠理论:fchollet 一个比喻,终结了你对 Agent 的所有幻觉
你有没有遇到过这种情况:
让 Agent 帮你改一个函数的返回值类型,结果它把整个文件重写了一遍。测试全过了,CI 绿了,你盯着屏幕看了三分钟,愣是没看懂它在干什么——但你也不敢说它错了,因为确实跑通了。
然后你把这段代码合进主分支,两周后,你的同事在 code review 里问你:「这里为什么要这么写?」你沉默了五秒,回答:「……Agent 写的。」
这不是你的问题。Keras 作者、Google DeepMind 研究员 François Chollet(fchollet)用一个词解释了这背后的根本原因——盲松鼠。
---
第一章:「盲松鼠」到底是什么意思?
fchollet 在 X(原 Twitter)上发过一条帖子,大意是:
"Code agents in large codebases are like blind squirrels finding nuts. They succeed often enough to look impressive, but the path is random. They're not solving problems — they're pattern-matching until something passes the test."
翻译过来:代码 Agent 在大型代码库里,就像一只瞎了眼的松鼠找坚果。它成功的频率高到看起来很厉害,但路径是随机的。它不是在解决问题,而是在做模式匹配,直到某个结果通过了测试。
注意,这个比喻有两个关键词容易被误读:
第一,「盲」不是说 Agent 笨。松鼠本来就很擅长找坚果,它有嗅觉、有记忆、有行动能力——但它的眼睛是瞎的。Agent 也一样,它有强大的语言能力、有海量训练数据、有推理能力,但它对你系统的「理解」是盲的。
第二,「找到坚果」不等于「走了正确的路」。松鼠可能绕了三圈、撞了两棵树、最后歪打正着找到了。Agent 可能生成了一段能跑通测试的代码,但这段代码的逻辑路径对你的系统来说是陌生的、脆弱的、不可维护的。
fchollet 不是在说 Agent 没用,他是在说:Agent 成功的定义和你以为的成功,根本不是同一件事。
---
第二章:比喻背后的 3 个具体判断
判断①:Agent 的成功依赖任务空间的「密度」
什么叫任务空间密度?
简单说:正确答案在所有可能答案里占的比例。
写一个标准的 CRUD 接口,正确答案有几十种写法,密度很高,Agent 随便试几次都能命中。但如果你让它重构一个跨模块的事件调度系统,正确答案可能只有几种,而且每一种都依赖对整个系统状态机的深度理解,密度极低——盲撞命中的概率接近于零。
翻译成大白话就是:任务越标准化、越孤立,Agent 越容易成功;任务越定制化、越耦合,Agent 越容易翻车。
这不是 Agent 的 bug,这是它的物理极限。
判断②:Agent 缺乏真正的「程序状态心智模型」
这是 fchollet 最核心的技术判断,也是最容易被忽视的一个。
当你写代码时,你脑子里有一张隐形的地图:这个变量在哪里被修改、这个函数在什么情况下会被调用、这个状态改变会触发哪些副作用。这张地图叫做程序状态心智模型(mental model of program state)。
Agent 没有这张地图。
它有的是:在 token 空间里做模式匹配的能力。它看到你的代码,它知道「这种写法通常跟着那种写法」,它知道「这个错误信息通常对应这个修复方式」——但它不知道你的系统现在处于什么状态,也不知道它的修改会在三个模块之外触发什么连锁反应。
翻译成大白话就是:Agent 是一个极其博学的人,但他从来没有真正跑过你的程序。他给的建议,是基于他见过的所有程序,而不是基于你的这个程序。
判断③:评测基准掩盖了「路径质量」问题
这一条是对整个 AI 评测生态的批评。
SWE-bench 是目前最权威的代码 Agent 评测基准之一,它的核心指标是:Agent 能否让测试用例通过。但这个指标有一个系统性盲区——通过测试 ≠ 代码可维护。
一段代码可以:
- 通过所有测试,但引入了一个隐性的内存泄漏
- 通过所有测试,但把一个 O(n) 的算法改成了 O(n²)
- 通过所有测试,但把两个本来解耦的模块强行耦合在一起
这些问题在 benchmark 里是看不见的,因为 benchmark 只关心「结果对不对」,不关心「路径好不好」。
翻译成大白话就是:你用来评判 Agent 好坏的那把尺子,本身就量不到最重要的维度。
---
第三章:把 3 个判断翻译成「任务分配决策表」
理解了三个判断,接下来是最实用的部分:到底哪些任务该交给 Agent,哪些任务该自己写?
| 任务类型 | 推荐执行者 | 判断依据 | 风险点 | | 写单元测试 | ✅ Agent | 模式高度标准化,验收标准明确 | 测试覆盖率虚高,边界 case 缺失 | | 生成样板代码(CRUD、DTO) | ✅ Agent | 密度高,几乎没有系统耦合 | 命名风格可能与项目不一致 | | 写文档注释 | ✅ Agent | 纯语言任务,无状态依赖 | 可能描述不准确,需人工校对 | | 简单 SQL 查询生成 | ✅ Agent(schema 简单时) | 结构化任务,密度尚可 | schema 复杂时开始翻车 | | 跨模块重构 | ❌ 自己写 | 需要完整程序状态心智模型 | Agent 容易破坏隐性约束 | | 性能调优 | ❌ 自己写 | 依赖 profiling 数据和系统上下文 | Agent 可能引入更深的性能问题 | | 安全敏感逻辑(鉴权、加密) | ❌ 自己写 | 错误代价极高,无法靠测试兜底 | 看起来能跑,实际有漏洞 | | 核心业务逻辑首次实现 | ⚠️ 协作 | 可以用 Agent 起草,人工深度审查 | 不审查直接用是最大的风险 |如果你之前用 Agent 踩过坑,大概率是把第二类任务(需要心智模型的任务)交给了它。 不是你用错了工具,是你用对了工具但给错了任务。
---
想亲自验证这张表?把「Agent 擅长的任务」分别丢给 GPT-5.1、Claude Sonnet 4.6、Gemini 3.1 Pro,看看它们在「高密度任务」上的表现差异——推荐直接用 [api.884819.xyz](https://api.884819.xyz),一个 API 接入主流模型,新用户注册即送体验 token,省去多平台切换的成本,方便做横向对比。
---
第四章:用真实案例压力测试这张表
案例一:写单元测试(Agent 擅长)
任务: 给一个纯函数写单元测试,函数功能是解析 ISO 8601 日期字符串。 Prompt:给这个函数写完整的 pytest 单元测试,覆盖正常输入、边界 case 和异常输入:
def parse_iso_date(date_str: str) -> datetime:
return datetime.fromisoformat(date_str)
Agent 输出: 生成了覆盖正常日期、带时区的日期、空字符串、非法格式、None 输入的完整测试套件,逻辑清晰,命名规范。
结论: 完全符合预期。这就是高密度任务——测试的「正确写法」非常标准化,Agent 在 token 空间里有无数个相似的参考样本可以匹配。
案例二:重构遗留系统的调度逻辑(Agent 容易翻车)
任务: 把一个基于回调的任务调度器重构成 async/await 风格,调度器有 4 个依赖模块,状态通过全局单例共享。 踩坑 Prompt:把这个回调式调度器重构成 async/await 风格,保持原有功能不变:
[粘贴了 300 行代码]
问题输出: Agent 生成的代码通过了基础测试,但:
1. 把全局单例改成了局部变量,破坏了跨模块的状态共享
2. 在一个关键的错误处理路径上,把同步的异常捕获改成了异步的,导致某类错误会被静默吞掉
3. 引入了一个新的 asyncio.Lock(),但在某个代码路径上没有正确释放,埋下了死锁隐患
案例三:生成 SQL 查询(中间地带)
简单 schema(5 张表以内): Agent 表现良好,JOIN 逻辑清晰,索引使用合理。 复杂 schema(20+ 张表,有历史遗留的反范式设计): Agent 开始出现问题——它会按照「标准写法」生成查询,但忽略了某些表里专门为性能优化而设计的冗余字段,生成的 SQL 在功能上正确,但在实际数据量下会慢 10 倍以上。 结论: SQL 生成是典型的「密度随复杂度下降」的任务。schema 越复杂,正确答案的密度越低,盲撞的代价越高。---
第五章:fchollet 给的不是悲观,是校准
读到这里,我想给你一个清醒的定位:
这篇文章不是让你少用 Agent,是让你用得更准。Agent 没有死。GPT-5.1 写单元测试的速度是你的 20 倍,Claude Sonnet 4.6 生成样板代码的质量已经超过大多数初级工程师。这些能力是真实的,不是幻觉。
幻觉是:「Agent 能搞定一切,我只需要描述需求。」
破掉这个幻觉之后,你真正需要建立的能力不是「会用 Agent」,而是「知道什么时候不用 Agent」——这个判断力本身,就是新时代最核心的开发者素养。
上手前自问三句话
在把任务交给 Agent 之前,问自己这三个问题:
① 这个任务的「正确答案」有多少种?
如果超过 10 种,Agent 大概率能搞定;如果只有 2-3 种,而且每一种都依赖系统上下文,自己写。
② 这个任务需要理解系统的「当前状态」吗?
如果需要知道某个变量在哪里被修改、某个事件在什么时候被触发——Agent 没有这张地图,你有。
③ 如果 Agent 的输出「看起来对但实际上错」,我能发现吗?
如果你没有能力审查输出,就没有资格让 Agent 独立完成这个任务。
把这三句话贴在你的显示器边上。
Agent 的上限不是它的问题,是你给它的任务质量的问题。
---
当然,fchollet 的「盲松鼠」主要针对的是代码补全类 Agent——它没有工具、没有记忆、没有规划循环。但如果是有工具调用、有持久记忆、有多步规划的 Agentic 系统呢?当 Agent 有了「工具手」和「记忆脑」,盲撞的比例会下降多少?这条升级路线,现在到底走到哪一步了?
下一篇,我们来拆解这个问题。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI开发 #Agent #fchollet #代码Agent #开发者工具 #8848AI #人工智能 #提示词工程