跳到主要内容

778 篇博文 含有标签「llm」

查看所有标签

没有根本原因的事后分析

· 阅读需 10 分钟
Tian Pan
Software Engineer

事故排查会议(incident bridge)安静得有些异样,这意味着大家都卡住了。一份支持工单显示,智能体(agent)告诉客户其退款已获批准,而事实并非如此。你有完整的追踪记录:提示词(prompt)、检索到的账户记录、工具调用、模型的推理过程以及最终的消息。你重放了一遍,智能体的操作是正确的。你又重放了一遍,依然正确。十次中有九次,产生该事故的追踪记录反而生成了正确的结果。会议上终于有人提出了那个复盘模板(retro template)无法处理的问题:那么,根本原因是什么?

根本没有。至少不是模板所指的那种。五个为什么(five-whys)的链条是这样运作的:“智能体告诉了客户错误的信息” → “因为模型生成了批准” → “因为它采样了一个断言批准的 Token 序列” → “因为……这是概率分布所允许的。”最后一个“为什么”最终以耸耸肩告终。“模型采样了一个错误的 Token”在技术上是正确的,但在操作上毫无用处。它没有指明修复方案,没有分配负责人,也没有弥补差距。你可以把它写进报告,但每个读到它的人都知道,你记录的是一个巧合,而不是一个原因。

两个模型厂商,一个功能:用冗余换来的连贯性噩梦

· 阅读需 12 分钟
Tian Pan
Software Engineer

你接入了第二个模型供应商,因为第一个挂了。那是一个星期二,主供应商的状态页在几个小时内一片通红,你的功能也随之陷入瘫痪。所以你做了件负责任的事:添加了一个备选方案。现在,如果 OpenAI 无法访问,你就路由到 Anthropic。如果 Anthropic 对你进行了频率限制,你就回退到 Gemini。架构图看起来干净且成熟。可靠性问题,解决了。

可惜你添加的不是一个副本。你添加的是第二种意见。而操作“第二种意见”与操作“第二个副本”是完全不同的两回事。

你引入的心理模型来自“无状态服务”的策略:在负载均衡器后运行三个相同的实例,如果一个挂了,另外两个会提供完全相同的响应。这之所以有效,是因为副本之间在字节级别是完全等效的。但来自两个供应商的两个语言模型并非如此。它们是在不同的数据上训练的,针对不同的目标进行了微调,而且它们在用户最容易察觉的输入点上——会产生系统性的、而非随机的——分歧。

你的 AI 账单只是一个未标记的行项目:当 Token 拒绝被标记时的 FinOps

· 阅读需 11 分钟
Tian Pan
Software Engineer

财务在月底打开发票。一个供应商。一个数字。它比上个月大,而且下个月还会更大。然后他们提出了唯一重要的问题 —— 这是哪个功能花的钱? —— 房间里没人能回答。

这是在生产环境中运行 AI 的一种隐蔽失败模式。并不是说账单数额巨大;如果价值匹配,数额大也没关系。失败之处在于账单是无法归因的。它作为一个单一的费用项出现 —— OpenAI、Anthropic、Bedrock、Azure —— 没有任何财务部门真正需要的维度:没有按功能、按团队、按客户,也没有按成功的任务进行拆分。你能看到总额在上升。但你看不出 原因,而当发票寄到时,原本可以解释它的请求上下文早已消失了。

你模型的置信度分数只是一种感觉,而非概率

· 阅读需 9 分钟
Tian Pan
Software Engineer

一名客服代理正准备办理退款。在触发工具调用(tool call)之前,你的团队添加了一个门控:只有当模型表示其置信度至少达到 90% 时才继续。模型尽职地返回了 "confidence: 0.95",退款发出去了,而模型用来证明金额合理性的引用——一条关于损坏商品的政策条款——其实并不存在。它从未存在过。模型虚构了该条款,然后为自己的虚构给出了 95% 的评分。

这就是陷阱。团队倾向于使用模型的置信度数值,因为它看起来就像你从经过校准的分类器中获得的概率——即 0.9 意味着“十次中有九次是正确的”。但事实并非如此。大语言模型(LLM)自我报告的置信度就像其他任何 token 一样,只是听起来流畅的 token,它受到语气、措辞和训练激励的影响,而这些与底层声明是否属实几乎没有任何关系。

如果你根据那个数字来限制实际行动,你就是在根据一种“感觉(vibe)”来做决定。

你的评估测试集对现任模型存在过拟合

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个新的前沿模型发布了。它更便宜、更快速,并在各大公开排行榜上霸榜。你使用你花了 18 个月构建的评估套件对其进行测试,结果它的得分比你目前运行的模型还要。于是你保留了现有的模型,将挑战者模型归类为“尚未准备好”,然后继续之后的工作。

