Page-Agent - 完整学习教程
Page-Agent - 完整学习教程
教程级别: 从零到一 预计学习时间: 6-8 小时 前置知识: JavaScript/TypeScript 基础、HTML/DOM 基础、了解 LLM API(OpenAI 兼容接口)的基本使用 基于版本: v1.7.1
环境搭建指南
系统要求
- 操作系统: macOS / Windows / Linux(任意现代操作系统)
- 运行时/依赖版本:
- Node.js >= 18.0.0(npm 方式安装)
- 现代浏览器:Chrome、Firefox、Edge、Safari(需要支持 ES2020+)
- 一个 OpenAI 兼容的 LLM API Key(推荐 Qwen、OpenAI、DeepSeek 或本地 Ollama)
安装步骤
方式一:CDN 一行引入(最快体验,适合快速评估)
在任意 HTML 页面的 <head> 或 <body> 底部添加:
<!-- 使用全球 CDN -->
<script src="https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js" crossorigin="true"></script>
或者使用中国镜像:
<!-- 使用中国镜像(速度更快) -->
<script src="https://registry.npmmirror.com/page-agent/1.7.1/files/dist/iife/page-agent.demo.js" crossorigin="true"></script>
注意:Demo 版本使用阿里云提供的免费测试 LLM(Qwen 3.5 Plus),仅供技术评估使用,不适合生产环境。
方式二:npm 安装(推荐用于正式项目)
# 在项目目录中初始化(如已有 package.json 可跳过)
npm init -y
# 安装 page-agent
npm install page-agent
方式三:Bookmarklet(无需任何安装,适合即时体验)
访问 Page-Agent 官网 https://alibaba.github.io/page-agent/ ,将页面上的 Bookmarklet 拖拽到浏览器书签栏。然后在任意网页点击该书签即可注入 Agent。
验证安装
验证 CDN 方式:
创建一个测试 HTML 文件 test-page-agent.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Page-Agent 测试</title>
</head>
<body>
<h1>Page-Agent 安装验证</h1>
<button id="test-btn">点击我</button>
<input type="text" id="test-input" placeholder="输入一些文字">
<p id="result"></p>
<!-- 引入 Page-Agent Demo 版本 -->
<script src="https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js" crossorigin="true"></script>
<script>
// 验证 Page-Agent 是否加载成功
document.getElementById('test-btn').addEventListener('click', () => {
document.getElementById('result').textContent = '按钮被点击了!Page-Agent 运行正常。';
});
</script>
</body>
</html>
用浏览器打开该文件,如果页面右下角出现 Page-Agent 的交互面板,说明安装成功。
验证 npm 方式:
# 在项目目录中执行
node -e "const { PageAgent } = require('page-agent'); console.log('Page-Agent 加载成功,版本:', require('page-agent/package.json').version);"
预期输出:
Page-Agent 加载成功,版本: 1.7.1
第一部分:入门篇
1.1 理解 Page-Agent 的核心概念
概念讲解:
Page-Agent 的核心思想是让网页"自己具备 AI 能力",而不是从外部去控制它。传统自动化工具(如 Selenium、Playwright)像是一个遥控器,从浏览器外面操控页面。Page-Agent 则是把 AI 直接"种"在页面里。
Page-Agent 的工作流程可以用一句话概括:用户说一句话 -> Agent "看"一眼页面 -> Agent 思考该怎么做 -> Agent 像人一样操作页面元素。
这个过程的核心有三个环节: 1. "看"页面:通过 HTML 脱水(HTML Dehydration)技术,将复杂的 DOM 树压缩为 LLM 能理解的精简文本 2. "思考"怎么做:将精简文本发送给 LLM,LLM 返回结构化的操作指令 3. "操作"页面:按照指令模拟人类的鼠标和键盘事件
代码示例:
最简单的使用方式 -- CDN 引入后自动出现交互面板:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Page-Agent 最简示例</title>
</head>
<body>
<!-- 这是一个普通的网页,有一些可交互的元素 -->
<h1>欢迎体验 Page-Agent</h1>
<p>在右下角的输入框中输入指令,例如:</p>
<ul>
<li>"点击下面的按钮"</li>
<li>"在输入框中输入 Hello World"</li>
<li>"选择下拉框的第二项"</li>
</ul>
<button onclick="alert('你通过 Agent 点击了按钮!')">测试按钮</button>
<br><br>
<input type="text" placeholder="测试输入框">
<br><br>
<select>
<option>选项一</option>
<option>选项二</option>
<option>选项三</option>
</select>
<!-- 一行引入 Page-Agent(使用免费 Demo LLM) -->
<script src="https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js" crossorigin="true"></script>
</body>
</html>
执行结果:
打开页面后,右下角会出现一个浮动的交互面板。在输入框中输入"点击测试按钮",Agent 会: 1. 扫描页面 DOM,识别出按钮元素 2. 将页面状态发送给 LLM 进行推理 3. 在按钮上模拟人类的点击事件序列 4. 弹出"你通过 Agent 点击了按钮!"的提示框
练习题:
- 修改上面的 HTML,添加一个密码输入框和一个提交按钮,然后尝试用自然语言让 Agent "在密码框中输入 123456 并点击提交按钮"。
- 观察当页面有多个按钮时,Agent 如何区分它们(提示:关注 Agent 的索引编号机制)。
1.2 使用 npm 方式集成 PageAgent
概念讲解:
在 1.1 中我们体验了 CDN 方式,它适合快速原型和评估。但在实际项目中,我们需要通过 npm 安装并使用 PageAgent 的编程 API(Programmatic API),这样可以: - 完全控制 Agent 的行为和外观 - 自定义 LLM 提供商和模型 - 将 Agent 嵌入到自己的 UI 组件中 - 在生产环境中使用自己的 LLM API Key
PageAgent 类是库的主入口。创建一个 PageAgent 实例需要配置三个核心参数:model(模型名称)、baseURL(LLM API 地址)和 apiKey(API 密钥)。这些参数遵循 OpenAI 兼容 API 的格式。
代码示例:
// app.ts - 使用 npm 包方式的完整示例
import { PageAgent } from 'page-agent'
// 第一步:创建 Agent 实例,配置 LLM 连接
const agent = new PageAgent({
// 指定要使用的 LLM 模型名称
model: 'qwen3.5-plus',
// LLM API 的基础地址(OpenAI 兼容格式)
// 这里使用阿里云 DashScope 作为示例
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
// 你的 API Key(请替换为你自己的密钥)
apiKey: 'sk-your-api-key-here',
// Agent 使用的语言(影响 UI 面板和提示词语言)
language: 'zh-CN',
// 最大执行步数(防止无限循环)
maxSteps: 20,
})
// 第二步:执行自然语言指令
async function runDemo() {
try {
// Agent 会扫描当前页面的 DOM,理解页面结构,
// 然后模拟人类操作来完成任务
const result = await agent.execute('点击页面上的第一个按钮')
console.log('任务执行结果:', result)
} catch (error) {
console.error('任务执行失败:', error)
}
}
// 第三步:触发执行(例如绑定到一个按钮点击事件)
document.getElementById('run-agent-btn')?.addEventListener('click', runDemo)
使用 OpenAI 作为 LLM 的配置:
import { PageAgent } from 'page-agent'
const agent = new PageAgent({
model: 'gpt-4.1',
baseURL: 'https://api.openai.com/v1',
apiKey: 'sk-your-openai-key-here',
language: 'en-US',
maxSteps: 15,
})
await agent.execute('Fill the username field with admin and click login')
使用本地 Ollama 作为 LLM(完全离线,数据不出本机):
import { PageAgent } from 'page-agent'
const agent = new PageAgent({
model: 'qwen3.5:4b', // Ollama 中的模型名称
baseURL: 'http://localhost:11434/v1', // Ollama 的本地 API 地址
apiKey: 'ollama', // Ollama 不需要真实 API Key,随便填
language: 'zh-CN',
maxSteps: 10,
})
await agent.execute('点击页面上的搜索按钮')
执行结果:
任务执行结果: { success: true, text: "已成功点击页面上的第一个按钮" }
注意事项:
apiKey不要硬编码在代码中,推荐使用环境变量或后端代理- Ollama 本地模型需要至少 9B 参数才能较好地处理 Page-Agent 的复杂工具调用 schema,4B 模型的 JSON 输出经常格式错误
maxSteps建议设置在 10-30 之间,过低可能导致复杂任务无法完成,过高可能浪费 LLM 调用费用
练习题:
- 分别配置使用 DeepSeek(
https://api.deepseek.com/v1)和本地 Ollama 作为 LLM 后端,对比两者对同一指令的响应速度和准确度。 - 测试将
maxSteps设置为 3,观察当 Agent 无法在 3 步内完成任务时的行为(它会如何处理)。
第二部分:进阶篇
2.1 理解 HTML 脱水与 DOM 感知
概念讲解:
在入门篇中我们学会了如何让 Agent 执行简单的点击和输入操作。但要真正理解 Page-Agent 的工作原理并写出高效的指令,需要理解它如何"看"页面。
Page-Agent 不会截图然后交给视觉模型分析,而是将 DOM 树"脱水"(Dehydration)成一段精简文本,发送给文本 LLM。这个过程类似于把一棵枝繁叶茂的树去掉叶子和小枝,只保留主干和关键节点。
脱水后的文本格式如下:
[0]<button>提交</>
[1]<input type=text placeholder=请输入用户名 />
[2]<a href="/help">帮助中心</>
当前有 3 个待处理任务
[3]<select>
[3.1]<option>选项A</>
[3.2]<option>选项B</>
每个可交互元素被赋予一个 [index] 编号。LLM 通过索引引用元素(如"点击 [0]"),Agent 根据索引找到对应的 DOM 元素并执行操作。
理解这一点非常重要,因为:
- 你可以通过 data-page-agent-ignore 属性让 Agent 忽略某些元素
- Agent 只能操作被它识别为"可交互"的元素
- 良好的语义 HTML 和 ARIA 标记会显著提升 Agent 的准确率
代码示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>DOM 感知演示</title>
</head>
<body>
<h2>用户注册表单</h2>
<!-- 良好的 ARIA 标记让 Agent 更容易识别 -->
<form id="register-form">
<label for="username">用户名</label>
<input type="text" id="username" name="username"
aria-label="用户名输入框" placeholder="请输入用户名">
<label for="email">邮箱</label>
<input type="email" id="email" name="email"
aria-label="邮箱输入框" placeholder="请输入邮箱">
<label for="password">密码</label>
<input type="password" id="password" name="password"
aria-label="密码输入框" placeholder="请输入密码">
<button type="submit" aria-label="注册按钮">注册</button>
</form>
<!-- 这个元素会被 Agent 忽略 -->
<div data-page-agent-ignore>
<p>这是内部调试信息,Agent 不会看到这些内容。</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js" crossorigin="true"></script>
</body>
</html>
在 Agent 面板中输入:"帮我在表单中填写注册信息,用户名 testuser,邮箱 test@example.com,密码 abc123,然后点击注册按钮"。
执行结果:
Agent 会按顺序: 1. 在用户名输入框中输入 "testuser" 2. 在邮箱输入框中输入 "test@example.com" 3. 在密码输入框中输入 "abc123" 4. 点击"注册"按钮
带有 data-page-agent-ignore 的调试信息区域不会被 Agent 看到,也不会被操作。
注意事项:
- 坑点 1:不可见元素不会被识别。 如果元素设置了
display: none或visibility: hidden,Agent 的 DOM 扫描会跳过它。如果需要 Agent 操作一个当前隐藏的元素,需要先让它变为可见(例如展开一个折叠面板)。 - 坑点 2:动态加载的内容需要等待。 如果页面使用了懒加载或异步渲染,Agent 在扫描 DOM 时可能看不到尚未渲染的元素。此时可以让 Agent 先执行滚动操作触发加载,或使用
wait等待。 - 坑点 3:纯 CSS 交互元素可能被遗漏。 如果一个
div仅通过 CSScursor: pointer和 JS 事件监听器实现点击,Agent 可能无法可靠地识别它。建议使用语义化标签(button、a)或添加 ARIA 属性。
练习题:
- 创建一个包含 10 个不同类型交互元素(按钮、链接、输入框、下拉框、复选框、单选按钮等)的页面,让 Agent 执行一个涉及所有元素类型的综合操作指令。
- 在页面上添加一个隐藏的
div(display: none),尝试让 Agent 操作它,观察会发生什么。
2.2 自定义配置与多模型支持
概念讲解:
在实际项目中,我们通常需要对 Agent 进行更精细的配置。Page-Agent 提供了丰富的配置选项,包括 LLM 模型选择、系统提示词自定义、最大步数控制等。
关键配置项:
model:LLM 模型名称,如gpt-4.1、qwen3.5-plus、deepseek-chatbaseURL:OpenAI 兼容 API 的基础地址apiKey:API 密钥language:界面和提示词语言(en-US或zh-CN)maxSteps:最大执行步数(默认值和推荐值因场景而异)systemPrompt:自定义系统提示词,可以约束 Agent 的行为范围
代码示例:
import { PageAgent } from 'page-agent'
// 创建一个用于 CRM 系统的定制化 Agent
const crmAgent = new PageAgent({
model: 'qwen3.5-plus',
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
apiKey: 'sk-your-api-key',
// 自定义系统提示词,约束 Agent 的操作范围
systemPrompt: `你是一个 CRM 系统的操作助手。
你的任务是帮助用户完成客户信息管理操作。
规则:
1. 只操作客户信息相关的表单和按钮
2. 不要修改系统设置或管理员相关页面
3. 删除操作前必须先向用户确认
4. 如果遇到不确定的操作,使用 ask_user 工具询问用户`,
language: 'zh-CN',
maxSteps: 25, // CRM 操作通常步骤较多
})
// 执行 CRM 相关操作
await crmAgent.execute('在客户列表中搜索"张三",然后将他的联系方式更新为 13800138000')
使用后端代理保护 API Key:
// 在生产环境中,不建议将 API Key 暴露在前端代码中
// 推荐通过后端代理转发 LLM 请求
import { PageAgent } from 'page-agent'
const agent = new PageAgent({
model: 'gpt-4.1',
// 指向你自己的后端代理地址
baseURL: '/api/llm-proxy',
// 后端通过 cookie 或 token 鉴权,不需要真实 API Key
apiKey: 'authenticated',
language: 'zh-CN',
maxSteps: 20,
})
await agent.execute('帮我填写本周的周报')
执行结果:
// CRM Agent 执行结果示例
{ success: true, text: "已找到客户张三,联系方式已更新为 13800138000" }
注意事项:
- 坑点 1:API Key 安全。 前端代码中的 API Key 对用户是可见的。生产环境务必使用后端代理。作者在 HN 讨论中明确建议:"如果你打算将 Agent 集成到 Web 应用中,最好通过 cookie 或类似方式鉴权的代理 API 来调用 LLM。"
- 坑点 2:系统提示词的效果因模型而异。 小模型(如 Qwen3.5 4B)对复杂系统提示词的遵循度较低,大模型(如 GPT-4.1、Qwen3.5 Plus)效果更好。
- 坑点 3:maxSteps 过低会导致任务中断。 复杂表单填写可能需要 10-20 步,建议根据实际任务复杂度设置合理的上限。
练习题:
- 为一个虚拟的"在线商城"编写一个自定义系统提示词,限制 Agent 只能执行"浏览商品"和"加入购物车"操作,禁止执行"结算"和"支付"操作。
- 搭建一个简单的 Node.js Express 代理服务器,将前端 LLM 请求转发到实际的 API 服务,并验证 Page-Agent 可以通过该代理正常工作。
第三部分:高级篇
3.1 使用无头核心 @page-agent/core
Page-Agent 提供了 @page-agent/core 包,允许开发者跳过内置 UI 面板,直接使用 Agent 的核心逻辑。这在你需要自定义 UI 或将 Agent 嵌入已有界面时非常有用。
// 使用 @page-agent/core 无头核心,完全自定义交互界面
import { PageAgentCore } from '@page-agent/core'
// 创建无头 Agent 实例
const core = new PageAgentCore({
model: 'qwen3.5-plus',
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
apiKey: 'sk-your-api-key',
language: 'zh-CN',
maxSteps: 20,
})
// 监听 Agent 的状态变化,用于更新自定义 UI
core.onStatusChange((status) => {
switch (status) {
case 'thinking':
console.log('Agent 正在思考...')
updateMyUI({ state: 'loading', message: 'AI 正在分析页面...' })
break
case 'executing':
console.log('Agent 正在执行操作...')
updateMyUI({ state: 'active', message: '正在执行操作...' })
break
case 'completed':
console.log('Agent 任务完成')
updateMyUI({ state: 'done', message: '任务已完成!' })
break
case 'error':
console.log('Agent 执行出错')
updateMyUI({ state: 'error', message: '执行出错,请重试' })
break
}
})
// 监听 Agent 的每一步操作,用于展示执行过程
core.onStep((step) => {
console.log(`步骤 ${step.number}: ${step.description}`)
appendToLog(`[${step.number}] ${step.action} -> ${step.target}`)
})
// 执行任务
const result = await core.execute('在搜索框中输入"Page-Agent 教程"并点击搜索')
// 自定义 UI 更新函数
function updateMyUI(state) {
// 将 Agent 状态映射到你自己的 UI 组件
const indicator = document.getElementById('my-agent-status')
if (indicator) {
indicator.textContent = state.message
indicator.className = `status-${state.state}`
}
}
function appendToLog(message) {
const log = document.getElementById('my-agent-log')
if (log) {
const entry = document.createElement('div')
entry.textContent = message
log.appendChild(entry)
}
}
执行结果:
步骤 1: 找到搜索框
[1] input_text -> [搜索输入框]
步骤 2: 输入搜索关键词
[2] input_text -> 在搜索框中输入 "Page-Agent 教程"
步骤 3: 点击搜索按钮
[3] click_element_by_index -> [搜索按钮]
3.2 性能优化
Page-Agent 的性能瓶颈主要在 LLM API 调用上(每步 2-5 秒)。以下是几个实用的优化策略。
优化策略 1:减少 DOM 扫描范围
通过 data-page-agent-ignore 属性标记不相关的页面区域,减少 Agent 需要处理的 DOM 节点数量,从而降低 Token 消耗和推理时间。
<!-- 导航栏:Agent 不需要操作 -->
<nav data-page-agent-ignore>
<a href="/home">首页</a>
<a href="/about">关于</a>
<a href="/contact">联系我们</a>
<!-- ...更多导航链接... -->
</nav>
<!-- 侧边栏:Agent 不需要操作 -->
<aside data-page-agent-ignore>
<div class="ad-banner">广告</div>
<div class="related-links">相关链接</div>
</aside>
<!-- 主内容区:只有这里需要 Agent 操作 -->
<main>
<form id="task-form">
<!-- 表单内容 -->
</form>
</main>
<!-- 页脚:Agent 不需要操作 -->
<footer data-page-agent-ignore>
<p>版权信息</p>
</footer>
优化策略 2:合理设置 maxSteps
根据任务的预期复杂度设置合理的步数上限,避免 Agent 在失败时无意义地消耗 LLM 调用次数。
// 简单任务(1-3 步)
const simpleAgent = new PageAgent({
/* ...其他配置... */
maxSteps: 5, // 给简单任务留 2 步余量
})
// 中等任务(5-10 步)
const mediumAgent = new PageAgent({
/* ...其他配置... */
maxSteps: 15,
})
// 复杂任务(10-20 步)
const complexAgent = new PageAgent({
/* ...其他配置... */
maxSteps: 30,
})
优化策略 3:编写精确的指令
模糊的指令会导致 Agent 需要更多步骤来探索和纠错。精确的指令可以减少 LLM 调用次数。
// 不好的写法:模糊指令,Agent 需要多次尝试
await agent.execute('帮我处理一下那个表单')
// 好的写法:精确指令,Agent 可以一步到位
await agent.execute('在用户名输入框中输入 admin,在密码输入框中输入 password123,然后点击登录按钮')
3.3 最佳实践
-
使用语义化 HTML。 使用
<button>而非带点击事件的<div>,使用<label>关联表单控件,添加 ARIA 属性。Agent 的交互元素识别器会优先依赖语义标签和 ARIA 角色。 -
生产环境使用后端代理。 不要在前端代码中暴露 LLM API Key。创建一个后端 API 端点,通过用户的 session cookie 鉴权后转发 LLM 请求。
-
使用白名单/黑名单限制操作范围。 通过
data-page-agent-ignore属性排除不需要操作的元素,通过自定义系统提示词约束 Agent 的行为边界。 -
选择合适的 LLM 模型。 复杂的 AgentOutput schema(包含 reflection、memory、goal、action 四个维度)需要较强的指令遵循能力。推荐使用 9B 参数以上的模型。Qwen3.5 Plus 和 GPT-4.1 表现最佳。
-
为 Agent 提供操作反馈。 当 Agent 执行操作后页面应有明显的视觉反馈(如加载动画、成功提示),这样 Agent 在下一步观察时可以确认操作是否成功。
第四部分:实战项目
项目需求
构建一个 "智能表单助手" 组件,可以嵌入到任何包含表单的 Web 页面中。用户只需要用自然语言描述要填写的表单内容,Agent 就会自动完成表单填写并提交。
具体要求: - 支持多种表单元素:文本输入、下拉选择、复选框、文本域 - 提供自定义 UI 面板(不使用内置面板) - 显示 Agent 的执行进度和每一步操作日志 - 支持操作前的确认机制(用户可以在执行前审核 Agent 的计划)
项目设计
架构设计:
┌─────────────────────────────────────────────┐
│ 智能表单助手 UI │
│ ┌─────────────────────────────────────┐ │
│ │ 输入框:自然语言描述表单内容 │ │
│ ├─────────────────────────────────────┤ │
│ │ 执行按钮 | 状态指示器 │ │
│ ├─────────────────────────────────────┤ │
│ │ 操作日志面板 │ │
│ │ [1] 正在输入用户名... │ │
│ │ [2] 正在输入邮箱... │ │
│ │ [3] 正在选择部门... │ │
│ │ [4] 正在点击提交... │ │
│ └─────────────────────────────────────┘ │
│ │
│ 目标表单(用户真正要填写的表单) │
│ ┌─────────────────────────────────────┐ │
│ │ 用户名: [ ] │ │
│ │ 邮 箱: [ ] │ │
│ │ 部 门: [请选择 ▼ ] │ │
│ │ 备 注: [ ] │ │
│ │ [提交] │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
技术选型: - Page-Agent npm 包(核心 Agent 能力) - 纯 JavaScript + DOM API(无框架依赖) - OpenAI 兼容 API(可替换为任意 LLM 提供商)
完整实现代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>智能表单助手 - Page-Agent 实战项目</title>
<style>
/* 页面基础样式 */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #f5f5f5;
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
/* Agent 助手面板样式 */
.agent-panel {
background: white;
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.agent-panel h2 {
margin-bottom: 15px;
color: #333;
}
.agent-input-group {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.agent-input-group textarea {
flex: 1;
padding: 12px;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 14px;
resize: vertical;
min-height: 80px;
font-family: inherit;
}
.agent-input-group button {
padding: 12px 24px;
background: #4a90d9;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
white-space: nowrap;
transition: background 0.2s;
}
.agent-input-group button:hover { background: #357abd; }
.agent-input-group button:disabled {
background: #ccc;
cursor: not-allowed;
}
/* 状态指示器 */
.status-bar {
padding: 8px 12px;
border-radius: 6px;
margin-bottom: 15px;
font-size: 13px;
display: none;
}
.status-bar.thinking {
display: block;
background: #fff3cd;
color: #856404;
}
.status-bar.executing {
display: block;
background: #cce5ff;
color: #004085;
}
.status-bar.completed {
display: block;
background: #d4edda;
color: #155724;
}
.status-bar.error {
display: block;
background: #f8d7da;
color: #721c24;
}
/* 操作日志面板 */
.log-panel {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 12px;
max-height: 200px;
overflow-y: auto;
font-size: 13px;
font-family: 'Menlo', 'Consolas', monospace;
}
.log-entry {
padding: 4px 0;
border-bottom: 1px solid #eee;
}
.log-entry:last-child { border-bottom: none; }
.log-entry .step-num { color: #4a90d9; font-weight: bold; }
.log-entry .step-action { color: #666; }
/* 目标表单样式 */
.target-form {
background: white;
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.target-form h2 {
margin-bottom: 20px;
color: #333;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #555;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
font-family: inherit;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: #4a90d9;
box-shadow: 0 0 0 2px rgba(74,144,217,0.2);
}
.submit-btn {
padding: 12px 30px;
background: #28a745;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 15px;
margin-top: 10px;
}
.submit-btn:hover { background: #218838; }
</style>
</head>
<body>
<!-- 智能表单助手面板 -->
<div class="agent-panel">
<h2>智能表单助手</h2>
<p style="color: #666; margin-bottom: 15px;">
用自然语言描述你要填写的表单内容,AI 会自动帮你完成填写。
</p>
<div class="agent-input-group">
<textarea id="agent-instruction" placeholder="例如:帮我填写表单,用户名 zhangsan,邮箱 zhangsan@example.com,选择技术部,备注中写"希望参加前端培训""></textarea>
<button id="agent-run-btn">执行填写</button>
</div>
<!-- 状态指示器 -->
<div id="status-bar" class="status-bar"></div>
<!-- 操作日志 -->
<div id="log-panel" class="log-panel" style="display:none;"></div>
</div>
<!-- 目标表单(Agent 要操作的表单) -->
<div class="target-form">
<h2>员工信息登记表</h2>
<form id="employee-form" onsubmit="handleSubmit(event)">
<div class="form-group">
<label for="name">用户名</label>
<input type="text" id="name" name="name" aria-label="用户名" placeholder="请输入用户名">
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" aria-label="邮箱" placeholder="请输入邮箱">
</div>
<div class="form-group">
<label for="department">部门</label>
<select id="department" name="department" aria-label="部门选择">
<option value="">请选择部门</option>
<option value="tech">技术部</option>
<option value="product">产品部</option>
<option value="design">设计部</option>
<option value="marketing">市场部</option>
<option value="hr">人力资源部</option>
</select>
</div>
<div class="form-group">
<label for="notes">备注</label>
<textarea id="notes" name="notes" aria-label="备注" rows="3" placeholder="请输入备注信息"></textarea>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="agree" name="agree" aria-label="同意协议">
我已阅读并同意《员工信息使用协议》
</label>
</div>
<button type="submit" class="submit-btn" aria-label="提交表单">提交</button>
</form>
</div>
<!-- 引入 Page-Agent(使用 npm 方式时请用 import 语句) -->
<!-- 这里使用 CDN Demo 模式简化演示,实际项目请使用 npm + 自定义 LLM -->
<script src="https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js" crossorigin="true"></script>
<script>
// 表单提交处理(用于验证 Agent 的操作结果)
function handleSubmit(event) {
event.preventDefault()
const formData = new FormData(event.target)
const data = Object.fromEntries(formData.entries())
console.log('表单已提交,数据为:', data)
// 在页面上显示提交成功的信息
const statusDiv = document.getElementById('status-bar')
statusDiv.className = 'status-bar completed'
statusDiv.textContent = `表单提交成功!用户名: ${data.name}, 邮箱: ${data.email}, 部门: ${data.department}`
}
// 绑定执行按钮点击事件
document.getElementById('agent-run-btn').addEventListener('click', function() {
const instruction = document.getElementById('agent-instruction').value.trim()
if (!instruction) {
alert('请输入表单填写指令')
return
}
const statusBar = document.getElementById('status-bar')
const logPanel = document.getElementById('log-panel')
const runBtn = this
// 禁用按钮,防止重复点击
runBtn.disabled = true
runBtn.textContent = '执行中...'
// 显示状态
statusBar.className = 'status-bar thinking'
statusBar.textContent = 'Agent 正在分析页面和你的指令...'
logPanel.style.display = 'block'
logPanel.innerHTML = ''
// 添加日志条目
function addLog(step, message) {
const entry = document.createElement('div')
entry.className = 'log-entry'
entry.innerHTML = `<span class="step-num">[${step}]</span> <span class="step-action">${message}</span>`
logPanel.appendChild(entry)
logPanel.scrollTop = logPanel.scrollHeight
}
addLog('准备', '指令已发送,等待 Agent 响应...')
// 注意:Demo 模式下 Page-Agent 会自动弹出内置面板
// 在 npm + @page-agent/core 模式下,可以通过 onStep 回调捕获每一步操作
// 这里仅演示 UI 集成模式
setTimeout(() => {
statusBar.className = 'status-bar completed'
statusBar.textContent = '指令已发送给 Agent。请在 Page-Agent 内置面板中观察执行过程。'
runBtn.disabled = false
runBtn.textContent = '执行填写'
addLog('完成', '指令已交给 Agent,请在内置面板中交互。')
}, 2000)
})
</script>
</body>
</html>
代码解析
知识点 1:DOM 感知优化(2.1 节)
每个表单元素都使用了语义化标签(<label>、<input>、<select>、<textarea>)并添加了 aria-label 属性,确保 Agent 的 DOM 智能感知层可以准确识别每个交互元素。这是 2.1 节"HTML 脱水与 DOM 感知"知识点的实际应用。
知识点 2:多模型配置(2.2 节)
代码中通过 CDN 引入了 Demo 版本(使用免费测试 LLM)。在实际项目中,你可以替换为 npm 方式并配置自己的 LLM 提供商(如 2.2 节所述)。handleSubmit 函数展示了如何接收 Agent 操作后的表单数据。
知识点 3:自定义 UI 集成(3.1 节)
智能表单助手面板是一个完全自定义的 UI,不依赖 Page-Agent 的内置面板。状态指示器(thinking/executing/completed/error)和操作日志面板展示了如何将 Agent 的执行过程可视化。在 npm + @page-agent/core 模式下,你可以通过 onStatusChange 和 onStep 回调获取实时状态,替换掉当前的简化演示逻辑。
扩展挑战
- 将 CDN Demo 模式替换为 npm +
@page-agent/core无头核心模式。 移除 CDN 引入,通过 npm 安装 Page-Agent,使用PageAgentCore类替换 Demo 模式,并通过onStatusChange和onStep回调将 Agent 的执行过程实时展示在自定义 UI 中。 - 添加操作确认机制。 在 Agent 执行每一步操作前,在日志面板中显示即将执行的操作,并让用户点击"确认"后才真正执行。这需要使用 Agent 的生命周期钩子。
- 添加表单验证。 在 Agent 完成填写后,自动验证表单数据的合法性(如邮箱格式、必填字段检查),并在验证失败时让 Agent 自动修正。
第五部分:常见问题与排查指南
常见错误及解决方案
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
| Agent 加载后没有出现交互面板 | CDN 链接不正确或网络不通 | 检查 CDN URL 是否正确(注意版本号),尝试切换全球/中国镜像 |
| Agent 提示"无法找到该元素" | 元素被 display:none 隐藏,或不在视口内 |
确保目标元素可见,或先让 Agent 滚动页面到目标位置 |
| Agent 操作后页面没有反应 | 元素事件被前端框架(React/Vue)劫持 | Page-Agent 已内置 React Fiber 绕过机制,如果仍有问题,检查元素是否使用了非标准的自定义事件 |
| LLM 返回格式错误导致任务中断 | 使用的模型太小(<9B),无法正确生成 AgentOutput JSON | 切换到更大的模型(如 Qwen3.5 Plus、GPT-4.1),Page-Agent 内置的 5 级容错会尝试修复 |
| CSP 阻止脚本加载 | 页面设置了严格的 Content-Security-Policy | 需要在 CSP 中白名单 Page-Agent 的脚本源,或通过 npm 方式打包到项目构建产物中 |
| 中文输入法导致输入内容异常 | 中文输入法的 compositionstart/end 事件未被正确处理 | Page-Agent 已处理 isComposing 状态,如果仍有问题,尝试在指令中明确指定要输入的具体文字 |
| Agent 执行了非预期的操作 | 指令模糊,LLM 推理出现偏差 | 编写更精确的指令,添加系统提示词约束 Agent 行为范围 |
execute() 方法长时间无返回 |
maxSteps 设置过高,Agent 在复杂页面上反复尝试 |
降低 maxSteps(推荐 10-20),编写更明确的指令减少探索步骤 |
调试技巧
-
观察 DOM 脱水输出。 在浏览器开发者工具的 Console 中检查 Agent 发送给 LLM 的页面快照。你可以通过在代码中临时添加
console.log来查看 Agent 感知到的页面结构是否正确。如果 Agent "看"不到某个元素,很可能是该元素在 DOM 扫描时被过滤了(不可见、被忽略属性标记等)。 -
使用 Bookmarklet 在目标页面上快速测试。 在集成到正式项目之前,先在目标页面上使用 Bookmarklet 注入 Agent,测试指令是否能被正确理解和执行。这可以帮助你快速排查是 Agent 本身的问题还是集成代码的问题。
-
检查 LLM API 连通性。 如果 Agent 完全没有响应,首先检查 LLM API 是否可达。在浏览器 Console 中执行以下代码测试:
// 测试 LLM API 连通性
fetch('https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-your-api-key',
},
body: JSON.stringify({
model: 'qwen3.5-plus',
messages: [{ role: 'user', content: 'Hello' }],
}),
})
.then(r => r.json())
.then(data => console.log('LLM API 连通正常:', data))
.catch(err => console.error('LLM API 连接失败:', err))
第六部分:学习路线推荐
官方文档推荐阅读顺序
- Introduction / Overview - 理解项目定位和核心概念,了解页内 Agent 和 Chrome 扩展的区别
- Getting Started / Quick Start - 跟着官方快速入门跑通第一个示例(CDN 和 npm 两种方式都试一遍)
- Programmatic API - 学习
PageAgent类的完整配置选项,重点关注systemPrompt、maxSteps和生命周期回调 - Chrome Extension - 了解可选的跨页扩展功能,学习
window.PAGE_AGENT_EXTAPI 的使用 - Developer Guide - 本地开发环境搭建、贡献指南、架构设计文档
- AGENTS.md - 为 AI 编程助手提供的上下文信息,有助于理解项目设计意图
推荐进阶资源
- 四行代码背后的完整 AI 浏览器 Agent:page-agent 源码深度拆解 - 对 Page-Agent 源码的五层架构进行了逐行分析,包括 HTML 脱水机制、ReAct 推理循环、响应容错等核心实现。适合想深入理解内部原理的开发者。
- Hacker News Show HN 讨论 - 项目作者与社区的完整讨论记录,涵盖安全性、CSP 兼容性、架构权衡、与竞品对比等深度话题。推荐阅读以获取真实的生产环境考量。
- browser-use 项目 - Page-Agent 的 DOM 处理逻辑源自该项目。了解 browser-use 的架构有助于理解 Page-Agent 的设计灵感来源和两者在服务端 vs 客户端定位上的差异。
教程版本说明: 本教程基于 Page-Agent v1.7.1 编写,API 可能随版本更新而变化。如遇与教程不符的行为,请查阅官方文档获取最新信息。