- 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、三分法、四板斧、六步法完整保留
9.9 KiB
⚠️ 反模式清单(v3.0.0 基于三次真实实战数据)
本文档是 AI 在每次分析前必读的"禁忌清单"。不是建议,不是"参考一下", 是打脸清单——本文档里的每一条都是某次真实 AI 分析中实际发生过的失败。
本文档的存在假设:加经验法则无效(46 条都记不住),但让错误路径显眼有效。 这里的每条反模式都配了:(1) 真实站点名;(2) AI 当时的辩护;(3) 为什么那辩护不成立。
反模式 1:用 Playwright 过反爬挑战取 cookie 作为最终方案
实战案例:瑞数 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 五项必须复述输出(可被用户验证)
- 红线四条违反即失败(明确后果)
- 高频站点速查表(不靠"主动想起来"而是"看到域名就命中")
如何使用本文档
- AI 激活 skill 后:本文档应该在 Checklist [CHECK-2] 步骤被简单扫视(至少看一眼反模式 1-6 的标题,避免踩坑)
- AI 在做决策时卡住:回到本文档,看自己正在考虑的方向是不是反模式之一
- AI 写代码写到一半意识到在滑向反模式:立即停,走 SKILL.md 第五条原则的降级梯度
- 用户发现 AI 违反:直接引用本文档的反模式编号质问 AI("你正在做反模式 X,看 references/common-pitfalls.md")
贡献新反模式
每次实战失败后,如果发现 skill 里没覆盖的新反模式:
- 走
retrospective-prompt.md做完整复盘 - 按本文档的"反模式 N:XXX"格式追加一条
- 更新 CHANGELOG
- 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 条反模式 |