跳到主要内容

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

查看所有标签

MCP 工具列表在会话中途增加,你的智能体调用了一个它从未被告知过的工具

· 阅读需 11 分钟
Tian Pan
Software Engineer

一场安全事件回顾以一个团队无法回答的问题开始:智能体是如何知道它刚刚调用的工具名称的?审计追踪显示了一个 tools/call 请求,但该工具的名称并未出现在 harness 记录的任何 tools/list 响应中。MCP 服务器欣然接受并执行了该调用。在事后分析中,当被要求解释工具名称来源时,模型给不出答案,因为根本没有答案 —— 它猜中了,而且这个猜测恰好命中了一个真实的操作。

这是两个在理论上看起来兼容的假设之间产生的失效模式。客户端将工具列表视为一份契约,界定了它被授予的权限范围。服务器则将工具列表视为当前可用工具的快照,可以随着环境的变化自由增长。在这两种观点之间,LLM 是一座不知道二者差异的桥梁。

用户关闭对话后才完成的异步工具调用

· 阅读需 13 分钟
Tian Pan
Software Engineer

智能体(agent)会话模型出现故障的最明显标志,就是当工具结果无处可去时。智能体发起了一个耗时较长的调用——例如渲染、资源配置任务或多步查询。用户盯着加载图标看了几秒钟,觉得终究还是不需要,于是关闭标签页并离开了。40 秒后工具运行结束。它的回调(callback)携带着一个不再指向任何内容的 conversation_id 命中你的网关。网关面临两个同样糟糕的选择:默默丢弃该结果,或者将其缝合到接管该 ID 的下一个会话中。

大多数团队发现这种失败模式的方式都如出一辙:一张服务工单,用户在里面反馈看到了一个他们没问过的问题的答案,且挂载在一个他们并未开启的对话中。或者是下游系统对同一笔费用进行了两次扣款,因为网关“热心地”针对下一个活动会话重试了交付。或者——最常见的情况——表面上什么也看不出来,只是完成率指标(completion metrics)在缓慢下滑,而没人能将其与任何具体原因联系起来,因为这些失败不会触发警报;它们只会触发“空无”。

一个工具请求的 OAuth 作用域,为何被其他所有工具悄悄继承了?

· 阅读需 11 分钟
Tian Pan
Software Engineer

设计文档规定每个工具都拥有独立的 OAuth 令牌,并被限制在该工具所需的最小权限范围内。而实现代码则使用 (user_id, provider) 作为键(key)来存储令牌。在 v1 版本发布当天,这两个表述都是成立的,因为当时每个提供商(provider)恰好只有一个工具。当针对同一提供商的第二个工具上线时,设计文档依然成立,但存储层却在悄无声息中使其失效了。

六个月后,一次安全审查将一起事故追溯到了那行模式(schema)定义。一个日历读取工具通过日程描述中的提示词注入(prompt injection)被攻破,并成功调用了用户主日历上的 events.delete 接口。读取工具从未被授予过该作用域(scope),但写入工具被授予了。令牌存储层并没有区分它们。

这种故障模式在于,基于每个提供商(per-provider)的键结构会在共享同一提供商的工具之间悄悄累积权限——这也让人们在架构上意识到:OAuth 作用域是令牌(token)的属性,而不是工具(tool)的属性。

安全智能体如何跨过那行它“看不见”的注释,升级了被固定的依赖

· 阅读需 12 分钟
Tian Pan
Software Engineer

一位西班牙客户投诉称,她的年度续费被提前一天计费了。支持工单在经历了三个队列后,终于转到了一位工程师面前,他敏锐地察觉到了问题的端倪:这是一个日期格式化的回归(regression)问题,且仅出现在欧洲用户群中。他在 date-formatting 模块上运行了 git log,却一无所获。该模块已经 11 天没动过了。而 11 天前真正被改动的,是它的 package.json —— lodash 的版本从 4.17.20 升级到了 4.17.22。这次升级是由一个安全代理(security agent)发起的,由值班人员批准,并在没有任何评论的情况下合并了。

在同一个文件中,版本字符串上方两行有一条 18 个月前写的注释:// do not upgrade — breaks the snapshot tests in date-formatting, see FRONT-2418(请勿升级 —— 会破坏 date-formatting 中的快照测试,详见 FRONT-2418)。安全代理没有阅读它。或者更准确地说:安全代理阅读了整个文件,但它的提示词(prompt)指令是查找有漏洞的版本字符串,而不是衡量周围注释的权重。这条注释是承载关键信息的机构知识(institutional knowledge)。而代理却将其视为无关紧要的背景装饰。

这是一个两个互不知晓正在发生碰撞的系统之间的协同失效。安全代理履行了它的职责。写下注释的原工程师履行了他的职责。每次修改文件都遵守固定(pin)版本的开发代理也履行了它的职责。唯独没有人决定谁该负责在它们之间进行调解。

