Copy as fetch + Skill:自动化问题记录分析的实践与思考

写在前面

第一次听说Anthropic的Skills功能时,我和很多同学一样,以为这就是那个"让AI替我写代码"的神器。但当我真正动手实践后才发现,AI工具的真正价值不在于替代思考,而在于放大能力。它让我能把更多精力放在问题分析、方案设计和工程优化上,而不是重复性的体力劳动。

这篇文章记录了我把问题记录分析流程 进行自动化的完整过程。从最初踩的各种坑,到最后找到一个既稳定又省钱的方案,这个过程中我对"什么是好的工程实践"有了更深的理解。谨以此文和大家学习共勉。(文中代码含AI生成,可根据自己的具体需求进行适当调整)

一、问题背景:如何既高效又高质的完成问题记录的分析?

1.1 真实的业务场景

假设某同学在实习期间负责一个B端产品的技术支持工作。每个版本发布后,都需要分析用户反馈的问题记录,找出共性问题,推动产品改进。听起来简单,实际操作起来却相当繁琐:

第一步:登录内网系统

  • 需要VPN+双因素认证
  • 每次分析都要重新登录

第二步:筛选导出数据

  • 按产品、版本、时间范围筛选
  • 导出Excel,经常遇到数据量过大需要分批导出

第三步:人工分析整理

  • 阅读问题记录内容,分类统计
  • 找出高频问题,分析根因
  • 整理成报告发给团队

整个过程需要30-60分钟,而且每周都要重复一遍。

1.2 更深层的痛点

并且随着和不同角色的同事交流,能发现这个问题远比表面复杂:

角色 关注重点 现有方案的痛点
研发同学 具体的技术问题、异常堆栈 需要从大量问题记录中筛选出技术相关的问题
产品经理 共性问题、产品化机会 缺乏系统性的问题聚类分析
技术负责人 跨产品对比、趋势分析 手动整理跨产品数据太耗时
核心矛盾 同一份数据,不同人需要看不同的"切面" 传统的固定报表无法满足这种灵活需求。

1.3 我的初步想法

既然AI擅长数据分析和文本处理,能不能让它帮我完成这个流程?理想情况下:

  1. 自动获取问题记录数据
  2. 智能分类和统计
  3. 生成针对不同角色的分析报告

但从现实来看,这个方法行不通 :数据在企业内网,AI不能进去。

二、技术探索:踩过的坑与学到的经验

2.1 方案一:让AI"操作浏览器"(Playwright MCP)

我首先想到的是用 Playwright MCP,让 AI 通过 accessibility tree 理解页面结构,自主决策点击、填写、导出等操作。

Playwright MCP(Model Context Protocol) 是微软推出的一个革命性工具,它让大语言模型能够直接"看懂"网页并生成自动化测试脚本。不同于传统的截图识别方式,MCP使用可访问性树来理解页面结构。

完成相应的配置(Claude Desktop、VS Code、Cursor 等),如果想在代码中使用 MCP Client 连接 Playwright MCP Server,大致的代码结构为:

javascript 复制代码
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';

// 1. 启动 Playwright MCP Server(stdio 模式)
const transport = new StdioClientTransport({
  command: 'npx',
  args: ['-y', '@playwright/mcp@latest'],
});

const client = new Client({ name: 'demo', version: '0.1' }, { capabilities: {} });
await client.connect(transport);

// 2. 通过 MCP 协议让 AI 执行浏览器操作
await client.callTool({ 
  name: 'browser_navigate', 
  arguments: { url: 'https://inner.company.com/workorders' } 
});

// 3. 获取 accessibility tree 快照
const snapshot = await client.callTool({ 
  name: 'browser_snapshot' 
});

// 4. AI 分析 snapshot 后,决定点击哪个元素
await client.callTool({
  name: 'browser_click',
  arguments: { element: '导出按钮', ref: 'e12' }  // 基于 accessibility tree 的引用
});

该方案遇到的问题

问题1:Token消耗爆炸

