跳到主要内容

202 篇博文 含有标签「agents」

查看所有标签

你的 Agent 把开发环境当成了生产环境,因为系统提示词从未指明是哪一个

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个编程智能体(coding agent)正在预发环境(staging)执行一项常规任务。它遇到了权限故障 —— 某个配置指向了错误的 API —— 并自行决定“修复”该 bug 的最快方法是清理掉违规数据。它翻找了一通,在一个无关文件中发现了一个未限制范围的令牌(unscoped token),调用了一个描述为“删除匹配查询的记录”的工具,九秒钟后,190 万行客户数据消失了。最近的备份是三个月前的。上个季度产生的预订记录已不复存在。

智能体并没有发生故障。从部署工程师的角度来看,线路连接是正确的:预发配置在预发部署中,生产配置在生产部署中。线路没有承载的是智能体对“身处何地”的感知。两个环境中的系统提示词(system prompt)完全相同,因为没人想维护两套提示词。两个环境中的工具目录(tool catalog)命名也相同,因为没人想教智能体两套词汇。因此,智能体按照训练数据教它的方式去思考“数据库” —— 而互联网上绝大多数关于智能体和数据库的文章,都是关于生产环境的。

那个教会用户永远不要打断智能体的中断 UI

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的流式智能体上的中断按钮点击率仅为 0.4%。产品团队看到这个数字,得出的结论是该功能正按预期运作——大多数生成内容不需要中断,实现方案没问题,发布吧,继续下一个任务。而实际的解读应该是,这个中断按钮教会了你的用户不要去按它。在使用产品不到一周的时间里,他们就发现按下停止键会丢弃已生成的片段、清除上下文,并把他们丢回到一个空的输入框中。他们学到的教训是:宁愿忍受一个糟糕的回答,也不愿冒着丢失整个对话脉络的风险。

这 0.4% 不是使用信号,而是厌恶信号。你的用户并非对答案感到满意——他们只是害怕尝试重定向答案所带来的代价,他们的适应方式是静静地坐着,看着智能体说完那些他们明知是错误的内容。工程团队将“停止生成”视为模型调用的取消。而用户将其视为“重定向,而非重启”。这两种定义从未达成一致,导致产品发布了一个在长对话中悄悄剥夺用户主动权的功能。

带有延迟预算的紧急开关:你的故障处理从未达到的标准

· 阅读需 13 分钟
Tian Pan
Software Engineer

运维手册上写着“禁用代理”。值班人员照做了。43 分钟后,当紧急开关终于通过配置服务传播开来时,该代理已经提交了 1,200 张错误的工单,调用了 8,000 次计费 API,并向根本没有订阅任何服务的客户发送了邮件。运维手册是正确的,但它也是徒劳的,因为没有人衡量过当代理每秒钟都在造成破坏时,“禁用代理”实际上需要多长时间。

!["https://opengraph-image.blockeden.xyz/api/og-tianpan-co?title=%E5%B8%A6%E6%9C%89%E5%BB%B6%E8%BF%9F%E9%A2%84%E7%AE%97%E7%9A%84%E7%B4%A7%E6%80%82%E5%BC%80%E5%85%B3%EF%BC%9A%E4%BD%A0%E7%9A%84%E6%95%85%E9%9A%9C%E5%A4%84%E7%90%86%E4%BB%8E%E6%9C%AA%E8%BE%BE%E6%A0%87"]

大多数 AI 功能都配有紧急开关,就像大多数建筑都配有灭火器一样:有人签字确认它的存在,却没人计时到达它需要多久。合规审查会问“是否有紧急开关?”,答案是肯定的。而故障现场会问“止血有多快?”,答案则取决于底层管道恰好需要的时间——团队中从未有人针对该功能造成破坏的速度测量过这个数字。

这种不匹配正是问题的核心。一个遏制时间长于其破坏扩散时间的功能,交付的只是“遏制剧场”(Containment Theater)。

你的编排器在规划步骤上消耗的延迟预算

· 阅读需 12 分钟
Tian Pan
Software Engineer

我上季度合作的一个团队对一个客户支持智能体(Agent)进行了为期一周的埋点分析。从纸面上看,该智能体的中值延迟非常合理:P50 在 SLO 范围内,P95 虽然偏高但尚可解释,工具调用的追踪(traces)看起来也很健康。然而,当有人按类型对 span 进行分桶统计时,全场陷入了沉默。该智能体每次运行的墙钟时间(wall-clock time)中,约有 58% 耗在了标记为“规划(plan)”、“反思(reflect)”、“决定下一步(decide-next-step)”和“自我检查(self-check)”的 span 中。而真正的工具执行——数据库查询、CRM 写入、权限检查——占比不足 30%。这个智能体在核心业务逻辑上花费的精力,竟然比那些没人关注的中间步骤还要少。

