卡门线是海拔 100 公里那条线。越过它才算进入太空,差一米都还在地面上。
上线是同一件事。这个仓库里的三个 Agent Skill:一个列出该测什么,一个替你造出越线的证据,一个守在线上决定你能不能越。
你用 AI 写完了产品,本地跑得很好。然后呢?
多数人此刻做的是:点部署,发到群里,等着看有没有人报错。这等于拿用户当测试环境。
少数想认真测的人,会掉进另一个坑:让 AI 生成一堆测试,看着覆盖率数字上去了,心里踏实了。 但有一份 30 人的对照实验(arXiv:2502.09801)给出了另一半事实:
| 一小时内 | 用 AI | 手写 |
|---|---|---|
| 人均写出的测试 | 59.3 | 27.1 |
| 人均分支覆盖率 | 26% | 16% |
| 人均找到的缺陷 | 6.5 | 3.7 |
| 人均假阳性 | 5.1 | 2.7 |
前三行是好消息,第四行是代价。论文自己的结论很诚实:假阳性变多主要是因为写得多了,不是 AI 让每个测试变差。
翻译成人话:AI 让你多出一倍的测试,也多出一倍的误报。 所以这两个 skill 的重心不在生成,在证明生成出来的东西真的有用。
test-cases 写用例 |
run-tests 跑测试出报告 |
smoke-check 上线前冒烟 |
|
|---|---|---|---|
| 什么时候 | 功能做完时 | 用例清单被人确认后 | 每次部署前 |
| 输入 | 需求文档加代码 | 确认过的用例清单 | 一份固定清单 |
| 产出 | 用例清单,交人过目 | 测试代码 + 测试报告 | 逐项红绿 |
| 失败了怎么办 | 清单改到人点头 | 补一轮,不阻塞任何人 | 红了就停,不许上线 |
为什么在「人过目」处切一刀:用例是整件事的地基。清单方向错了, 后面的代码写得再对、报告写得再全都是白搭。过目只要一分钟(扫模块对不对、缺没缺类), 而落码和跑测完全不用人盯,所以人只出现在这一个点上。
用例清单按九类目录列:输入 · 状态 · 网络与上游 · 支付 · AI 产品特有 · 登录与用户身份(含横向越权,出一次就是事故) · 接口稳定性 · UI 与交互 · 多语言。
依赖是单向的:run-tests 吃 test-cases 的清单;冒烟可以选择性调用 run-tests 产出的代码;反过来都不依赖。
如果你只用一个,用
smoke-check。 前两个是锦上添花,不写测试产品也能上线;冒烟是保命的,跳过它就是拿用户当测试环境。
不同的 agent 平台能操控浏览器的方式完全不同,所以先探测,再按四档降级:
| 档 | 用什么 | 判据 |
|---|---|---|
| 1 | 平台自带的浏览器能力(Claude Code 的内置面板或 Chrome 扩展,Cursor 的内置 Browser) | 会话工具清单里能找到对应工具 |
| 2 | Kimi WebBridge | curl http://127.0.0.1:10086/status 同时返回 running: true 与 extension_connected: true |
| 3 | Playwright | 本地已装,或有 npx 可现装 |
| 4 | 只有 curl | 前三档都拿不到 |
唯一原则:每一档的判据必须是「拿到一份证据」,不是「看到一个名字」。
名字只说明有人装过,证据才说明现在能用。这条不是理论,是实测踩出来的:
开发这个 skill 的机器上,Kimi WebBridge 的目录在、版本文件在,但 daemon 没跑,
curl 直接被拒。装了不等于能用,目录存在不能当判据。
降到哪一档要写在报告第一行。用浏览器跑的和只用 curl 跑的,能下的结论完全不同,不许混为一谈。
顺带说清一个容易混的名字:Kimi 的 Computer Use(操作桌面应用)和 WebBridge(操作浏览器) 是两个独立能力,装的时候是两步。这里要的是 WebBridge。 它自带把自己装进其它 agent 的能力,所以任何有 Bash 的环境都能用同一条 curl 拿到真浏览器。
python3 skills/smoke-check/scripts/infra_audit.py https://你的域名 --locales en,es,de任何档位都必须跑这一组,因为它零成本,且抓的正是最容易上线后才发现的问题:
- sitemap:相对路径、混进别的域名、超过 5 万条或 50MB、裸的
&没转义 - canonical:一页多个、用相对路径、带
#、指向了别的语言版本、分页页指回第一页 - hreflang:缺自指、不是双向互指、没有兜底版本
- 语言标记:缺
lang、写成en_US、与 URL 语言段对不上、RTL 语言缺dir - 翻译缺失:正文里出现未替换的变量、
undefined、或把翻译键直接渲染出来
三条最值得单独记住的:
**canonical 必须指向同语言页。**把 /es/pricing 的规范链接写成英文版是多语言站最常见的错,
后果是其它语言不被单独收录。判据是纯字符串比较,零成本。
hreflang 必须自指且双向。Next.js 官方文档里那个本地化 sitemap 示例本身就漏了自指, 照抄上线整组是残缺的。
**翻译缺失会把变量名渲染给用户。**实测见过某产品登录页的证言轮播直接显示
login.testimonial2Quote,而登录页是转化意图最高的那一页。
这类事故一条正则就能扫出来,但几乎没人扫。
这一项极易误报,所以脚本分两级判:
{{变量}}、undefined、[object Object]判不合格; 点分标识符只判待确认。第一版没分级,在一个技术博客上把PyPDF2.PdfReader、SKILL.md全报成了翻译缺失。一刀切的检查会把真问题淹没在误报里,等于没有检查。
四组,按「红了后果多严重」排序,每项都要留证据:
| 组 | 查什么 |
|---|---|
| 能不能用 | 注册 · 登录 · 核心流程 · 支付成功 · 支付失败 · 额度耗尽 |
| 稳不稳 | 健康检查端点是不是真的打依赖 · 出站请求有没有超时 · 数据库连接方式 · 限流 · 重复提交 · 连的是不是生产库 · 环境变量 |
| 好不好用 | 404 与报错页 · 空状态 · 错误状态 · 加载状态 · 表单报错 · 移动端 · 性能三指标 |
| 多语言 | 切换后 URL 变不变 · 直接访问会不会被跳转 · 切换器是不是真链接 |
几条不常见但真会出事的:
- **健康检查端点必须真的打一次依赖。**验法:临时把数据库连接串改错,断言它返回 5xx。
只
return "ok"的端点等于没有。 - **出站请求必须显式设超时。**Node 全局 fetch 默认要挂 300 秒,等于没有超时, 而多数托管平台的函数上限也是 300 秒。一个卡住的上游能占满你整个函数。
- 支付要验三件事:扣款成功、回调收到、账号权益真的变了。只验前两件是最常见的漏。
- 性能只卡三个实验室能测的:最大内容绘制、布局偏移、总阻塞时间。 交互延迟那个指标实验室测不了,它依赖真实用户,只能上线后看。
固定格式,第一行必须写清跑在哪一档。红了就输出「不许上线」并指出是哪一项, 不给「建议修复」这种模糊结论。没测到的写「未测」,不写「通过」。
另一份研究(arXiv:2607.22880,11 个模型、10 万多个测试用例)发现:
- 对没有 bug 的代码生成测试,覆盖率和缺陷发现能力强相关
- 但如果代码本身带 bug 再生成测试,这个相关性全面变弱
因为模型会把当前行为当成期望行为写进断言。 **所以顺序是:你先手动确认核心路径是对的,再让 AI 补测试。**反过来就是让它把 bug 当规格固化下来。
-
**列出该测什么。**按五类边界情况目录逐类过:输入 · 状态 · 网络与上游 · 支付 · AI 产品特有。 每条都要具体到能直接写成断言,写出「测试边界情况」这种句子说明这一步没做。
其中「输入」那一类不用你操心:skill 自带一份 500 多条的问题输入样本 (空值、保留字、数字边界、注入片段、零宽字符、emoji 组合、超长串), 第一次运行时自动下载并缓存,之后离线可用,断网时用内置兜底样本。 你只要写一条参数化用例,就能一次性覆盖几百种输入。
-
**生成代码。**优先用 Playwright 官方自带的三个 agent(一条命令装完,不引入第三方), 零代码起步用录制。
-
三条红线自查。
-
变异自检。
生成工具会写测试,但不会问自己「我写的这堆东西有没有用」。
三条红线:
| 红线 | 为什么是错的 |
|---|---|
| 把能 mock 的全 mock 了 | 断言在验证你自己写的假数据,等于测了一遍自己的配置 |
| 同义反复 | 测试内部调用同一个实现再和预算值比相等,永远不会失败也永远发现不了问题 |
| 耦合实现细节 | 重命名一个内部变量就让测试挂了,那它测的是实现不是行为 |
变异自检:故意改坏一行实现代码,跑一遍,不变红的测试直接删。
这比看覆盖率数字有用得多。全绿不代表有效,只有「你把功能弄坏它会叫」才叫有效。
顺序不能错:
正版修改 → 测试绿 → 提交 → 故意改坏 → 测试红 → 恢复 → 重跑确认还是绿 → 再推送
**恢复之后必须重跑一次。**如果用版本控制的撤销命令来恢复,而这时正版修改还没提交, 那次恢复会把你没提交的改动一起冲掉,而你以为自己只是撤销了那行故意写坏的代码。
这一类最少人写,但对 AI 产品最要命:模型返回空 · 返回被截断 · 返回不合法的结构化数据 · 触发内容安全拦截 · 生成超时 · 并发生成 · 编造事实。
最后一条实测见过:一个给本地商户自动写社媒内容的产品,替一家咖啡店编出了 「我们每次烘焙都会毁掉一把豆子做品控」这种从没提供过的经营细节。 这种内容会被顾客当面拆穿,而任何常规测试都抓不到。
可行的测法:准备一份结构化的事实清单,生成后用一次额外的模型调用做核对, 问「产出里有哪些陈述在事实清单之外」,断言返回为空。不完美,但比不测强得多。
这是 Agent Skill,不绑定某一个客户端。把 skills/ 下的两个目录放进你的 agent 读取 skills 的位置:
git clone https://github.com/ai798-Lab/karman.git
cp -R karman/skills/test-cases karman/skills/run-tests karman/skills/smoke-check <你的 skills 目录>/常见位置:~/.claude/skills/(Claude Code)· ~/.codex/skills/(Codex)· 其它 agent 按各自文档。
对宿主能力的唯一要求:能读写本地文件、能跑 python3、能联网。
浏览器能力是可选的,没有会自动降级并在报告里写清降到哪一档。
对你的 agent 说人话即可:
上线前检查一下 https://你的域名
给这个功能写测试用例
把确认过的用例落成代码跑一遍
明天要上线,跑一遍冒烟
**一 · 组一「能不能用」至今没在真站点上跑过。**因为它每一项都要产生真实数据 (注册、支付、扣额度),而唯一跑过的真站是已上线的生产站,只能走只读子集。 冒烟检查跑过一次真站,出了 5 条不合格、0 条误报,但那 5 条全在组三与组四。 组一要验,得先有一个预览环境。
**二 · 四档降级里第 2 档只验了探测逻辑。**开发机上 Kimi 的 daemon 没在跑,
curl 直接被拒,所以判据「不可用」是对的,但「可用时能不能真驱动」没验过。
第 1、3、4 档都真跑过。
三 · 翻译缺失只查得到占位符泄漏,查不到英文兜底漏出。
{{变量}}、undefined、[object Object] 这类能查到;但多语言站最常见的事故是
某个语言没翻译、直接漏出英文原文,这个方法根本测不到,
所以它判「通过」时你别把它当成「多语言没问题」的背书。
另外点分标识符仍可能误报,所以只判待确认不判不合格。
**四 · 变异自检目前靠人工挑改哪一行。**没有做成自动化,因为自动变异工具对 JavaScript 生态的支持和运行成本都不理想,而人工挑三处关键逻辑(权限、金额、额度) 已经能覆盖大部分价值。两次真跑里,agent 都自己写了一套替换与恢复的脚手架, 这一段每个人都要重写一遍,是目前最值得补的一个脚本。
五 · 性能那一项只覆盖上线前能测的部分,而且档位不是越高越强: 最大内容绘制、布局偏移、总阻塞时间这三项第 3 档测得了,第 1 档反而测不了, 因为内置面板的页面可见性恒为隐藏,浏览器不给从未可见的页面产出这些条目。 交互延迟那一项必须有真实用户才能测,这个 skill 不做,也不假装做。
三次真跑,每次都是「先派一个 agent 严格照着 skill 做完一遍,再派一个不知情的评审 只读产出判值不值得留」,而最重要的产出不是测试代码,是 skill 自己的问题清单。
| 靶子 | 形态 | 评审分 | 报出的 skill 问题 |
|---|---|---|---|
| 一个测评站的评分与分享链路 | 纯前端逻辑,无需求文档 | 7.0 | 10 |
| 一个生成产品的收尾与退款 | 服务端 + 托管数据库 + 上游回调 | 7.5 | 11 |
| 一个十语言站的上线前冒烟 | 已上线的生产站 | 7.0 | 21 |
三次一共抓到 6 个真实缺陷。但更值钱的是那 42 条 skill 问题, 其中最难看的三条是同一类:文件索引里列着一个并不存在的文件。 连着犯三次之后才明白,这不是笔误,是「写索引时顺手写下应该有的东西」这个习惯。
**自己写的 skill 自己复核,查得出的只有笔误。**所以验收标准只有一条: 拿一个没跑过的项目再跑一次,看还能掉出几条。
卡门线是那条把「还在地面上」和「已经进入太空」分开的界线。它不宽,只有一条线, 但越过与没越过是两种状态。
上线也是。这个仓库不帮你造火箭,只帮你确认自己真的越过了那条线。
MIT License · ai798 Lab