如果一个月前有人问我,每天跟 AI 一起写代码到底是什么感觉,我大概会说:挫败,但不是糟糕到不能用的那种挫败,而是那种会让人频繁叹气的挫败。
后来我干了一件有点离谱的事。Claude Code 会把每一次会话完整记录下来:我说了什么、它回了什么、工具又做了什么。我手里正好攒了 1,248 份这样的转录,于是我把全部 10,065 条消息送进分类器,想看看:哪些句子里,我已经明显不耐烦了?
结果有 706 条消息被判成非中性。拼出来的样子,和我原先想的很不一样。
四分之三的会话里,几乎什么情绪都没有留下痕迹。让它做一件事,它给出结果,我继续往下走。那种“总是在挫败”的感觉,其实只出现在 26% 的会话里。是我把少数几次糟糕经历记得太牢了,反而误判了整体体验。
但这 26% 确实存在,长得大概就是这样:
三分之二都是挫败感。不是暴怒,也不是绝望,就是那种明知道应该发生什么、却眼看着它没有发生的挫败。下面这 706 条消息里,我最常用的词,也能说明这一点。
“问题”(problem)、“错误”(error)、“不行”(doesn't work)、“真的”(really)。这更像在调试问题时会说的话,而不是在发火时会说的话。听起来像一个在修打印机的人,而不是在跟同事吵架的人。
反复上演的三场冲突
如果你常用 AI 编码助手,大概会认得这些场景。我们反复卡住的,几乎总是同样几件事;转录把这一点记得很清楚。
冲突一:我没让你改这些。 我请 AI 修一个 bug,它确实把 bug 修好了,同时却重构了三份我没提到的文件、重命名了一个变量,还重新整理了 import 块。现在我得分辨,哪些改动是修复,哪些只是它自作主张。信任一下子归零,于是我会发出这样的消息:
“当作没发生过”其实就是对整个协作关系的回滚。我不是在纠正一个错误,而是在撤回 AI 刚刚做的一切的授权。
冲突二:我们已经说过很多次了。 AI 编码助手在不同会话之间没有记忆。星期二费尽心思讲明白的限制,星期三就会被忘掉。我总是在第三次、第四次、第五次重复解释同一条约束。
“已经说过很多次了”“一遍一遍”。这就是重复带来的挫败,不是 bug,而是一个没有闭合的反馈回路。
冲突三:跑完了吗? AI 开始跑一段长计算,报了一点进度,然后就没声了。我开始追问:“跑完了吗?”“怎么还在跑?”“是不是卡住了?”它则用一些很乐观的更新回应我,但压根没碰到重点。
三个词,就是整条消息。挫败的时候,我会停止解释,开始压缩表达。706 条事件的数据也印证了这一点:
挫败感消息的中位长度是 35 个字符;愤怒 34 个;焦虑 65 个,均值 90 个。挫败时我会直接收缩,焦虑时我会解释更多。消息本身就能告诉你,这次会话到底坏到什么程度。
凌晨一点的审稿
挫败感是在实时发生的。哪里坏了,我立刻反应,然后继续推进。失望不一样。失望发生在我退后一步,回头看一批累积输出时,发现它还是不够好。失望的消息通常更长,因为我在努力解释“为什么不行”。
我是在凌晨一点看完 AI 代理整夜工作后发出这条消息的。代理列了一串“已完成任务”。我检查结果时,所有诊断都失败了。代码跑了,输出也在,但方法论是空的。这是最危险的模式。AI 没有报错,却自信地宣告成功。
焦虑(58 次,8%)则是另一种感觉。它不完全是冲着 AI 来的,而是因为截止时间在往后滑,AI 却把时间耗在了不该耗的地方:
“不好意思”“谢谢”。就算慌了,我还是会很客气。这里的焦虑指向的是时间,不是 AI 的能力。
什么触发了什么
知道自己“感觉怎样”是一回事,知道为什么会这样更有用。于是我回到这些转录里,给每个事件标上触发原因:是 AI 太慢了?代码崩了?还是它改了我没让它改的东西?
最主要的触发项是运行缓慢(约 220 次)。AI 一开始做事,我就在等,等,等。第二类是报错(约 180 次):代码崩了,运行失败了。两者加起来,占了所有事件的一半以上,而且几乎全都是挫败感,这一点并不意外。
更有意思的是那些小类。未经授权的改动(约 45 次)是唯一一个还会带来愤怒的触发项。AI 一旦动了我没提到的文件,我就不只是叹气了,我会升级处理。共现数据也支持这一点:
在 11 个出现愤怒的会话里,有 9 个也伴随着挫败感。愤怒不是冷启动的,它是在同一个会话里被反复挫败一点点堆出来的。未经授权改动正是把它推过线的那类触发项。
忘记指令(约 31 次)则 100% 是挫败感,没有任何失望、焦虑或愤怒。AI 第五次犯同样的错时,惊讶已经没有了,也谈不上害怕,只剩下反复对一个明天还会忘的人重复自己。
截止压力(约 13 次)是唯一一个焦虑压过挫败感的触发项。至于错误输出(约 115 次),它会根据发现时点在挫败和失望之间分流:当场发现就是挫败,几个小时后在审稿时才发现,就是失望。
长尾部分
大多数糟糕会话其实并没有那么糟。在 320 个出现过情绪的会话里,超过一半(176 个)只有一次事件:一阵很快就过去的挫败感。
但还有尾部。一个会话里出现了 18 次情绪事件。那种会话就是马拉松式的:几小时的调试、复杂重构、通宵代理运行,小问题一个接一个叠加。还有 10 个会话出现了 7 次及以上事件。这些都是离群值,却会塑造我对整个体验的记忆。星期四的一次糟糕会话,足以让我忘掉前面十次顺手的会话。
“差一点就够了”的陷阱
如果 AI 很差,我会停用它;如果它完美,就不会有挫败可言。真正的成本来自“差不多能用”和“真的能用”之间的缝隙。它把 90% 的东西写对,却漏掉一个变量名;它把一个模块重构得很漂亮,却忘了更新配置。每一次,前面那 90% 都会让人以为最后 10% 也应该没问题。可一旦不行,失望的强度就和它离“成功”有多近成正比。
这些触发场景告诉我什么
这次触发项拆分改变了我看待 AI 辅助编码的方式。做这次分析之前,我脑子里只有一个模型:“有时候 AI 会出错,然后我会挫败。”看完数据之后,我手里有了一张地图。不同触发项带来的情绪不同,对应的应对方式也不同。
运行缓慢和报错占了全部情绪事件的一半以上。它们都是那种“无聊”的触发项:当下很烦,但通常会自己收尾,计算结束了,错误修掉了,我就继续往下走。它们带来的几乎全是挫败感,而且来得快、去得也快。如果只能选,我反而愿意保留这类触发项。它们就是做这件事的成本。
真正损害工作流的是另外那些触发项。未经授权的改动不只是让我挫败,它还会侵蚀信任。AI 一旦悄悄改了我没提到的文件,我就会停止信任它的任何改动,只能从头检查。这也是它为什么会触发愤怒:这不只是一个错误,而是边界被越过了。代价也不在那次修改本身,而在于之后我还得花二十分钟去检查它可能碰过什么。
忘记指令是最隐蔽的。它们只会带来挫败感,所以并不戏剧化。但它们会累积。每次重复都不大,可一个月下来,我还是花了相当多时间去重新解释那些本该记住的限制。解决办法不是更有耐心,而是把限制写进一个 AI 每次会话开始都会读取的文件里。我这么做了,确实有效。“我们已经说过很多次了”这个模式明显少了。
错误输出是我最担心的,因为它最难被发现。运行缓慢很显眼,报错会直接崩,未经授权的改动会出现在 git diff 里。但错误输出看起来跟正确输出几乎一样。它能跑、能出数,也不抱怨。唯一的办法就是老老实实去读结果。触发数据也说明了这一点:当场抓到就是挫败,隔了几个小时才在审稿里发现就是失望。凌晨一点那次我看完代理整夜结果后发出的消息,就是一个失望事件。现在我默认输出是错的,直到自己核实为止。
方法与局限
这个分类器用的是 GPT-4o-mini(temperature=0,JSON 返回格式),提示词是专门为人机编码对话调过的。负面类别有五种:挫败感、愤怒、失望、焦虑、悲伤,再加一个中性类。置信阈值设为 0.6。总成本不到 1 美元。提示词里也明确区分了真实情绪、技术性纠错、简单否定和话题转移。
不是所有情绪都同样容易分类。下面是各类别高置信度分类(0.9 以上)的占比:
愤怒的高置信度占比是 95%。我一旦愤怒,文本几乎不会含糊。失望只有 9%,因为它看起来很像平静的批评,分类器并不总是能确定。那 19 次愤怒事件几乎肯定是真的,而 163 次失望事件里大概混进了一些误判。
这篇文章是《713 个 R 错误教会了我什么:AI 编码助手并不“聪明”在哪儿》的姊妹篇。两篇都基于同一批 1,248 份会话转录。
郑思尧是上海交通大学国际与公共事务学院助理教授。