普通视图

发现新文章,点击刷新页面。
昨天以前首页

搭建自动化 Web 页面性能检测系统 —— AI 篇

2025年6月27日 10:55

我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。

本文作者:琉易

这一篇是系列文章:

搭建自动化 Web 页面性能检测系统 —— 设计篇

搭建自动化 Web 页面性能检测系统 —— 实现篇

搭建自动化 Web 页面性能检测系统 —— 部署篇

页面性能对于用户体验、用户留存有着重要影响,当页面加载时间过长时,往往会伴随着一部分用户的流失,也会带来一些用户差评。性能的优劣往往是同类产品中胜出的影响因素,也是一个网站口碑的重要评判标准。

系统架构图(简略)

本篇重点讲解 AI 分析模块的设计与实践。

画板

AI 分析模块的设计与实现

输入与输出

  • 输入:Lighthouse 检查产生的 JSON 数据
    • 由于每次检测产生的 JSON 数据较大,一般有 350KB ~ 500KB,而大模型往往是根据输入 Tokens 进行计费,且并不是单纯的按量计费,类似于生活中常见的阶梯计费;另外模型支持的输入也有限,一般为 32k Tokens 或 64k Tokens。所以我们将 JSON 数据传输给大模型前需要进行精简。
    • 保留检测结果中的关键数据,如:环境数据(environment)、每一项检测指标的详细结果(audits)、检测时的配置参数(configSettings)、汇总各类指标的最终得分(categories)。
  • 输出:自然语言优化建议列表
    • 如:建议将图片资源启用 lazy-load
    • 如:减小某个图片文件的大小以减少传输时间

核心组成

  • JSON 清洗与摘要
  • Prompt 定义
  • openai 接口集成
  • 流式处理

Prompt 设计要点

构建一个高质量的 Prompt 是成功的关键,以下是一个例子:

你是一个网页性能优化专家。我将提供一个通过 Google Lighthouse 生成的 JSON 报告,请你根据报告中的内容:
1. 每个关键指标给出两三条优化建议,需要结合 json 中的实际数据进行举例。
2. 回答的内容使用 markdown 格式。
3. 专业名词需要使用中文。

实际测试中 Kimi 的 moonshot-v1-auto 模型回答更快,百炼平台的模型输入输出 Tokens 限制更宽泛,但是输出速度略慢;百炼平台的免费额度更多,OpenAI 费用较高且部署后会有访问的问题。

关键技术点

Lighthouse 报告数据结构解析

JSON 数据清洗与摘要是大模型调用能否成功的关键,清洗后的结果是 Prompt 的数据来源,如果内容较多可能会超出模型输入 Tokens 的限制从而导致调用失败。

  • audits 中会包含各种指标近百种,我们可以删除一些内容较多但对分析用处不大的数据,如:offscreen-images、screenshot-thumbnails 等。
  • Lighthouse 生成的 JSON 数据会直接保存瀑布图等图片的 Base64 格式数据,这些图片数据占用 Tokens 明显。

经过清洗,尽量将输入的 Tokens 控制在 100k 以内。

流式输出

openai 是一个 npm 包,通过这个 npm 包可以快速的对接各种大模型的 API 调用服务。

// 流式输出
const stream = await client.chat.completions.create({
    model: 'moonshot-v1-auto',
    messages: [
        {
            role: 'system',
            content: `你是一个网页性能优化专家。我将提供一个通过 Google Lighthouse 生成的 JSON 报告,请你根据报告中的内容:
1. 每个关键指标给出两三条优化建议,需要结合 json 中的实际数据进行举例。
2. 回答的内容使用 markdown 格式。
3. 专业名词需要使用中文。`,
        },
        { role: 'user', content: jsonData },
    ],
    temperature: 0.3,
    stream: true,
});

// 当启用流式输出模式(stream=True),SDK 返回的内容也发生了变化,我们不再直接访问返回值中的 choice
// 而是通过 for 循环逐个访问返回值中每个单独的块(chunk)
for await (const chunk of stream) {
    if (abortSignal?.aborted) {
        console.log(`${taskIdLogStr}任务中止, kimi chat`);
        break;
    }

    // 在这里,每个 chunk 的结构都与之前的 completion 相似,但 message 字段被替换成了 delta 字段
    const delta = chunk.choices[0].delta;
    if (delta.content) {
        onData(delta.content);
    }
}
@ApiOperation({ summary: '分析检测结果' })
    @HttpCode(HttpStatus.OK)
    @Post('reportChat')
    @RawResponse()
    async reportChat(@Body() query: ReportChatReqDto, @Res() res: Response) {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.flushHeaders();

    const abortController = new AbortController();

    // 👇 监听客户端断开连接(如 Abort)
    res.on('close', () => {
        abortController.abort();
    });

    try {
        await this.AIService.reportChat(
            query,
            (content: string) => {
                res.write(`data: ${JSON.stringify({ content })}\n\n`);
            },
            abortController.signal
        );
        res.write(`data: [DONE]\n\n`);
    } catch (error) {
        res.write(`data: [ERROR] ${error.message || 'stream error'}\n\n`);
        abortController.abort();
    } finally {
        res.end();
    }
}

非流式输出

// 非流式输出
const completion = await client.chat.completions.create({
    model: 'moonshot-v1-auto',
    messages: [
        {
            role: 'system',
            content: `你是一个网页性能评分分析专家。我将提供一个产品的性能评分数据,帮我分析得分趋势和较大的得分变化。回答的内容不要带格式符号,尤其是 **。`,
        },
        { role: 'user', content: jsonData },
    ],
    temperature: 0.3,
});

return completion.choices[0].message.content;

实现的功能点

检测报告的智能分析与建议

由于保存的是 html 文件,我们可以通过正则将 html 文件中的 JSON 数据提取出来,用于后续的清洗与分析。

image.png

结合清洗后的 JSON 数据给出优化建议。

数据周报的趋势分析

将过去一周的分数给到大模型,由大模型分析解读得分的变化趋势。

image.png

后续规划

  • JSON 数据清洗更精确,确定好哪些是关键性能指标
  • 将 Lighthouse 的具体评分规则同步给大模型
  • 优化 Prompt,更换更合适的大模型
  • 结合埋点数据
    • 分析页面性能与用户停留时长的关系
    • 分析用户跳出率与页面性能的关系
    • 结合采集到的埋点数据分析页面性能对业务指标的影响
❌
❌