Playwright MCP 每一步都要把 accessibility tree(页面的语义化结构树,而非完整 HTML)发给 AI 分析。对于一个中等复杂度的页面,accessibility tree 仍可能有 50KB-100KB,转换成 token 就是几万。我实测了一个15步的登录+导出流程,消耗了 22 万 token。这个成本对于个人学习和小团队来说,根本承受不起。

问题2:稳定性仍存挑战

虽然 MCP 用 accessibility tree 摆脱了对 CSS selector 的依赖,但现代 Web 应用的动态特性依然带来问题:下拉菜单的异步加载导致 AI 误判"元素不存在"; 前端改动按钮文案(如"导出"改"下载"),AI 基于语义的理解就会失效。

问题3:调试困难

当脚本失败时,很难定位问题:是 accessibility tree 解析不完整?还是 AI 对页面语义理解错误?还是网络延迟导致状态不同步?需要比对 tree 快照和页面实际状态来排查。

问题4:数据提取局限

accessibility tree 只包含交互元素的文本标签,不包含 DOM 中的结构化数据(价格、ID、class、data属性)从而丢失了大量DOM细节。比如:如果业务需要提取"折扣价¥5999"或"product-id=12345",MCP 无法直接提供,需要额外编写代码注入页面抓取,这增加了复杂度。

2.2 方案二:更智能的浏览器工具(Agent Browser)

后来我发现 Vercel Labs 推出的 agent-browser ,它针对 AI 操作浏览器做了专门优化:

核心创新:refs 机制

传统方式需要告诉 AI"去找 class 包含 submit 的按钮",agent-browser 会给每个可交互元素打上唯一标签(如 @e1、@e2),AI 直接说"点击 @e2"就行。

bash 复制代码
agent-browser 的工作流程
agent-browser open https://example.com 
agent-browser snapshot -i
# 输出: @e1 button "Submit", @e2 input "Email"
agent-browser click @e1
agent-browser fill @e2 "user@example.com"

优势:

Token 消耗降低 90%+:只返回可交互元素的精简快照;
稳定性提升:基于语义化引用(refs),不受 CSS class 变动影响;但仍需重新 snapshot 应对动态内容变化;
Rust 编写 + Node.js Daemon:CLI 层用 Rust 实现高性能,底层仍基于 Playwright 控制浏览器;

实测数据对比:

操作 Playwright MCP Agent Browser 效率提升
页面快照 8,000-50,000 tokens 500-800 tokens 90-95%
点击操作 8,000-12,000 tokens 200-300 tokens 95%+
表单填写 8,000-10,000 tokens 300-500 tokens 90%+

注:Playwright MCP 消耗取决于 accessibility tree 的完整度;Agent Browser 消耗取决于可交互元素数量。复杂页面(如大型数据表格)可能偏离上述区间。

但核心问题依然存在

即使是agent-browser,只要是"让AI去操作页面",行为就一定存在不确定性。AI需要理解页面结构、决策操作路径、处理异常情况,每一步都可能出错。

尝试了以上两种方案,能够得到的结论是:
适合优先上 Playwright MCP 的场景:需要长期保留登录态;要在真实网站里深度浏览要搜索、点详情、看评论、看图;更重视稳定性和可预期性;不希望折腾 profile 和会话管理;希望独立窗口运行,不影响自己正在用的 浏览器。
适合优先试 agent-browser 的场景:操作多、阅读少;页面是后台系统或工具型 Web App;需要更真实的键盘、hover、drag 交互;希望工具返回更轻,尽量省 token;更习惯 CLI / shell 风格的 agent 工作流;愿意自己把 session、profile 这些细节配置好。

2.3 方案三:退回到"固定脚本"(传统自动化)

既然使用AI工具没有那么大的优势,那如果放弃AI操作,用固定的Playwright脚本呢?

javascript 复制代码
// 固定selector的脚本
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://example.com');

// 高度依赖DOM结构的选择器
await page.locator('.data-table > tbody > tr:nth-child(2) > td:nth-child(3) > .action-btn').click();
// UI微调后,这个选择器可能就失效了