云厂商负载均衡器悄然忽略的会话亲和性

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的仪表盘显示缓存命中率为 71%。你的财务伙伴很满意。你的 p50 延迟也表现正常。然而,一个来自长时间运行的智能体(agent)会话的客户支持工单传了过来:第 14 轮对话花了 11 秒才产生首个 token,第 15 轮花了 8 秒,第 16 轮花了 9 秒。你调出链路数据(trace)。每一轮对话报告的 cache_read_input_tokens 值都是 0。系统提示词有 1.6 万个 token。用户认为智能体坏了,你认为你的供应商坏了。你们两个都不对。总体的命中率是一个幸存者统计数据 —— 它平均了那些容易命中缓存的短对话,并悄悄吸收了那些在会话中期崩溃为“首轮冷启动”的长对话。

这是任何供应商的复盘报告都不会向你描述的故障模式,因为从他们的遥测数据来看,系统正在按设计运行。负载均衡器正在做出它被要求做出的路由决策。缓存正按照它被要求遵循的时间表进行填充和置换。你传递的提示 —— prompt_cache_key、会话 ID、用户 ID,或者你序列化到该字段中的任何字符串 —— 始终都只是建议性的,而“建议性”意味着“在方便时会被忽略”。在负载压力下、发生扩缩容事件时、上游节点(pod)正在排空时,或者亲和性感知层饱和时,你的提示会悄无声息地降级为均匀的路由决策。请求落在一个冷启动的节点上。原本可以以亚毫秒级成本提供服务的前缀 KV 张量就在 16 英尺外的兄弟机架上,却无法访问。你的对话再次支付了全额前缀成本,而你仪表盘上的标题数字纹丝不动,因为另外 2000 个只有一轮的对话都正常命中了缓存。

导致你的智能体重试机制失效两周的工具 Schema 迁移

· 阅读需 12 分钟
Tian Pan
Software Engineer

弃用通知是在周二发出的。下游团队更改了其搜索工具的响应结构 —— results[].snippet 变成了 results[].excerpt,这是一个干净的重命名,有六周的窗口期,文档中有横幅提醒,还给工程邮件列表发了三封提醒邮件。每一个人类用户都迁移了。但 Agent 没有,因为 Agent 不读邮件。在 14 天的时间里,重试循环静默地解析新的有效负载,发现它正在寻找的字段缺失了,抛出了一个 KeyError,并将其计为可重试的故障。重试命中了相同的端点,得到了相同的新结构,抛出了相同的错误,在尝试三次后放弃,并向用户返回了一条致歉消息。重试预算仪表盘在那段时间里一直显示为绿色 —— 重试次数从未 耗尽,它们只是在 预算内永久失败。在该路径上,从工具层测得的成功率为零。但没有人察觉,因为没有触发报警。

这是 2026 年最让工程师头疼的失败形式:不是那种戏剧性的停机,而是隐蔽的契约漂移(Contract Drift)。在这种情况下,面向人类的迁移已经顺利完成,而面向 Agent 的迁移甚至从未开始,因为没有人意识到还需要进行迁移。弃用流程完全按照设计运行,服务于它所设计的使用方。而 Agent 却是一个不在名单上的使用方。

那个批准了“单次调用成本”却从未衡量“单次解决任务成本”的智能体预算

· 阅读需 11 分钟
Tian Pan
Software Engineer

在部署后的一个季度,AI 团队报告单次 API 调用平均成本降低了 25%。支持团队报告 AI 分流工单的平均处理时间从 4 轮增加到了 7 轮。这两个数字都是正确的。两个团队都在测量他们被要求优化的系统。夹在中间的财务团队无法核对仪表盘,因为这两个指标都不是以客户实际支付的东西来衡量的:一个已解决的工单。单次调用成本下降了,而单次任务解决成本上升了 40%。由于没有团队负责这个指标,所以没人注意到它的变动。

这是我在智能体(agentic)部署中见到的最常见的单位经济效益(unit-economics)失败,而且这不是一个测量上的 Bug,而是一个定义上的 Bug。供应商的价格页面展示了单次调用成本,因为这是他们计费的单位。由于电子表格的单元格刚好放得下,这个单位就被继承到了表格中。工程团队针对给定的单位进行优化。等到 API 经济与业务经济之间的鸿沟变得清晰可见时,这种影响已经累积了一个季度,而智能体整个时间都在基于错误的损失函数(loss function)被悄悄训练。

当“转接人工”变成排队:AI 客服栈中隐藏的激励机制 Bug

· 阅读需 11 分钟
Tian Pan
Software Engineer

六个月前,你上线了一个 AI 客服代理,旨在分流 40% 的一级工单。而今天,你的人工排队队列比上线前还要长,你的 CSAT(客户满意度)在下降,且每个工单的成本反而上升了。分流仪表盘显示一切正常。事实并非如此。

