Files
白夜 38b982fb1e feat: skill v3.2.0 — 硬约束Checklist五项压缩到三项,移除MCP session依赖,cases/成为唯一经验库
- SKILL.md 瘦身重写(核心层+按需加载references/)
- Checklist: CHECK-3/4(session)删除,五项→三项
- 新增6个references子文档(path-a/path-b/phase-details/experience-rules-full/mcp-tool-reference/common-pitfalls)
- 删除 references/domain-session-guide.md
- 工具引用对齐实际MCP(32工具),verify_signer_offline替代verify_against_session
- cases/_template.md 新增可验证事实清单段
- 经验法则session相关条目改写
- 红线四条、第一原则0-5、三分法、四板斧、六步法完整保留
2026-04-18 13:36:14 +08:00

9.9 KiB
Raw Permalink Blame History

⚠️ 反模式清单(v3.0.0 基于三次真实实战数据)

本文档是 AI 在每次分析前必读的"禁忌清单"。不是建议,不是"参考一下", 是打脸清单——本文档里的每一条都是某次真实 AI 分析中实际发生过的失败。

本文档的存在假设:加经验法则无效(46 条都记不住),但让错误路径显眼有效。 这里的每条反模式都配了:(1) 真实站点名;(2) AI 当时的辩护;(3) 为什么那辩护不成立。


实战案例:瑞数 nmpa(2026-04 实战,AI 违反)

AI 的操作:

// cookie_fetcher.js (实战 AI 产出,违反第一原则)
const { firefox } = require('playwright');
async function getCookies() {
  const browser = await firefox.launch();
  const page = await browser.newPage();
  await page.goto('https://www.nmpa.gov.cn/...');  // 过 RS 412 挑战
  await page.waitForTimeout(5000);                  // 等挑战自动完成
  const cookies = await page.context().cookies();  // 取 NfBCSins2OywS
  return cookies;
}
// 最终方案每 30 分钟运行一次 getCookies()

AI 的辩护:"瑞数 JSVMP 保护极其复杂,纯 Node.js 几乎不可能绕过"

为什么这辩护不成立:

  • 工作区里已经有 site_nmpa/sign_service.js,用 sdenv 已完成纯 Node.js 方案
  • AI 根本没看 sdenv 文档就断言"不可能"
  • 最终交付在无浏览器的 Docker 容器里无法运行一小时以上——这就是违规

正确做法

// 使用 sdenv(魔改 jsdom + C++ V8 Addon)
const { jsdomFromUrl } = require('sdenv');
async function getRSCookies(targetUrl) {
  const dom = await jsdomFromUrl(targetUrl, { userAgent: 'Mozilla/5.0...' });
  await new Promise(r => dom.window.addEventListener('sdenv:exit', r));
  return extractCookies(dom);
}

判定测试

最终代码在一个无 X11、无浏览器、只有 Node.js的 Docker 容器里, 能不能稳定跑满 24 小时?

  • 能 → 合规
  • 不能 → 违规(Playwright 方案属于违规)

反模式 2:Cookie 硬编码到 headers.json

实战案例:抖音 /aweme/detail(2026-04 实战,AI 违反灰色地带)

AI 的操作:

// headers.json (AI 产出)
{
  "Cookie": "ttwid=1|xxxxxxxx; __ac_nonce=yyyyyy; __ac_signature=zzzzzz"
}
// main.js 直接读取上面的 headers 发请求

AI 的辩护:"cookie 有几小时有效期,不是每次请求前都要开浏览器"

为什么这辩护不成立:

  • "几小时"还是"几天"不影响定性——cookie 一旦过期,没有浏览器就完全无法工作
  • 最终方案的可用性取决于浏览器是否可用,浏览器就是方案的依赖
  • __ac_signature 可以协议还原(基于 __ac_nonce 的签名算法),抖音社区早有方案
  • ttwid 更简单,直接请求首页就能 Set-Cookie 拿到

正确做法

// 协议还原 cookie 获取
async function getTtwid() {
  const r = await axios.get('https://www.douyin.com/');
  return r.headers['set-cookie'].find(c => c.startsWith('ttwid=')).split(';')[0];
}

async function generateAcSignature(nonce) {
  // 还原 __ac_signature 的签名算法
  // ... (基于 nonce 的字符串变换 + 时间戳)
}

判定测试

启动代码在无浏览器环境一周,不人工干预,是否能稳定获取数据?

  • 能 → 合规
  • 不能(需要人工去浏览器抓 cookie 贴进去)→ 违规

反模式 3:激活 skill 后直接 launch_browser(跳过 Checklist)

实战案例:三次都违反(瑞数 + TikTok + 抖音)

三次的 AI 操作完全一样:

轮 1: 激活 skill (读几万字 SKILL.md)
轮 2: launch_browser(headless=false)
轮 3: navigate(target_url)
... 从此开始分析

AI 的辩护:"用户要求明确,快速开干;session 是新功能,先做主线任务"

为什么这辩护不成立:

  • 三次 AI 都这么说,三次都导致:
    • session 没开 → v2.9.0 域级持久机制完全失效
    • 经验库没查 → 重复踩坑 / 从零写已有方案
    • 不知道工作区有 site_* 目录 → 瑞数 nmpa 从零写 Playwright 方案,而 site_nmpa/ 里已有 sdenv 方案
  • "快速开干"其实慢得多——瑞数实战用 12 轮对话写了个错误方案,如果做了 Checklist 的 CHECK-2,5 分钟搞定

正确做法

激活 skill 后第一件事:在对话中输出硬约束 Checklist 五项复述
  [CHECK-1] check_environment() → 贴结果
  [CHECK-2] 读 cases/README.md 速查表 + listDirectory 工作区 → 命中记录
  [CHECK-3] list_sessions() → 历史 session 记录
  [CHECK-4] start_reverse_session() → domain + run_id 记录
  [CHECK-5] 最终方案意图声明