await browser.close();

优点:确定性强,执行速度快

缺点

  • 编写成本高,需要深入理解页面DOM
  • 维护成本极高,前端迭代频繁
  • 健壮性差,对异常处理支持有限

2.4 关键观察:SPA架构下的接口复现

在反复尝试中,我注意到一个现象:

现代Web应用(SPA)的数据,本质上都来自接口请求。页面只是"渲染层",数据在"接口层"。

SPA架构(单页面应用)是一种仅加载一个核心HTML文件的Web应用设计,通过JavaScript动态更新页面内容,无需整页刷新。其核心优势在于流畅的交互体验和高效资源利用,广泛应用于后台系统和移动端应用。

与传统多页面应用(MPA)相比,SPA首次加载资源较多但后续交互更快,适配性强但对SEO优化要求更高。现代前端框架如Vue、React等均以SPA为核心,通过前端路由和异步数据请求实现视图更新。

既然页面能正常渲染并展示了最新的业务数据,说明对应的接口在当前登录态下是可用的,且返回了符合预期的数据结构.

比如可以做个实验:

实验网站:https://jsonplaceholder.typicode.com/

JSONPlaceholder 是一个提在线 REST API 的网站,我们在开发时可以使用它获取一些假数据、假图片。其返回的数据为 JSON 格式,且同时支持 HTTP 和 HTTPS 这两种请求类型。
以 JSONPlaceholder 提供的 /posts/1 接口为例,这是典型的 RESTful API 端点,模拟了真实业务系统中'根据 ID 查询文章'的数据请求。

  1. 在 Edge DevTools 的 Network 面板中,对问题记录列表接口执行 Copy as fetch
  2. 将代码粘贴到Console中执行
  3. 成功获取到 JSON 格式的问题记录数据

具体操作如下:

右击后选择copy as fetch
通过 DevTools 的'Copy as fetch'功能,可将浏览器已验证成功的请求(含完整 Headers、Cookie 等上下文)一键转换为 JavaScript 代码。这意味着我们无需手动拼接请求参数,直接复用浏览器当前的登录态和请求配置。

然后将复制的信息粘贴在控制台,然后回车

然后点击nextwork功能项,可以看到返回的304状态码信息
首次请求返回 200(OK)并缓存数据,再次执行时服务器返回 304(Not Modified),这是 HTTP 缓存优化机制。无论 200 还是 304,均表明成功获取到结构化的 JSON 数据,验证了接口的可用性。


或者是在打开该网站后,直接在开发者模式下的控制台中输入

javascript 复制代码
// 返回 JSON 的测试接口
const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");

// 查看状态
console.log("状态码:", res.status);  // 应该是 200

// 解析 JSON 数据
const data = await res.json();
console.log(data);

有兴趣的话还可以尝试以下代码:

javascript 复制代码
// DevTools生成的fetch代码(headers已脱敏,实际包含完整认证信息)
fetch("https://inner.company.com/api/workorders/list", {
  "headers": {
    "accept": "application/json",
    "content-type": "application/json"
    // 实际还包含:authorization/x-requested-with/user-agent 等
  },
  "body": JSON.stringify({
    "page": 1,
    "pageSize": 50,
    "product": "API Gateway"
  }),
  "method": "POST",
  "credentials": "include" // 自动携带当前登录态的cookie
});

从这个实验可知:当页面能正常展示数据时,说明对应的接口在当前登录态下已被验证可用。只要浏览器能拿到数据,外部代码也能通过相同接口拿到,且数据格式是结构化的(JSON)而非视觉化的(DOM)
这个实验给了我重要启发 :与其让AI操作UI,不如让AI执行已经验证过的接口请求。

三、最终方案:Copy as fetch + Playwright CDP + Skill封装

我想到了最近很火爆的Skills,也许可以结合'Copy as fetch'获取数据与Playwright CDP控制浏览器,再通过Skill封装将代码封装成标准化执行流程。

