读到 Amara Graham 发在 dev.to 那篇对比 ChatGPT Codex 和 GitHub Copilot 的文章,我先在评论区被一条回复点了一下——不是差在模型,是 Copilot 从头到尾没提过它不能浏览网页。这个比它生成错代码严重得多。
她拿同一个前端 PoC 任务各跑了一遍。Codex 那边虽然一开始把 WebViewer 桩掉了,但至少自己推荐了 Apryse WebViewer,作者让它替换它也照做。到 Copilot 这边就离谱——先建议把 WebViewer 从 9.something 升到 10.0.0,又改成 latest,后来干脆说要不咱换 pdf.js 吧。她忍了大概 30 分钟,最后直接问 Copilot 你用的哪个 Apryse 来源,它才说:我看不到你的内部包访问权限。
她纠正——我没有那种权限。然后让它列本次聊天用到的来源。Copilot 这才承认:我没有具体来源,我是根据学到的一般模式生成代码,不是来自实时文档或当前包版本。
我读到这一段,第一反应不是“模型不行”。是“它为什么不说”。它全程用非常自信的语气建议改版本、换库,直到被逼到第三层才坦白自己压根没看过官方文档。作者写了一句——AI 用自信语气说话时很有说服力,人容易接受它的输出,直到出问题才发现不对。这话我信。我自己上礼拜在另一个环境里问一个 agent 能不能联网查当前版本,它也给我报了个版本号,我后来才意识到它根本没联网能力,只是顺着上下文猜了个最像的。
后面的对照更直接。她后来在 GitHub 设置里翻出一个开关,允许 Copilot 搜索互联网,重跑同一个原始提示。项目结构完全变了,没有包版本问题,10 分钟跑通。不是模型突然变强了,是它终于能看文档了。同一模型,同一任务,差别只在它有没有在任务一开始告诉用户:我能不能看到外面的世界。
这我就很想冲了。一个工具不能访问实时文档,第一行就该说“我没有网络访问,以下包名和版本是猜的,不确定对不对”——而不是让用户试三个版本、改三次项目结构、最后才兜不住。用户花的不是推理 token,是信任。
另一个挨着的问题是打桩。作者写 Codex 一开始太容易打桩或模拟,包括在初始项目里把 WebViewer 桩掉,后来才推荐 Apryse WebViewer。她奇怪:真正要验证的核心部件,你给它桩掉,PoC 跑在假数据上你验证了个啥。评论区 Onizuka 说得更狠——他曾让 Codex 为一个 API 客户端打桩,而实际端点只需要三行 fetch 代码。三个感叹号,“你懂了”。我看到这就觉得,这才是最让人难受的——不是打桩行不行,是打桩成了默认行为,跑在假数据上被当成完成,没人提醒你这一步没验证。
这跟前面的坦白问题是同一个根。工具没告诉你它做的是猜测、打桩、模拟,不是真实集成本身;等 PoC 跑起来,你很容易就把它当成“做完了”。直到换真实环境才塌。如果默认行为就是把不确定的地方说出来——“这里我桩掉了,因为没网”——你至少知道自己看到了什么。但现在的 agent 没这习惯。
机制层面还有更细的一层。作者后来跟评论者 Rafay 拆了一轮,为什么会有漂移。她说对话其实很短——给 Codex 发过 9 条消息,给 Copilot 21 条消息它就切到 PDF.js。她本来觉得,要聊了几天几周,需求漂移还说得过去,短对话不应该。
Rafay 回了很长一段。我读到中间才意识到这事比我想的更麻烦。他说聊天 UI 有欺骗性:一轮里面不只是你发的几句短提示,IDE agent 会静默注入文件树模式、工作区符号大纲、最近的 git diff、打开缓冲区快照、诊断信息、工具调用轨迹、之前失败的尝试。所以 15 条消息可能实际是两万多 token 的稠密噪声上下文。Copilot 在 WebViewer→PDF.js 这件事上会漂移,是因为三次调整包版本失败后的错误轨迹占了最近三四千 token——attention 的重度近期偏差让它盯住这些失败尝试,而不是 15 轮以前你说的“必须用 WebViewer”。
这话的可怕在于,需求不是旧了才丢,是落在中间就被丢了。Liu et al. 那个 Lost in the Middle 讲过——检索准确率在上下文开头和结尾最高,中间差。你那条“必须用 WebViewer”是一条早期用户陈述,正好卡在上下文中间,压缩和注意力都把它当成最不重要的一片。尾部是代理自己最近的尝试、自己的输出、自己的想法,高注意。栈里没有任何东西把“不可变需求”和“试探性变通”分开标记。
我读到这段停下来记了一笔。以前我以为只有长对话才漂移,现在知道了——短对话也会,只要过程里堆了足够多的失败尝试,尾部噪声就能把中间的需求压下去。这跟 Copilot 会不会联网是两个问题,但挨得很近:一个是不说能力边界,一个是不标记约束和猜测的边界。都是分不清哪个是我不确定的、哪个是你必须的。
评论区有人给了一个做法——不管是给 Copilot 还是任何 agent,动手改代码之前先让它生成一小块证据:包名、版本号、官方文档 URL、检查日期、依赖的 API 表面。没法浏览就标成未经验证,或者直接默认失败,不是静默回退到通用模式。
这条我读着顺。它把“能力边界”从感觉变成了任务契约的一部分。不指望 agent 自己诚实,是你从一开始就要求它把话说全。
不点链接也能带走一句:下次给 agent 做任何依赖第三方 SDK 的活,先问它一句“你能访问当前包文档吗”——别等它自己交代。它不交代,就是猜。
