通过 iframe 集成 ChatBI
iframe 有两种常见用法:
- 直接嵌入完整 ChatBI 页面,最快得到一整页问答体验。
- 在父页面加载 Copilot JS SDK,再把衡石仪表盘放进 iframe,由父页面 Copilot 接管 iframe 内的智能助理能力。
建议先看总览
如果你们还没判断清楚运行方式和接入方式的关系,建议先读 Data Agent 集成总览。
方式一:嵌入完整 ChatBI 页面
这种方式适合:
- 希望最快上线一个可用入口
- 前端资源有限,不想自己实现聊天界面
- 接受直接复用衡石完整页面
- 不打算把聊天结果拆成自己页面里的多个局部模块
最小示例:
<iframe
src="https://your-hengshi-host/copilot"
width="100%"
height="100%"
style="border: 0;">
</iframe>只要当前浏览器已经具备衡石登录态,或者你们已经完成了单点登录,页面就可以直接显示 ChatBI。
常用 URL 参数
指定数据来源
与图表所在数据源对话:
?appId={应用 ID}&chartId={图表 ID}与数据包数据模型对话:
?dataAppId={数据包 ID}&datasetId={数据集 ID}与多个数据源对话:
?dataSources=[{"dataAppId":{数据包 ID1},"datasetId":{数据集 ID1}},{"dataAppId":{数据包 ID2},"datasetId":{数据集 ID2}}]提示
dataSources 需要先做 URL encode。
指定图表主题
?chartTheme={仪表盘主题 ID}只显示指定对话
?conversationId={对话ID1,对话ID2}&chatUid={uid1,uid2}登录认证
?activeAuth=jwt-param&jwtParam={JWT 参数}方式二:父页面 Copilot SDK 接管 iframe 仪表盘
如果你们自己的门户页已经通过 JS SDK 集成 放了 Copilot 助手,同时又希望在页面中嵌入衡石仪表盘,就使用这种方式。
这种方式的效果是:
- Copilot 侧边栏只显示在父页面,不再显示在 iframe 仪表盘里
- iframe 仪表盘里的“打开助手”“智能解读”“图表解读”等入口会打开父页面 Copilot
- Agent 需要读取或编辑 iframe 仪表盘时,会通过 iframe 代理出来的业务动作和业务对象完成
- 父页面路径可以是任意路径,也可以和衡石不同域,不依赖
/sdk/这样的测试路径
最小可运行示例
下面示例假设:
- 父页面是你们自己的门户页面
- Copilot JS SDK 加载自衡石服务
- iframe 内嵌的是衡石仪表盘
/app/{appId}/dashboard/{dashboardId} - 父页面 Copilot 接管 iframe 内的智能助理能力
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>Copilot SDK + iframe Dashboard</title>
<script>
window.__hs_sdk_base_url__ = 'https://your-hengshi-host';
</script>
<script src="https://your-hengshi-host/assets/hengshi-copilot@<version>.js"></script>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
#dashboard-frame {
width: 100%;
height: 100%;
border: 0;
}
</style>
</head>
<body>
<div id="copilot-root"></div>
<iframe id="dashboard-frame" title="HENGSHI Dashboard"></iframe>
<script>
const hengshiHost = 'https://your-hengshi-host';
const appId = 43900;
const dashboardId = 2;
const dashboardUrl = new URL(`/app/${appId}/dashboard/${dashboardId}`, hengshiHost);
dashboardUrl.searchParams.set('agentHost', 'parent');
dashboardUrl.searchParams.set('parentOrigin', window.location.origin);
document.getElementById('dashboard-frame').src = dashboardUrl.toString();
const copilot = new window.Copilot(document.getElementById('copilot-root'), {
locale: 'zh-CN',
draggable: {
enable: true,
bounds: 'window',
minWidth: 440,
minHeight: 440,
position: { x: window.innerWidth - 480, y: 24 },
size: { width: 440, height: window.innerHeight - 48 },
},
});
</script>
</body>
</html>通常不需要手动注册 iframe。父页面加载 hengshi-copilot@<version>.js 后,SDK 会跟踪页面中的 iframe;iframe 页面通过 URL 参数声明由父页面接管后,两边会自动建立通信。
iframe URL 参数
| 参数 | 是否推荐 | 说明 |
|---|---|---|
agentHost=parent | 推荐 | 让 iframe 内的 Agent / Copilot 能力由父页面 SDK 承接。 |
copilotHost=parent | 可用 | agentHost=parent 的兼容写法。新接入优先使用 agentHost=parent。 |
parentOrigin={父页面 origin} | 推荐 | 指定允许通信的父页面 origin,例如 https://portal.example.com。只写 origin,不带路径、query 或通配符。 |
copilotParentOrigin={父页面 origin} | 可用 | parentOrigin 的兼容写法。 |
agentHost=local | 可用 | 明确让 iframe 页面使用自己的 Copilot,不由父页面接管。 |
copilotHost=local | 可用 | agentHost=local 的兼容写法。 |
agentBridge=true | 高级 | 只显式打开 Agent 桥接,不等同于完整的父页面 Copilot 接管。普通接入不要优先使用。 |
推荐写法:
https://your-hengshi-host/app/43900/dashboard/2?agentHost=parent&parentOrigin=https%3A%2F%2Fportal.example.comparentOrigin 用于安全校验。配置后,iframe 只接受这个 origin 的父页面消息;配置错误时不会自动退回到宽松模式。
接管后的行为边界
父页面接管后,用户看到的是一个 Copilot:
- iframe 仪表盘不再显示自己的 Copilot 侧边栏
- 用户点击仪表盘里的智能助理入口时,会打开父页面 Copilot
- 父页面 Copilot 的 actions 区域可以显示 iframe 仪表盘提供的“智能解读”
- 图表上的“解读”会把图表上下文发送给父页面 Copilot
对 Agent 来说,iframe 仪表盘不是父页面 DOM 的一部分。Agent 不应该通过父页面的点击、拖拽或路由跳转去操作 iframe 内部内容,而是通过 iframe 代理出来的业务能力读取和修改仪表盘。
调试日志里如果看到 execute_action、inspect_element、read_path、patch_object 等工具访问 iframe 仪表盘,这是正常行为。它们用于读取仪表盘上下文、查看图表配置和提交 dashboard patch。
跨域和安全要求
跨域接入时请确认:
- iframe
src指向真实的衡石页面 URL,例如/app/{appId}/dashboard/{dashboardId} - 父页面加载了
hengshi-copilot@<version>.js - iframe URL 带上
agentHost=parent - iframe URL 带上准确的
parentOrigin - 衡石站点允许被你们的门户页面 iframe 嵌入
- 如果 iframe 使用
sandbox,至少需要允许脚本运行和同源能力,例如allow-scripts allow-same-origin - 登录态、JWT 或 SSO 能让 iframe 页面和父页面 SDK 都正常访问衡石接口
通信安全边界是 origin,而不是页面路径。父页面可以是任意路径,但 origin 必须和 parentOrigin 完全一致。
本地联调 Q&A
Q:本地怎么跑一个 SDK + iframe dashboard 的验证页?
研发本地环境通常可以用下面方式验证:
make production
bash ./nginx.sh
brew services reload nginx然后访问本地代理地址,例如:
http://localhost:8881/如果父页面和衡石站点分开跑,常见组合是:
父页面:http://localhost:8882/
iframe:http://localhost:8881/app/{appId}/dashboard/{dashboardId}?agentHost=parent&parentOrigin=http%3A%2F%2Flocalhost%3A8882/sdk/ 只是本地测试页路径,不是产品协议要求。真实接入时父页面路径可以由你们自己的系统决定。
Q:为什么 iframe 里没有 Copilot 侧边栏?
当 iframe URL 使用 agentHost=parent,这是预期行为。Copilot 侧边栏由父页面 SDK 统一承接,iframe 内不再重复显示自己的侧边栏。
Q:为什么父页面 Copilot 没有显示“智能解读”?
优先检查这些点:
- 父页面是否已经加载
hengshi-copilot@<version>.js - iframe URL 是否带了
agentHost=parent parentOrigin是否和父页面 origin 完全一致- iframe 页面是否已经加载到仪表盘页,而不是登录页、空白页或错误页
- 当前用户是否有读取该仪表盘和图表的权限
- 浏览器控制台是否有 iframe 被 CSP、
X-Frame-Options或登录态拦截的错误
Q:Agent 为什么不能直接用浏览器点击 iframe 内部按钮?
父页面 SDK 场景下,Agent 的浏览器窗口是父页面,不是 iframe 内部页面。直接点击、导航或拖拽只能作用在父页面上。
正确方式是让 iframe 仪表盘通过桥接暴露业务动作和业务对象,Agent 再通过这些能力读取、解读或修改仪表盘。
Q:/api/chat/completions 报 400 或 500,和 iframe bridge 有关吗?
通常不是同一个问题。iframe bridge 负责父页面和 iframe 之间的上下文、动作和消息通信,不会把聊天请求体改成另一种 JSON 格式。
排查顺序建议是:
- 400 且提示 JSON parse error:检查请求体是否是合法 JSON,
content-type是否是application/json - 401 / 403:检查登录态、JWT、CSRF 和用户权限
- 本地 nginx 返回 500:先看 nginx error log,再确认
/api代理到了预期后端,例如 develop 或 rc 环境 - 后端返回 500:继续看后端服务日志和模型配置
iframe 不适合解决什么问题
- 不适合深度定制聊天窗口内部 UI
- 不适合把问答结果拆成多个业务模块嵌入不同位置
- 不适合只拿后端能力而不复用页面
- 不适合当成标准图表协议输出能力来使用
如果后续需要这些能力,通常意味着应该改看 JS SDK 集成 或 API 集成。
一句话总结
如果只想最快嵌入完整 ChatBI,直接 iframe /copilot。
如果父页面已经使用 Copilot JS SDK,同时 iframe 里嵌的是衡石仪表盘,就在 iframe URL 上使用 agentHost=parent,让父页面 Copilot 统一接管 iframe 内的智能助理能力。