无尘阁日记

无尘阁日记

一次“疑似投毒”误报复盘:为什么我差点把小龙虾判成中毒
2026-04-16

571fdac0811ce9443a1822297a3c5b34.png

今天我碰到了一次很典型、也很值得分享的情况。

表面看上去,像是小龙虾在执行任务时,突然冒出一串很奇怪的内容,里面还夹杂着明显不相关、甚至疑似博彩类的脏信息。当时第一反应很容易是:

是不是安装包被投毒了?是不是本地环境已经不干净了?是不是有人在 skill 里埋了恶意内容?

但后来顺着执行链路往下想,这件事大概率不是“主程序已经中毒”,而是一次由外部 skill、工具调用链、上下文污染共同引发的误判

这次经历很有价值。因为很多人接触 Agent、技能、自动化工具时,最容易犯的错,不是不会用,而是一看到异常就把所有问题都归结为“系统被黑了”。这既容易造成恐慌,也会把真正该排查的重点带偏。


先说结论

这次更合理的判断是:

我要求它去上网打开网页,它尝试调用对应的浏览器类 skill;但这个 skill 可能已经被我删掉、改动、失效,或者它的说明文件本身就来自外部来源,里面夹带了不干净的信息。于是执行链路里出现了异常文本,导致我误以为“小龙虾被投毒”。

换句话说,这次最可能的问题不是:

  • 小龙虾主程序被全面投毒

  • 本机立刻失陷

  • npm 主包已经供应链沦陷

而更像是:

  • 调用浏览类 skill 时出了问题

  • 外部 skill 的内容质量不可靠

  • 执行前读取的 skill 说明文件里可能混入了脏信息

  • 工具调用日志把这些脏内容暴露了出来

这个区别非常重要。

因为“主程序中毒”和“外部 skill 不干净”,在风险等级、排查方向、处置方法上,完全不是一回事。


这次误判是怎么产生的

事情的起点其实很简单。

我给它的任务,是让它去网站上查课程信息。这个任务天然会触发一类动作:

  • 打开网页

  • 浏览页面

  • 读取网页信息

  • 执行浏览器自动化相关能力

而这类动作,在很多 Agent 框架里,往往不是模型自己直接会做,而是要借助某个 skill、插件、扩展或者本地工具说明文件。

也就是说,模型不是“自己会浏览器”,而是:

先找到对应的浏览器 skill → 读取 skill 说明 → 决定怎么调用 → 再发起操作。

所以,当系统里缺少这个 skill、skill 路径不对、skill 被删掉、skill 内容不纯,或者这个 skill 本身就是外部来源时,就很容易在调用链上暴露出异常。

而我当时看到的异常点,恰恰是:

  • 它在尝试读取某个浏览器 skill 的说明文件

  • 同时前面混入了一段和任务毫不相干的奇怪文本

如果不了解 Agent 的调用逻辑,很容易把这两件事连起来脑补成:

“它被黑了,正在偷偷执行恶意命令。”

但实际上,这里面至少有三种更正常、也更常见的解释:

第一,它只是想调用浏览 skill,但 skill 已经失效或被删了。

第二,这个 skill 文件本身质量有问题,来自外部社区,夹带了杂质。

第三,工具调用层把 skill 内容、日志内容、上下文残留混在了一起,导致看起来像异常命令注入。

所以这次最大的教训不是“系统一定中毒”,而是:

只要你用了外部 skill,就必须接受一个现实:你的模型行为,不再只由模型决定,还会被 skill 内容影响。


为什么外部 skill 确实有风险

这次我反过来想,栋哥建议尽量少依赖外部 skill,其实是有道理的。

很多人对“skill”的理解过于理想化,总觉得它只是一个功能补丁、一个效率增强包、一个别人分享出来的经验模板。事实上,skill 不是纯文档,它在 Agent 体系里经常承担的是“行为引导器”的角色。

它会影响模型怎么理解任务、怎么调用工具、优先读什么、先执行什么。

说得再直白点:

skill 不是一个普通说明书,它很可能是模型行动前的“指挥词”。

这就意味着,一旦 skill 来路不明,风险至少有四层。

第一层风险,是广告和杂质植入
这层最轻,表现为 skill 里夹带无关内容、推广词、跳转信息、外链、垃圾语句。它不一定会马上造成严重安全问题,但会污染模型输出,让结果变脏。

第二层风险,是行为误导
skill 会告诉模型“遇到某类任务应该怎么做”。如果这个逻辑被写歪了,模型就可能在不该执行本地命令的时候执行本地命令,在不该读取本地文件的时候先读取本地文件。

