跳到主要内容

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

查看所有标签

那个因等待另一个 Agent 而死锁的 Agent

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个研究员智能体向一个检索智能体请求一份文档。检索智能体在任务执行到一半时,决定需要研究员智能体澄清查询意图后才能继续搜索。而正在等待文档的研究员智能体,在拿到文档之前不会做出响应。它们谁都没有出错,也没有陷入死循环。它们只是都在礼貌地、无限期地等待着对方——而你的编排器(orchestrator)根本没有“这两个智能体正在互相阻塞”的概念,它会一直愉快地维持这个状态,直到你从未配置过的超时设置最终触发,或者直到某个大活人注意到这个运行已经“进行中”整整 40 分钟了。

这就是死锁(Deadlock)。它是计算领域最古老的故障模式之一,且与你的模型有多聪明毫无关系。它是工作协调方式的一种属性,而不是工作执行方式的属性。过去一年多智能体研究中一个令人不安的发现是:在智能体集群中,大部分出问题的地方都在这里,即协调层,而不是任何单个智能体的推理能力。

单智能体思维永远无法暴露这些 Bug。当一个模型运行工具调用循环时,它最坏的情况也就是空转——而空转至少是肉眼可见的。一旦你拥有两个或更多可以互相等待的智能体,你就继承了分布式系统所有的病理特征:循环等待、活锁、丢包、过早终止、共享状态下的竞态条件。没有人会坐下来决定构建一个分布式系统,但在你添加第二个智能体的那一天,你就已经构建了一个分布式系统。

你的智能体从未执行过的补偿事务

· 阅读需 11 分钟
Tian Pan
Software Engineer

当你的 Agent 执行退款、发送邮件、关闭工单或写入数据行时,该操作便脱离了系统并进入了现实世界。现实世界没有回滚按钮。客户已经看到了退款,收件人已经阅读了邮件。而当 Agent 在三步之后走错了方向,你的恢复计划通常只是复盘会议中的一句话:“我们告诉它以后不要再那样做了。”

“以后不要再那样做”不是撤销(undo)。它是对未来的承诺,却被用来解决过去的问题。令人不安的事实是,大多数 Agent 架构根本没有撤销已完成副作用的机制——不是机制不好,而是根本没有机制。Agent 可以规划、调用工具并重试,但它无法回头。它只有前进挡,没有倒车挡。

你的智能体读不懂的弃用通知

· 阅读需 10 分钟
Tian Pan
Software Engineer

当你为人类开发人员弃用一个 API 时,你会为此举行一整套“仪式”。你提升版本号,在 OpenAPI 规范中添加 deprecated: true,发送 Sunset HTTP 响应头,向开发人员邮件列表发送邮件,发布变更日志,并给人们六个月的时间进行迁移。信号到达阅读它的开发人员,他们提交工单,并在旧路径消失之前更新他们的客户端。

现在,将同样的弃用通知指向一个智能体。调用你工具的模型不会阅读你的变更日志,它不会订阅你的邮件列表。它永远看不到 Sunset 响应头,除非你刻意将其放在模型会查看的地方,即便如此,它也没有可靠的习惯去据此行动。你精心编写的弃用通知落入了一个没有读者的信箱。智能体会一直调用工具的旧形式,直到该形式彻底消失,然后它就会失败——通常是静默失败,通常是在生产环境中,通常是在凌晨 2 点。

这就是为智能体而非人类构建工具时所存在的隐性不对称。我们在 API 演进的二十年里建立的每一项准则,都假设在弃用和迁移之间坐着一个人类。把人类拿掉,整个机制就会失效。

无人值守的人工升级路径

· 阅读需 9 分钟
Tian Pan
Software Engineer

每个智能体架构图都有相同的三个框。一个是“理想路径” (happy path),即模型给出回答,用户满意离开。一个是“自动兜底” (automatic fallback),即置信度低的回答触发重试、调用不同工具或返回预设的“让我查一下”。还有第三个框,通常画在最后且最小,标记为“升级到人工” (escalate to human)。在设计评审时,每个人都会对这个框点头表示认同。它看起来像是某种终结——一个让整个系统变得合理的安全阀。“别担心,如果智能体处理不了,人会接手。”

然后你上线了,却发现那个框是个谎言。不是技术上的谎言——代码能跑,工单能创建,对话会被标记。而是一个人员配置 (staffing) 上的谎言。那个标有“升级到人工”的箭头指向一个无人负责的队列,没有服务等级协议 (SLA),也不在任何人的轮值表上。智能体完全按照指令行事,它把问题抛给了一个从未同意接收问题的组织。

