Files
GEOAgentArticleOptimizer/docs/superpowers/specs/2026-07-01-geo-sample-e2e-skill-design.md

12 KiB
Raw Permalink Blame History

GEO 样例文章 E2E skill 工作流设计

目标

设计一个未来可以包装成 Codex skill 的自动验收工作流。用户启动该 skill 后,系统使用 samples/articles/*.json 中的测试文章,打开当前网页,按真实用户路径完成一键流式优化,并生成可复查的测试报告。

默认模式必须使用当前真实 LLM 配置,不使用 mock,不静默降级。本工作流的定位是“近似人工验收”的自动化,而不是快速单元测试或只测 API 的冒烟测试。

当前实现依据

当前首页主路径是一键流式优化:

  • 用户填写 访问密钥
  • 用户在文章输入区填写 文章内容图片描述或图片链接目标平台用户要求
  • 用户点击 开始优化
  • 前端调用 POST /api/jobs/optimize-stream,读取 NDJSON 流式事件。
  • 页面依次展示事实卡、草稿或终稿、质量报告、导出入口。
  • 终稿到达后显示 optimized.mdoptimized.docxqa_report.json 三个导出链接。

现有 tests/e2e/mvp.spec.ts 仍保留旧的“分析文章 -> 确认事实卡 -> 开始优化”路径,后续实现时应新增或替换为当前一键流式路径。

样例文件形状为:

{
  "name": "Sample name",
  "input": {
    "title": "",
    "body": "",
    "image_lines": "",
    "platform": "official_site",
    "user_instructions": ""
  },
  "expectedHardFailures": [],
  "expectedWarnings": []
}

工作流范围

本设计覆盖:

  • 本地启动或复用 Next.js 开发服务。
  • 读取 samples/articles 下的 JSON 样例。
  • 使用 Playwright 打开网页并完成当前 UI 主流程。
  • 使用真实 LLM 跑事实提取、文章优化、QA 和必要的定向修复。
  • 验证页面结果、质量报告和导出文件。
  • 为每篇样例保存截图、日志、耗时和结构化结论。
  • 输出汇总报告,供用户判断当前实现是否可交付或需要排查。

本设计不覆盖:

  • 自动修复失败。
  • token 级模型流式输出验证。
  • 线上 Cloudflare 环境压测。
  • 多用户协作、权限矩阵或发布平台 API。
  • 把测试报告提交进 Git。

总体架构

建议把能力拆成三层。

第一层是仓库内 runner,作为真实执行入口。它负责读取配置、启动服务、调用 Playwright、收集报告。未来可以通过 npm run test:e2e:samples 或等价命令运行。

第二层是 Playwright 测试和辅助库。它负责页面操作、等待流式结果、下载导出文件、截图和 trace 采集。

第三层是 Codex skill 包装器。skill 本身保持轻薄,只做前置说明、参数解析、运行仓库命令、总结结果。仓库脚本仍是行为来源,避免把项目选择器和业务断言硬编码进用户级 skill。

默认执行模式

默认模式为 live

  • .env.local 和当前 shell 环境读取配置。
  • 要求 API_ACCESS_KEY 可用,除非 API_AUTH_DISABLED=true
  • 要求当前 LLM_PROVIDER 对应的真实 API key 已配置。
  • 不安装 mock handler。
  • 不把 LLM/provider/schema 错误转换成通过。
  • 每篇样例顺序执行,默认并发为 1,避免真实 LLM 请求互相干扰或触发限流。

可选模式可以后续增加:

  • --sample <name-or-glob>:只跑指定样例。
  • --limit <n>:只跑前 n 篇样例。
  • --headed:打开可见浏览器,方便人工观察。
  • --reuse-server:复用已有服务。
  • --mock:开发调试用 mock 模式,但不是默认入口。

服务启动策略

默认策略是启动专用本地服务:

  1. 读取 .env.local,合并当前 shell 环境。
  2. 为本次运行创建报告目录。
  3. 设置 APP_DATA_DIR=<reportDir>/app-data,隔离 SQLite 数据和导出文件。
  4. 找一个可用端口,优先 3000,被占用时使用下一个可用端口。
  5. 运行 npm run dev -- --port <port>
  6. curl 或 Playwright request 确认首页返回 200 OK
  7. 捕获服务 stdout/stderr,保存到报告目录。

如果用户显式传入 --reuse-server,runner 可以复用已有服务,但报告必须标记:

  • server_mode: "reused"
  • 无法保证数据隔离。
  • 无法完整证明 LLM 日志来自本次运行,除非用户同时提供服务日志。

LLM 参与证明

由于默认是 live 模式,runner 必须做两类证明。

前置证明:

  • LLM_PROVIDER 有效。
  • DeepSeek 模式下 DEEPSEEK_API_KEY 存在。
  • OpenAI 模式下 OPENAI_API_KEY 存在。
  • 报告只记录 provider 和 model,不记录密钥。

运行证明:

  • 专用服务模式下,从服务日志中提取 [llm:start][llm:response][llm:validated][llm:error]
  • 每篇成功样例至少应看到 fact_extractorarticle_optimizerquality_inspector 任务。
  • targeted_rewriter 只在 QA 失败触发修复时出现,不作为所有样例的必需任务。
  • 如果 LLM 报错或 schema 校验失败,该样例失败,但报告保留真实错误和阶段。

样例读取

runner 按文件名排序读取 samples/articles/*.json,保证运行顺序稳定。

每个样例先做静态校验:

  • input.body 必须是非空字符串。
  • input.platform 必须是当前系统支持的发布平台。
  • input.image_linesinput.user_instructions 缺失时按空字符串处理。
  • expectedHardFailuresexpectedWarnings 缺失时按空数组处理。

无效样例不进入浏览器流程,直接记为 sample_invalid

浏览器操作流程

每篇样例使用新的页面,减少状态串扰。

页面操作按当前实现执行:

  1. 打开首页。
  2. 如果存在 访问密钥 输入框,填写 API key。
  3. 填写文章输入框。当前标签是 文章内容,后续实现可兼容 粘贴文章
  4. 填写 图片描述或图片链接
  5. 选择 目标平台
  6. 填写 用户要求
  7. 点击 开始优化
  8. 等待事实卡区从待生成状态进入可见事实卡状态。
  9. 等待结果区出现草稿、终稿或完成提示。
  10. 等待 质量报告 出现。
  11. 等待 optimized.mdoptimized.docxqa_report.json 三个导出入口出现。

等待终稿的默认超时建议为每篇 10 分钟。长文和真实 LLM 可能较慢,超时值必须可通过参数覆盖。

导出验证

当前导出链接是页面上的普通 <a>,但导出 API 仍需要 x-api-key。普通浏览器点击无法附加自定义 header。因此测试拆成两层:

  • UI 层:确认页面显示三个导出入口。
  • API 层:用 Playwright request 或 Node fetch 携带 x-api-key 请求导出 URL,确认文件可读。

导出断言:

  • optimized.md 返回 200,正文非空,并包含优化标题或正文片段。
  • optimized.docx 返回 200content-type 或文件头符合 Word 文档预期。
  • qa_report.json 返回 200,可解析为 JSON,并包含 overall_statuschecks

如果未来产品要求“用户直接点击即可下载”,应另加一个点击下载断言。按当前实现,该断言预期会暴露访问密钥无法通过 <a> header 传递的问题。

QA 期望对照

expectedHardFailuresexpectedWarnings 用于校准样例意图,但第一版不把它们作为硬性失败条件。

原因是 live LLM 输出会波动,而且优化后文章可能已经修复了原文缺陷。测试报告应记录:

  • 样例预期的 hard failures。
  • 样例预期的 warnings。
  • 实际 QA 中 fail/warn/pass 的 rule_id。
  • 预期缺陷是否被命中。
  • 预期缺陷是否被修复或未复现。

这些差异在 summary.md 中作为“质量对照”呈现,不影响浏览器全流程是否通过。

失败分类

每篇样例只能有一个主失败分类,方便汇总:

  • preflight_failed:环境、服务、密钥或 LLM 配置不满足。
  • sample_invalid:样例 JSON 不符合最低要求。
  • page_flow_failed:页面选择器、按钮、导航或 UI 状态异常。
  • stream_timeout:超过单篇超时仍未出现终稿或失败提示。
  • stream_failed:页面或捕获的流式事件返回失败。
  • llm_failedLLM provider、网络、额度、schema 校验等真实 LLM 错误。
  • export_failed:导出入口缺失或带密钥请求导出文件失败。
  • console_error:页面出现未允许的 console error 或 pageerror。
  • unknown_failed:无法归类的异常。

失败时必须保留:

  • 最后一张页面截图。
  • 当前 URL。
  • 控制台日志。
  • 网络请求摘要。
  • 服务日志片段。
  • 如果能提取到,保留 LLM task 和错误文本。

报告输出

报告目录建议为:

test-results/geo-sample-flow/<timestamp>/

目录结构:

summary.json
summary.md
server.log
samples/
  <sample-slug>/
    result.json
    console.jsonl
    network.jsonl
    final.png
    failure.png
    trace.zip
    exports/
      optimized.md
      optimized.docx
      qa_report.json

summary.json 保存机器可读信息:

{
  "started_at": "2026-07-01T00:00:00.000Z",
  "mode": "live",
  "provider": "deepseek",
  "model": "deepseek-v4-pro",
  "base_url": "http://127.0.0.1:3000",
  "totals": {
    "passed": 0,
    "failed": 0,
    "skipped": 0
  },
  "samples": []
}

每篇 result.json 保存:

{
  "file": "samples/articles/title-quality.json",
  "name": "title quality sample",
  "status": "passed",
  "duration_ms": 180000,
  "job_id": "job_xxx",
  "qa_status": "warn",
  "qa_fail_rules": [],
  "qa_warn_rules": ["title_quality"],
  "expected_hard_failures": [],
  "expected_warnings": ["title_quality"],
  "exports": {
    "optimized.md": "passed",
    "optimized.docx": "passed",
    "qa_report.json": "passed"
  },
  "llm_tasks": ["fact_extractor", "article_optimizer", "quality_inspector"]
}

summary.md 面向人阅读,包含:

  • 本次运行环境。
  • 总通过率。
  • 每篇样例的状态、耗时、QA 状态、失败原因。
  • LLM 任务参与情况。
  • 导出文件校验结果。
  • 需要人工复查的问题列表。

安全和 Git 边界

报告目录可能包含模型输出、客户文章、服务日志和导出文件,不能提交进 Git。

后续实现时应确认:

  • test-results/.gitignore 忽略。
  • 报告不写入真实 API key。
  • 日志中的 x-api-key、Authorization header 和 provider key 必须脱敏。
  • 不清理或覆盖用户已有 data/,除非 runner 启动了自己的隔离 APP_DATA_DIR

后续实现建议

第一阶段:

  • 新增 repo 内 sample runner 和 Playwright 辅助函数。
  • 新增 npm run test:e2e:samples
  • 让 runner 默认 live 模式、顺序跑全部样例。
  • 更新或替换旧的 tests/e2e/mvp.spec.ts,避免继续测试已下线的分步主路径。

第二阶段:

  • 增加 --sample--limit--headed--reuse-server 参数。
  • 报告中加入 LLM 日志解析和 QA 期望对照表。
  • 对失败样例生成更易读的 Markdown 复盘。

第三阶段:

  • 创建 Codex skill。
  • skill 读取本设计约定,调用 repo 命令。
  • skill 在最终回复里摘要展示通过率、失败样例、报告路径和下一步排查入口。

验收标准

本设计实现后,用户启动 skill 应得到以下结果:

  • 本地网页被真实打开。
  • samples/articles 中的样例被逐篇填入页面。
  • 每篇样例真实触发当前 LLM provider。
  • 成功样例展示事实卡、优化结果、质量报告和三个导出入口。
  • 导出文件通过带密钥请求验证可读。
  • 失败样例保留可复查证据,而不是只返回一行超时或错误。
  • 最终报告能回答三个问题:哪些样例跑通了,失败在哪里,当前实现是否值得人工继续验收。