Skills(技能文件) 是一种结构化的上下文文档,通常以 Markdown 格式编写,放置在项目仓库的特定目录中,专门用来告诉 AI 编程智能体:"在这个项目里,我们是这样工作的。" 想了解Skills的更多细节,可以参考这篇文章:一文搞懂爆火的SKills原理及实践案例

Skills的Skill 框架规范:

3.1 方案设计

结合前面的探索,可以设计了一个"分层"的解决方案:

核心思想

  • 人做的:首次登录系统(处理 MFA、扫码等复杂认证)、验证最终数据准确性、处理异常边界情况
  • 工具做的:利用 Playwright CDP 连接已登录浏览器,复用 Cookie 会话执行标准化的数据获取脚本(稳定、低成本、可复现)
  • AI做的:基于获取的结构化 JSON 数据进行模式识别、根因分析、生成改进建议报告(发挥 LLM 的推理与生成优势)
    关键技术路径:Copy as fetch(复用浏览器已验证的请求模式)→ Playwright CDP(在保持登录态的页面上下文中执行)→ Skill 封装(标准化执行流程)

3.2 关键技术实现

3.2.1 浏览器端数据获取脚本(Copy as fetch 的代码化复现)

核心逻辑:将 DevTools 中 "Copy as fetch" 得到的请求模式,封装为可在浏览器环境中运行的脚本。通过 credentials: 'include' 自动携带当前登录态 Cookie,无需处理复杂的认证逻辑。

javascript 复制代码
// scripts/fetch-workorders.js
// 在已登录浏览器的页面上下文中执行(通过 Playwright CDP 注入)

const CONFIG = {
    API_BASE: '/api/v1/workorders',
    PAGE_SIZE: 100,
    MAX_PAGES: 10,        // 安全限制,防止无限循环
    RETRY_TIMES: 3,
    RETRY_DELAY: 1000
};

/**
 * 带重试机制的 fetch 封装
 * 网络抖动时自动重试,提高稳定性
 */
async function fetchWithRetry(url, options, retryCount = 0) {
    try {
        const response = await fetch(url, options);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        return response;
    } catch (error) {
        if (retryCount < CONFIG.RETRY_TIMES) {
            console.log(`请求失败,${CONFIG.RETRY_DELAY}ms后重试(${retryCount + 1}/${CONFIG.RETRY_TIMES})...`);
            await new Promise(resolve => setTimeout(resolve, CONFIG.RETRY_DELAY));
            return fetchWithRetry(url, options, retryCount + 1);
        }
        throw error;
    }
}

/**
 * 获取问题记录数据(分页)
 * 完全复用浏览器当前的 Cookie 和 Headers,无需额外认证
 */
async function fetchWorkorders(params = {}) {
    const allData = [];
    let page = 1;
    let hasMore = true;
    
    console.log('开始获取问题记录数据,参数:', params);

    while (hasMore && page <= CONFIG.MAX_PAGES) {
        console.log(`正在获取第 ${page} 页数据...`);
        
        // 核心:复用浏览器原生的 fetch,自动携带 Cookie
        const response = await fetchWithRetry(
            `${CONFIG.API_BASE}/search`,
            {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                    // 注意:无需手动设置 Cookie,浏览器自动处理
                },
                credentials: 'include',  // 关键:确保发送当前域的 Cookie
                body: JSON.stringify({
                    page,
                    pageSize: CONFIG.PAGE_SIZE,
                    product: params.product,
                    startDate: params.startDate,
                    endDate: params.endDate,
                    status: params.status || ['open', 'processing', 'resolved']
                })
            }
        );

        const result = await response.json();
        
        if (!result.data || !Array.isArray(result.data.list)) {
            throw new Error('接口返回数据格式不符合预期');
        }

        allData.push(...result.data.list);
        hasMore = result.data.list.length === CONFIG.PAGE_SIZE;
        
        console.log(`第 ${page} 页获取完成,本页 ${result.data.list.length} 条`);
        page++;
        
        // 防请求过快,避免触发限流
        if (hasMore) {
            await new Promise(resolve => setTimeout(resolve, 500));
        }
    }

    const finalResult = {
        total: allData.length,
        data: allData,
        meta: {
            product: params.product,
            dateRange: [params.startDate, params.endDate],
            fetchedAt: new Date().toISOString(),
            pagesFetched: page - 1
        }
    };

    // 关键:将结果挂载到全局,供外部(Playwright)读取
    window.__WORKORDER_RESULT__ = finalResult;
    console.log(` 数据获取完成,总计 ${allData.length} 条`);
    return finalResult;
}

