跳到主要内容

55 篇博文 含有标签「testing」

查看所有标签

AI 应用的开发与生产环境一致性:预发布环境欺骗你的七种方式

· 阅读需 13 分钟
Tian Pan
Software Engineer

12 要素应用(12-Factor App)准则让开发/生产环境一致性(dev/prod parity)变得家喻户晓:尽可能保持开发、预发布和生产环境的相似。对于传统的 Web 服务,这基本是可以实现的。但对于 LLM 应用,这在结构上是不可能的 —— 且其中的差距远比大多数团队意识到的要大。

问题不在于开发者粗心大意。而是在于 LLM 应用依赖于一类特殊的基础设施(缓存计算、实时模型权重、不断演进的向量索引以及随机性生成),在这些设施中,预发布环境(staging)与生产环境之间的差异不仅是令人不便,而是本质上完全不同。一个看起来正确的预发布环境至少会在七个具体方面对你撒谎。

长尾覆盖问题:为什么你的AI系统在最关键的地方失败

· 阅读需 12 分钟
Tian Pan
Software Engineer

某医院部署的医疗AI在测试中达到了97%的准确率。它通过了所有内部审查,顺利上线,然后悄然失败——当寄生虫密度低于1%的细胞时,它无法检测出寄生虫感染,而这恰恰是早期干预最为关键的场景。直到一位医生注意到特定患者群体中异常高的漏诊率,问题才得以浮出水面。

这就是长尾覆盖问题。你的聚合指标看起来很好,但系统在最重要的输入上已经损坏。

AI 系统的影子流量:在上线前验证模型变更的最安全方式

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数团队上线 LLM 变更的方式,与 2005 年上线 Web 变更如出一辙——跑几个离线评估,说服自己数字看起来不错,然后直接推上去。意外总在周一早上到来:一个通过了所有基准测试的系统提示词调整,悄无声息地破坏了评估集之外 40% 的用户查询。

影子流量就是解决方案。思路很简单:将候选模型或提示词与生产系统并行运行,向其输入每一个真实请求,对比输出结果,同时只让用户接触当前版本。零用户暴露、真实生产数据、上线前的统计置信度。但将这一方法应用于 LLM,需要重新思考几乎所有实现细节——因为语言模型是非确定性的、推理成本高昂,且其输出无法通过简单 diff 进行比较。

LLM 本地开发循环:在不耗尽 API 预算的情况下实现快速迭代

· 阅读需 12 分钟
Tian Pan
Software Engineer

大多数构建 LLM 应用的团队在第三周左右都会发现同样的问题:每次有人运行测试套件时,它都会发起实时 API 调用,消耗真金白银,耗时 30 多秒,且每次运行返回的结果都不尽相同。在原型阶段感觉良好的“直接调用 API”方法,现在变成了迭代速度的沉重负担——而且是账单上的一项重要支出。一个工程团队审计了他们每月的 API 支出,发现 2,847 美元中有 1,240 美元(43%)是由于开发和测试流量不必要地访问实时端点而产生的纯粹浪费。

解决方案不是停止测试,而是从一开始就构建正确的开发循环——让快速路径既便宜又具有确定性,而将慢速路径(真实的 API 调用)留给真正需要的时刻。

模型弃用就绪:在 90 天倒计时之前审计你的行为依赖

· 阅读需 10 分钟
Tian Pan
Software Engineer

当 Anthropic 去年废弃一个 Claude 模型时,一家公司察觉到了——但这仅仅是因为下游解析器在生产环境中开始报错。罪魁祸首?新模型偶尔会将其 JSON 响应包裹在 Markdown 代码块中。旧模型从不这样做。没人记录过这一假设,也没人对此进行过测试。修复只花了一个下午;诊断却花了三天。

这种模式——无声的行为依赖在生产环境中“震耳欲聋”地崩盘——是模型迁移中典型的失败模式。你更新了模型 ID,跑了一个简单的冒烟测试(sanity check),然后发布。六周后,一些细微的问题出现了。你的 JSON 解析失败率提高了 0.6%。边缘情况下的拒绝率翻了一番。你的结构化提取漏掉了一个以前能可靠填充的字段。差异不在代码中——而在模型的行为中,而你从未为此编写过契约(contract)。

随着主要供应商现在的废弃周期缩短至 60–180 天,且模型发布的速度在加快,这已不再是一个理论上的担忧。这是一个周期性的运营挑战。以下是如何提前应对的方法。

真正能阻断 PR 合并的提示词回归测试

· 阅读需 12 分钟
Tian Pan
Software Engineer

问任何一个 AI 工程团队是否测试了他们的提示词,他们都会说"是的"。再问一句:一个有问题的提示词能否让 PR 失败并阻断合并?房间里会安静很多。对大多数团队而言,诚实的答案是否定的 —— 他们偶尔会跑一些评估笔记本,也许有一份记录已知提示词问题的共享 Notion 文档,以及一种模糊的感觉:事情比以前更糟了。那不是测试,那是在碰运气。

这个差距的存在,是因为提示词测试在感觉上与单元测试有本质区别。代码要么行为正确,要么不正确。提示词的输出处于一个连续谱上,输出是非确定性的,而且运行足够多的样本以建立信心会花费真金白银。这些都是真实的约束,但没有一个是无法克服的。那些建立了真正阻断合并的提示词 CI 的团队,并不是在每次构建上花费五十美元 —— 他们在三分钟以内、花费不到一美元的情况下完成运行,这得益于几个让这个问题变得可处理的设计决策。

