跳转到内容

接入实战

本文档以本项目的 docs 站点为例,演示如何在 Astro 文档站点中集成 RTC Agent Web Component。

  • 框架: Astro 7.x + Starlight
  • 集成方式: CDN(jsdelivr)
  • 组件版本: @rtc-agent/component@0.3.0-rc.4

RTC Agent 组件内部使用 SharedWorker 实现多 Tab WebSocket 复用。通过 CDN 加载可以确保 Worker 文件路径正确解析,无需额外配置 Vite 或构建工具。

方式优点缺点
CDN(推荐)零配置、Worker 自动解析依赖外部 CDN
npm install本地开发、类型提示需要配置 Vite 处理 Worker

在 astro.config.mjs 的 head 中注入 CDN 脚本,使用 createRtcAgent() 工厂函数全局加载组件:

文件: astro.config.mjs

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
export default defineConfig({
site: 'https://your-site.github.io',
base: '/docs',
integrations: [
starlight({
title: 'Your Site',
head: [
// 使用工厂函数加载和配置 RTC Agent
{
tag: 'script',
attrs: { type: 'module' },
content: `
import { createRtcAgent } from 'https://cdn.jsdelivr.net/npm/@rtc-agent/component@0.3.0-rc.4/dist/index.js';
const initRtcAgent = async () => {
if (document.querySelector('#rtc-agent-global')) return;
const agent = createRtcAgent({
appLabel: 'RTC Agent 助手',
theme: 'system',
server: {
url: 'https://rtc-agent.cherish.chat',
redirectUri: '/docs/auth/callback.html',
},
window: {
defaultMode: 'minimized',
draggable: true,
resizable: true,
bubblePosition: {
corner: 'bottom-right',
offset: { x: -24, y: 24 },
},
},
});
const container = document.createElement('div');
container.id = 'rtc-agent-global';
container.appendChild(agent);
document.body.appendChild(container);
// 全局样式
const style = document.createElement('style');
style.textContent = \`
#rtc-agent-global {
position: fixed;
bottom: 0;
right: 0;
z-index: 9999;
pointer-events: none;
}
#rtc-agent-global rtc-agent {
pointer-events: auto;
}
\`;
document.head.appendChild(style);
};
document.addEventListener('DOMContentLoaded', () => initRtcAgent());
`,
},
],
}),
],
});

与旧模式的关键区别:

  • 从 CDN 导入 createRtcAgent 工厂函数
  • 使用工厂函数代替手动创建元素和设置属性
  • 所有配置在一个声明式对象中完成
  • 无需等待 rtc-agent-ready 事件来配置窗口

如果需要使用 GitHub 登录,创建回调页面处理 OAuth 回调。

文件: public/auth/callback.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>授权完成</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.container {
background: white;
border-radius: 16px;
padding: 48px;
text-align: center;
max-width: 400px;
}
.icon { font-size: 48px; margin-bottom: 16px; }
</style>
</head>
<body>
<div class="container">
<div class="icon" id="icon">⏳</div>
<h1 id="title">处理中...</h1>
<p id="message">请稍候,正在完成授权</p>
</div>
<script>
(function() {
var params = new URLSearchParams(window.location.search);
var code = params.get('code');
var state = params.get('state');
var error = params.get('error');
var icon = document.getElementById('icon');
var title = document.getElementById('title');
var message = document.getElementById('message');
if (error) {
icon.textContent = '✕';
title.textContent = '授权失败';
message.textContent = error;
return;
}
if (code && state) {
var target = window.opener || window.parent;
if (target) {
target.postMessage({
type: 'oauth-callback',
code: code,
state: state,
}, window.location.origin);
icon.textContent = '✓';
title.textContent = '授权成功';
message.textContent = '正在返回应用...';
setTimeout(function() { window.close(); }, 2000);
}
}
})();
</script>
</body>
</html>

在 GitHub OAuth App 中设置回调地址:

  • 开发环境: http://localhost:4321/docs/auth/callback.html
  • 生产环境: https://your-site.github.io/docs/auth/callback.html

启动开发服务器:

终端窗口
pnpm dev

访问 http://localhost:4321/docs/,应该能看到右下角的 RTC Agent 悬浮窗。