// 执行入口:支持通过 URL 参数或全局变量注入配置
const params = window.__SKILL_PARAMS__ || {
    product: new URLSearchParams(location.search).get('product'),
    startDate: new URLSearchParams(location.search).get('start'),
    endDate: new URLSearchParams(location.search).get('end')
};

fetchWorkorders(params).catch(err => {
    console.error('数据获取失败:', err.message);
    window.__WORKORDER_ERROR__ = err.message;
    throw err;
});
3.2.2 Playwright CDP 执行器(连接已登录浏览器)

Playwright 的 connectOverCDP() 可以连接到以 Debug 模式运行的 Chrome 实例,复用其所有页面上下文(包括登录态)。这相当于用代码实现了 "Copy as fetch" 后手动在 Console 粘贴执行的过程,但实现了自动化和结果捕获。

javascript 复制代码
// scripts/cdp-runner.js
// 功能:连接已登录的 Chrome,在页面中执行 fetch-workorders.js,捕获 JSON 结果

const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');

async function runWithCDP(cdpPort, scriptPath, outputPath, params = {}) {
    console.log(`连接到 Chrome CDP (端口 ${cdpPort})...`);
    
    let browser;
    try {
        // 连接到已运行的 Chrome(用户需提前启动并登录)
        browser = await chromium.connectOverCDP(`http://localhost:${cdpPort}`);
        
        // 获取默认上下文(Default Context),包含用户的手动登录态
        const context = browser.contexts()[0];
        if (!context) {
            throw new Error('未找到浏览器上下文,请确保 Chrome 已正常启动');
        }
        
        // 使用当前已打开的页面(避免新建页面丢失 Cookie)
        const pages = context.pages();
        const page = pages.find(p => p.url().includes('inner.company.com')) || pages[0];
        
        console.log(`当前页面: ${page.url()}`);
        
        // 注入参数到页面全局变量
        await page.evaluate((p) => {
            window.__SKILL_PARAMS__ = p;
        }, params);
        
        // 读取并执行数据获取脚本(等效于在 DevTools Console 中粘贴执行)
        const scriptContent = fs.readFileSync(scriptPath, 'utf-8');
        console.log(` 执行脚本: ${path.basename(scriptPath)}...`);
        
        await page.evaluate(scriptContent);
        
        // 等待异步操作完成(脚本会将结果写入 window.__WORKORDER_RESULT__)
        await page.waitForFunction(() => 
            window.__WORKORDER_RESULT__ !== undefined || window.__WORKORDER_ERROR__ !== undefined, 
            { timeout: 120000 }  // 2分钟超时,应对大数据量
        );
        
        // 提取结果
        const result = await page.evaluate(() => window.__WORKORDER_RESULT__);
        const error = await page.evaluate(() => window.__WORKORDER_ERROR__);
        
        if (error) {
            throw new Error(`脚本执行错误: ${error}`);
        }
        
        // 写入文件供后续 AI 分析
        fs.mkdirSync(path.dirname(outputPath), { recursive: true });
        fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));
        console.log(`结果已保存: ${outputPath}`);
        console.log(` 共获取 ${result.total} 条记录,${result.meta.pagesFetched} 页`);
        
        return result;
        
    } catch (err) {
        console.error('执行失败:', err.message);
        throw err;
    } finally {
        // 重要:保持浏览器运行(不关闭 Chrome),只断开连接
        if (browser) await browser.close({ runBeforeUnload: false });
    }
}

