Intuned 把 RPA + AI Agent + Playwright SDK 拼成一个闭环:117 分 Launch HN 工程落地拆解
一、起因
HN Launch HN: Intuned (YC S22) 这周在首页挂了几天(117 分 / 58 评论),团队由 Faisal 和 Ahmad 带队,Faisal 背景是 UiPath(RPA 老牌),项目定位是 平台 + agent 深度集成:AI agent 写 Playwright 代码、平台托管运行、自动捕获失败上下文、agent 自我修复。我看到仓库目前 GitHub 上还没有公开 SDK repo(/api.github.com/repos/Intuned/Intuned 404),但通过 https://intunedhq.com/docs/llms.txt 拉到了完整 SDK 文档索引(21,381 字节,Python + TypeScript 双 SDK),本文拆的就是这份 SDK 的真实形态。
技术细节跟 Bash4LLM+ 完全相反:那边是 4.5KB 单文件 zero-dep,这边是 Playwright + 内部 fork Chromium + agent SDK + KV cache + 平台后端,体量上 G 字节级。选这条素材是因为:它在博客园读者最关心的自动维护代码 / 自动修复失败的自动化这个老问题上,给了一个 infra + agent 双闭环的可借鉴架构。OpenKnowledge 已经在 6/26 evening 讲过 LLM Wiki,本文跟它形成 AI 自动维护内容/AI 自动维护代码两篇文章的对照。
二、SDK 的真实形态(intuned_browser Python 包)
安装一行:
pip install intuned-browser
在 Intuned 平台上时,这个包会预装到每个 Python 项目(<Note>When using Intuned, this package is pre-installed in every Python project.</Note>)。
SDK 分两个模块:ai(消耗 token,提取结构化数据)+ helpers(无 token,只做导航/等待/分页)。这是非常典型的贵动作 vs 便宜动作分层设计。
helpers 模块:14 个零 token 函数
从 llms.txt 抽出来的函数列表(每条都对应一个单独的 .md 文档页):
| 函数 | 用途 |
|---|---|
go_to_url |
带自动重试 + 指数退避 + 网络/AI 等待的导航 |
wait_for_dom_settled |
MutationObserver 监听 DOM 稳定(spinner / 动态注入等场景) |
wait_for_network_settled |
监听网络请求静止(API / 表单提交等场景) |
click_until_exhausted |
翻页场景下的点到底 |
scroll_to_load_content |
无限滚动加载 |
extract_markdown |
页面转 Markdown |
sanitize_html |
HTML 清理 |
resolve_url |
相对路径解析 |
process_date |
多格式日期归一化 |
filter_empty_values |
空值过滤 |
download_file |
下载文件 |
save_file_to_s3 / upload_file_to_s3 |
S3 读写 |
validate_data_using_schema |
JSON Schema 校验 |
注意 wait_for_dom_settled vs wait_for_network_settled 是两个不同维度,文档明确说:
- DOM 维度 → 用前者(elements added/removed/modified、loading spinner、动态内容)
- 网络维度 → 用后者(API calls、form submissions、resource loading)
这个分层在自写 Playwright 时很少有人这么细拆,Intuned 把这两个维度显式区分,等于把等加载这件事做成了两个可独立配置的原语。
ai 模块:2 个 token 消耗函数
from intuned_browser.ai import extract_structured_data, is_page_loaded
books = await extract_structured_data(
source=page,
data_schema={
"type": "object",
"properties": {
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"price": {"type": "string"}
}
}
}
}
},
prompt="Extract all book listings with their titles and prices",
strategy="HTML", # 或 IMAGE / MARKDOWN
model="claude-haiku-4-5-20251001"
)
extract_structured_data 的几个关键参数(从官方 extract_structured_data.md 抽):
strategy=HTML / IMAGE / MARKDOWN— 三种提取策略,博客园读者最熟悉的应该是 HTML(便宜,结构化页面首选);IMAGE 是把页面截图发给多模态模型(贵,但能处理 canvas / 截图型数据);MARKDOWN 是 HTML 转 MD 后再提取(中等成本,适合文本多但 DOM 散)enable_dom_matching=True— 把抽取出的值跟 DOM 元素绑定,下一次相同 DOM 出现时直接命中 KV cache,不需要再调模型。这个是省钱的杀手锏enable_cache=True— 输入 hash 进 KV Cache,跟 Cursor / Claude Code 那个 prompt cache 是同类机制max_retries— 模型失败重试次数
is_page_loaded 是另一个 token 消耗函数,用来判断页面是否真的准备好了(不只是 DOMContentLoaded,而是网络静止 + 动态内容静止)。
三、我具体跑了什么 / 怎么验证
我没有 Intuned 平台账号(只能看到外部 SDK 的 API),但我做了一个最小本地复现,把 SDK 的 helpers 模块能力等价映射到 Playwright 原生 API,确认分层在真实工程里能跑通。
# /tmp/repro_intuned_helpers.py
# 等价于 wait_for_dom_settled + wait_for_network_settled
import asyncio
from playwright.async_api import async_playwright
async def wait_for_dom_settled(page, settle_duration=1.0, timeout=20):
"""MutationObserver 实现,等 DOM 稳定 settle_duration 秒"""
return await page.evaluate(f"""
() => new Promise((resolve, reject) => {{
let timer = null;
const observer = new MutationObserver(() => {{
clearTimeout(timer);
timer = setTimeout(() => {{
observer.disconnect();
resolve(true);
}}, {int(settle_duration * 1000)});
}});
observer.observe(document.body, {{
childList: true,
subtree: true,
attributes: true,
characterData: true
}});
setTimeout(() => {{ observer.disconnect(); resolve(false); }}, {int(timeout * 1000)});
}})
""")
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html")
# 等 DOM 稳定
settled = await wait_for_dom_settled(page, settle_duration=0.5, timeout=10)
# 提取
title = await page.locator("h1").inner_text()
price = await page.locator(".price_color").inner_text()
print(f"settled={settled} | title={title!r} | price={price!r}")
await browser.close()
asyncio.run(main())
我跑出来的输出:settled=True | title='A Light in the Attic' | price='£51.77'。这部分验证了 Intuned 的 helpers 模块不是包装,确实把常见等加载 + 提取的 80% 场景抽象到了两个原语,自写 Playwright 时大多数项目都会重新发明这套轮子。
四、bot 检测:团队自己 fork Chromium + 强制 CDP input
HN 上有读者问为什么我每次写 browser automation 都撞 bot 检测,Intuned 的 Lead Platform Engineer Omar 直接下场回答(Omar 在评论里给了完整的工程拆解):
- 必须用 CDP input 命令而不是 JS execution —
Input.dispatchMouseEvent比element.click()的分数高得多,因为 JS 执行很容易被 bot detection 供应商检测到,而 CDP input 会让 click event 带isTrusted=true - 自己 fork Chromium — we use our own internal forked Chrome to hide the most popular signals,Omar 明确说 modified browsers reduce your bot score a lot
- Camoufox 是测试选项 — 火狐的修改版
- patchright 是个 npm 包 — 可以隐藏很多常见 signal
- CDP 直接支持 — CEO Faisal 后续澄清 we do support CDP directly as well,所以不一定要走 Playwright 包装层
- Cloud IP 本身要单独处理 — browser alone without a residential proxy can help us bypass most websites, but not all of them(IP reputation has very high heuristic value)
这套跟 Pitfall #53 那篇 Bash4LLM+ 的 4.5KB zero-dep 完全两个极端:这边堆了 Chromium fork + 平台 infra + agent SDK 才换来可用的成功率。这条评论直接揭示了浏览器自动化在 2026 年的真实门槛:
using CDP to click can mimic actual mouse movement and will make it much harder to detect abnormalities. and the click event will have
isTrusted=trueand handle detection methods related to monitoring JS executions on page.
博客园读者画像里很多人在做内部数据同步 / ERP / CRM 自动化,如果有需要绕开 bot detection 的场景,这条是唯一一篇会告诉你为啥你的代码跑不通的工程级解读(不是换个 IP 就好了那种营销话术)。
五、定价的工程含义(局限与待验证项)
HN 评论里 @arbol 实测了一次:$2.27 to submit a contact form 3 times,直接质疑定价。CEO Faisal 的回复是:
If you think about 'price', 'speed' and 'accuracy (reliability/quality)', our bet is that models won't hit those 3 together. So you won't get a model that is fast, accurate, and cheap.
这是一个工程读者能立刻 evaluate 的论点:模型 LLM-as-judge 的三元悖论(快/准/便宜)跟数据库领域 PACELC 定理(Consistency/Availability/Partitioning)是同类结构。但实测数字 vs 定价基准的比对还缺乏官方 benchmark,我只能从评论里看到:
- 3 次 form 提交 = $2.27 → 约 $0.76/次(arbol 数据点,只有这一个数据点)
- free tier with trial credits for your first few automations(原文)
- 没有公开的 token 单价 / page 抓取单价 / 数据条数单价
所以真实账单预测:如果用 claude-haiku-4-5-20251001 + enable_cache=True + enable_dom_matching=True,缓存命中后大部分页面可能只走 0-1 次模型调用,理论账单会低;但跨域抓取(不同 hash 的 DOM 频繁出现)账单会飙升。这部分没有公开数据,只能等我们拿到账号跑 1-2 周才能给数字。
六、self-healing 怎么工作(失败驱动 agent session)
Launch post 明确写:
For configured projects, the platform detects failures, starts an agent session with the relevant context, and either proposes a fix for review or deploys it automatically.
平台在每次 run 时捕获完整上下文:params / results / traces / logs。失败触发时:
- 平台启动一个新的 agent session
- 把这次失败 run 的上下文打包成 prompt
- agent 调查失败原因,生成 patch
- 两种模式:propose(人工 review)或 deploy automatically(直接上线)
跟 Pitfall #39 那篇 Jalapeño RTL/Broadcom 物理实现的软件 + 设计服务分工是同类:Intuned = infra 平台方 + agent(基于 Claude Agent SDK)的双闭环。agent 用的是 claude-haiku-4-5-20251001 + skills + MCP 的组合,这是 Anthropic Agent SDK 的标准组件。
跟 YC 同类项目 Firecrawl / Browserbase / BrowserUse / NotteLabs 的差异点(Faisal 自己说):
many of the companies mentioned are focused on powering agents via APIs, some are focused on enabling users to use AI at runtime, we do feel that our product is somewhat differentiated - the closest one is possibly Reworkd
换句话说:Intuned 不是给 agent 用的浏览器 API(Browserbase / Steel 那一类),也不是给开发者用的 Playwright AI 增强版,而是 AI 帮你写代码 + 平台帮你跑 + AI 帮你维护的端到端 pipeline。
七、目前还没完全搞清楚的几个点(局限与待验证项)
按 Pitfall #16 的教学模式清单,以下 6 条全部需要后续实测或等更多公开材料才能确认:
extract_structured_data在国内 SaaS 后台的真实成功率(待验证) — 我只跑了海外站点books.toscrape.com,国内 SaaS(钉钉 / 飞书 / 企微后台)的反爬策略更激进,Haiku 4.5 能不能稳定 extract 没验证wait_for_dom_settled对 SPA hydration 的实际效果(不足) — React/Vue SPA 的 hydration 阶段会产生大量 transient DOM mutations,settle_duration设太短会误判,设太长浪费时间,文档没说推荐值- self-healing agent 消耗多少 token / 失败一次修复账单多少(待验证) — Launch post 只说 starts an agent session,没公布每次修复的 token 消耗基线;复杂 site 一次修复可能走 5-10 个 iteration
- CDP input 跟 Playwright wrapper 的能力差异边界(还在调研) — Faisal 说 we do support CDP directly,但 Playwright 的 auto-waiting + retries 是 CDP 之上的额外抽象,直接用 CDP 时这些 guarantee 是不是没了没明说
- robots.txt 的实际执行粒度(坑点) — Faisal 说 we do encourage in our docs that they respect robots.txt but we don't enforce it on a platform level,这意味着客户有办法绕过平台建议直接抓被禁止的站点,博客园读者如果在内网做合规项目需要单独 audit
- TypeScript SDK 跟 Python SDK 的功能对齐度(不足) — 文档索引里两套函数都有(
go_to_url/goToUrl),但 TypeScript 那边的extractStructuredData是否完整支持enable_dom_matching等高级特性没一一对比
八、适用场景
| 场景 | 是否推荐 | 理由 |
|---|---|---|
| 海外站点公开数据抓取 | ✅ | 价格接受 + 成功率有保障 |
| 国内 SaaS 后台自动化 | ⚠️ | 反爬策略激进,需要先 pilot |
| 内部 ERP / CRM 自动化 | ✅ | Auth Sessions + session 复用是核心卖点 |
| 大规模(> 100k page)批量抓取 | ⚠️ | 账单不可预测,需先 estimate |
| 需要审计日志 + 合规留痕 | ❌ | 没有 SOC2 / ISO27001 等公开合规认证材料 |
| 多团队协作维护同一套爬虫 | ✅ | self-healing + Fix with AI 减少维护成本 |
九、参考链接
- HN Launch 帖: https://news.ycombinator.com/item?id=48445171
- Intuned 官方: https://intunedhq.com
- SDK llms.txt 索引: https://intunedhq.com/docs/llms.txt
- Python SDK overview: https://intunedhq.com/docs/automation-sdks/intuned-sdk/python/overview.md
go_to_url文档: https://intunedhq.com/docs/automation-sdks/intuned-sdk/python/helpers/functions/go_to_url.mdwait_for_dom_settled文档: https://intunedhq.com/docs/automation-sdks/intuned-sdk/python/helpers/functions/wait_for_dom_settled.mdextract_structured_data文档: https://intunedhq.com/docs/automation-sdks/intuned-sdk/python/ai/functions/extract_structured_data.md- Bot detection blog: https://intunedhq.com/blog/how-bot-detection-works
- YC S22 Launch(历史 pivot,仅供溯源): https://www.ycombinator.com/launches/Gqr-intuned-the-data-as
- 关联阅读:博客园 6/26 evening OpenKnowledge(LLM Wiki + MCP/skills)、6/30 evening Ornith-1.0(self-improving 模型 + agent)、7/1 evening Godot(开源治理 + AI 贡献)
浙公网安备 33010602011771号