CDN 方式确保 SharedWorker 文件路径正确解析,无需额外配置构建工具。

工厂函数将所有配置集中在一个声明式对象中,无需手动创建元素或等待 rtc-agent-ready 事件:

const agent = createRtcAgent({
appLabel: 'RTC Agent 助手',
server: { url: 'https://rtc-agent.cherish.chat' },
window: { defaultMode: 'minimized', draggable: true },
});
<!-- 跳过 SSR,只在客户端渲染 -->
<rtc-agent client:only="astro"></rtc-agent>

组件使用 Shadow DOM,样式已隔离,不会与 Starlight 主题冲突。

本项目的 docs 站点已经完成了集成,可以参考以下文件:

对于生产应用,使用 createRtcAgent() 工厂函数,获得完整类型安全和 SharedWorker 多 Tab 同步支持。

终端窗口
pnpm add @rtc-agent/component
# 或
npm install @rtc-agent/component
# 或
yarn add @rtc-agent/component

第二步:配置 SharedWorker(多 Tab 所需)

Section titled “第二步:配置 SharedWorker(多 Tab 所需)”

RTC Agent 使用 SharedWorker 在浏览器标签页之间复用 WebSocket 连接。Worker 文件必须在浏览器可访问的公共目录中。

运行 CLI 工具自动将 SharedWorker 文件复制到正确位置:

终端窗口
npx rtc-agent-setup

工具会自动:

  • 检测项目类型(Vite、Webpack、SvelteKit 等)
  • 将 SharedWorker 文件复制到正确目录(static/rtc-agent/ 或 public/rtc-agent/)
  • 创建稳定文件名 shared-worker.js 便于引用
  • 生成包含版本信息的 manifest.json
  • 清理旧 Worker 文件防止堆积

将 setup 工具添加到 postinstall 脚本,在 npm install 后自动运行:

{
"scripts": {
"postinstall": "rtc-agent-setup"
}
}

这确保:

  • 新开发者克隆项目后自动配置 SharedWorker 文件
  • 升级 @rtc-agent/component 时 Worker 文件同步更新
  • 依赖变更后无需手动操作

💡 如果已有 postinstall 脚本,在其后追加 && rtc-agent-setup:

{
"scripts": {
"postinstall": "your-existing-script && rtc-agent-setup"
}
}

如果 CLI 工具不适用于你的项目,手动复制 Worker 文件:

终端窗口
# 创建目标目录
mkdir -p public/rtc-agent
# 复制 Worker 文件并重命名为稳定文件名
cp node_modules/@rtc-agent/component/dist/assets/shared-worker-*.js public/rtc-agent/shared-worker.js

使用工厂函数创建并配置组件:

import { z, withMeta, createRtcAgent } from '@rtc-agent/component';
import type { RtcAgentWithLifecycle } from '@rtc-agent/component';
// 创建 agent 实例
const agent: RtcAgentWithLifecycle = createRtcAgent({
// 基础配置
appLabel: '我的 AI 助手',
theme: 'system',
lang: 'zh-CN',
// Server 配置
server: {
url: 'https://rtc-agent.cherish.chat',
redirectUri: '/auth/callback.html',
},
// SharedWorker URL(多 Tab 支持所需)
workerURL: '/rtc-agent/shared-worker.js',
// 场景文档
scenariosURL: '/scenarios/',
// 窗口配置
window: {
defaultMode: 'normal',
bubblePosition: {
corner: 'bottom-right',
offset: { x: -24, y: 24 },
},
},
// 函数注册(使用 Zod schema - 推荐)
agentName: 'MyApp',
agentDescription: '我的应用 AI 助手',
persona: '你是一个有帮助的助手...',
groups: [
{
name: 'editor',
description: '编辑器操作',
functions: [
{
name: 'getCode',
description: '获取当前代码',
handler: () => window.editorAPI.getCode(),
returns: { zodSchema: z.string().describe('当前编辑器中的代码') },
},
{
name: 'setCode',
description: '设置编辑器代码',
zodSchema: z.object({
code: withMeta(z.string(), { example: 'console.log("hello")' }).describe('要设置的代码'),
}),
handler: (params) => {
window.editorAPI.setCode(params.code);
return { success: true };
},
},
],
},
],
// 事件处理
on: {
ready: () => {
console.log('RTC Agent 已就绪');
},
},
});
// 添加到 DOM
document.body.appendChild(agent);
// 清理
agent.destroy();