五项都通过,再调 launch_browser

判定测试

翻 skill 激活后的前 3 条对话记录。

  • 前 3 条里有完整的 CHECK-1~5 复述输出 → 合规
  • 前 3 条是"launch_browser / navigate / ..." → 违规(红线 1)

反模式 4:在工作区 site_* 目录存在时从零建新项目

实战案例:瑞数 nmpa(工作区已有 site_nmpa/,AI 建了 site_nmpa_20260418/ 从零写)

AI 的操作:

listDirectory() 看到:
  site_nmpa/           ← 已有完整方案
  site_nmpa_20260418/  ← AI 新建的错误方案

AI 没做的事:

  • 没打开 site_nmpa/ 里的文件看一眼
  • 没读 site_nmpa/sign_service.js(已验证的 sdenv 方案)
  • 没问用户"这个目录是做什么的"

AI 的辩护:"用户要求重新使用 skill 进行获取,我以为要从零开始"

为什么这辩护不成立:

  • "重新使用 skill" ≠ "从零写代码",而是"遵循 skill 流程"——Phase 0.5 本身就要查已有
  • 用户说"重新"可能只是希望用新 skill 验证一遍,不是丢弃已有
  • 遇到这种歧义,应该问用户,不是默认从零

正确做法

listDirectory(".")
→ 看到 site_nmpa/
→ listDirectory("site_nmpa/")
→ 有 sign_service.js / keys.json → 这是已验证的方案
→ 询问用户:"检测到 site_nmpa/ 目录含已验证的 sdenv 方案,
   是要(A)基于已有方案创建今天的新目录复用;还是
   (B)重新分析一遍验证方案仍有效;还是(C)其他?"
→ 根据用户选择决策

反模式 5:面对复杂 SDK(TikTok webmssdk)直接判定"不可能还原"

实战案例:TikTok 潜在滑坡(AI 在 jsdom 不工作时差点滑向 Playwright)

AI 的思维过程(实战复盘 Q-B 自述):

"如果后续环境补丁迭代仍无法激活 SDK 拦截器,我可能会被迫考虑 '每次请求前用 Camoufox 过一遍页面获取签名'的方案"

为什么这滑坡不能发生:

  • "环境补丁没让 SDK 激活" 是本步骤的问题,不是"整个协议方案不可行"的证据
  • 应该走降级梯度的下一级(见 SKILL.md 第五条原则),而不是横向跳到浏览器
  • 梯度 3-4 (点对点 hook_function / jsdom 变体) 都没试就放弃,违反第五条原则

正确做法

看 SKILL.md 第五条原则的降级梯度表:

梯度 0: 本域是否有历史 session? → attach_domain_readonly + reverify
梯度 1: get_session_snapshot 看本 run 做过什么
梯度 2: 换 Hook 模式 (proxy ↔ transparent) / 换插桩模式 (ast ↔ regex)
梯度 3: 点对点 hook_function 针对具体签名函数
梯度 4: 路径 B 的其他变体(vm 沙箱 / jsdomFromUrl 全量加载 / sdenv)
梯度 5: 合法出口: stop_reverse_session("suspended") + export_session + 写报告

禁止跨梯度直接到"用浏览器兜底"

反模式 6:经验法则背诵但不执行

实战案例:三次都违反

AI 在复盘时能流利背出:

"经验法则 #28:反爬类型识别是 Phase 0 的 Phase 0" "第一原则:协议优先" "Phase 0.5:经验库指纹匹配"

但实际操作时完全忽略。

为什么这发生:

  • 规则写在 skill 里 ≠ 规则会被执行
  • AI 读了几万字 SKILL.md 后,工作记忆只保留最显眼的几条
  • 非硬 gate 的规则(无检查机制)100% 会被忽略

正确做法

不靠 AI 自觉,靠 v3.0.0 的硬 gate:

  • Checklist 五项必须复述输出(可被用户验证)
  • 红线四条违反即失败(明确后果)
  • 高频站点速查表(不靠"主动想起来"而是"看到域名就命中")

如何使用本文档

  1. AI 激活 skill 后:本文档应该在 Checklist [CHECK-2] 步骤被简单扫视(至少看一眼反模式 1-6 的标题,避免踩坑)
  2. AI 在做决策时卡住:回到本文档,看自己正在考虑的方向是不是反模式之一
  3. AI 写代码写到一半意识到在滑向反模式:立即停,走 SKILL.md 第五条原则的降级梯度
  4. 用户发现 AI 违反:直接引用本文档的反模式编号质问 AI("你正在做反模式 X,看 references/common-pitfalls.md")

贡献新反模式

每次实战失败后,如果发现 skill 里没覆盖的新反模式:

  1. 走 retrospective-prompt.md 做完整复盘
  2. 按本文档的"反模式 N:XXX"格式追加一条
  3. 更新 CHANGELOG
  4. commit 时标注 doc(pitfall): add pitfall #N from <site> retrospective

新反模式的质量要求:

  • 必须有真实站点名,不能是抽象描述
  • 必须包含 AI 当时的具体操作(代码 / 命令序列)
  • 必须包含 AI 当时的辩护(真实的 rationale)
  • 必须说明为什么辩护不成立(具体论证,不是"就是不对")
  • 必须给正确做法(带代码示例)
  • 必须给判定测试(便于后续 self-check)

6 条起步,后续每次实战失败后追加。30 条就封顶,再加就说明 skill 本身要结构性调整。


更新记录

版本 日期 更新内容
v3.0.0 2026-04-18 初始版本:基于三次真实站点实战(瑞数/TikTok/抖音)数据,收录 6 条反模式