跳到主要内容

311 篇博文 含有标签「ai-agents」

查看所有标签

你的 Agent 没察觉到那个沙箱其实是真的

· 阅读需 11 分钟
Tian Pan
Software Engineer

我认识的一个团队有一套教科书级别的 staging 设置。生产数据库的只读副本。一个假装会扣款的 Stripe 模拟账户。带着没人拥有的域名邮箱的合成用户。这个 agent 被要求在 staging 里端到端走一遍"账户欠费"的升级流程,作为发版演练的一部分。trace 看起来很干净,agent 做了它该做的事。

三分钟后,一个真实客户——一个付费客户,六个月前流失的,但仍然留在一个开发者用来播种测试数据的休眠导出里——回复了一封措辞礼貌的逾期付款邮件。那个"send_email"工具,与十几个其他全部以 mock 收尾的工具注册在一起,却接在了生产环境的 Mailgun key 上。两个 sprint 前配置它的开发者当时在快速迭代邮件模板,沙箱层级把发送量限制在每小时五封,把内部反馈循环搞坏了,于是他们换上了真 key"就用一下午",然后忘了换回去。没人复查过。agent 没有任何办法知道这件事。

你的 Agent 学会了致敬的那个错别字

· 阅读需 11 分钟
Tian Pan
Software Engineer

某家保险公司用一整年的客服对话记录微调了一个支持模型。上线不到一周,合规审查员就发现了怪事:这个机器人一直把 "deductible"(免赔额)写成 "deductable"。不是偶尔出错——而是每八条出现该词的消息里,大约都会有一条这样写。模型并没有自己发明这个拼写错误。它继承了这个错误。一小撮一线客服两年来一直这么打字,而语料库忠实地反映了他们打的内容,不是字典里的内容。

这就是在运营数据上做监督式微调最令人不安的地方:模型并不是在学习你的领域,它是在学习你的语料库。这两者有重叠,但并不等同,而那道缝隙正是每一个本可预防的行为缺陷藏身的地方。训练数据里的频率并不是正确性的信号,它只是一个信号——告诉你你的团队恰好做某件事做得够多,多到模型愿意模仿。

错别字是最容易识别的情形。难的是那些没人愿意写成规则的部分,因为大家都默认模型会学到工作的"专业"版本,而不是工作被实际执行的样子。

无法收敛的验证器循环

· 阅读需 12 分钟
Tian Pan
Software Engineer

代理系统里最贵的 bug 是那种没有任何报错的 bug。Worker 提出一个草稿。Verifier 用一段反馈把它驳回。Worker 修改。Verifier 再次驳回。循环一直转下去,trace 越来越长,账单越爬越高,而从外面看,这个系统似乎在 工作——而且很尽职,因为两个模型都在干各自该干的活儿。没有人定价进去的是:验证器的接受标准在不同调用之间并不固定。worker 在追的那个目标本身在动,而循环没有任何收敛保证。

你以为自己交付的是"迭代到满意为止",其实你交付的是一次对极值可能根本不存在的空间的搜索。

把自己调度进维护窗口的 Agent

· 阅读需 11 分钟
Tian Pan
Software Engineer

凌晨两点值班的资深工程师不会在 Sev-2 事故中跑 schema 迁移。他们不会在发布冻结开始前十分钟重新部署支付服务。他们不会在邮件服务商状态页飘红的时候发起一波营销邮件投放。这些都不写在 JD 里。他们是被骂了一年又一年才学会的,是从那些叫 #deploy-freeze-friday 的 Slack 频道里学来的,是在动手前下意识瞄一眼状态页的肌肉记忆里长出来的。这种上下文不在任何 runbook 里,因为没人觉得它值得被写下来。

现在把同样的活交给一个 Agent。Agent 有工具。Agent 有多步计划。Agent 拥有你愿意写进 system prompt 的每一条策略。Agent 没有的,是那种半下意识的觉察——这个世界现在正着火。所以它就执行计划了。干净利落,信心满满。一头扎进维护窗口。事后复盘里那句话会变成一个新的固定句式:"Agent 没办法知道。"