令人不安的部分在这里:那个结果几乎没有告诉你哪个模型更好。它告诉你的其实是,你的评估套件是通过观察当前模型的失败、处理一次又一次的生产事故而构建的,然后通过修补来消除那些特定的失败。这个套件并不是对质量的客观衡量,它是某个模型“疤痕组织”的目录。而一个拥有不同弱点的挑战者模型,在面对一个针对现有模型特定弱点而收集的测试集时,表现总是会显得更差——即使它在你实际服务的流量上表现得更好。

这就是“现有模型偏见 (incumbent bias)”,它是没人会在迁移决策中计算的切换成本。它在更好的选择出现很久之后,依然悄悄地将你锁定在旧模型上,而且它还是披着“严谨工程”的外衣做到这一点的。

智能体输出的验收抽样:制造业质量保证领先于代码审查的秘诀

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的智能体集群(agent fleet)本周开启了 40 个拉取请求(pull requests)。你审查了其中涉及支付代码的 6 个请求,浏览了几个正好在你打开标签页时提交的请求,然后只要通过了 CI 测试,就将其余的全部合并了。如果有人问你的审查政策是什么,你大概会描述成类似上面的做法——但这根本不是政策。这只是一种“心情”(mood)。

数据表明大多数团队都处于同样的境地。最近一项针对流行开源仓库中智能体生成的拉取请求的大规模研究发现,61% 的请求完全没有任何审查记录;而在确实经过审查的请求中,大多数也仅由其他智能体进行审查。与此同时,产量仍在攀升:智能体现在生成 PR、文档、支持响应和工单的速度,已经超出了任何人类审查流程的设计初衷。审查所有内容是不可能的,而完全不审查则是玩忽职守。因此,团队在两者之间即兴发挥,既没有明确的规则,也没有衡量的覆盖率,更无法判断当前的审查力度是过于偏执还是草率鲁莽。

制造业在一个世纪前就解决了这个问题。20 世纪 20 年代,当西部电气(Western Electric)大量生产电话设备时,对每一个单元进行检查在经济上是不可能的,而运送未检查的批次又是不可接受的——于是贝尔实验室的统计学家们建立了“验收抽样”(acceptance sampling):这是一门具有数学依据的学科,用于决定一批产品中需要检查多少、何时拒绝整批产品,以及供应商何时赢得了放宽检查的信任。它在二战期间演变为 MIL-STD-105 标准,随后成为 ANSI/ASQ Z1.4 和 ISO 2859-1,至今仍规范着港口如何验收一整箱货物。这与智能体集群的对应关系几乎是直截了当的,但在 AI 工程领域几乎没有人采用它。

Best-of-N 是一种架构,而不仅仅是打榜技巧

· 阅读需 14 分钟
Tian Pan
Software Engineer

每个前沿实验室的发布公告现在都附带同样的脚注:“包含并行测试时计算 (parallel test-time compute)”。Sonnet 的 SWE-bench 分数因此提升了约 5 分。GPT-5 级别的模型利用它将错误率降低了两位数。Gemini 的 Deep Think 依靠它几乎将其 ARC-AGI-2 分数翻了一番。大多数工程团队将该脚注视为基准测试的“调味剂”——一种虚标排行榜数字的手段,且认为没有实际系统会为此买单——然后继续围绕他们能负担得起的最强模型,进行单次尝试 (one attempt) 的产品架构设计。

这种直觉大概落后了两年。实验室在专业版 (pro tiers) 中加入并行采样并非为了营销装饰;他们加入它是由于在单个答案背后运行 N 次尝试通常是获得高质量的最廉价方式,有时甚至是唯一方式。当一个廉价模型的三次尝试加上一个像样的选择器 (selector) 能够击败每个 token 成本高出十倍的模型的一次尝试时,Best-of-N 就不再是一个基准测试把戏,而变成了一个架构决策——它拥有自己的成本模型、延迟特征以及标志性的失败模式。以此方式对待它的团队,正悄无声息地以比那些仍在旗舰模型上进行单次推理 (one-shot inference) 的团队更低的成本,交付更好的答案。

当你最大的客户端是 Prompt 时,如何弃用 API

· 阅读需 12 分钟
Tian Pan
Software Engineer

你完美地执行了弃用指南。提前六个月发布公告邮件。包含四种语言代码示例的迁移指南。在每个 v1 响应中添加了 Sunset 响应头。开发者仪表板上的横幅。两封提醒邮件。然后你关闭了 v1 —— 但结果并非指南所承诺的安静切换,你的错误率直线飙升并维持在高位。流量没有迁移。它只是不断涌入、失败并重试,且容量比以前更高,因为每一次失败都触发了另一次尝试。

指南之所以失败,并不是因为你执行得不好。它的失败是因为它假设另一端是一个人类 —— 一个会阅读邮件、浏览变更日志并在截止日期前提交 Jira 任务进行迁移的人。你很大一部分流量背后已经没有这样的人了。它来自智能体 (Agent),它们对你 API 的认知被冻结在系统提示词、工具 schema 以及散布在成千上万个你看不见也永远无法触达的代码库中的模型训练数据里。你的停用通知是写给读者看的。而你的最大客户端是一个 Prompt。

