Skip to content

CrossBridge 业务集成实战指南:智能体嵌入场景

本文档专门针对 "独立应用 + 嵌入式交付" 的双重业务场景,提供具体的架构设计灵感和代码实现模式。

🎯 核心痛点与解决思路

现状分析

你的智能体应用 (Child) 需要支持:

  1. 独立运行模式: 直接访问 URL,拥有完整的默认功能。
  2. 嵌入运行模式: 被第三方系统 (Parent) 通过 iframe 嵌入,UI 文案和交互行为需要受控于父系统。

CrossBridge 的边界

  • 能做的: 极其稳定地在父子之间传递 JSON 数据、指令、状态字符串。
  • 不能做的: 直接传递 JavaScript Function 对象(序列化会丢失);直接操作对方的 DOM 节点(跨域限制)。

🔑 核心设计模式:数据驱动与控制反转


💡 场景一:子 App 控制父 App (跳转/功能联动)

需求: 子应用中点击按钮,要求主应用跳转页面或打开弹窗。

实现方案:Action Dispatcher 模式

子应用不应该关心"如何跳转",它只需要发出"请求跳转"的意图。

1. 子应用 (Agent Chat) 代码

在子应用中,封装一个统一的行为触发器:

typescript
// utils/action.ts
const handleAction = (actionType: string, payload: any) => {
  // 判断环境:如果是独立运行,执行默认逻辑
  if (bridge.role === 'standalone') {
    if (actionType === 'navigate') {
      window.location.href = payload.url;
    }
    return; // 结束
  }

  // 如果是嵌入环境,将意图"外包"给父页面
  bridge.emit('child-request-action', {
    type: actionType,
    data: payload,
    timestamp: Date.now()
  });
};

// 业务组件中使用
<button onClick={() => handleAction('navigate', { url: '/user/profile' })}>
  查看画像
</button>

2. 父应用 (Container) 代码

父应用注册监听,接管所有请求:

typescript
bridge.on('child-request-action', (request) => {
  switch (request.type) {
    case 'navigate':
      // 父应用使用自己的路由系统进行跳转
      myAppRouter.push(request.data.url);
      break;
      
    case 'open-modal':
      // 打开父应用的弹窗
      Modal.show(request.data.title);
      break;
      
    case 'auth-expired':
      // 处理子应用 Token 过期,父应用弹出登录框
      showLoginDialog();
      break;
  }
});

💡 场景二:父 App 修改子 App 的文案和点击事件

需求: 交付给客户A时按钮叫"提交",交互是提交表单;交付给客户B时按钮叫"咨询",交互是跳转客服。

难点: 无法跨域传递函数。

实现方案:UI Configuration + Event Hook 模式

此方案将子应用改造为"可配置组件"。

1. 子应用改造 (数据驱动 UI)

定义一份 UI 配置协议(Schema),并设置默认值。

typescript
// default-config.ts
const defaultConfig = {
  submitBtn: {
    text: '开始对话', // 默认文案
    actionId: 'default-chat', // 默认行为标识
    visible: true
  },
  theme: {
    primaryColor: '#007AFF'
  }
};

// 业务组件 (Vue/React)
const AgentButton = () => {
  const [config, setConfig] = useState(defaultConfig);

  // 监听父页面发来的配置覆盖
  useEffect(() => {
    bridge.on('update-ui-config', (newConfig) => {
      // 深度合并配置
      setConfig(prev => ({ ...prev, ...newConfig }));
    });
  }, []);

  const handleClick = () => {
    // 关键点:点击时,不硬编码逻辑,而是上报行为标识
    const actionId = config.submitBtn.actionId;
    
    // 1. 先尝试执行内部逻辑
    if (actionId === 'default-chat') {
       startChat();
       return;
    }
    
    // 2. 如果是自定义行为,广播出去让父页面处理
    bridge.emit('component-event', {
      source: 'submit-btn',
      actionId: actionId
    });
  };

  if (!config.submitBtn.visible) return null;

  return (
    <button style={{ color: config.theme.primaryColor }}>
      {config.submitBtn.text}
    </button>
  );
};

2. 父应用配置 (客户交付代码)

交付给不同客户时,只需在父页面初始化时发送不同的配置。

typescript
// 客户 A 的父页面代码
await bridge.connect();

// 场景:想要修改文案,并未点击按钮绑定自定义逻辑
bridge.emit('update-ui-config', {
  submitBtn: {
    text: '联系人工客服',   // 修改文案
    actionId: 'customer-service-redirect' // 修改行为标识
  },
  theme: {
    primaryColor: '#FF6600' // 修改皮肤
  }
});

// 监听自定义行为
bridge.on('component-event', (event) => {
  if (event.actionId === 'customer-service-redirect') {
    // 这里写父页面特有的逻辑
    window.open('https://kefu.baidu.com');
  }
});

🚀 总结:架构设计的灵感

为了实现高质量的独立+嵌入双模交付,建议遵循以下三个原则

  1. 子应用"无状态"化 (UI 即函数): 不要在子应用的组件里写死 "点击按钮=发起POST请求"。而是写成 "点击按钮=执行当前配置的 ActionID"。

  2. 父应用是"大脑",子应用是"手脚": 在嵌入模式下,复杂的业务判断(如权限校验、页面跳转、全局弹窗)尽量上浮到父应用处理,子应用只负责展示和基础输入。

  3. 定义协议 (Protocol): 你需要维护一份 JSON 协议文档,告诉你的集成方:

    • 发送什么 JSON 可以通过 update-ui-config 改界面。
    • 监听什么事件可以捕获 child-request-action

使用 CrossBridge 插件,你已经拥有了最稳固的通信管道。现在只需要在其实封装这层简单的 JSON 协议,就能完美解决你面临的两个交付难题。

Released under the MIT License.