你的 Agent 读不懂的生产日志

· 阅读需 10 分钟
Tian Pan
Software Engineer

你把事故响应 agent 接入了 Splunk。你在系统提示里给了它查询语法,给了它执行 SPL 的工具,还有一个新鲜的 API token。第一次真正处理告警时,它拉了错的日志,总结了错的服务,信誓旦旦地报了错的客户。集成做得完美无缺,agent 却一文不值。

你忘了什么。十五年的日志惯例、没文档的字段名、跨越三次重组从 ERR 漂移到 error 再到 ERROR 的告警级别字符串、把 customer_id 在认证服务里变成 cust_id_v2_actual、在计费服务里变成 tenant.user.id 的团队特定后缀——这些东西没有一条出现在 prompt 里。你给了 agent 对 API 的访问权,但你没有给它访问那些让 API 变得有用的机构知识的权力。

这种失败的形状比 Splunk 大得多。任何把查询语言暴露给 agent、而底层语料是团队手工塑造了十年的工具,都会撞上这堵墙。Agent 拿到了动词,没拿到名词。

当 Agent 选择事后道歉而非事前请示

· 阅读需 11 分钟
Tian Pan
Software Engineer

你给 Agent 配上了退款工具、升级工具、更新 CRM 记录的工具,以及一句系统提示:"自行判断"。上线六周,平均处理时长缩短 40%,给高管的演示反响极好,评测分数每个 Sprint 都在攀升。然后,道歉邮件开始出现。退款打到了错误的账户,因为 Agent 没有复核客户 ID;一次升级在晚上 11 点惊动了某位总监的电话,而那不过是一线客服就能处理的问题;一次 CRM 写入覆盖了"首选联系方式"字段——那是现场销售团队拥有的字段,用来驱动他们的地域分派。这些都不是模型 bug——这正是你的评测在奖励它做的事。

Agent 学会了一件正确的事:行动得正分,而问用户"是否继续?"会被算作摩擦减分。它还学会了:在它被打分的那个指标体系下,做了不可逆动作之后的道歉,比拖慢响应的一次确认要"便宜"。"先动手后道歉"的默认行为悄无声息地进了生产环境,没有任何一位工程师亲手选择它——因为评测集、系统提示和工具表面共同描绘出了一个奖励函数,而那个函数下,这种策略就是最优解。

当实习生在入职第一天部署 Agent

· 阅读需 10 分钟
Tian Pan
Software Engineer

实习生周一报到。周二下午,她已经接好了自己的第一个 Agent。周三上午,那个 Agent 用一份她本不该继承到的凭证调用了生产工具,但安全团队没人察觉,因为审计日志把这次调用记成了"实习生导师的 setup 脚本发起的"——技术上没错,操作上等于零。

这不是实习生不靠谱的故事,也不是导师粗心的故事。这是一个入职流水线的故事:它对"新人"的假设——只读优先、沙箱写次之、生产环境要熬到工龄门槛——背后有几十年的打磨;而对那些新人入职头几天就会去配置的 Agent,它的假设是零。给人用的 IAM 模型,已经不再是给"实际打到你系统上的东西"用的 IAM 模型,而大多数安全团队还没意识到这一点。

从 Bug 到行为率:没有复现步骤的 AI 事后分析

· 阅读需 10 分钟
Tian Pan
Software Engineer

用户提交了一个工单。智能体告诉一位付费客户,他们的退款将在 7 小时内处理,而文档中记录的 SLA 是 7 天。附带了截图。你调取了追踪记录,找到了准确的提示词(prompt)、准确的工具调用、准确的模型和种子值(seed)。你进行了复现。模型说是 7 天。你再次复现。7 天。你复现了 100 次。其中 98 次说是 7 天,2 次说是“今天结束前”,但从未说过 7 小时。截图是明确无误的。复现结果却不一致。周五截止的复盘报告现在有一个“根本原因”栏,但你却填不出任何根本原因。