createRtcAgent() 中的 auth 属性控制组件如何与 Server 进行认证。选择适合你应用的模式:

模式一:静态令牌(开发 / CI / 测试)

Section titled “模式一:静态令牌(开发 / CI / 测试)”

直接传入固定的 access token。简单但不适用于生产环境——令牌会过期且无法刷新。

const agent = createRtcAgent({
server: { url: 'https://rtc-agent.example.com' },
workerURL: '/rtc-agent/shared-worker.js',
auth: {
accessToken: 'your-jwt-token',
userId: 'user-123',
},
});

模式二:动态令牌(生产环境推荐)

Section titled “模式二:动态令牌(生产环境推荐)”

提供 getToken 回调(必选)和 refreshToken 回调(可选),让组件按需获取和刷新令牌。这是大多数生产应用的推荐方式。

const agent = createRtcAgent({
server: { url: 'https://rtc-agent.example.com' },
workerURL: '/rtc-agent/shared-worker.js',
auth: {
userId: 'user-123',
getToken: async () => {
const res = await fetch('/api/auth/token');
const data = await res.json();
return data.accessToken;
},
refreshToken: async () => {
const res = await fetch('/api/auth/refresh', { method: 'POST' });
return res.json();
},
},
});

模式三:认证提供者(高级 / 多租户)

Section titled “模式三:认证提供者(高级 / 多租户)”

实现完整的 auth 接口,包含 isLoggedIn 和 logout 钩子。适用于已有认证系统或需要多租户支持的场景。

const agent = createRtcAgent({
server: { url: 'https://rtc-agent.example.com' },
workerURL: '/rtc-agent/shared-worker.js',
auth: {
getToken: async () => myAuthProvider.getToken(),
refreshToken: async () => myAuthProvider.refresh(),
isLoggedIn: () => myAuthProvider.isLoggedIn(),
logout: async () => myAuthProvider.logout(),
getUserId: () => myAuthProvider.getUserId(), // 返回当前用户唯一标识(强烈建议提供)
},
});