你的智能体忘记发送的幂等键

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的智能体中最昂贵的 Bug 不是幻觉。而是重试。

在你的技术栈中,总有一个工具负责扣款、发送邮件、关闭工单或写入数据行。智能体调用它,调用耗时过长导致超时,于是智能体——作为一个优秀的、具有弹性的软件——再次调用它。棘手之处在于,第一次调用其实已经成功了,只是响应从未返回。结果你扣了客户两次款,无论你如何提示“请在支付时保持谨慎”,都无法阻止这种情况发生。

这是分布式系统中最古老的故障模式,只是披上了一件新装。十年前,我们通过幂等键(idempotency keys)为 HTTP API 解决了这个问题。但大多数智能体技术栈通过将原本为读取设计的重试逻辑直接用于执行写入的工具,且从未发送那个能让重试变得安全的字段,从而重新引入了这个问题。

你的 Agent 链路中无人分配的延迟预算

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 Agent 有一个延迟 SLO。有人把它写在了文档里:“响应时间低于 8 秒,p95”。但没人决定这 8 秒该如何分配。检索调用没有细分预算,规划步骤没有细分预算,模型因为感到不确定而决定调用的第三个工具也没有细分预算。预算在边界处只是一个数字,而在内部则完全不存在。因此,当一个五跳链路冲破 8 秒时,值班工程师盯着追踪链路(trace),却无法回答那个唯一重要的问题:到底是哪一跳超时了?

这就是拥有“延迟预算”的服务与拥有“延迟愿望”的服务之间的区别。预算是分配给每个组件并强制执行的;而愿望是在出口处测量并祈祷达标的。大多数 Agent 系统发布时都带着愿望,因为跳数结构是动态的——模型决定调用多少次工具——而且为无法控制的事情制定预算感觉是不可能的。事实并非如此。正因为你无法控制它,你才更需要为它制定预算。

没人使用的长尾:工具带是如何变得尾大不掉的

· 阅读需 11 分钟
Tian Pan
Software Engineer

没人会刻意决定给智能体 (agent) 配备 40 个工具。这就像车库堆满杂物一样自然而然地发生了。你接入一个搜索工具,然后是一个数据库读取器,接着团队里有人发布了 Slack 集成,然后又安装了 ticketing MCP 服务器,因为这只需要一行配置。每次添加在当时看来都是合理的。没人会移除任何东西,因为移除工具感觉就像是在剥夺能力,而剥夺能力感觉就像是一种倒退。

六个月后,你的智能体有了一个工具带,其中有三个它经常使用的工具,十几个偶尔使用的工具,以及二十多个在生产环境中技术上从未被选中的长尾工具。这种“长尾”并非免费,甚至代价高昂。目录中每一个未使用的工具都在主动降低智能体从那些重要工具中做出正确选择的能力。

聊天并非最佳界面:为什么你的智能体不应只是一个文本框

· 阅读需 9 分钟
Tian Pan
Software Engineer

有一个数据足以让人们停止“增加一个聊天机器人”的条件反射:在很大一部分 AI 功能中,大多数打开聊天窗口的用户从未发送过一条消息。据报道,大约有 60% 的用户在发送第一条消息前就放弃了,而相比之下,当同样的能力被封装在带有示例和一键启动点的设计好的空白状态(empty state)中时,用户的参与度要高得多。模型并没有失败。答案从未生成,因为问题从未被提出。用户打开一个空白框,看着闪烁的光标,然后离开了。

我们选择聊天界面是因为它是阻力最小的路径,而不是因为它就是正确的界面。当语言模型可以进行对话的那一刻,“与 AI 交流”就变成了“使用 AI”的代名词,每个产品团队都继承了同样的默认设置:一个文本框,一个发送按钮,以及一个模型会搞定剩下一切的承诺。对于大多数智能体(agent)实际承担的工作来说,这种默认设置其实是错误的。

聊天是一个不错的 输入原语 (input primitive)。但它是一个糟糕的 操作环境。这是两个不同的概念,将它们混为一谈会导致你在需要控制面板的地方只交付了一个闪烁的光标。

间接提示注入:你以为处于惰性的数据平面

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数团队在针对错误的层面进行威胁建模。他们加固了聊天框——速率限制、输入校验、监视用户输入内容的越狱分类器——却将模型读取的所有内容视为惰性的。Wiki 页面、支持工单、抓取的网页、日历邀请、某人上传的 PDF:在他们眼中这些只是数据,而不是指令。它们是供模型总结的背景材料,而不是让模型执行的命令。