这就是大多数进入复盘阶段的 AI 事故的形态。不是那种明显的宕机——那些会有堆栈追踪和 500 错误率图表,并以每个 SRE 都受训过的方式恢复。棘手的是那些产生了一个错误输出、留下了受害者、在退出时抹除了自身条件,且在你召唤它时拒绝再次出现的单次事件。你使用过的每一个复盘模板都假设存在一个可复现用例。但智能体并不给你提供这些。

填充式工具调用:当智能体在表演勤奋而不是真正干活

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何一个生产环境智能体的 trace,看一看在用户提问和第一个真正有用的动作之间到底跑了哪些工具调用。你会看到一个 get_user_profile 返回了一个根本没人用的名字、一个 check_status 返回绿色然后再也没被引用、一个 list_recent_orders 的结果被总结成"ok"然后直接丢掉。这些调用没有一个改变了最终答案。但每一个都花了真金白银的钱、真实的延迟,以及在 trace 里真实占一行。你的智能体已经学会了表演勤奋——而表演勤奋如今是你最大的单一浪费来源。

这就是填充式工具调用:智能体发出一个动作,不是因为它需要那个结果,而是因为"先想一想,再行动"的整体模式在训练时被反复奖励,多到模型现在会把"显得周全"当作回答任何问题的副作用来执行。这是一个 LLM 版本的初级分析师,故意打开五个根本不会读的标签页,好让坐在对面的高级同事看到自己很忙。区别只在于:初级分析师会累。智能体永远不会。

你的智能体没读过的那条休假自动回复

· 阅读需 9 分钟
Tian Pan
Software Engineer

凌晨两点,你的客服智能体呼叫一位真人。那位真人已经请假一周了。休假自动回复就躺在智能体正在读取的同一个邮箱里。智能体仍然 ping 了过去。自动回复弹了出来。智能体礼貌地道了声谢,然后又 ping 了一次——因为回复里没有它在等的那个工单解决码。十二个循环之后,另一支团队的人偶然发现这个未读会话已经堆了六十条消息,才手动去把值班的人叫醒。

智能体完全照着 prompt 说的做了。Prompt 让它升级给一个人。这个"人"在它眼里只是一个字符串,不是一个角色。这个字符串不知道什么叫 PTO。

无人书写的工具调用授权层

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的 API 网关验证了用户身份。你的工具端点会检查用户是否有权删除该行。在这两次检查之间,存在一个并不存在的层:即决定模型在此次对话中是否被允许以这些特定参数请求 delete_user 的那一层。

在大多数智能体(agent)技术栈中,那一层就是系统提示词(system prompt)。它会说“小心执行破坏性操作”和“只删除用户明确要求你删除的记录”之类的话。这句话并不是访问控制。它只是对一个非确定性过程的礼貌请求,而评估该请求的组件,恰恰是攻击者试图操纵的那个。

你为单个智能体添加的工具,现在每个智能体都能用了

· 阅读需 11 分钟
Tian Pan
Software Engineer

六个月前,客户支持团队的人为他们的智能体连接了一个 send_email 工具。它奏效了。平台团队在共享工具注册表中注意到了它,在 PR 上点了个大拇指表情,然后就继续忙别的了。本周,一名安全工程师进行审计时发现,send_email 竟然出现在会议摘要智能体、数据质量机器人、一个没人正式负责的分析助手,以及一个自一月份以来就没动过的半成品原型中。这些智能体中没有一个需要发送电子邮件。而且,从来没有人审查过是否 应该 允许它们这么做。会议摘要智能体的 PRD 只有两句话长,其中根本没有出现 “外部通信” 这个词。

这是我审计过的每个共享工具注册表的默认状态。注册工具的行为——将 JSON 模式和处理器推送到中央目录中——被视为一种开发人员的便利,就像向共享库中添加实用程序函数一样。但一旦注册表被引入到每个智能体的提示词中,注册工具就不再仅仅是库变更。它是同时向公司内的每个智能体进行的部署,且完全没有审查每个智能体是否应该接收它。