跳到主要内容

702 篇博文 含有标签「llm」

查看所有标签

Eval 测试集是滞后指标:你的绿色仪表盘只反映上季度的失败

· 阅读需 9 分钟
Tian Pan
Software Engineer

每一个成熟的 AI 团队构建其评估套件的方式都如出一辙,而且几乎没有人会公开说出那个潜台词。生产环境中出现了一个故障。有人写了一份复盘报告。一名工程师将该事故提炼为一个测试用例,将其添加到评估套件中,于是仪表盘再次变绿。重复这个循环一年,你就会拥有几百个案例、一个令人满意的通过率,以及一个足以让你在演示幻灯片上感到无比安心的数字。

潜台词是:那个评估套件其实是一个博物馆。每一件展品都是团队已经挺过来的故障类别。98% 的通过率证明了你的系统可以抵御过去 —— 抵御那些已经发生过的特定破坏方式 —— 而对于模型迁移、提示词编辑或用户行为转变即将引入的新型故障模式,它几乎给不出任何参考。评估集是一个披着先行指标外衣的滞后指标。

那个你从未进行过负载测试的备用模型

· 阅读需 10 分钟
Tian Pan
Software Engineer

每一个具有韧性的 LLM 设计在配置中都有一行代码指定了一个备选模型。它之所以存在,是因为有人在设计评审中提出了正确的问题——“如果主模型宕机了怎么办?”——而另一个人用一个 fallback: 键回答了这个问题。大家都点头表示赞同。架构图上多了一个带有虚线箭头的第二个框。合规文档中也增加了一句关于优雅降级的描述。

然后,再也没有人碰过它。

备选模型是大多数生产环境 AI 系统中被断言得最自信、但演练最少的组件。它被命名、被记录、被画在图中——而在它真正承载流量的那一天,也是它第一次遇到真实请求的一天。你并没有建立安全网。你只是构建了第二个断裂强度未知的模型,而你将在最糟糕的时刻发现那个极限。

你的备用路径是生产环境中唯一未经测试的代码

· 阅读需 10 分钟
Tian Pan
Software Engineer

每个成熟的 AI 系统都会配备回退方案(fallback)。当主模型被限流时,路由到更廉价的模型。当服务商返回 5xx 错误时,提供缓存的答案。当置信度低于阈值时,回退到手写的启发式规则(heuristic)。架构图中有一个清晰的小分支,标注为“降级模式”(degraded mode),每个人都因此感到更安全。

令人不安的部分在于:那个分支是系统中几乎从未运行过的唯一代码。主路径每天执行数百万次,并经过大量流量的调试、性能分析和实战测试。回退路径几乎从不执行——直到某天,它在负载下、在事故期间、在三名工程师看着仪表盘变红时,突然为所有人同时执行。

一个你不练习的回退方案并不是冗余。它是一个不受监控的第二系统,其“首秀”在统计学上注定会发生在最糟糕的时刻。

Happy Path 是你的 Agent 评估测试过的唯一路径

· 阅读需 11 分钟
Tian Pan
Software Engineer

看看大多数智能体(Agent)评测集是从哪里来的。有人构建了智能体,向团队演示,演示成功了,于是演示脚本就变成了评测套件。那些通过评审的案例,正是有人已经亲眼看到它们运行成功的案例。评测集在构建之初,几乎就是“快乐路径”(Happy path)的录音——即在截屏当天成功运行的那一段工具调用序列。

所以,当仪表盘显示智能体得分为 94% 时,它实际上是在说:它通过了我们能想象到的案例。它完全没有提及搜索 API 在多步计划中途返回 429 错误的情况,或者用户推翻了两轮前设定的约束的情况,亦或是检索结果为空,智能体必须在胡乱猜测和承认不知道之间做出选择的情况。这些情况并非没有通过你的评测。它们压根就没在评测里。

这就是黄金路径偏见(Golden-path bias),除非你刻意对抗,否则它就是智能体评测套件的默认形态。解决方法不是增加案例数量,而是增加不同种类的案例——这些案例应根据失败模式(Failure mode)来选择,从生产环境中收集,并针对刻意引入的故障进行压力测试。

你的内部 API 在智能体调用的那一天起就变成了公共 API

· 阅读需 12 分钟
Tian Pan
Software Engineer

内部 API 依赖于一种默契而存在:没人会写下契约,因为每个人都已经心知肚明。那些碰巧存在的字段、调用者在暗地里解析的报错、返回空列表而非 404 的 200 响应 —— 这些都是关键的承重行为。而维系这些行为的基础是,你可以叫出每个调用者的名字,并在做出任何更改之前通过 Slack 联系他们。这种安排一直有效,直到它失效的那天。

