# 联网选择微信公众号文章 Skill，并交付 HTML 报告

用 SoyaOS Cloud、GitHub 实时搜索和确定性质量门禁，生成可追溯的 Skill 选型单文件 HTML。

这是一个真实可运行的 SoyaOS Cloud 最佳实践。你会从实时网络结果中找到多个微信公众号文章 Skill，比较优缺点并给出推荐，最后得到一个经过内容、结构、设计与安全检查的单文件 HTML。

## 你要完成的需求

我们把原始需求只做语句和标点优化，不改变范围：

> 请联网搜索可用于生成微信公众号文章的 Skill，提供多个真实可用的候选方案，并分析各自的优点、缺点与适用场景；随后给出推荐方案、推荐理由和需要注意的取舍。最终请把完整结果交付为一个现代、美观、结构清晰合理的单一 HTML 文件。结束前请检查该 HTML 文件能够正常打开，并确认内容、结构与设计均符合预期；如有异常，修复后再交付。

## 为什么不能只发一次 Chat 请求

Cloud v0.2.0 的 `soya:starter` 是托管文本 Agent，不提供浏览器、Shell 或 Tool Calls。让模型声称“已经联网”，或者让它自由生成一大段未经检查的 HTML，都不能形成真实案例。

这个 Recipe 把职责拆清楚：

1. 本地 Node.js 脚本通过 GitHub 公共 API 实时搜索仓库。
2. 脚本抓取候选 `SKILL.md`，记录来源 URL、仓库更新时间与检索时间。
3. SoyaOS Cloud 只在本次来源白名单内完成比较和推荐，返回受约束 JSON。
4. 版本化模板把 JSON 渲染成 HTML；模型不能注入标签、脚本或样式。
5. 四类机器门禁全部通过后，脚本才写入最终文件。

这属于“客户端 Recipe 编排 + Cloud 推理”，不是 Cloud 原生 Tool Calls。

## 准备工作

- 安装 Node.js 22 或更高版本。
- 按 [Cloud 快速上手](/zh/docs/cloud-quickstart)登录 Developer Portal。
- 创建一个 API Key，并立即保存到密码管理器。客户端把 Key 当作 opaque string，不需要也不应该了解其格式。

获取源码：

```bash
git clone https://github.com/soyaos/cloud-recipes.git
cd cloud-recipes
```

## 运行案例

只在当前终端设置 Key，不要写进代码或提交到 Git：

```bash
export SOYA_API_KEY='your-soyaos-api-key'
npm run run:wechat-skill-research
```

默认输出：

```text
output/wechat-skill-research.html
```

公共 GitHub API 通常无需登录。遇到 `github_rate_limited` 时，可以稍后重试，或临时设置最小权限的 `GITHUB_TOKEN`：

```bash
export GITHUB_TOKEN='your-github-token'
npm run run:wechat-skill-research
```

重复运行且确认要覆盖现有产物时，加 `--force`：

```bash
node recipes/wechat-skill-research/run.mjs --force
```

## 如何判断真的成功

成功日志包含：

- `candidates`：不少于 3；
- `searchedAt`：本次实时搜索时间；
- `requestIds`：SoyaOS Cloud 的 `x-request-id`，可到 Portal 查 Trace；
- `qualityGates`：必须同时包含 `content`、`structure`、`design`、`security`。

四类门禁分别验证：

| 门禁 | 检查内容 |
|---|---|
| 内容 | 候选数量、优缺点、唯一推荐、推荐必须来自候选、来源链接与实时检索时间 |
| 结构 | doctype、语言、viewport、单一主内容、标题层级、五个必要章节、闭合文档 |
| 设计 | 内嵌设计变量、候选卡片、推荐强调、移动端响应式、键盘焦点与打印布局 |
| 安全 | 无脚本、iframe、表单、事件处理器、外部 CSS/JS/字体/图片或 Key 泄露 |

任一门禁失败时，Recipe 返回非零退出码，不会交付“看起来差不多”的文件。

## 结果为什么每次可能不同

候选来自实时 GitHub 搜索。仓库内容、更新时间和搜索排序会变化，因此最佳实践保证的是可追溯流程与质量合同，不是固定候选名单。报告会保留本次看到的来源，方便你复核。

## 隐私与配额

- GitHub 会收到搜索词和公开仓库请求。
- 候选摘要和你的需求会发送给 SoyaOS Cloud 的托管模型；正文不会由 Recipe 写入服务端存储。
- 本地 HTML 会包含分析结果和公开仓库链接，请在分享前自行检查是否加入了敏感需求。
- 一次正常运行消耗一次 Cloud 请求；模型 JSON 无效时最多增加一次格式修复请求。

## 常见错误

- `missing_api_key`：当前终端没有 `SOYA_API_KEY`。
- `cloud_http_error ... invalid_api_key`：Key 无效或已经撤销；回到 Portal 创建新 Key。
- `github_rate_limited`：等待 GitHub 限流重置，或临时设置 `GITHUB_TOKEN`。
- `insufficient_live_candidates`：实时结果不足 3 个；不要用 fixture 冒充成功，稍后重试。
- `html_quality_failed`：查看失败的门禁名称；修复数据或模板后再运行。

源码与测试：[soyaos/cloud-recipes](https://github.com/soyaos/cloud-recipes)

---

Canonical HTML: https://soyaos.ai/zh/docs/cloud-recipes/wechat-skill-research
