你的网站有个 AI 聊天框。用户问"帮我预订下周二下午3点的会议",AI 回复"好的,已为您预订"——然后什么都没发生。
聊天框和网页之间隔着一堵墙。AI 能说,不能做。
Persona.js 就是来拆这堵墙的。15KB 首屏加载,零框架依赖,WebMCP 让 AI 直接操作页面元素。最关键的是:5 分钟就能跑起来。
Persona.js 是什么
一句话:一个零框架依赖的 AI 聊天组件,支持 WebMCP,让 AI 能直接操作你的网页。
GitHub:https://github.com/runtypelabs/persona Star:193(项目 2026 年 1 月才创建,还在早期) 协议:MIT 当前版本:4.9.0(7 月 22 日刚发)
它不绑 React,不绑 Vue,不绑任何框架。原生 JS 渲染,Shadow DOM 样式隔离,装上就走。
核心能力:
- 流式回复 + Markdown 渲染 + 6 种打字动画
- WebMCP:AI 直接调用页面工具(搜索、加购、预订、表单提交)
- 3 种布局:悬浮 / 停靠 / 全屏,一行配置切换
- 审批门控:只读操作自动放行,变更操作必须用户确认
- 语音输入/朗读、多模态内容、插件系统
5 分钟上手:最简安装
方式一:script 标签(零构建)
这是最快的路径。不需要 npm、不需要 webpack、不需要任何构建工具。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Persona.js Demo</title>
</head>
<body>
<h1>我的网站</h1>
<div id="chat"></div>
<script>
window.siteAgentConfig = {
target: "#chat",
apiUrl: "https://your-api.com/chat",
};
</script>
<script src="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@4/dist/install.global.js"></script>
</body>
</html>
保存为 index.html,浏览器打开,右下角出现聊天按钮。点开就能聊。
注意:apiUrl 需要指向一个支持 SSE(Server-Sent Events)流式传输的后端。后端用什么语言都行——Python、Go、Node.js,只要能流式返回数据。
方式二:npm 安装
npm install @runtypelabs/persona
import { initAgentWidget } from "@runtypelabs/persona";
initAgentWidget({
target: "#chat",
config: {
apiUrl: "https://your-api.com/chat",
},
});
两种方式效果完全一样。script 标签适合快速验证,npm 适合正式项目。
3 种布局模式
改一个配置就能切换:
悬浮模式(默认)
右下角浮动按钮,点击展开聊天面板。适合客服、文档问答、产品导购。
initAgentWidget({
target: "#chat",
config: { apiUrl },
});
// 悬浮是默认的,不用额外配置
停靠模式
侧边栏固定面板,适合"AI 副驾驶"常驻工作区。
initAgentWidget({
target: "#workspace",
config: {
apiUrl,
launcher: {
mountMode: "docked",
dock: { side: "right", width: "420px" },
},
},
});
停靠模式支持 4 种展开方式:resize(挤压内容区)、emerge(浮出)、overlay(覆盖)、push(推开)。
全屏模式
占据整个页面,适合需要专注对话的场景。
initAgentWidget({
target: "#app",
config: {
apiUrl,
launcher: { enabled: false, fullHeight: true },
},
});
在线演示:
- 悬浮:https://persona-chat.dev/launcher-demo.html
- 停靠:https://persona-chat.dev/docked-panel-demo.html
- 全屏:https://persona-chat.dev/fullscreen-assistant-demo.html
WebMCP:让 AI 真正"动手"
这是 Persona.js 的杀手锏。WebMCP 是 Chrome 146 引入的新特性,让 AI 能通过结构化接口直接操作网页,而不是靠截图+DOM 猜测。
注册页面工具
// 在页面中注册工具,AI 就能调用
document.modelContext = {
tools: [
{
name: "add_to_cart",
description: "将商品加入购物车",
parameters: {
type: "object",
properties: {
product_id: { type: "string", description: "商品ID" },
quantity: { type: "number", description: "数量" },
},
required: ["product_id"],
},
},
{
name: "search_products",
description: "搜索商品",
parameters: {
type: "object",
properties: {
query: { type: "string", description: "搜索关键词" },
},
required: ["query"],
},
},
],
};
启用 WebMCP
initAgentWidget({
target: "#chat",
config: {
apiUrl,
webmcp: { enabled: true },
},
});
启用后,Persona.js 会自动发现 document.modelContext 中注册的工具,AI 就能调用它们。
审批门控
不是所有操作都该让 AI 随便执行。Persona.js 内置了审批机制:
webmcp: {
enabled: true,
// 只读操作自动放行,变更操作需要用户确认
autoApprove: (info) => {
const READ_ONLY = new Set(["search_products", "get_product"]);
return READ_ONLY.has(info.toolName);
},
}
用户说"帮我加入购物车",AI 执行前会弹出确认提示。用户点头了才真正执行。只读操作自动放行,变更操作必须确认。
后端对接:11 种方案
Persona.js 不挑后端。官方提供了 11 个示例,覆盖主流技术栈:
| 示例 | 技术栈 | 说明 |
|---|---|---|
| echo-script-tag | 纯 HTML + Node | 零框架,最快上手 |
| echo-hono | Hono | Node/Bun/Deno/Workers 通用 |
| echo-express | Express | 传统 (req, res) 风格 |
| echo-sveltekit | SvelteKit | 一行 +server.ts 路由 |
| ai-sdk-webmcp | Next.js + AI SDK | WebMCP 页面工具 |
| ai-sdk-next | Next.js + AI SDK | 最小 SSE 适配器 |
| openai-agents-next | Next.js + OpenAI Agents SDK | OpenAI 官方 SDK |
| langgraph-next | Next.js + LangGraph | LangChain 编排 |
| eve-next | Next.js + Vercel Eve | Vercel 新框架(beta) |
| runtype-script-tag | 静态页面 + Runtype | 零后端,clientToken 嵌入 |
| runtype-hono-proxy | Hono + Runtype | Runtype API 代理 |
不想写后端? 用 runtype-script-tag 方案,只需要一个 clientToken,连后端代码都不用写:
<script>
window.siteAgentConfig = {
target: "#chat",
clientToken: "your-client-token",
};
</script>
<script src="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@4/dist/install.global.js"></script>
实战:给电商网站加 AI 助手
完整示例,从 HTML 到后端:
前端(index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>AI 购物助手</title>
</head>
<body>
<div id="workspace">
<h1>我的商城</h1>
<div id="product-list">
<div class="product" data-id="p001">
<h3>机械键盘</h3>
<p>¥399</p>
<button onclick="addToCart('p001')">加入购物车</button>
</div>
</div>
</div>
<script>
// 注册页面工具
document.modelContext = {
tools: [{
name: "add_to_cart",
description: "将商品加入购物车",
parameters: {
type: "object",
properties: {
product_id: { type: "string" },
quantity: { type: "number" },
},
required: ["product_id"],
},
}, {
name: "search_products",
description: "搜索商品",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
}],
};
// 初始化 Persona
window.siteAgentConfig = {
target: "#workspace",
apiUrl: "http://localhost:3000/chat",
launcher: {
mountMode: "docked",
dock: { side: "right", width: "380px" },
},
webmcp: {
enabled: true,
autoApprove: (info) => info.toolName === "search_products",
},
};
</script>
<script src="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@4/dist/install.global.js"></script>
</body>
</html>
后端(Node.js,最小 SSE 示例)
import { createServer } from "node:http";
createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
});
// 发送执行开始事件
const execId = "exec_" + Date.now();
res.write(`event: execution_start
data: ${JSON.stringify({
type: "execution_start", executionId: execId, kind: "agent",
agentId: "shopping-assistant", startedAt: new Date().toISOString(),
})}
`);
// 发送文本回复
res.write(`event: text_start
data: ${JSON.stringify({
type: "text_start", executionId: execId, id: "text_1", iteration: 1,
})}
`);
const reply = "你好!我是购物助手,可以帮你搜索商品或加入购物车。";
for (const char of reply) {
res.write(`event: text_delta
data: ${JSON.stringify({
type: "text_delta", executionId: execId, id: "text_1", delta: char,
})}
`);
}
res.write(`event: text_complete
data: ${JSON.stringify({
type: "text_complete", executionId: execId, id: "text_1",
})}
`);
res.write(`event: execution_complete
data: ${JSON.stringify({
type: "execution_complete", executionId: execId, kind: "agent",
success: true, completedAt: new Date().toISOString(),
})}
`);
res.end();
}).listen(3000);
这是最简的 echo 后端——不接模型,只回固定文本。真实项目需要接入 AI SDK / OpenAI / LangGraph 等,参考官方 examples 目录。
代价清醒:3 个你该知道的问题
问题一:WebMCP 还在早期。 Chrome 146 才引入,目前是 feature flag 阶段。Chrome 149 有 origin trial,但其他浏览器还没跟进。生产环境用 WebMCP 需要考虑兼容性。
问题二:193 Star 意味着什么。 项目 2026 年 1 月创建,半年不到。社区小、文档还在完善、API 可能变。适合尝鲜和快速验证,不适合直接上生产核心流程。
问题三:零框架不是零代价。 不绑框架是优点,但也意味着你得自己处理 React/Vue 组件集成。如果你的项目重度依赖 React 状态管理,Persona.js 的 Shadow DOM 渲染可能和你的组件树产生冲突。官方推荐重度 React 用户考虑 Assistant UI 或 CopilotKit。
竞品对比
| 维度 | Persona.js | Assistant UI | CopilotKit | Vercel AI Elements |
|---|---|---|---|---|
| 框架依赖 | 零 | React | React | React |
| 首屏大小 | ~15KB | ~50KB | ~80KB | ~40KB |
| WebMCP | ✅ 原生 | ❌ | ❌ | ❌ |
| 布局模式 | 3 种 | 2 种 | 2 种 | 2 种 |
| 插件系统 | ✅ 14 个 hook | ✅ | ✅ | 有限 |
| 协议 | MIT | MIT | MIT | MIT |
| Star | 193 | 8K+ | 15K+ | 新项目 |
Persona.js 的差异化很明确:零框架 + WebMCP 原生。如果你不需要 React 绑定,或者想用 WebMCP 让 AI 操作页面,它是目前唯一的选择。
趋势判断:WebMCP 会改变什么
WebMCP 的本质不是"让 AI 操作浏览器"——browser-use 那类工具已经在做了。WebMCP 做的是更底层的事:给网站一个机器可读的操作接口。
以前的网站只给人看。AI 想操作网页,要么截图识别(慢且不准),要么解析 DOM(脆弱且易碎)。WebMCP 让网站主动暴露结构化的工具菜单,AI 直接调用,不需要猜。
这意味着:未来每个网站都该有一个 WebMCP 接口,就像每个网站都该有一个 API 一样。 Persona.js 是目前最快给网站加上这个接口的方式——15KB,5 分钟,零框架。
相关链接:
- Persona.js GitHub:https://github.com/runtypelabs/persona
- 在线演示:https://persona-chat.dev
- WebMCP 示例:https://ai-sdk-webmcp.persona-chat.dev
- WebMCP 介绍(Chrome 团队):https://developer.chrome.com/docs/web-mcp
- npm 包:https://www.npmjs.com/package/@runtypelabs/persona
- Agnes AI(1M 上下文+4K 生图+视频全免费):https://platform.agnes-ai.com/
暂无评论。