// CLI 入口
const [,, cdpPort = '9222', scriptPath = './scripts/fetch-workorders.js', 
       outputPath = `./.output/workorders-${Date.now()}.json`, paramsJson = '{}'] = process.argv;

const params = JSON.parse(paramsJson);

runWithCDP(cdpPort, scriptPath, outputPath, params)
    .then(() => process.exit(0))
    .catch(() => process.exit(1));
3.2.3 Skill 配置文件(标准化执行流程)
yaml 复制代码
# SKILL.md
name: workorder-analyzer
description: 基于 Copy as fetch + Playwright CDP 的问题记录分析工具。复用已登录浏览器会话,直接调用内网 API 获取数据,规避 AI 操作 UI 的高成本和不稳定性。

version: 1.0.0
author: "你的名字"

## 前置依赖检查
environment:
  node: ">=16.0.0"
  dependencies:
    - playwright: "^1.40.0"

## 执行流程

### 步骤1:启动并登录(人工操作,一次性)
# 终端1:启动 Chrome Debug 模式(保持运行)
macOS:
  /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
    --remote-debugging-port=9222 \
    --user-data-dir="$HOME/chrome-debug-profile" \
    --no-first-run

Windows:
  "C:\Program Files\Google\Chrome\Application\chrome.exe" ^
    --remote-debugging-port=9222 ^
    --user-data-dir="%TEMP%\chrome-debug-profile"

# 在启动的 Chrome 中手动登录问题记录系统(只需做一次,Cookie 会保留)

### 步骤2:执行数据获取(工具自动化)
# 使用 Playwright CDP 连接已登录浏览器,执行数据获取脚本
# 等效于:手动 Copy as fetch → 粘贴到 Console → 执行 → 复制结果
# 但实现了完全自动化

node scripts/cdp-runner.js 9222 \
  scripts/fetch-workorders.js \
  .output/workorders-$(date +%Y%m%d-%H%M%S).json \
  '{"product":"API Gateway","startDate":"2024-01-01","endDate":"2024-03-31"}'

# 验证数据
if [ ! -s .output/workorders-*.json ]; then
  echo "数据获取失败,请检查:1) Chrome是否已登录 2) 网络连接 3) 接口权限"
  exit 1
fi

echo "数据获取成功"

### 步骤3:AI 分析(自动化)
# 读取获取的 JSON 数据,进行 AI 分析
# 这里可以接入 Claude / GPT-4 等,通过 MCP 或 API 调用
cat .output/workorders-*.json | your-ai-cli analyze \
  --template "分析高频问题,提出产品改进建议" \
  --output .output/analysis-report.md

## 数据获取脚本说明
scripts:
  fetch-workorders.js:
    desc: "在浏览器上下文执行的脚本,复用 Cookie 调用 /api/v1/workorders/search"
    params:
      product: "产品名称(如 API Gateway)"
      startDate: "开始日期(YYYY-MM-DD)"
      endDate: "结束日期(YYYY-MM-DD)"
      status: "问题状态数组(默认 open, processing, resolved)"

## 输出规范
output:
  format: "JSON + Markdown"
  files:
    - "workorders-{timestamp}.json": "原始数据(数组格式)"
    - "analysis-report.md": "AI 分析报告(包含统计图表、根因分析、改进建议)"
3.2.4 环境检查脚本(辅助工具)
bash 复制代码
#!/bin/bash
# scripts/check-env.sh
# 检查执行环境是否满足要求

echo "=================="
echo "环境检查"
echo "=================="

# 检查 Chrome CDP
if lsof -Pi :9222 -sTCP:LISTEN -t >/dev/null 2>&1; then
    echo " Chrome CDP 正在端口 9222 运行"
    # 尝试获取版本
    curl -s http://localhost:9222/json/version 2>/dev/null | grep '"Browser"' || true
else
    echo "Chrome CDP 未运行"
    echo "   请先执行启动命令(见 SKILL.md 步骤1)"
    exit 1
fi