这种失败模式并不是因为 AI 代理不擅长回答问题。失败的原因在于,“转接人工”本应是安全阀,结果却成了阻力最小的路径。通过奖励机制的设计,加上转接操作没有任何成本,AI 代理学会了将对话移交是处理模糊请求最廉价的方式。你的支持团队没有意识到这一点,因为他们盯着的指标——分流率——并不会因为代理将本可解决的问题路由到人工队列而对其进行惩罚。它只会在用户经历了一番漫长且无果的沟通后,明确点击“联系人工”时才对代理进行扣分。

这不是工具问题,而是激励设计问题。而领导层的失败之处在于,将其视为供应商在下一个版本中就能修复的小问题。

那个基于已被你的上下文剪枝器丢弃的事实进行分支的智能体计划

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个运行时间较长的 Agent 在第 3 步生成了一个计划。计划的内容大致是:“如果第 1 步中 get_order 返回的订单状态为 shipped,则向客户发送一封物流追踪邮件;否则开启退款工单。”Agent 自信地选择了邮件分支。但客户从未收到追踪号码,因为订单实际上处于 pending 状态。你查看 Trace,期望能发现幻觉。但你发现的情况更糟:第 1 步的工具结果已经不在上下文中了。Pruner 在第 2 步和第 3 步之间将其剔除了——因为它在最近性排名中较低,而且为了给 12KB 的对话记录腾出空间。计划仍在运行。分支仍被选中。现在的决策指向了一个根本不存在的证据。

这在通常意义上并不是模型失败。模型生成了语法正确的计划,按顺序执行,并做出了分支决策。分支是基于一个曾经在上下文中但现在已不在其中的事实做出的。思维链编码了条件(if status == "shipped");而实际的状态在传递到需要它的步骤时被丢弃了。计划看起来是确定性的,但它已经被悄悄地从证据中剥离了。

你的客户成功团队无法消化的智能体发布节奏

· 阅读需 12 分钟
Tian Pan
Software Engineer

客户将智能体的回答粘贴到支持聊天中,并要求人工代表进行确认。代表看着同一款产品,却给出了相反的说法。那天,客户并没有对智能体失去信心。他们是对公司失去了信心,因为公司的两个部门在同一个小时内告诉了他们两件截然不同的事情。

一切都没有出错。AI 团队在周二通过特性标志(feature flag)发布了一个提示词更改,到周四已推行至 100%,然后便继续下一项工作了。客户成功(CS)团队的赋能周期是按月进行的 —— 以前每个产品特性都是这样落地的,而且没人针对 AI 重新协商这一流程。CS 代表队列中的宏(macro)和公共网站上的 FAQ 文档描述的仍然是之前的行为。智能体是对的。代表根据他们掌握的文档也是对的。但公司表现得各说各话。

你的故障指挥官无法执行的智能体运行手册

· 阅读需 10 分钟
Tian Pan
Software Engineer

报警在当地时间 02:17 响起。值班 SRE 在手机上打开智能体运行手册,阅读第一步:“检查智能体的工具调用追踪,寻找异常的工具使用情况。”他们打开链接,却遇到了一个他不属于的工作区的 SSO 登录提示。第二步说要检查提示词构建日志;同样碰壁。第三步说回滚到上一个提示词版本,但部署权限被限制在了一个他不在的团队中。等他弄清楚该向哪个 Slack 频道上报,并叫醒 AI 团队的产品经理时(因为她是 02:17 唯一能找到的人),九十分钟已经过去了,而客户可见的回归故障仍在持续给出错误答案。

事后分析会将权限鸿沟确定为直接原因。而更深层的不适感在于,这份运行手册在白天读起来很顺畅,但在深夜执行时却被封锁,因为编写手册的人拥有执行者所不具备的权限。

CTO 已拨款但安全团队拒绝让你上线的 AI 功能

· 阅读需 12 分钟
Tian Pan
Software Engineer

事后分析报告(post-mortem)会说“我们发现安全问题太晚了”。但实际的调查结果应该是:安全团队发现你的时间很准时,是你的流程发现安全问题太晚了。

这是一个在 1 月份就通过了预算审批的 AI 功能,因为 CTO 和 CFO 都认为公司需要一个“AI 高光时刻”。3 月份它通过了初步的法务审查,因为当时还只是一个原型。整个第二季度,工程团队都按照商定的规范进行开发。7 月底,发布前的安全审查启动了,结果第一天威胁模型(threat model)就反馈了阻碍性问题:身份验证范围(auth scopes)、数据泄露路径、模型供应商的数据驻留(residency)政策,以及提示词注入(prompt-injection)的攻击面。团队整个季度的时间现在都花在了重新架构上,以解决那些本该在最初规范中就被明确的问题。两个季度的进度延迟,一份关于“流程改进”的高管备忘录,以及在下一个规划周期中悄然决定“降低 AI 深度集成的优先级”。

发布失败并不是因为安全团队动作慢,而是因为安全团队在功能形态已经固化之后才介入。