当你将一个智能体(Agent)连接到该 API 的那天起,这种默契就失效了。这并非因为智能体怀有恶意或粗心大意,而是因为智能体是一个你无法触及的调用者。它没有 Slack 账号。它没有阅读你的迁移说明。它依赖于从示例载荷或 Schema 快照中吸收的响应形态,并且在你早已更新版本后,它仍会长期依赖这些形态。

一个令人不安的事实是,“内部”从未是 API 本身的属性。它其实是调用者列表的属性。将列表缩减到你认识的人,API 就是内部的;一旦增加一个你无法协调的参与者,API 就是公共的 —— 这意味着你需要承担“公共”一词所暗示的所有严谨规范,尽管你并没有构建任何本应具备的基础设施。

模型已到生命周期终点,并带走了你的提示词

· 阅读需 12 分钟
Tian Pan
Software Engineer

弃用通知看起来人畜无害。它以更新日志或邮件中一段平静的文字形式出现:该模型快照将在几个月后的某个日期从 API 中移除,这里是推荐的替代方案,感谢你与我们一起构建。其中暗含的工作量似乎只是一行代码的改动 —— 换掉模型字符串,重新部署,搞定。

这种设想是错误的,而且错得很昂贵。模型字符串是你损失的最小的东西。真正随着旧模型一起消失的,是你花了六个月调优的提示词(prompt) —— 每一个针对边缘案例的补丁、每一个重新排序的指令、每一个你因为那个特定模型会有特定烦人行为而添加的“仅以有效的 JSON 响应,不要用 Markdown 包装”。这些都不是可移植的。从统计学意义上讲,它是针对一个模型的行为进行拟合的。替代模型并不是“缺陷对缺陷”兼容的,因此这种拟合不再成立。

模型生命周期的结束是一个迁移项目。如果把它仅仅视为一次配置更改,你就会在生产环境中、在新模型上通过真实流量发现其中的差异。

像入职初级工程师一样入职 AI 智能体是一种范畴错误

· 阅读需 11 分钟
Tian Pan
Software Engineer

当一个智能体(agent)加入你的团队时,每个工程经理脑海中最接近的类比就是新员工。因此,应对策略显而易见:给它一个沙盒和只读日志,将最初的任务范围缩小,与其结对编程,预留一段磨合期,并随着信任的累积让它承担更重的工作。这听起来很负责任。这感觉就像是你把上一个初级工程师培养成高级工程师时那种耐心的管理方式。

这也是一个范畴错误(category error)——它不只是一个略显不完美的类比,而是一个错误的类比。初级工程师是一个还不太了解你系统的人。而智能体是一个无状态的函数,无论接触系统多少次,它永远都不会真正“了解”你的系统。这是两种完全不同的事物,适用于前者的管理直觉会在无形中让你错配注意力。

这之所以重要,是因为这个隐喻不仅会产生误导,还会让你把精力投在错误的地方。“培养智能体”并不是一种策略。智能体是固定的,你真正能改变的一切都存在于它之外。

Prompt Caching 的隐形代价:当缓存命中提供错误的用户上下文时

· 阅读需 13 分钟
Tian Pan
Software Engineer

Prompt 缓存被宣传为一种稳赚不赔的方案。缓存长期的共享前缀——你的系统提示词、工具定义、检索到的上下文——只需为变化的短尾部分支付全额费用,然后看着账单下降。数字是真实的:缓存读取的成本大约是新鲜输入 Token 的十分之一,因此具有大量稳定前缀的工作负载,其输入成本可以降低 80% 或更多。团队因此采用它,因此调整它,并用单一指标来汇报:缓存命中率,且趋势向好。

这种表述掩盖了一个事实:你刚刚划定的边界——缓存前缀与非缓存尾部之间的界线——并不是一个计费旋钮。它是一个正确性边界。缓存断点之上的所有内容都是系统认为可以在请求之间互换的内容。如果你为了最大化命中率而划定这条线,你就是在让财务指标来决定你的 Prompt 中哪些事实可以在用户之间、租户之间以及跨时间共享。这是一个隔离决策,理应有目的地做出。

这种失效模式是隐蔽的,因为它永远不会报错。如果缓存命中提供了一个由另一个用户概况塑造的上下文,它会返回一个格式完全正确的响应。如果缓存命中提供了一个在缓存预热时为真、但在重用时已失效的个性化信息,它会返回一个自信、连贯但错误的答案。你的延迟图表或错误率不会有任何波动。唯一的信号是看起来 非常棒 的命中率——因为 Key 太粗颗粒度了。

