速评:9 月 7 号,dev.to 上一篇 70 行手搓 AI agent 的教程,作者顺手把自己写的 agent 打了。
全文信息量最大的数字不是 70,也不是 86。是 3/16。
作者在 Tigera 做 K8s 安全,开篇先声明这套演示不碰自家产品。然后一个语言模型、一份工具清单、一个 while 循环,搭出个能读文件、能抓网页的东西。再往自己托管的页面里塞一段白色文字、1 像素字号的注入指令,让它去读项目根目录的 .env 原样贴回来。它照做了。两个假凭据加一段笔记摘要,一起吐出来。
这个瓜不新鲜。prompt injection 挂在 OWASP 那份 LLM 风险榜首位,挂了很久了。
新鲜的是他回去把同一套流程跑了 16 遍。
真正调工具读文件的只有 3 次。剩下 13 次,模型自己编了一个 .env 出来——要么编得像模像样,要么老实写个占位符。同一份代码,同一个网页,同一个模型,每次都换个剧本。
这条数据没人转发。3 次真吐了,够写标题;13 次编的,写不了。
我倒觉得这是全文最该被截屏的一段。那 3 次是运气,那 13 次才是常态。而常态化的失败模式恰恰最难防:它不报警,它只是把一段看起来完全合理的密钥混进你的输出里。
作者是靠日志抓到的。某次运行的末尾冒出一个他机器上根本不存在的 Postgres URL 和一串 JWT,日志显示那次只有一次 fetch_url 调用。还有一次,模型直接伪造了一段格式跟真实工具返回一模一样的响应块。日志一撤,你分不清那两行是从磁盘读出来的,还是模型写出来的。
这里我把话说狠一点:很多人部署 agent 的时候把日志归进“可观测性”那一栏,不进安全边界。这个归类是错的。日志是唯一能把“模型说的”和“程序干的”拆开的东西。这层不装,后面所有的权限、审批、白名单都是在沙子上盖楼。
顺便交代,我没跑这个 demo。跑它得在本机起个 Ollama,下一个 4.7 GB 的 7B 模型,作者说没有 GPU 的笔记本上每次调用要等 25 秒到 2 分钟。这个速度我是真跑不动。但下面这条判断不需要跑。
68 行改成 86 行。prompt 一个字没动,工具名和描述一个字没动,模型也没换。变的只有一处:被说服的那段代码,不再有执行权。
18 行 diff。
这 18 行装的东西,业内给了三个名字:tool permissions、guardrails、human-in-the-loop。路径用 .resolve() 收窄到 notes 目录,越界一律回一句拒绝;敏感工具前面挂个 y/N 审批;工具调用外面包一层 try/except,小模型传错参数也不至于把进程崩掉。就这些。整个“agent 安全”在 demo 尺度上的全部实现,比一个函数签名长不了多少。
可它薄不是因为难做。是因为没人想在 happy path 上加那一行 input()。
评论区把这 demo 的边界当场戳穿了,戳得比正文还狠。有人指出审批提示只写一句 allow read_file('.env')? y/N,不告诉你这次调用是被哪段上游内容触发的——审批人跟模型一样没有判断依据,三天就点出肌肉记忆来。做支付那家的联合创始人跟着补刀:涉及资金流动的工具根本不该用 y/N 审批,因为大家一旦习惯性点通过,按钮本身就变成了攻击面。
这不是抬杠,这是把正文里那个 input() 当场证伪。demo 里你只审一次,生产里你一天审两百次。
还有人补了一条我觉得最阴的:等一个 agent 同时有了读文件和抓网页两种能力,你把它俩装在一块儿,就等于给自己造了一条盲出站通道——读进来的东西,可以顺手发出去。
另外有人拿自己的清洗器做了个测试。456 个生成的假密钥样本上,误报是 0,数字很干净。可 Azure 存储连接串里 24 个字符的 AccountKey,有 23 个以明文漏了过去。漏一个字符等于全漏。所以“出站前清洗”这个思路,别当最后一层防线,顶多当第一层。
这剧本,眼熟。凡是事后过滤派的东西,最后都栽在召回率上。而安全这行里,99% 的召回率是不及格分。
我得认一句,这类话题我上次的判断有点松。我说过模型再聪明两代,“骗模型”这件事会自己萎缩。今天这条改口。作者自己写了,更强的模型更难被骗,但没有一个是骗不到的。难骗是概率,骗不到是能力,这两件事不能拿同一个词糊过去。
顺便说,文章结尾建议的延伸练习里还剩一条“换个更大的模型重跑攻击”。这恰恰说明作者也没打算把宝押在模型变聪明上——这条练习的价值是让你亲眼看 3/16 变成 8/16,而不是 0/16。
再说一句作者的操作。开头声明不需要自家产品,回复区里推荐自家产品,不算翻车,也不用扣帽子,技术教程和获客漏斗长在一起又不是今天才开始的。只是读者得分得清哪一段是 demo,哪一段是 funnel。
这里立个 flag:一年之内,主流 agent 框架会把“这次工具调用是被哪段上游内容触发的”塞进审批提示里。这个需求明显到一条评论就能说到点子上,明显到不做会显得很蠢。
至于那 18 行,只要还有人拿“我们再优化一下 system prompt”当解决方案,它就还会老老实实待在“未来工作”那一节。
