用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/jacardl/viceroy-skills --skill radar-data-collection命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | radar-data-collection |
| description | 雷达数据采集 — 金价、TIPS、政治、AIHOT、GitHub 写入 PostgreSQL(docker exec)。采集失败按 PATCH-2026-08-10-001 分类告警。 |
| category | operations |
每日数据采集技能。写入 radar-db PostgreSQL。
docker exec radar-db psql -U radar -d radar -t -c "SQL"http://localhost:20128~/.9router/db/data.sqlite 动态读取Asia/ShanghaiTODAY=$(TZ=Asia/Shanghai date '+%Y-%m-%d')
SCRIPT_DIR="/Users/apple/.shared-agent-skills/operations/radar-data-collection/scripts"
# GitHub trending:至少重试 3 次,每次间隔 ≥30s
for i in 1 2 3; do
python3 "$SCRIPT_DIR/gh_collect.py" "$TODAY" && break
[ $i -lt 3 ] && sleep 30
done
# 金价 + TIPS + 政治 + AI(collect.py 超时 300s,超时后用对应回退脚本补数据)
python3 "$SCRIPT_DIR/collect.py"
重试判定规则:
脚本路径:~/.shared-agent-skills/operations/radar-data-collection/scripts/。不要用 collect.py 内置的 gh 路径,见下方陷阱。
/v1/search 彻底失效(2026-08-28 实测)9Router key 验证已重新启用,~/.9router/db/data.sqlite 中存储完整 key(35 字符,格式 sk-0d6...)传入 /v1/search 返回 401 Unauthorized(旧 hardcoded 截断值 "sk-0d6...a7da" 同样失效)。collect.py 已修复为从 SQLite 动态读取完整 key。
政治采集回退链(已验证可行):
gpt-5.6-sol → MiniMax-M3 → sonnet → src[:200] 中文改写链⚠️ 不要在 politics 步骤上反复重试 collect.py(每次 60s 间隔会迅速耗尽超时)。超时后直接用 RSS 回退脚本。
可用 RSS 源:
BBC World: https://feeds.bbci.co.uk/news/world/rss.xml
BBC Asia: https://feeds.bbci.co.uk/news/world/asia/rss.xml
Al Jazeera: https://www.aljazeera.com/xml/rss/all.xml
collect.py 已修复:从 ~/.9router/db/data.sqlite 动态读取完整 key,不再硬编码截断值。
正确代码(sqlite3 默认返回 str,无需 text_factory = bytes):
import sqlite3
conn = sqlite3.connect(os.path.expanduser("~/.9router/db/data.sqlite"))
cur = conn.cursor()
cur.execute("SELECT key FROM apiKeys LIMIT 1")
NINE_ROUTER_KEY = cur.fetchone()[0] # 直接 str,无须 decode
conn.close()
⚠️ text_factory = bytes 是错误做法——加了它会返回 bytes 而非 str,后续 Bearer 拼接会出错。
cron job 的 skill 必须在 cron 执行前已存在于 ~/.hermes/skills/。
2026-08-26 04:22 cron 运行时 skill 目录于 04:23 才创建,导致 cron 找不到 skill,触发 fallback 手动执行,最终 RuntimeError。
排查类似问题时先查 ~/.hermes/skills/operations/radar-data-collection/ 是否存在 + mtime 是否早于 cron 时间。
aihot.virxact.com 返回 items 而非 data:
items = data.get("items", []) # 不是 data.get("data", [])
正确 API 端点:https://aihot.virxact.com/api/public/items?mode=selected&take=10
必需 UA:aihot-skill/0.2.0(带此 UA 才能返回 200,不带则 404)
所有国内源全部失败:
push2.eastmoney.com → Remote end closed connectionRemote end closed connection金价缺失已是常态,非偶发。当前 collect.py 无自动国际金价兜底,飞书标注「金价缺失」即可,无需人工干预。
collect.py 的 self-check 显示 ❌ github 0/10,但此时 gh_collect.py 已成功写入了 7 条数据到 DB。
原因:collect.py 内部 gh 路径错误(见下),导致它查 DB 得到 0 条,但数据实际已在 DB 中。
验证方法:不要相信 collect.py 的 self-check github 行。采集完成后直接查 DB:
docker exec radar-db psql -U radar -d radar -t -c "
SELECT category, COUNT(*) FROM news_articles
WHERE article_date = '$TODAY' GROUP BY category"
若 ai/politics 达标但 github=0,进一步确认:
docker exec radar-db psql -U radar -d radar -t -c "
SELECT category, article_date, COUNT(*) FROM news_articles
WHERE category = 'github' ORDER BY article_date DESC LIMIT 3"
若有昨日旧数据无今日数据 → 确认 github 采集失败,走告警流程。 若有今日数据(gh_collect.py 已写)→ 自检误报,跳过 github 告警。
gh_collect.py 报告 "Inserted 10/10" 但 DB 查询 $TODAY 显示 github=0,同时存在昨日旧数据。
原因未定位(可能是 playwright 异步写帧竞争、docker exec date 与 python datetime 小幅偏差累积)。
补采流程(2026-08-29 实测可行):
# 1. 确认 github 条目存在但日期错误
docker exec radar-db psql -U radar -d radar -t -c "
SELECT article_date, COUNT(*) FROM news_articles
WHERE category = 'github' GROUP BY article_date
ORDER BY article_date DESC LIMIT 3"
# 2. 若有数据但 article_date 非目标日期,删掉错误日期数据
docker exec radar-db psql -U radar -d radar -t -c "
DELETE FROM news_articles WHERE category='github' AND article_date='<错误日期>';"
# 3. 重新运行 gh_collect.py,传入目标日期
TODAY=$(TZ=Asia/Shanghai date '+%Y-%m-%d')
python3 "$SCRIPT_DIR/gh_collect.py" "$TODAY"
# 4. 验证:article_date = 目标日期,count ≥ 1
docker exec radar-db psql -U radar -d radar -t -c "
SELECT article_date, COUNT(*) FROM news_articles
WHERE category = 'github' AND article_date = '$TODAY'"
⚠️ 验证必须检查 article_date,不能只查 count。count>0 不代表日期正确。
collect.py 存在 600s 超时上限,超时后 既不写数据也不抛异常,DB counts 完全不变。 已知卡死环节:gold 步骤(国内源全挂后的网络重试)、politics 步骤(9Router 搜索无响应时 60s × 3 次重试间隔)。
处理流程:
SELECT COUNT(*) FROM news_articles WHERE article_date = '$TODAY'超时后手动补采 AI(aihot 直接 fetch):
import urllib.request, json, subprocess
TODAY = "2026-09-01"
url = "https://aihot.virxact.com/api/public/items?mode=selected&take=10"
req = urllib.request.Request(url, headers={"User-Agent": "aihot-skill/0.2.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
items = json.loads(resp.read().decode()).get("items", [])
for it in items:
title = (it.get("title") or "").replace("'", "''")
desc = (it.get("description") or it.get("content") or "").replace("'", "''")[:500]
src = (it.get("source") or "aihot").replace("'", "''")
link = (it.get("url") or "").replace("'", "''")
sql = f"INSERT INTO news_articles (category, title, content, source, url, lang, article_date, summary, description) VALUES ('ai', E'{title}', E'{desc}', E'{src}', E'{link}', 'zh', '{TODAY}', E'{desc[:200]}', E'{desc}')"
subprocess.run(f"docker exec radar-db psql -U radar -d radar -t -c \"{sql}\"", shell=True)
超时后手动补采 politics(RSS → docker exec insert):
import urllib.request, xml.etree.ElementTree as ET, json, subprocess
TODAY = "2026-09-01"
rss_sources = [("BBC World","https://feeds.bbci.co.uk/news/world/rss.xml"),("BBC Asia","https://feeds.bbci.co.uk/news/world/asia/rss.xml"),("Al Jazeera","https://www.aljazeera.com/xml/rss/all.xml")]
all_items, seen_titles = [], set()
for src_name, url in rss_sources:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
root = ET.fromstring(resp.read().decode("utf-8", errors="ignore"))
for item in root.findall(".//item"):
title = (item.findtext("title") or "").strip()
desc = (item.findtext("description") or "").strip()
link = (item.findtext("link") or "").strip()
if title and title not in seen_titles:
seen_titles.add(title)
all_items.append({"title": title, "description": desc, "link": link, "source": src_name})
unique, seen_content = [], set()
for it in all_items:
cp = it["description"][:100].lower()
cp cp seen_content:
seen_content.add(cp); unique.append(it)
it unique[:]:
t,d,s,l = it[].replace(,), it[].replace(,)[:], it[].replace(,), it[].replace(,)
sql =
subprocess.run(, shell=)
⚠️ psycopg2 直接连接无效(端口映射问题),所有手动 INSERT 必须走 docker exec radar-db psql -U radar -d radar -t -c "SQL"。
news_articles 表无 score 列(2026-08-28 实测)collect.py 的 insert_news() 试图写入 score 列,但表里无此列(schema 以 stars_count 替代)。手动 INSERT 时必须省略 score,否则 500 报错。
正确列:category, title, content, source, url, lang, article_date, summary, description
collect.py 内部硬编码了错误的 gh_collect.py 路径:
/Users/apple/.openclaw/workspace/scripts/radar/gh_collect.py # 不存在!
会导致 GitHub 采集 Attempt 3/3 FAILED,但数据实际已被外部 gh_collect.py 写入,self-check 会漏报 github=0。
正确做法:先单独跑 gh_collect.py,再用 collect.py 跑其余三项,不要依赖 collect.py 内部调用 GitHub。
gh_collect.py 第 17-20 行内部用 docker exec radar-db date 取 CST 日期作为 TODAY,但 GitHub Trending 页面实际展示的是上一个日历年日期(GitHub UTC~00:00 更新 = CST ~8:00)。
后果:凌晨 4-6AM 运行时,脚本取到今日 CST 日期(如 08-27),但 GitHub 页面仍是 08-26 的数据,最终数据以错误日期(08-27)写入 DB——之后 push.py 按 08-27 查 DB 找不到数据,误判 GitHub 失败。
复现场景:
# 这两个命令结果不同!
TZ=Asia/Shanghai python3 gh_collect.py # 写 2026-08-26(错误)
TZ=Asia/Shanghai python3 gh_collect.py 2026-08-27 # 写 2026-08-27(正确)
正确调用方式:始终显式传入目标日期:
TODAY=$(TZ=Asia/Shanghai date '+%Y-%m-%d')
python3 "$SCRIPT_DIR/gh_collect.py" "$TODAY"
验证:运行后直查 DB:
docker exec radar-db psql -U radar -d radar -t -c "
SELECT article_date, COUNT(*) FROM news_articles
WHERE category = 'github' GROUP BY article_date
ORDER BY article_date DESC LIMIT 3"
若今日有数据且条数合理 → 成功。若只有昨日数据 → 需删旧数据后重新运行并传参。
GitHub Trending 每日 repo 数量不固定(周末/节假日可能 <10),≠ 采集失败。判断标准:
news_articles: AI ≥8,政治 ≥10,GitHub ≥10gold_prices: 当日有行验证必须直查 DB,不要依赖 collect.py 的 self-check 输出(github 行经常假阴性)。
docker exec radar-db psql -U radar -d radar -t -c "
SELECT
(SELECT COUNT(*) FROM news_articles WHERE article_date = '$TODAY' AND category = 'ai') as ai,
(SELECT COUNT(*) FROM news_articles WHERE article_date = '$TODAY' AND category = 'politics') as pol,
(SELECT COUNT(*) FROM news_articles WHERE article_date = '$TODAY' AND category = 'github') as gh,
(SELECT COUNT(*) FROM gold_prices WHERE price_date = '$TODAY') as gold"
| 条件 | 标注 |
|---|---|
| 政治 <5 | 🚨 告警 |
| 金价全失败 | 「金价缺失」 |
| AI <5 | 「AI不足」 |
| GitHub = 0(3次重试后) | 「GitHub失败」 |
| GitHub 1-9(3次重试后仍不足) | 接受,不告警(源数据不足,非采集失败) |
| 政治中文改写全失败 | 「⚠️ 政治中文未改写」 |
当采集结果不满足「验证标准」时,仍发送日报,在对应消息中标注问题,不阻塞推送:
| 不达标项 | 日报处理 |
|---|---|
| 金价=0 | MSG1 显示「⚠️ 金价数据缺失」 |
| AI <5 | MSG2 显示「⚠️ AI热讯数据缺失」 |
| 政治 <5 | MSG3 显示「⚠️ 国际政治数据缺失」 |
| GitHub = 0(3次重试后) | MSG4 显示「⚠️ GitHub数据缺失」 |
| GitHub 1-9(3次重试后) | MSG4 正常发送,标注「⚠️ GitHub今日源数据仅N条」(不阻塞) |
| 政治全英文无改写 | MSG3 正常发送,标注「⚠️ 政治中文未改写」 |
gpt-5.6-sol → MiniMax-M3 → sonnet → src[:200]
全失败时 description 落英文,飞书标注「⚠️ 政治中文未改写」。
| 表 | 正确列名 | ⚠️ 旧错误 |
|---|---|---|
| news_articles | article_date | ❌ date |
| gold_prices | price_date | ❌ date |
| TIPS | gold_prices.tips_yield_10y | ❌ tips_rates 表不存在 |
-- 综合验证
SELECT
(SELECT COUNT(*) FROM news_articles WHERE article_date = '2026-08-26' AND category = 'ai') as ai,
(SELECT COUNT(*) FROM news_articles WHERE article_date = '2026-08-26' AND category = 'politics') as pol,
(SELECT COUNT(*) FROM news_articles WHERE article_date = '2026-08-26' AND category = 'github') as gh,
(SELECT COUNT(*) FROM gold_prices WHERE price_date = '2026-08-26') as gold;
~/.hermes/skills/operations/radar-data-collection/ ← cron 从这里加载 SKILL.md
- 脚本:`~/.shared-agent-skills/operations/radar-data-collection/scripts/`
- `references/9router-key-pattern.md` — 9Router key 格式说明(已过时,见上方陷阱)
⚠️ ~/.hermes/skills/.../radar-data-collection/ 只有 SKILL.md + references/,无 scripts/。
cron prompt 里引用 ~/.shared-agent-skills/.../scripts/ 是正确的。
技能名在两个目录均有,hermes 优先用 ~/.hermes/skills/ 下的版本。