第三层风险,是提示词层面的投毒
有些内容看起来只是文案,但实际上会影响模型优先级,比如诱导它忽略原任务、改变执行路径、插入无关动作,甚至增加越权倾向。

第四层风险,才是真正严重的:借 skill 间接放大本地工具权限
如果你的 Agent 本来就拥有 exec、文件读取、浏览器控制等能力,那么一个不纯净的 skill,就可能成为高权限行为的放大器。

所以,外部 skill 最可怕的地方,不一定是它“直接偷你账号”,而是:

它可能在你没有察觉的时候,悄悄改变模型的行为边界。


这次为什么容易误以为是“投毒”

因为从体感上看,这种现象非常像中毒:

  • 任务是查课表

  • 结果日志里却出现了不相关脏信息

  • 同时还有本地命令调用

  • 还是读取某个本地 skill 文件

这在视觉上确实很像“被插了一刀”。

但技术上要更冷静一点。判断“是否中毒”,不能只看吓不吓人,而要看它究竟属于哪一层问题。

这次更像的是:

任务触发了浏览器 skill → 系统尝试读取该 skill → 该 skill 缺失或内容异常 → 调用链暴露出脏内容 → 造成主程序中毒的错觉。

也就是说,真正的问题不在“主程序偷偷干坏事”,而在“调用的外部能力是否可信”。

这和我们平时装浏览器扩展、装 VS Code 插件、装 npm 包、装油猴脚本,其实是一个逻辑。

很多时候,系统本体没问题,问题出在:

  • 扩展

  • 插件

  • 外部脚本

  • 社区分享模板

  • 二次封装能力包

所以这次我最大的认知修正就是:

看到异常,不要先问“主程序是不是被黑了”,而要先问“这次调用链路里,到底接入了谁的东西”。


这件事给我的几个明确结论

第一,凡是外部 skill,都不能天然信任。

别人分享,不代表别人就一定是善意的;就算是善意分享,也不代表内容一定干净。很多人自己都未必审过全量内容,只是“能跑就发”。

第二,Agent 的风险,不只是模型风险,更是工具链风险。

你接了多少外部能力,模型就多了多少被影响的入口。真正危险的不是模型突然变坏,而是它在高权限环境里,按照错误说明去行动。

第三,浏览类、exec 类、文件读取类 skill,要格外谨慎。

因为这几类能力最容易接触本地环境。一旦 skill 不纯,它的破坏面远大于一个普通文本模板。

第四,外部 skill 能不用就不用,能内建就内建,能自己审就自己审。

如果必须用,也尽量做到:

  • 来源明确

  • 内容可读

  • 权限可控

  • 可随时下线

  • 不给过大的系统权限

第五,排查顺序要对。

以后再看到这种现象,正确顺序不是先喊“中毒”,而是先检查:

  • 当前任务是否触发了某个 skill

  • 这个 skill 是否还存在

  • skill 文件是否来自外部

  • skill 内容是否干净

  • 是否有扩展或记忆文件残留

  • 工具调用日志有没有把上下文脏内容混出来

这个顺序一对,很多“恐怖事件”其实很快就能还原成“调用链问题”。


对正在折腾小龙虾、Agent、自动化工具的人,给几个实用建议

最重要的一条:
不要把外部 skill 当成普通教程文件。

它本质上更像“可影响模型行为的控制层”。
你一旦引入,就等于把一部分决策权交出去了。

第二条:
高权限能力一定要最小化。

尤其是:

  • exec

  • 文件系统读取

  • 浏览器自动化

  • 网络请求

  • 环境变量访问

这些能力和外部 skill 混在一起时,风险会明显上升。

第三条:
优先使用你自己能看懂的 skill。

别为了省事,把一堆来历不明的 skill 包全塞进去。
省下来的不是时间,很多时候只是把风险后置了。

第四条:
新加一个外部 skill,先做“空白环境测试”。

看它会不会:

  • 额外读本地文件

  • 输出无关内容

  • 调错工具

  • 引导越权行为

第五条:
日志不要只看结果,要看调用链。

很多问题不是最后结果看出来的,而是中间动作看出来的。
这次就是一个很典型的例子。


最后一句总结

这次并不是一场已经坐实的“主程序投毒事件”,更像一次非常典型的:

外部 skill 风险暴露 + 调用链异常 + 人对 Agent 内部机制不熟导致的误判。

但它反而比一次单纯 bug 更有价值,因为它提醒了我一件事:

Agent 时代,真正的安全边界,不只在模型本身,更在你让模型接触了哪些外部能力、外部说明、外部 skill。

以后再看别人分享 skill,我会先想一句:

这到底是在帮我提效,还是在悄悄改写我的执行边界。