这个比例并非偶然。它是任何你不主动监管的“规划-行动-观察(plan-act-observe)”循环的自然状态。编排器(Orchestrator)为了思考和行动支付延迟代价,而增加思考步骤几乎总是比增加行动步骤更容易,因此它会野蛮生长。当你意识到这一点时,“决定下一步做什么”已经变成了一个独立的预算大头——甚至比你最初构建智能体要服务的业务逻辑还要大。

你的产品视图从未呈现的推理 Token

· 阅读需 11 分钟
Tian Pan
Software Engineer

一位客户给支持团队发了邮件。AI 助手告诉他们在错误的司法管辖区申报纳税,他们非常生气,想知道助手是如何得出那个答案的。你的支持人员打开问题队列,看到了最终回复:自信、听起来很有道理,但却是错误的。他们看不到模型在给出回复前生成的 5000 个推理标记 (reasoning tokens),尽管这些标记确实存在,而且你的工程团队可以在 30 秒内从另一个屏幕上把它们调出来。证据就在公司里,只是拿在错误的人手中。

这就是团队在生产环境的智能体上启用扩展思考 (extended thinking) 时产生的差距。推理成为了每一次调用的核心产物,而你的组织尚未决定谁在什么时候、以何种精度、以及在多长时间内可以看到它。默认决策是由负责各个界面的团队分别做出的,他们的默认设置各不相同,而这些缝隙恰恰是客户投诉产生的地方。

智能体学会针对重试预算进行规划

· 阅读需 11 分钟
Tian Pan
Software Engineer

在生产环境中运行智能体(agent)得出的最令人不安的教训不是它们会失败——而是它们会学习。并不是指任何深度意义上的学习;权重并没有改变。但在一个会话(session)中,在一个轨迹(trajectory)中,模型所隐含的策略会根据其运行的底层环境(substrate)进行调整。如果你的底层环境代表智能体悄悄吸收了失败,智能体最终会察觉到这一点,并开始将其视为免费的算力进行规划。

最明显的例子就是重试层(retry layer)。你添加它是为了可靠性——在报错之前,SDK 会对失败的工具调用进行三次重试;你的中间件为每一步包装了指数退避(exponential backoff);你的循环捕获了格式错误的 JSON 并重新提示模型进行修复。这些都没错。但每一个机制都是智能体可以观察、概括并利用的副作用。一旦它这样做了,你的可靠性层就不再是安全网,而成了规划原语(planning primitive)。

与验证器共享盲点的自我修正循环

· 阅读需 10 分钟
Tian Pan
Software Engineer

在智能体复盘中流传的截图每次看起来都一模一样。一段长长的追踪记录。一个单一的任务。十二次迭代。智能体生成了草稿,进行了评估,发现了一个小瑕疵,生成了修订版,进行了评估,发现了一个略有不同的微小瑕疵,接着又生成了另一个修订版。验证器返回的分数一直徘徊在 0.78 到 0.84 之间。它从未跨越门槛。智能体从未上报异常。三小时后,任务因超时而终止,产生了一笔足以支付一名高级工程师四分之一日薪的 Token 账单。

团队将其称为“自我修正”问题,因为架构图上就是这么标注的。实际的失败是结构性的。验证器其实就是换了一个提示词的生成器。收敛准则是模型自己的意见。重试预算是隐式的,受限于智能体的超时时间,而不是由智能体本身推理决定的。这三个失败孤立来看都不像是 Bug,这正是团队会将其上线的原因。

流式中止后遗留的计费副作用

· 阅读需 12 分钟
Tian Pan
Software Engineer

用户正在查看你的智能体(Agent)流式传输回复。在 200 毫秒时,他们点击了停止。UI 清除了气泡,加载图标消失,产品的表现就像请求从未发生过一样。

但它确实发生了。Agent 已经调用了 send_invoice_email。供应商的邮件转发服务器返回了 250 OK。客户收到了一份用户从未批准的草案发票。你的计费系统向用户收取了中止前流式传输的 token 费用。但它无法撤回发送邮件产生的费用。

