你有没有遇到过这样的场景
你在公司内部系统里打开一个工单填写页,想着:"要是能直接跟它说一句话,让 AI 帮我把表单填完、提交,再确认一下结果就好了。"
或者,你负责一个 ERP 系统,每天有大量重复操作------找到入口、填数据、点提交、看结果------用户叫苦不迭,你也知道这事该自动化,但一直没有好的切入点。
又或者,你看到 AI Agent 这几年火起来,想给自家产品加一个"AI 助手",但发现市面上的方案要么太重(整套后端 RPA),要么太弱(只能回答问题,不能真的操作页面)。
这篇文章要讲的,就是一个让你的网页直接内置智能体 的方案------AutoPilot。
先聊聊阿里的 page-agent
去年阿里开源了 page-agent,方向很对:让 AI 直接操作浏览器页面,完成复杂的交互任务。
它的定位和 AutoPilot 很像------同样是纯浏览器端运行 、无需后端、BYOK(自带 API Key)架构,同样支持 OpenAI 兼容接口,同样内置 UI 面板,用一个 <script> 或 npm 包就能接入。
值得肯定的地方:
- 纯客户端设计,Agent 与用户同活在页面内部,无需服务端支持
- 内置
ask_user工具,支持人机协同(HITL)随时介入干预 - 提供 Chrome 扩展,可跨标签页执行复杂工作流
- 阿里背书,社区活跃
但在执行稳定性 和长任务可靠性上,它还有明显的短板:
| 维度 | page-agent | AutoPilot |
|---|---|---|
| 长任务拆解 | 顺序执行,每步依赖上一步结果,长链路易跑偏 | REMAINING 协议增量消费,每轮基于最新快照决策 |
| 执行稳定性保障 | 每次 LLM 调用前重新提取 DOM | 14 层收敛保护机制 |
| 任务完成验证 | 无独立验证,依赖 AI 自判 | AI 驱动的三阶段独立断言 |
| 空转/死循环 | 依赖 maxRounds 兜底 | 多维空转检测,提前识别并停机 |
| 停机可观测性 | 无结构化停机原因 | stopReason 枚举,每次停机原因清晰可查 |
其他方面,比如 Chrome 扩展跨标签页控制、HITL 人机协同等,page-agent 各有其优势,两者各有侧重。
核心差距就一句话:page-agent 能跑起来,AutoPilot 能稳定跑完。
AutoPilot 是什么
AutoPilot 是一个浏览器端原生 AI Agent SDK,让你的网页直接内置一个可以真正操作 UI 的智能体。
它不需要后端,不需要 Playwright,不需要 Puppeteer------直接运行在你的前端项目里,作为一个 npm 包引入,配上 API Key,告诉它一句话,它就开始干活。
bash
npm install agentpage
typescript
import { WebAgent } from "agentpage";
const agent = new WebAgent({
token: "your-api-key",
provider: "openai", // 也支持 deepseek / qwen / doubao / claude 等
model: "gpt-4o",
});
agent.registerTools(); // 注册内置 Web 操作工具
const result = await agent.chat("打开新建工单弹窗,填写标题为「紧急Bug」,优先级选高,然后提交");
console.log(result.reply); // AI 的最终回复
console.log(result.stopReason); // "assertion_passed" / "converged" / ...
这段代码会让 AI 真正地在你的页面上找到按钮、点击、填写表单、提交------而不是生成一段操作步骤让你自己去执行。
技术深度:为什么能"稳定跑完"
这是本文的核心。大多数 Agent 方案面临的最大问题不是"能不能执行",而是"执行过程中崩不崩、转不转圈、最后有没有真正完成"。
AutoPilot 针对这个问题做了系统性设计,下面讲最关键的四个机制。
机制一:REMAINING 协议 --- 增量任务消费
问题背景: 给 AI 一个长任务("填三个字段,提交,然后跳转到详情页验证结果"),AI 很可能在第一轮就试图把所有事情一次性规划完,但页面状态是动态变化的,第一轮的规划到第二轮就失效了。
AutoPilot 的解法: REMAINING 协议。
AI 每轮返回时,除了工具调用,还必须在回复末尾写一行:
shell
## REMAINING: <还没做的任务>
或者任务全部完成时写:
shell
## REMAINING: DONE
这样,Agent Loop 每轮只根据当前快照 来执行当前能执行的动作,然后把"剩余任务"传给下一轮,而不是靠 AI 记忆来维持状态。
实际执行流示意:
css
总任务: "填写姓名和手机号 → 点提交 → 确认成功提示"
Round 1: 快照显示表单可见
→ AI 执行: fill(姓名输入框, "张三")
→ AI 执行: fill(手机号输入框, "138xxxx")
→ REMAINING: 点提交 → 确认成功提示
Round 2: 快照显示表单已填,提交按钮可点击
→ AI 执行: click(提交按钮)
→ REMAINING: 确认成功提示
Round 3: 快照显示成功弹窗
→ AI 调用: assert({})
→ 断言通过 → stopReason: "assertion_passed"
每轮的决策基于最新 DOM 快照,不靠记忆,不靠猜测,快照驱动。
机制二:14 层收敛保护 --- 稳定而非偶然成功
"能偶尔成功"和"能稳定成功"之间,差了一套系统性的保护机制。AutoPilot 内置了 14 层,分为几大类:
① 元素定位失败的恢复
bash
元素 #abc123 未找到
→ 等待 100ms
→ 刷新快照(此时可能 DOM 已更新)
→ 重试定位,最多 2 轮
② 空转与死循环检测
typescript
// 连续多轮"只读不写"(只调 snapshot、get_text 等,没有 click/fill)
// → 触发空转检测 → stopReason: "idle_loop"
// 连续 3 轮提交了完全相同的工具调用批次
// → 触发防自转 → stopReason: "repeated_batch"
// 近 4 轮内反复在 ≤2 个元素上循环点击
// → 将这些元素加入拦截集,同时推荐周边可点击元素
③ 快照指纹变化检测
每轮执行后,AutoPilot 计算快照指纹。如果动作执行了但快照没有变化(说明点击无效),下一轮会注入强提示,强制 AI 换目标,而不是继续重复同一个无效操作。
④ 协议修复
如果 AI 的回复里忘写 REMAINING 协议(大模型偶尔会忘),Agent Loop 不会直接崩,而是注入修复提示,要求 AI 补全协议,给它一次改正机会。
⑤ 稳定等待
每轮有 DOM 变化后,自动等待:
- 检测 loading 状态消失(
.ant-spin、.el-loading-mask、.bk-loading、[aria-busy="true"]等主流组件库均已内置) - DOM 进入静默窗口(200ms 内无变化)
- 总超时兜底 4000ms
所有保护机制都有对应的 stopReason,执行结果完全可观测:
typescript
type StopReason =
| "converged" // 正常完成(REMAINING: DONE)
| "assertion_passed" // 断言全部通过
| "assertion_loop" // 断言失败后陷入死循环
| "repeated_batch" // 连续相同工具调用
| "idle_loop" // 空转检测触发
| "no_protocol" // 多轮无 REMAINING 协议
| "stale_remaining" // 任务多轮不推进
| "max_rounds" // 达到最大轮次上限
| "dry_run"; // 干运行模式
机制三:AI 驱动的三阶段断言 --- 任务是否真的完成了
问题背景: AI 执行完操作,认为自己完成了,但页面上可能出现了报错弹窗、表单校验失败、或者根本没有跳转成功。
AutoPilot 的断言不是简单的"是否有某个元素",而是让一个独立的 AI 实例(不继承 system prompt、不带 tools)去判断任务是否真正完成。
三阶段快照设计:
| 快照 | 拍取时机 | 用途 |
|---|---|---|
| Initial | 任务开始前 | 基线:判断页面是否发生了预期变化 |
| Post-Action | 工具执行完、页面稳定前 | 捕获瞬态:成功提示、确认弹窗(这些可能几秒后消失) |
| Current | 稳定后 | 最终状态:确认结果是否持久存在 |
断言 AI 拿到这三个快照,再加上已执行的操作记录,独立判断:任务描述所要求的结果,是否在页面上得到了体现?
自定义断言示例:
typescript
const result = await agent.chat("关闭开关,满意度评五星,标签选灰度", {
assertionConfig: {
taskAssertions: [
{
task: "关闭开关",
description: "开关组件不应有 is-checked class",
},
{
task: "满意度评五星",
description: "满意度 slider 的 5 个 star 均应有 is-active class",
},
{
task: "标签选灰度",
description: "灰度 checkbox 应处于 checked 状态",
},
],
},
});
不传 assertionConfig 时,默认以用户原始消息作为整体断言依据,零配置开箱即用。
断言失败不会直接停机,而是把失败信息注入上下文,让 Agent 继续重试,直到全部通过(或触发断言死循环保护)。
机制四:RefStore + 快照 --- 确定性元素定位
问题背景: 基于 CSS 选择器或 XPath 的定位方式,在动态渲染的现代前端框架中极易失效------组件库升级、动态 class 生成、条件渲染都会让选择器失效。
AutoPilot 的做法是:快照时给每个可交互节点 分配一个临时的 #hashID,存入 RefStore(一个 WeakRef 映射表)。AI 的工具调用使用 #hashID 指定目标,执行时从 RefStore 里取真实 DOM 元素。
css
快照片段(AI 看到的):
<button #a3f2 role="button">提交</button>
<input #b91c type="text" placeholder="请输入标题" />
AI 工具调用:
click({ ref: "#a3f2" })
fill({ ref: "#b91c", value: "紧急Bug" })
执行时:
RefStore.get("#a3f2") → 真实 DOM 元素 → 执行点击
#hashID 每轮快照后刷新,不跨轮复用,确保每个 ID 始终指向当前 DOM 中真实存在的元素。
5 分钟上手:从安装到运行
安装
bash
npm install agentpage
# 或
pnpm add agentpage
基础用法
typescript
import { WebAgent } from "agentpage";
const agent = new WebAgent({
token: import.meta.env.VITE_API_KEY,
provider: "deepseek", // 支持: openai / anthropic / deepseek / qwen / doubao / minimax
model: "deepseek-chat", // 性价比之选
});
// 注册所有内置 Web 工具(click / fill / navigate / wait / evaluate 等 34 种动作)
agent.registerTools();
// 监听执行过程
agent.callbacks = {
onRound: (round) => console.log(`[Round ${round + 1}]`),
onToolCall: (name, input) => console.log(` → ${name}`, input),
onToolResult: (name, result) => console.log(` ✓ ${name}`),
onText: (text) => process.stdout.write(text),
};
// 执行任务
const result = await agent.chat(
"进入用户管理页,搜索「张三」,点击第一条结果,把邮箱改成 zhangsan@example.com,保存"
);
console.log("停机原因:", result.stopReason);
console.log("总轮次:", result.metrics.rounds);
console.log("工具调用次数:", result.metrics.toolCalls);
内置 UI 面板(零依赖,开箱即用)
如果你想直接给页面加一个聊天框,不用自己写 UI:
typescript
const agent = new WebAgent({
token: "your-api-key",
provider: "openai",
model: "gpt-4o",
panel: true, // 右下角浮窗,零框架依赖
});
agent.registerTools();
// 用户在面板里输入任务,AI 直接在当前页面执行
企业落地:按路由构建 AI Skill
真实的企业应用通常有几十上百个页面,每个页面有自己的业务逻辑和操作边界。AutoPilot 支持按路由定义 AI Skill:
typescript
const routeSkills: Record<string, {
prompt?: string;
tools?: () => void;
}> = {
"/tickets": {
prompt: `你在工单列表页。
可以执行:筛选工单、查看详情、批量操作。
不允许:删除工单、修改其他人的工单。`,
},
"/deploy": {
prompt: `你在发布管理页。
执行发布操作前,必须先确认环境和版本号。
危险操作(回滚、强制发布)需要用户二次确认。`,
tools: () => {
// 注册部署专用工具
agent.registerTool(createDeployConfirmTool());
agent.registerTool(createRollbackTool());
},
},
"/reports": {
prompt: `你在报表页。只读模式,不允许任何写操作。`,
},
};
// 路由切换时更新 Skill
router.afterEach((to) => {
agent.clearCustomTools();
agent.clearSystemPrompts();
const skill = routeSkills[to.path];
if (skill) {
if (skill.prompt) agent.setSystemPrompt(skill.prompt);
skill.tools?.();
}
});
这样,AI 在每个页面都有明确的操作边界,既能发挥能力,又不会越权乱操作。
支持的 AI Provider
typescript
// OpenAI / Azure OpenAI
{ provider: "openai", model: "gpt-4o" }
// Anthropic Claude(推荐长任务场景)
{ provider: "anthropic", model: "claude-sonnet-4-20250514" }
// DeepSeek(性价比首选)
{ provider: "deepseek", model: "deepseek-chat" }
// 通义千问
{ provider: "qwen", model: "qwen-plus" }
// 豆包(字节 Ark 协议)
{ provider: "doubao", model: "doubao-1.5-pro-32k" }
// MiniMax
{ provider: "minimax", model: "MiniMax-M2.5" }
// 自定义(任何 OpenAI 兼容接口)
{
provider: "openai",
baseURL: "https://your-proxy.com/v1",
model: "your-model",
}
为什么选 AutoPilot
| 你的场景 | AutoPilot 给你的 |
|---|---|
| 想快速验证 AI Agent 方案可行性 | npm install,5 分钟跑通,不需要部署任何后端 |
| B 端系统有长流程、多步骤任务 | REMAINING 协议 + 14 层保护,长任务稳定执行 |
| 担心 AI 操作失控或越权 | 按路由 Prompt 约束 + 可观测 stopReason |
| 需要验证任务是否真正完成 | 三阶段快照断言,而不是 AI 自己说"完成了" |
| 在中国大陆部署,需要国内模型 | DeepSeek / Qwen / 豆包,全都支持 |
| 想定制 Agent 能力和 UI | 工具注册、Prompt 覆盖、面板配置,全部开放 |
结语
把 AI Agent 内嵌到网页里,不是遥远的未来,现在就可以做到。
但"能跑"和"稳定跑完"之间的差距,比想象的要大。AutoPilot 花了大量精力在稳定性和可观测性上------14 层保护机制、REMAINING 协议、三阶段断言,都是为了让 Agent 不只是偶尔成功,而是可靠地完成任务。
项目还在持续迭代中,任务后台模式、可视化调试、测试用例框架等能力都在路上。
如果这个项目对你有启发,欢迎去 GitHub 点个 ⭐ Star 支持一下,这对开源作者真的很重要!
🔗 GitHub:github.com/wenps/AutoP...
有问题、有想法,欢迎在 Issues 里交流,或者直接提 PR。