Token FinOps:将 AI 支出归因到具体功能

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的云账单可以具体到标签,告诉你上个月一个被遗忘的 S3 存储桶花费了 14,000 美元。但如果你问 LLM 账单同样的问题——到底是哪个功能烧掉了价值 40,000 美元的 token——大多数公司的真实反应只能是耸耸肩。供应商的发票上每个模型、每个 API 密钥只有一行记录,而三个团队共享这个密钥,财务报表中的 “AI 成本” 行则是根据人头、感觉,或者在上次规划周期中抱怨最少的人来分摊的。

这不仅仅是一个小的簿记烦恼。当没人能说出每一美元的 token 支出背后具体对应哪个功能时,会出现两种失败模式。低成本的功能被限制了,因为它们与昂贵的功能共用一个预算额度。而真正浪费的功能却永远存在,因为它们的成本是隐形的——被分摊到了共享的密钥、共享的缓存以及服务于六个不同产品界面的共享智能体(agent)循环中。

FinOps 基金会 2026 年的调查发现,目前 98% 的组织都在积极管理 AI 支出,而一年前这一比例为 63%,再前一年仅为 31%——这是该基金会有记录以来最快的采用曲线。每个人突然都在做 “AI 领域的 FinOps”。但很少有人注意到,云 FinOps 的核心原语——资源标签(resource tag)——在 token 的世界里并不存在,而且现代 LLM 使用的三个特定机制正活跃地破坏着成本归因。

GraphQL 终于找到了它的客户端,而且它不是人类

· 阅读需 12 分钟
Tian Pan
Software Engineer

GraphQL 的核心赌注是客户端应该能够自主组合其数据需求。在过去的十年里,这个赌注大体上是输了——因为客户端是由人类团队组成的,而他们根本不想组合任何东西。前端工程师想要的是一个可以调用后就不用管的稳定端点。GraphQL 推销的灵活性是以解析器复杂度(resolver complexity)、缓存变通方案和安全审查为代价的,而换取的收益——按请求进行字段选择——对于已知的、变化缓慢的 Web 应用来说几乎毫无必要。到 2024 年,从业者的共识已明显降温:大多数内部 API 只服务于两三个已知客户端,一个设计良好的 REST 端点或 BFF 层就能很好地覆盖这些需求。

接着,一种新型的客户端出现了。AI 智能体没有固定的一套屏幕。它根据每个任务决定自己需要什么数据,并且它为响应的每一个字节付费——字面意义上是在为 Token 付费,而在认知意义上,随着上下文窗口被没人要求的字段填满,推理能力也会随之下降。真正能够自主组合数据需求的客户端终于出现了。只是它不是人类。

Agent 的端口与适配器架构:为什么你的工具 Schema 应该比供应商更长寿

· 阅读需 11 分钟
Tian Pan
Software Engineer

这是一个在每一个发布 Agent 的团队中都会重复发生的迁移故事。你基于某个供应商的 SDK 构建了你的 Agent。工具定义以该供应商预期的 JSON Schema 形式存在。工具结果被格式化为该供应商的消息结构。接着,某些原因迫使你做出改变 —— 竞争对手发布了更好的模型,采购部门为了冗余要求引入第二个供应商,或者一个 MCP 服务器取代了手写的集成 —— 然后你发现迁移的真正工作量:它不仅仅是一个 API 客户端。它是代码库中的每一个工具定义、每一个结果格式化器、每一个重试处理器以及每一个测试固件。

失败的原因并不是你选错了供应商。而是你让别人的序列化格式变成了你的内部架构。针对这个问题,早在二十年前就有了一个答案 —— Alistair Cockburn 的六边形架构,更广为人知的名字是“端口与适配器” —— 而 Agent 系统是它多年来最引人注目的新用例。

Postel 法则在工具边界是一种负担

· 阅读需 11 分钟
Tian Pan
Software Engineer

1980 年,Jon Postel 在 TCP 规范中写下了一句话,这成为了互联网的奠基原则:“对自己发送的内容要保守,对接收的内容要宽容。”四十年来,工程师们将其应用到各个角落——容忍尾随逗号的解析器、将 "10" 强制转换为 10 的 API、静默修复错误标记的 HTML 渲染器。可以说,万维网之所以存在,是因为浏览器宽容了所有人的错误。

然而,当调用者不再是人类时,这条建议就反转了。当一个 AI Agent 调用你的工具并传入字符串类型的数字、嵌套错误的 JSON 对象,或者一个 几乎 正确的枚举值时,那个原本能节省人类开发人员 20 分钟调试时间的宽容解析器,对 Agent 来说却造成了更糟糕的后果:它确认了这个草率的调用是正确的。Agent 在循环中唯一的训练信号就是你的工具返回的反馈。接受垃圾数据,你就在教导模型——就在此时此刻,在这个会话片段中——垃圾数据是行得通的。