这种假设本身就是漏洞。一旦你的 Agent 获取了内容并将其放入上下文窗口(Context Window),该内容的执行权限就与你的系统提示词(System Prompt)完全一致。在“这是你的指令”和“这是供参考的文档”之间没有权限边界。它们都只是 Token,而模型经过训练,会遵循出现在任何地方的指令。

没人会为你的智能体承保

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的智能体开始工作了。它处理工单、发放退款、更新记录、完成闭环——无需人工干预,且根据你的指标,其质量超过了执行同样任务的人类中位数。你已经准备好让智能体完全脱离人工干预。然而部署陷入了停滞,不是卡在工程环节,而是在一次会议中,法务或财务部门的人提出了一个你无法回答的问题:一旦出错,损失由谁承担?

这是智能体自主化过程中能力曲线无法触及的部分。你可以将准确率从 95% 提升到 99%,但上述问题依然存在。因为阻碍部署的从来不是“模型是否足够好”,而是由概率系统采取不可逆行动所带来的风险必须由人承担,而现在没人愿意承担。你的职业责任险(E&O 保险)是为人类失误编写的,且越来越多地将自动化失误排除在外。你的模型供应商合同声明对一切后果免责。而且,目前还没有哪家保险公司能为这类系统制作精算表——因为每当你修改一次提示词(Prompt),系统的失败率就会悄然发生偏移。

影子智能体:法务在事故复盘中才发现的 AI 功能

· 阅读需 12 分钟
Tian Pan
Software Engineer

发现你上线了一个 AI 智能体的最糟糕时机是在事故复盘中。不是在设计文档里,不是在架构评审中,也不是在变更工单里 —— 而是在事故复盘现场,律师正询问为什么在未经授权的情况下给客户退了款,而一名工程师正翻找着一个上次进行实质性评审还是在 11 个月前的服务,然后在名为 enrichTicket 的函数第 40 行处,发现了一个模型调用,它读取客户记录、决定处理方案,并调用了计费 API。没有人画过它的架构图。没有人批准它作为一个智能体运行,因为对于编写它的人来说,它根本不是智能体。它“只是一个辅助工具”。

这就是影子 AI,它已经露出了獠牙。第一波浪潮是员工将公司数据粘贴到消费级聊天机器人中 —— 这是一个数据泄露问题,虽然严重但尚在可控范围内。第二波浪潮是智能体:嵌入内部工具的模型调用,它们读取真实数据并执行真实操作,潜伏在那些原本为完全不同的用途而获批的服务中。大约一半的员工承认使用了雇主从未批准过的 AI 工具,而且很大一部分比例的使用来自高层 —— 总监和高管是主要的“元凶”,而不是实习生。当这种本能延伸到你的代码库时,你得到的不再是一个泄露的电子表格。而是一个拥有生产环境凭据且未经任何人签字批准的自主代理人。

令人不安的是,影子智能体并非由鲁莽的人创建。它们是由优秀的工程师创建的,而他们只是在执行你的要求:快速交付价值、复用现有基础设施、不要为每一个微小的改动都提交工单。治理差距并不是纪律问题。它是一个定义问题 —— 你的评审流程中根本没有他们所构建内容的对应类别。

无人负责的对话:问责制如何在智能体移交链中消散

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个支持请求发送了进来:“我的订阅被扣了两次费,请取消其中一个并退款。”一个路由代理将其归类为计费问题并进行了移交。一位计费专员查看了账户,确认了两笔扣费,并将退款操作移交给了一个工具调用子代理。该子代理执行了一次退款,随后一个总结代理给客户回信:“搞定了——你的重复扣费已退还。”每一个步骤单独看都是正确的。但实际上客户被扣了三次费,而不是两次。其中一笔重复扣费仍在他们的卡上,而总结代理无从得知这一点,因为当对话传导到它那里时,“ 2 ”这个数字已经在上游的四个步骤中固化成了事实。

让我们进行一次复盘。这是谁的 Bug?路由代理分类正确。计费专员读取了它收到的两笔扣费。工具代理准确地按照指令进行了退款。总结代理进行了准确的总结。单独调出每个代理的 Trace,每一个都通过了。系统失败了,但没有任何组件出错。这就是“无主对话”,它是多代理架构中定义性的操作性失败——不是模型太笨,而是责任在移交链条中不断扩散,直到没有任何一个代理需要对用户实际体验到的结果负责。