# 检查 Node.js 版本
NODE_VERSION=$(node --version 2>/dev/null || echo "none")
if [[ "$NODE_VERSION" != "v16"* && "$NODE_VERSION" < "v18" ]]; then
    echo "Node.js 版本 $NODE_VERSION 可能过低,建议 v16+"
else
    echo "Node.js 版本: $NODE_VERSION"
fi

# 检查 Playwright
if npm list playwright >/dev/null 2>&1; then
    echo " Playwright 已安装"
else
    echo " Playwright 未安装"
    echo "   执行: npm install playwright"
    exit 1
fi

# 检查脚本文件
if [ -f "scripts/fetch-workorders.js" ] && [ -f "scripts/cdp-runner.js" ]; then
    echo "执行脚本存在"
else
    echo " 执行脚本缺失"
    exit 1
fi

echo ""
echo "环境检查通过,可以开始执行数据获取"

3.3 项目结构

复制代码
workorder-analyzer-skill/
├── SKILL.md                      # Skill 核心定义与执行流程
├── README.md                     # 项目说明与快速开始指南
├── package.json                  # Node.js 依赖(playwright等)
├── .gitignore                    # 忽略.output/、node_modules/等
│
├── scripts/                      # 执行脚本
│   ├── fetch-workorders.js       # 浏览器端数据获取脚本(Copy as fetch代码化)
│   ├── cdp-runner.js             # Playwright CDP执行器(Node.js)
│   ├── check-env.sh              # 环境检查(Chrome CDP、Node.js、Playwright)
│   └── install-deps.sh           # 一键安装依赖脚本
│
├── config/                       # 配置文件(可选)
│   ├── api-endpoints.json        # API端点配置
│   └── default-params.json       # 默认查询参数
│
├── templates/                    # 报告模板
│   └── analysis-template.md      # AI分析报告模板
│
├── examples/                     # 示例与文档
│   ├── sample-output/            # 示例输出
│      ├── workorders-sample.json
│      └── analysis-report-sample.md
│
└── .output/                      # 实际输出目录
    ├── workorders-latest.json    # 最新数据(软链接或复制)
    └── 20240314-143052/          # 带时间戳的执行目录(每次执行新建)
        ├── metadata.json         # 执行元数据(时间、参数等)
        ├── workorders.json       # 原始数据(从API获取)
        └── analysis-report.md    # AI生成的分析报告

关键约束

本方案要求目标系统提供可访问的 REST API(SPA 架构下的标准做法)。如果系统完全依赖服务端渲染且无 API 暴露,则仍需退回到浏览器自动化方案。

四、工程化反思

4.1 从"让 AI 做一切"到"人与 AI 的合理分工"

AI从风口席卷成海啸,很容易把人打个"措手不及",在这种大模型百家争鸣的背景下,人类的持续学习和反思显得尤为重要。在探索过程中,我经历了一个重要的认知转变

最初的误区:试图让 AI 完成所有事情------登录、导航、数据提取、分析。

最终的方案

  • 人做的:登录(涉及安全权限)、验证数据准确性、审核分析报告
  • 工具做的:数据获取的执行(稳定、低成本)
  • AI 做的:数据分析、报告生成(发挥 AI 优势)

延伸这种思路可知: 在这样的时代里,路径依赖是最大的风险。面对持续发生的变化,最重要的,是始终保持乔布斯所说的那种"初学者心态",不断地去重新理解,并不断尝试与 AI 的新协作方式。

4.2 稳定性优先的工程原则

在企业环境中,稳定性比炫酷更重要。我的方案选择"接口直调"(直接调用已验证的 REST API)而非"AI 操作浏览器"(基于 accessibility tree 的 DOM 操作),核心考量就是稳定性

稳定性来源

  • 接口契约相对稳定(相比 UI)
  • 登录态由浏览器原生维护
  • 请求脚本可人工验证
  • 错误处理和重试机制
  • 输出可追溯(时间戳目录)

4.3 可维护性的长期价值

一个好的工程方案,不仅要解决当前问题,还要考虑长期维护:

可维护性设计

  • 纯文本配置,易于版本管理
  • 模块化脚本,职责清晰
  • 时间戳组织输出,便于追溯
  • 检查脚本前置,快速定位问题
  • 详细的注释和文档

五、总结与展望

通过方案的不断改进和探索,让我对"软件工程师"这个角色的理解发生了根本变化:工程师不再只是一个写代码的人,而是变成一个定义软件,并对结果负责的人。 当然,目前我和 AI 的协作方式还谈不上成熟。我仍然需要和它一起确定一个具体的架构、定义模块的边界,并持续检查代码在实践中的可行性,这部分判断工作依然消耗着大量精力。但是我一直相信,随着更成熟的产品形态出现:尤其是更可靠的流程和测试机制,这部分判断成本本身,也很可能会被系统性地消化掉。

5.1 方案成果

通过这个 Skill,原本需要 30-60 分钟的人工流程:

  • 打开内网系统
  • 多次筛选、导出
  • 人工分析、整理

现在变成了 5-10 分钟的自动化流程:

  • 一条命令触发 Skill
  • 自动完成数据采集与分析
  • 输出结构化分析报告,人工快速审核后应用

更重要的是,这个 Skill 具有:

  • 可复用性:不同产品、不同版本都能使用
  • 可扩展性:轻松适配新的分析维度
  • 稳定性:基于接口而非 UI,健壮性高
  • 低成本:仅分析环节使用 AI,整体成本降低 95%+

5.2 核心收获

技术层面

  • 深入理解了 SPA 架构下接口与渲染的关系
  • 掌握了 Chrome DevTools Protocol 的高级用法
  • 实践了"稳定性优先"的工程化设计
  • 学会了成本控制和性能优化

思维层面

  • 从"AI 能做什么"转变为"什么问题适合用 AI 解决"
  • 认识到工程化思维在 AI 时代依然重要
  • 体会到"简单方案"有时比"复杂方案"更有价值
  • 培养了成本意识和可维护性意识

5.3 未来优化方向

当然,这个 Skill 还有进一步优化的空间:

  1. 数据缓存机制:对于不频繁变化的历史数据,引入缓存减少重复请求
  2. 增量分析:只分析新增问题记录,与历史分析结果合并
  3. 可视化输出:生成图表而非纯文本报告
  4. 定时任务:结合 cron 实现定时自动分析
  5. 多 Skill 协作:将数据获取、分析、报告生成拆分为独立的子模块/Agent,通过标准 JSON 接口协作,实现更灵活的组装

附录

参考项目地址

https://github.com/microsoft/playwright-mcp

https://github.com/heimanba/order-analysis-skill/tree/main

相关资源

参考文章

相关推荐
赛博云推-Twitter热门霸屏工具2 小时前
从手动运营到自动化增长:赛博云推让Twitter推广效率提升10倍
运维·自动化·twitter
Crazy CodeCrafter2 小时前
租金要交,但客流为零,要关店了?
大数据·运维·经验分享·自动化·开源软件
码农杂谈00072 小时前
全栈可视化开发新选择 网易 CodeWave 开发效率拉满
人工智能·ai
yingxiao8882 小时前
土耳其拟加强数字平台监管;腾讯或参投派拉蒙收购华纳兄弟交易
游戏·ai·腾讯·手游出海·任天堂·clash royale
marsh02062 小时前
6 OpenClaw架构深度剖析:理解其设计哲学与核心组件
ai·架构·编程·技术
zhping10113 小时前
Linux 系统上使用 GitHub 加速工具
linux·运维·github
墨10243 小时前
与 AI 并肩成长:从个人知识库到每日新闻系统的实践记录
人工智能·ai·ai编程·openclaw
于眠牧北3 小时前
ubuntu22.04安装docker以及安装过程中报错解决方法
运维·docker·容器
北京耐用通信3 小时前
耐达讯自动化CC linkie转Devicenet网关:架起三菱PLC与电导率仪跨协议“沟通之桥”
人工智能·物联网·网络协议·自动化·信息与通信