CI 流水线中的 AI 智能体:如何为无法单元测试的部署设置质量关口

· 阅读需 11 分钟
Tian Pan
Software Engineer

发布一个调用 LLM 的功能很容易。但要判断该功能的下一个版本是否优于生产环境中的当前版本,却相当困难。传统 CI/CD 对确定性行为提供通过/失败信号:函数要么返回正确值,要么不返回。但当函数封装了一个语言模型时,输出是概率性的——相同的输入在不同运行、不同模型版本和不同时间会产生不同输出。

大多数团队的应对方式是绕过这个问题。他们运行单元测试,对几个提示词做快速的人工检查,然后发布。这种方式在出问题之前都还能用——直到某个模型提供商悄悄更新了底层权重,或者一个看似没问题的提示词改动在孤立测试中没有异常,却在凌晨三点以生产流量规模改变了输出分布。

更好的答案并非假装 LLM 输出是确定性的,而是构建基于分布、阈值和评分标准的 CI 质量关口,而不是精确匹配。

非确定性服务的 API 契约:随机输出下的版本管理

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的内容审核服务返回 {"severity": "MEDIUM", "confidence": 0.85}。下游计费系统将 severity 解析为枚举值 ["low", "medium", "high"]。一次模型更新后,服务偶尔开始返回首字母大写的 "Medium"。没有任何部署发生,没有 schema 变更。集成在生产环境中悄然崩溃,整整六天无人察觉——因为所有 HTTP 状态码都是 200。

这是 LLM 支撑服务 API 契约的根本问题:表面看起来像 REST API,但底层行为是概率性的。标准契约工具假设确定性。当这个假设被打破时,它是悄无声息地崩溃的。

演示到生产的失败模式:为什么AI原型在真实用户到来时会崩溃

· 阅读需 11 分钟
Tian Pan
Software Engineer

30%的生成式AI项目在概念验证后被放弃。95%的企业试点没有产生任何可衡量的业务影响。Gartner预测,到2027年底,40%的智能体AI项目将被取消。这些并非底层技术的失败——而是演示与生产之间差距导致的失败。

演示到生产的失败模式是可预测、可重复的,也几乎完全可以预防的。它的发生是因为让演示看起来很棒的条件与让生产正常运行的条件系统性地不同。团队优化前者,却被后者打个措手不及。

LLM 输出的基于属性的测试:发现你的评估集从未想过的 Bug

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的评测集(eval suite)显示准确率为 94%。但用户反馈,对于名字不是 "John" 或 "Alice" 的情况,该功能是失效的。这两者都是事实,而它们之间的差距有一个专门的名字:你精心挑选的测试集只编码了你已经预料到的失败模式。

基于属性的测试(Property-based testing,简称 PBT)诞生于 1999 年,旨在揭示确定性软件中正是这一类的盲点。将其应用于 LLM 输出时,它会自动生成数以万计的对抗性输入变体,探测手写测试用例在结构上无法触及的领域边界。2025 年的一项 OOPSLA 研究发现,平均每个基于属性的测试发现的变异 Bug 数量大约是普通单元测试的 50 倍。另一项研究测量出,PBT 和基于示例的测试(EBT)在不同的 Bug 上会失败——将两者结合后,检测率从 68.75% 提高到了 81.25%。这 12.5 个百分点的差距并非舍入误差,它代表了单一方法无法察觉的整整一类故障。

本文面向那些已经拥有评测集,并希望找出那些评测集在结构上无法发现的 Bug 的工程师。

语义化版本控制对 AI 智能体意味着什么

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的客服智能体稳定运行了三个月。一次例行模型更新在周二悄然上线。到周三下午,三个下游服务已在静默地解析智能体响应中的错误字段——JSON 键值发生了微妙变化,但没有任何报错。到周四,你追溯到订单完成率下降,原因是某个 JSON 字段从 "status" 被重命名为 "current_state"。模型更新了,智能体版本号仍是 v2.1.0,没有人收到告警。

这正是传统 API 设计从未需要解决的版本管理空白。语义化版本控制(Semver)在能够从规范中确定性地复现输出时才有效。AI 智能体无法做出这种承诺。然而下游服务对其行为的依赖程度,与对任何微服务 API 的依赖一样关键。"我们打了一个发布标签"与"下游消费者受到了保护"之间的鸿沟,从未如此之大。

测试不可测之物:LLM 驱动 API 的集成契约

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的测试套件通过了。CI 是绿色的。你发布了新的 prompt。三天后,一个用户反馈你的 API 正在返回带有尾随逗号的 JSON——而你的下游解析器已经静默丢弃数据长达 72 小时。你从没为此写过测试,因为 LLM 在开发环境中"总是"返回合法的 JSON。

这就是毁掉 LLM 驱动产品的失败模式:不是灾难性的模型崩溃,而是确定性测试套件在结构上无法捕获的安静、间歇性的降级。根本原因不是懒惰——而是当你的系统产生非确定性的自然语言时,"期望 == 实际"的整个范式就失效了。

修复这个问题需要重新思考你在测试什么,以及对于 LLM 驱动的 API 而言"通过"究竟意味着什么。那些弄明白这一点的工程师并没有编写更聪明的相等性断言——他们编写的是根本上不同类型的测试。