详见 认证与授权 了解登录流程、令牌生命周期和安全最佳实践的完整说明。

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { base } from '$app/paths';
import { createRtcAgent } from '@rtc-agent/component';
import type { RtcAgentWithLifecycle } from '@rtc-agent/component';
let rtcAgent: RtcAgentWithLifecycle | null = null;
onMount(() => {
rtcAgent = createRtcAgent({
appLabel: 'My App',
theme: 'system',
server: {
url: 'https://rtc-agent.cherish.chat',
redirectUri: `${base}/auth/callback.html`,
},
workerURL: `${base}/rtc-agent/shared-worker.js`,
scenariosURL: `${base}/scenarios/`,
// ... 其他配置
});
document.body.appendChild(rtcAgent);
});
onDestroy(() => {
if (rtcAgent) {
rtcAgent.destroy();
rtcAgent = null;
}
});
</script>
import { useEffect, useRef } from 'react';
import { createRtcAgent } from '@rtc-agent/component';
import type { RtcAgentWithLifecycle } from '@rtc-agent/component';
function RtcAgentWrapper() {
const agentRef = useRef<RtcAgentWithLifecycle | null>(null);
useEffect(() => {
agentRef.current = createRtcAgent({
appLabel: 'My App',
theme: 'system',
server: {
url: 'https://rtc-agent.cherish.chat',
redirectUri: '/auth/callback.html',
},
workerURL: '/rtc-agent/shared-worker.js',
// ... 其他配置
});
document.body.appendChild(agentRef.current);
return () => {
if (agentRef.current) {
agentRef.current.destroy();
agentRef.current = null;
}
};
}, []);
return null;
}
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { createRtcAgent } from '@rtc-agent/component';
import type { RtcAgentWithLifecycle } from '@rtc-agent/component';
const agentRef = ref<RtcAgentWithLifecycle | null>(null);
onMounted(() => {
agentRef.value = createRtcAgent({
appLabel: 'My App',
theme: 'system',
server: {
url: 'https://rtc-agent.cherish.chat',
redirectUri: '/auth/callback.html',
},
workerURL: '/rtc-agent/shared-worker.js',
// ... 其他配置
});
document.body.appendChild(agentRef.value);
});
onUnmounted(() => {
if (agentRef.value) {
agentRef.value.destroy();
agentRef.value = null;
}
});
</script>
属性类型默认值说明
appLabelstring"RTC Agent"标题栏文字和提示
theme"light" | "dark" | "system""system"主题模式
lang"zh-CN" | "en-US""zh-CN"UI 语言
databaseNamestring"rtc-agent"IndexedDB 名称前缀
属性类型默认值说明
server.urlstring""Server 地址(回退到当前域名)
server.redirectUristring"/auth/callback.html"OAuth 回调 URL
属性类型默认值说明
workerURLstringundefinedSharedWorker 文件 URL(多 Tab 支持所需)
属性类型默认值说明
auth.accessTokenstring—静态 JWT 令牌(模式一)
auth.userIdstring—用户标识
auth.getToken() => Promise<string>—异步获取 access token 的回调(模式二/三)
auth.refreshToken() => Promise<object>—异步刷新令牌的回调(模式二可选,模式三必选)
auth.isLoggedIn() => boolean—检查用户是否已认证(模式三)
auth.logout() => Promise<void>—用户登出(模式三)
auth.getUserId() => string—返回当前用户唯一标识(模式三,强烈建议提供,用于 IndexedDB 按用户隔离)
属性类型默认值说明
window.defaultMode"normal" | "maximized" | "minimized""normal"初始窗口模式
window.embeddedbooleanfalse嵌入模式(无拖拽/缩放/按钮)
window.draggablebooleantrue是否可拖拽
window.resizablebooleantrue是否可缩放
window.bubblePosition.corner"top-left" | "top-right" | "bottom-left" | "bottom-right""bottom-right"气泡位置角落
window.bubblePosition.offset.xnumber-20水平偏移
window.bubblePosition.offset.ynumber20垂直偏移
属性类型默认值说明
agentNamestring—应用名称
agentDescriptionstring—应用描述
personastring—AI 人设/指令
groupsFunctionGroup[][]函数注册组
属性类型说明
on.ready() => void组件就绪时调用
on.beforeDestroy() => void组件即将销毁时调用(disconnectedCallback 执行时,清理之前)

升级 @rtc-agent/component 后,重新运行 setup 工具更新 SharedWorker 文件:

终端窗口
npx rtc-agent-setup

工具会:

  1. 复制新的 Worker 文件
  2. 更新 manifest.json 中的版本信息
  3. 覆盖旧的 shared-worker.js

对于生产部署,使用基于版本的缓存清除:

// 读取 manifest.json
const manifest = await fetch('/rtc-agent/manifest.json').then(r => r.json());
const workerURL = `/rtc-agent/shared-worker.js?v=${manifest.version}`;
// 在 createRtcAgent() 中使用
const agent = createRtcAgent({
workerURL,
// ...
});

或配置 Web 服务器对 Worker 文件禁用缓存:

location /rtc-agent/shared-worker.js {
add_header Cache-Control "no-cache, must-revalidate";
}

现象:控制台显示 SharedWorker 文件 404 错误

解决:

  1. 验证 Worker 文件存在:ls public/rtc-agent/ 或 ls static/rtc-agent/
  2. 检查 workerURL 路径与实际文件位置匹配
  3. 重启开发服务器
  4. 重新运行 npx rtc-agent-setup

现象:一个标签页的变更不显示在其他标签页

解决:

  1. 确保 createRtcAgent() 中配置了 workerURL
  2. 检查浏览器控制台是否有 SharedWorker 错误
  3. 验证所有标签页在同一 origin(协议 + 域名 + 端口)
  4. 检查 SharedWorker 是否被浏览器扩展阻止

现象:Cannot find module '@rtc-agent/component'

解决:

  1. 验证包已安装:pnpm list @rtc-agent/component
  2. 检查 node_modules/@rtc-agent/component 是否存在
  3. 重新安装:pnpm install