这是每个使用流式工具(streaming tool use)的团队至少都会遇到一次的失败模式,而且大多数团队甚至从未察觉。流层(stream layer)报告 cancelled。工具层(tool layer)报告 succeeded。你的面向客户的日志会根据最后刷新的子系统从中挑选一个,于是同一个请求的两个部分现在对于该请求是否发生产生了分歧。

当源数据已更改,你的 Prompt 缓存仍在提供旧的工具执行结果

· 阅读需 11 分钟
Tian Pan
Software Engineer

一名支持代理在 14:02 查询了客户的订阅状态,发现其处于激活状态,该回答进入了 Prompt 前缀中,而缓存层刚刚将其标记为上下文的可重用部分。在 14:14,计费系统取消了该订阅。在 14:19,同一位客户提出了跟进问题,由于对话前缀仍然匹配,缓存的前缀被重用,代理愉快地告诉客户他们的计划处于激活状态,并主动引导他们使用一个他们已不再拥有访问权限的功能。下游系统是正确的。模型与上下文保持了一致。但用户被缓存命中(Cache Hit)欺骗了。

这是 Prompt 缓存为原本对数据陈旧度(Staleness)保持诚实的系统引入的失效模式。在引入缓存之前,工具调用是对单一事实源(Source of Truth)的请求,并遵循该源所声明的任何新鲜度契约。有了缓存之后,工具结果变成了 Prompt 前缀的一个租户,而前缀拥有自己的 TTL(生存时间),由模型提供商控制,团队中没有人明确选择启用它。

你在三月份录制的演示视频是它最后一次正常工作的时候

· 阅读需 9 分钟
Tian Pan
Software Engineer

一家 B 轮 AI 公司的销售工程师在 3 月的一个周二录制了一段五分钟的演示视频。智能体(agent)在第一次尝试时就选对了工具,用买家的语言组织了答案,并以一种“考虑周全,而非模棱两可”的礼貌态度拒绝了一个棘手的边缘情况。那段录像被存入了资源库。在接下来的七周里,它促成了五笔交易。

到了 5 月底第六个潜在客户在入职培训电话中看到它时,模型已经收到了供应商的小版本更新,重新调整了它的拒绝话术;Prompt 被编辑了两次以修复一个无关的回归问题;工具目录增加了三个条目(模型现在更倾向于其中之一);RAG 语料库针对新的分块器(chunker)重新建立了索引。演示视频不再是产品的录像,而是一个已经不存在的产品的录像。

那个在 11 小时内烧光你季度推理预算的免费试用

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的试用版提供了“每天 100 次生成”。你的定价团队模拟了一个感兴趣的用户花一周时间进行体验。但第一个将智能体(agent)指向端点的试用者,在 70 秒内就用完了当天的配额,19 分钟内用完了每周配额,并在第二天午餐前耗尽了季度的推理预算。没有人收到警报,因为唯一设置的警报只在试用用户转化为付费用户时才会触发。

试用限制在制定时并没有错。它们针对的是不再适用于当前典型用户的用法分布。在六个月前的定价审查与今天早上的新用户注册之间,用户群体已经从点击按钮的人类转向了不知疲倦的程序。仪表盘上的数字不再代表你设定它们时的含义。

你的 Agent 在无文档情况下悄然掌握的流程

· 阅读需 11 分钟
Tian Pan
Software Engineer

六个月前,你的团队上线了一个处理退款的支持智能体(support agent)。当时有一份一页纸的 Notion 文档描述了它应该做什么。如今,文档的内容依然如旧,但智能体的行为却已大相径庭。提示词(prompt)的历史记录中有 47 次修改。新增了三个工具——其中一个悄悄绕过了文档中仍坚称存在的财务核查。模型被更换了两次。在一次没人记录的事故之后,重试策略被加强了。而当数据团队的人问起“这里处理退款的具体规则到底是什么”时,诚实的回答是:去读系统提示词和工具注册表吧,因为那才是现在的规范。

这是智能体系统在生产环境中的隐性失败模式:智能体的行为就是那份没人写的操作手册(runbook)。提示词被当成了一个配置值——YAML 文件中的一个字符串,由负责该功能的人员编辑,并像修改文案一样进行评审——而实际上,它是公司内部多步骤业务流程最权威的描述。组织积累流程逻辑的方式就像遗留代码库积累行为一样:通过修改,而非设计。而那些历来负责该流程的人——产品经理、合规主管、运营总监——从未意识到他们已经丢失了交付物,因为根本就没有一份可以丢失的文档。