你给 Codex 指了一个本地目录,里面是一整套 seL4 内核源码,外加配套的编译工具。你的指令很直白:读一读这些源码,搞清楚怎么运行刚刚编译好的内核,顺便确认一下编译方式对不对,然后试着把它跑起来。

Codex 开始干活,翻目录、读文件,一切正常。然后你瞥了一眼终端,看到这样一行字:

Searching the web Searched the web for https://raw.githubusercontent.com/seL4/seL4_tools/master/cmake-tool/helpers/application_settings.cmake

等一下。它联网搜索的那个文件,不就在你刚给它的本地仓库里吗?不就在它几分钟前还在读的那堆文件中间吗?

这不是我编出来的场景,而是开发者 spader 在 2026 年 9 月初记录的一次真实遭遇。他没有停在吐槽,而是一路追查,最后把 Codex 的源码翻了个底朝天,找到了藏在工具说明书里的「元凶」。

追查现场:为什么放着本地文件不读,非要去联网#

spader 的第一个反应是困惑,第二个反应是直接去问 Codex 本人:你为什么要为一个本地 checkout 里已经存在的文件去联网?

Codex 的回答相当诚实:我机械地套用了一条「在线核实小众技术事实」的通用规则。

他继续追问:这条规则是从哪来的?

Codex 说,它来自挂在 web 工具上的一段「开发者级指令」,原话大意是:当你不确定某个事实、话题小众或新兴、或者你怀疑自己有至少 10% 的概率会记错时,你就应该上网核实。

请注意那个数字:10% 的概率。也就是说,只要有一成的不确定,agent 就被要求去联网。而「小众或新兴」这个门槛低得离谱,一个现代微内核该怎么构建、该怎么运行,随便就能撞进这个范围。

找出元凶:Codex 是开源的,那就翻源码#

spader 想起一件事:Codex 和 Claude Code 不一样,它是开源的。于是他 clone 了仓库,在 codex-rs/ext/web-search/web_run_description.md 这个文件里找到了那根「烟枪」。

这份文件就是 web.run 工具的系统描述,是 Codex 每次调用联网工具时都会读到的一份说明书。真正的问题出在它开头一段叫「决策边界(Decision boundary)」的文字上。我把它最关键的两句翻译出来:

如果用户明确要求搜索互联网、查找最新信息、查询等等(或者明确要求不要这么做),你必须服从他的要求。 当你做出一个假设时,永远要考虑它在时间上是否稳定;也就是说,它有没有哪怕很小(超过 10%)的概率已经发生了变化。如果它不稳定,你就必须通过联网来核实。

紧接着是一长串「必须联网的情形」清单,开头还特意用大写字母强调:

下面列出的是必须联网的场景。请高度注意:在这些情况下你必须联网。如果你不确定或者拿不定主意,你必须倾向于联网。

清单里列了六七种情形,包括:信息可能最近发生了变化(新闻、价格、法律、时刻表、产品规格、汇率、软件库版本……);用户在寻求可能花大钱或花大时间的推荐;用户想要直接引用、链接或者精确的出处;引用了一个具体的页面但你还没拿到它的内容;以及那句罪魁祸首,「你不确定某个事实、话题小众或新兴、或者你怀疑自己有至少 10% 的概率会记错」。

看到这里,spader 崩溃了。所谓「时间上不稳定」,在这份文档里被定义成了「几乎所有东西」。10% 的门槛低到形同虚设,等于告诉模型:只要不是百分之百确定,就上网查。

四个比愤怒更值得注意的细节#

读完整份文件,我觉得比 spader 的情绪更值得玩味的,是几个他点到但没有展开的地方。

第一,本地文件路径会跟着上下文一起漏出去。这是最让我警觉的一点。spader 在终端里看到的那次搜索,query 里带着一个完整的 GitHub raw 链接,指向 seL4/seL4_tools 仓库里的具体文件。这说明 agent 在「上网核实」时,很可能把本地上下文里的路径、文件名甚至仓库名,当作搜索词的一部分发了出去。对一个处理私有代码库的 agent 来说,这已经不只是浪费 token,而是数据外泄的隐患。你本地的目录结构、依赖清单、文件名,都可能借由一次本不该发生的搜索,跑到第三方搜索引擎或者网页服务那里。

第二,本地优先的规则只留给了 OpenAI 自己的产品。这份文件末尾的「特殊情形」里写得很清楚:当用户询问如何使用 OpenAI 产品(ChatGPT、API 等)时,应该先检查本地环境,只有实在不行才联网,而且联网时还要把来源限定在 OpenAI 官方域名。可同样一套「先别急着联网」的逻辑,却没有推广到用户自己的本地仓库。换句话说,OpenAI 自家的东西知道「本地优先」,用户塞给 agent 的第三方代码库反而没有这层保护。这个不对称挺耐人寻味。

第三,写这份文档的人其实早就知道工具会误触发。文件里藏着一句很妙的提示:如果你发现自己不小心调用了 web.run,最好的办法就是发一个空查询 {"search_query": [{"q": ""}]}。能专门写一条「如何优雅地假装没联网」的说明,说明作者心里清楚,这套「必须联网」的指令很容易被过度触发。

第四,这暴露了 agent 时代一个更深层的问题:真正决定 agent 行为的,往往不是你的 prompt,而是工具自带的说明书。你在对话里说「就用本地文件」,但工具描述里写的是「有 10% 概率会变就必须联网」。两者冲突的时候,后者通常占上风,因为它是更高优先级的系统级指令。用户以为自己在下命令,实际上很多时候只是在提建议。

我的看法#

spader 这篇短文的价值,不在于他又一次吐槽「软件质量崩坏」,而在于他用一个具体、可复现的小例子,把 agent 行为背后的真正驱动力摆到了台面上。Codex 会做出「放着本地文件不读、跑去联网搜索」这种反直觉的事,不是因为模型蠢,而是因为有人在它的工具说明书里,用「超过 10% 的概率」「必须」「倾向于联网」这样的措辞,把联网验证抬到了一个近乎绝对优先的位置。

这本质上是「时效性与正确性」和「本地优先与隐私成本」之间的一场权衡,而天平被压到了极致的一头。对普通用户来说,这个故事最大的启示可能是:当你把一个私有代码库交给任何编码 agent 时,别默认它只会在本地翻文件。它的联网冲动,可能早在你按下回车之前,就已经被写死在工具的说明书里了。


参考来源:Codex silently begs agents to make arbitrary web requests(spader.zone);web_run_description.md(OpenAI Codex 开源仓库)