15KB 给网站装了个会动手的 AI——从零到上线,3 种模式 5 分钟搞定

你的网站有个 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 },
  },
});

在线演示:

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 分钟,零框架。


相关链接:

评论

暂无评论。

登录后可发表评论。