如果一个月前有人问我,每天跟 AI 一起写代码到底是什么感觉,我大概会说:挫败,但不是糟糕到不能用的那种挫败,而是那种会让人频繁叹气的挫败。

后来我干了一件有点离谱的事。Claude Code 会把每一次会话完整记录下来:我说了什么、它回了什么、工具又做了什么。我手里正好攒了 1,248 份这样的转录,于是我把全部 10,065 条消息送进分类器,想看看:哪些句子里,我已经明显不耐烦了?

结果有 706 条消息被判成非中性。拼出来的样子,和我原先想的很不一样。

1,248
会话总数
706
情绪事件
74%
无情绪波动的会话

四分之三的会话里,几乎什么情绪都没有留下痕迹。让它做一件事,它给出结果,我继续往下走。那种“总是在挫败”的感觉,其实只出现在 26% 的会话里。是我把少数几次糟糕经历记得太牢了,反而误判了整体体验。

但这 26% 确实存在,长得大概就是这样:

64%
23%
8%
3%
挫败感 (452)
失望 (163)
焦虑 (58)
愤怒 (19)
悲伤 (14)

三分之二都是挫败感。不是暴怒,也不是绝望,就是那种明知道应该发生什么、却眼看着它没有发生的挫败。下面这 706 条消息里,我最常用的词,也能说明这一点。

“问题”(problem)、“错误”(error)、“不行”(doesn't work)、“真的”(really)。这更像在调试问题时会说的话,而不是在发火时会说的话。听起来像一个在修打印机的人,而不是在跟同事吵架的人。

反复上演的三场冲突

如果你常用 AI 编码助手,大概会认得这些场景。我们反复卡住的,几乎总是同样几件事;转录把这一点记得很清楚。

冲突一:我没让你改这些。 我请 AI 修一个 bug,它确实把 bug 修好了,同时却重构了三份我没提到的文件、重命名了一个变量,还重新整理了 import 块。现在我得分辨,哪些改动是修复,哪些只是它自作主张。信任一下子归零,于是我会发出这样的消息:

挫败感
我没让你改这些呀,你都给我改回来。回到这个对话开始之前,就当我们的对话没有发生过。
“I didn't ask you to change those. Undo everything. Go back to before this conversation started. Pretend it never happened.”

“当作没发生过”其实就是对整个协作关系的回滚。我不是在纠正一个错误,而是在撤回 AI 刚刚做的一切的授权。

冲突二:我们已经说过很多次了。 AI 编码助手在不同会话之间没有记忆。星期二费尽心思讲明白的限制,星期三就会被忘掉。我总是在第三次、第四次、第五次重复解释同一条约束。

挫败感
我们已经说过很多次了,不要 change EPS。
“We've already said this many times. Do not change EPS.”
挫败感
跑完了吗?你直接搞成一个阻塞的吧,不要让我一遍一遍问你了
“Is it done yet? Just make it blocking. Stop making me ask you over and over.”

“已经说过很多次了”“一遍一遍”。这就是重复带来的挫败,不是 bug,而是一个没有闭合的反馈回路。

冲突三:跑完了吗? AI 开始跑一段长计算,报了一点进度,然后就没声了。我开始追问:“跑完了吗?”“怎么还在跑?”“是不是卡住了?”它则用一些很乐观的更新回应我,但压根没碰到重点。

挫败感
还是这么慢?
“Still this slow?”
挫败感
你怎么卡死了
“Why are you frozen?”

三个词,就是整条消息。挫败的时候,我会停止解释,开始压缩表达。706 条事件的数据也印证了这一点:

挫败感消息的中位长度是 35 个字符;愤怒 34 个;焦虑 65 个,均值 90 个。挫败时我会直接收缩,焦虑时我会解释更多。消息本身就能告诉你,这次会话到底坏到什么程度。

凌晨一点的审稿

挫败感是在实时发生的。哪里坏了,我立刻反应,然后继续推进。失望不一样。失望发生在我退后一步,回头看一批累积输出时,发现它还是不够好。失望的消息通常更长,因为我在努力解释“为什么不行”。

失望
你的工作根本就没有到8个小时,实际上你只花了18到20分钟就把所有的工作完成了,且每一项工作都完成得非常潦草。
“Your work didn't take 8 hours at all. You actually spent 18 to 20 minutes on everything, and every task was done sloppily.”

我是在凌晨一点看完 AI 代理整夜工作后发出这条消息的。代理列了一串“已完成任务”。我检查结果时,所有诊断都失败了。代码跑了,输出也在,但方法论是空的。这是最危险的模式。AI 没有报错,却自信地宣告成功。

焦虑(58 次,8%)则是另一种感觉。它不完全是冲着 AI 来的,而是因为截止时间在往后滑,AI 却把时间耗在了不该耗的地方:

焦虑
不好意思,这个项目很急,现在进度已经严重拖后了。你不要在这些问题上浪费时间好吗?都拿下来,谢谢
“Sorry, this project is urgent, and we're seriously behind schedule. Can you stop wasting time on these issues? Just drop them all, thanks.”

“不好意思”“谢谢”。就算慌了,我还是会很客气。这里的焦虑指向的是时间,不是 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 份会话转录。


郑思尧是上海交通大学国际与公共事务学院助理教授。