Prompt Injection 是混淆代理问题,而非内容过滤问题

· 阅读需 12 分钟
Tian Pan
Software Engineer

在 Prompt Injection(提示词注入)违规事件发生后,最常见的调查结果通常是某种形式的“模型被骗了”。检索到的文档包含了隐藏指令,Agent(智能体)执行了这些指令,导致客户数据泄露。随后的修复方案几乎无一例外地是内容过滤器:扫描输入、对恶意指令进行分类,并在其到达模型之前将其剥离。部署过滤器,结案。

这个结论是错误的,而过滤器就像是一台无休止的“跑步机”。“模型被骗了”描述的是症状,而不是漏洞。漏洞在于,一个拥有实际权限的 Agent——如数据库令牌、发送邮件能力、文件系统写入权——接受了来自一个永远不该被允许指挥这些权限的来源的指令。这并不是一种新型漏洞,而是一个“混淆代理”(Confused Deputy)问题,操作系统在近 40 年前就已经对其进行了命名并基本解决了它。

如果你将 Prompt Injection 视为检测问题,你就是在参与一场与每一个能组织语言的攻击者之间的军备竞赛。如果你将其视为权限问题,你就可以复用数十年来行之有效的安全工程经验。

对话的平方成本:为什么 AI 聊天支出呈超线性增长

· 阅读需 9 分钟
Tian Pan
Software Engineer

一次 10 轮的对话成本并不是单轮对话的 10 倍,而是接近 55 倍。这是大多数团队在建模 AI 功能的单位经济效益(unit economics)时最容易犯的错误,也是为什么一个在表格上看起来有利可图的产品在生产环境中却在不断亏钱的原因。

错误在于将对话视为一系列独立的请求。事实并非如此。由于 LLM API 是无状态的,每一轮对话都会重新发送累积的全部历史记录。第一轮发送 1 个单位的上下文,第二轮发送 2 个,第十轮发送 10 个。整个会话中计费的总 Token 数是 1 + 2 + ... + N 的总和,其增长趋势为 N²/2 —— 即平方级增长 —— 而你的产品几乎肯定收取的是固定的线性价格。

那些最喜欢你产品的用户,正是那些进行最长对话的用户。他们也是在悄无声息中摧毁你利润空间的人。

演变成产品决策的速率限制

· 阅读需 11 分钟
Tian Pan
Software Engineer

频率限制(Rate limit)过去曾是一个基础设施细节。当你遇到 429 错误,你会使用退避算法(backoff)重试,将溢出的请求排队,而 On-call 频道之外的人甚至根本不知道这回事。用户看到的响应只是比平时慢了几百毫秒。这就是故事的全部。

对于智能体(agentic)功能,这个故事不再适用。当一个智能体在执行多步计划的过程中,中途触及了供应商的每分钟 Token 数(TPM)上限时,失败并不会停留在基础设施层。它会表现为一个半成品的答案、一个在最后一次调用前卡住的工具循环,或者让用户盯着一个永远无法解决的加载动画。配额不再仅仅是后端容量数字,而变成了一个产品必须围绕其进行设计的约束条件 —— 就像产品围绕结账流程或空状态进行设计一样。

自信地返回错误答案的语义缓存

· 阅读需 11 分钟
Tian Pan
Software Engineer

两个支持用户在短短一分钟内向你的智能体提出了几乎相同的问题。第一个用户问:“我们针对 EU 订单的退款期限是多久?”第二个用户问:“我们针对 US 订单的退款期限是多久?”这两个句子的嵌入向量(embeddings)仅有一丝之差——长度相同,结构相同,只有一个两字母 token 的区别。你的语义缓存经过了相似度阈值的微调(在演示中看起来非常合理),将它们判定为匹配。于是,第二个用户得到了第一个用户的答案。EU 的 14 天冷静期被当作事实,以流利的文字呈现给了一位 US 客户,且没有任何补充说明。

没有人会因此收到报警。缓存返回了 200。延迟表现优异。成本看板显示了一次命中,这正是每个人想要的结果。唯一能说明出了问题的信号是客户根据一项不适用于他们的政策行事——而这个信号在几天后才会通过退款纠纷传来,而不是通过你的监控系统。

正是这种故障模式,让语义缓存与你之前构建过的任何缓存都截然不同。精确匹配缓存可能会过期,但它永远不会 错误——key 要么匹配,要么不匹配。语义缓存则是有意放弃了这种保证。它被设计为能针对从未见过的 key 返回答案,而这种延迟优势的代价是正确性风险,大多数团队从未对这一风险进行过量化。