QBC(行为中心)使用文档

概述

QBC(行为中心)是一个允许业务方订阅和推理行为的模块。它提供了一种集中式的方式来处理不同应用实例之间的正负反馈和推理操作,支持跨实例通信。该模块区分了普通端QBC端两种角色:

  • 普通端:通常是业务页面,调用 init 方法,主要负责发起推理 (infer)、注册反馈监听 (register) 等。
  • QBC端:通常是后台运行的行为中心模块 (pf_behaviorcenter_rn),不调用 init 方法,负责监听普通端的请求 (onInit, onInfer, onDestroy) 并返回结果 (notify*)。

API兼容性: QRN:v6.5.3 iOS:80011137 Android:60001168

安装

该模块通过 qunar-react-native 包提供。

const { QBC } = require('qunar-react-native');

API 参考

普通端接口

1. QBC.init(sceneId, options, callback)

启动行为中心,并将当前实例标记为普通端

const unsubscribe = QBC.init(sceneId, options, result => {
  if (result.code === 0) {
    console.log('行为中心初始化成功:', result.data);
  } else {
    console.error('行为中心初始化失败:', result.msg);
  }
});

参数:

  • sceneId (string): 场景ID,格式为三段式,使用下划线分隔 (_),例如 "部门_业务_场景"
  • options (object, 可选): 初始化时传递给QBC端的额外选项。默认为 {}
  • callback (function): 处理初始化结果的回调函数,接收一个包含 code, data, msg 的结果对象。

返回值:

  • function: 用于取消初始化结果监听的函数(通常不需要手动调用,因为它是内部一次性监听)。

2. QBC.register(sceneId, callback)

注册一个回调函数用于接收指定场景的正负反馈通知。

const unsubscribe = QBC.register(sceneId, feedback => {
  console.log('收到反馈:', feedback);
});

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • callback (function): 处理正负反馈的回调函数。

返回值:

  • function: 用于取消订阅的函数。

3. QBC.registerOnce(sceneId, callback)

注册一个一次性的回调函数,该回调函数将在第一次收到通知后自动取消订阅。

const unsubscribe = QBC.registerOnce(sceneId, feedback => {
  console.log('收到一次性反馈:', feedback);
});

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • callback (function): 处理正负反馈的回调函数。

返回值:

  • function: 用于取消订阅的函数。

4. QBC.unregister(sceneId, callback)

移除指定场景的正负反馈监听器。

const success = QBC.unregister(sceneId, specificCallback);
// 或移除所有
const successAll = QBC.unregister(sceneId);

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • callback (function, 可选): 要移除的特定回调函数。如果不提供,则移除该场景的所有回调。

返回值:

  • boolean: 表示取消注册是否成功。

5. QBC.infer(sceneId, options, callback)

执行推理并注册一个一次性监听器来接收结果。

const unsubscribe = QBC.infer(sceneId, options, result => {
  if (result.code === 0) {
    console.log('推理成功:', result.data);
  } else {
    console.error('推理失败:', result.msg);
  }
});

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • options (object, 可选): 推理时传递给QBC端的额外选项。默认为 {}
  • callback (function): 处理推理结果的回调函数,接收一个包含 code, data, msg 的结果对象。

返回值:

  • function: 用于取消推理结果监听的函数(通常不需要手动调用,因为它是内部一次性监听)。

6. QBC.destroy(sceneId, callback)

销毁指定场景的推理会话,并注册一个一次性监听器来接收销毁结果。

const unsubscribe = QBC.destroy(sceneId, result => {
  if (result.code === 0) {
    console.log('销毁成功');
  } else {
    console.error('销毁失败:', result.msg);
  }
});

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • callback (function): 处理销毁结果的回调函数,接收一个包含 code, data, msg 的结果对象。

返回值:

  • function: 用于取消销毁结果监听的函数(通常不需要手动调用,因为它是内部一次性监听)。

7. QBC.sendData(data)

发送数据到原生推理管理器 (QRCTInferenceManager)。

QBC.sendData({ type: 'custom_event', payload: { ... } });

参数:

  • data (object): 要发送的数据对象。

返回值:

  • void

QBC端接口 (仅限行为中心项目中使用)

8. QBC.onInit(callback)

监听所有普通端的 init() 调用。

const unsubscribe = QBC.onInit(initData => {
  // initData 包含 sceneId, timestamp, options
  console.log('检测到初始化:', initData);
  // 可以根据 initData.sceneId 和 initData.options 进行处理
  // ...
  // 通知普通端初始化结果
  QBC.notifySceneInitResult(initData.sceneId, { code: 0, data: { config: '...' }, msg: '初始化成功' });
});

参数:

  • callback (function): 处理初始化事件的回调函数,接收包含 sceneId, timestamp, options 的数据对象。

返回值:

  • function: 用于取消监听的函数。

9. QBC.onInfer(sceneId, callback)

监听指定场景的 infer() 调用。

const unsubscribe = QBC.onInfer(sceneId, inferData => {
  // inferData 包含 timestamp, options
  console.log(`场景 [${sceneId}] 触发推理:`, inferData);
  // 处理推理逻辑...
  const resultData = { result: 'some_value' };
  // 通知普通端推理结果
  QBC.notifyInferResult(sceneId, { code: 0, data: resultData, msg: '推理成功' });
});

参数:

  • sceneId (string): 要监听的场景ID,格式要求同 init
  • callback (function): 处理推理触发事件的回调函数,接收包含 timestamp, options 的数据对象。

返回值:

  • function: 用于取消监听的函数。

10. QBC.onDestroy(callback)

监听所有普通端的 destroy() 调用。

const unsubscribe = QBC.onDestroy(destroyData => {
  // destroyData 包含 sceneId, timestamp
  console.log('检测到销毁:', destroyData);
  // 处理销毁逻辑...
  // 通知普通端销毁结果
  QBC.notifySceneDestroyResult(destroyData.sceneId, { code: 0, data: null, msg: '销毁成功' });
});

参数:

  • callback (function): 处理销毁事件的回调函数,接收包含 sceneId, timestamp 的数据对象。

返回值:

  • function: 用于取消监听的函数。

11. QBC.notifyFeedBackResult(sceneId, result)

向订阅了指定场景的普通端发送正负反馈结果数据。

QBC.notifyFeedBackResult(sceneId, { value: 1 });

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • result (object): 正负反馈结果数据。
    • value (number): 正负反馈计算结果值。

12. QBC.notifyInferResult(sceneId, result)

向调用了 infer() 并等待结果的普通端发送推理结果数据。

QBC.notifyInferResult(sceneId, { code: 0, data: { ... }, msg: '推理成功' });

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • result (object): 推理结果数据。
    • code (number): 结果状态码 (0 表示成功)。
    • data (object): 结果数据。
    • msg (string): 结果消息。

13. QBC.notifySceneInitResult(sceneId, result)

向调用了 init() 并等待结果的普通端发送初始化结果数据。

QBC.notifySceneInitResult(sceneId, { code: 0, data: { config: '...' }, msg: '初始化成功' });

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • result (object): 初始化结果数据 (格式同 notifyInferResult)。

14. QBC.notifySceneDestroyResult(sceneId, result)

向调用了 destroy() 并等待结果的普通端发送销毁结果数据。

QBC.notifySceneDestroyResult(sceneId, { code: 0, data: null, msg: '销毁成功' });

参数:

  • sceneId (string): 场景ID,格式要求同 init
  • result (object): 销毁结果数据 (格式同 notifyInferResult)。

通用方法

15. QBC.clearAllSubscribers()

清除当前实例的所有订阅者。

QBC.clearAllSubscribers();

场景ID格式

场景ID (sceneId) 必须遵循三段式格式,并使用下划线 (_) 分隔:

  • "部门_业务_场景"

例如:"flight_booking_rerank"

错误处理

模块在以下情况下会抛出错误:

  • 场景ID格式无效。
  • 缺少或无效的回调函数。
  • 通知数据格式无效(例如 _notifydata 参数不是对象)。
  • 场景ID为空字符串。

最佳实践

  1. 始终使用符合格式要求的场景ID。
  2. 当不再需要监听器时(特别是对于 register, onInit, onInfer, onDestroy 返回的函数),记得调用返回的取消订阅函数。
  3. 对于一次性操作(如 init, infer, destroy),通常不需要手动管理返回的取消函数,因为它们是内部一次性监听。
  4. 在回调函数中适当处理错误或检查结果对象的 code 字段。
  5. 在组件卸载时取消所有持久订阅(通过 register, onInit, onInfer, onDestroy 创建的),避免内存泄漏。
  6. 跨实例通信会自动过滤掉自己发出的消息。
  7. QBC端接口(如 onInit, onInfer, onDestroy, notify*)仅应在行为中心项目 (pf_behaviorcenter_rn) 中使用,已通过标题分组说明。

使用示例 (普通端)

import React, { useEffect, useRef } from 'react';
const { QBC } = require('qunar-react-native');

const MyComponent = () => {
  const sceneId = 'flight_booking_rerank';
  const feedbackUnsubscribe = useRef(null);

  useEffect(() => {
    // 初始化,将当前实例标记为普通端
    const initUnsubscribe = QBC.init(sceneId, { version: '1.0' }, initResult => {
      if (initResult.code === 0) {
        console.log('QBC 初始化成功');

        // 注册反馈监听
        feedbackUnsubscribe.current = QBC.register(sceneId, feedback => {
          console.log('收到反馈:', feedback.value);
        });

        // 执行推理
        QBC.infer(sceneId, { context: 'some_data' }, inferResult => {
          if (inferResult.code === 0) {
            console.log('推理结果:', inferResult.data);
          } else {
            console.error('推理失败:', inferResult.msg);
          }
        });

      } else {
        console.error('QBC 初始化失败:', initResult.msg);
      }
    });

    // 组件卸载时清理
    return () => {
      console.log('组件卸载,清理QBC订阅');
      if (feedbackUnsubscribe.current) {
        feedbackUnsubscribe.current(); // 取消反馈监听
      }
      // 注意:init, infer, destroy 返回的取消函数通常不需要手动调用
      // 如果需要强制中断等待结果,可以调用它们
      // initUnsubscribe(); // 如果需要在初始化完成前取消

      // 也可以选择调用 destroy
      // QBC.destroy(sceneId, destroyResult => console.log('销毁结果:', destroyResult));
    };
  }, []);

  // ... 组件渲染逻辑 ...
  return null;
};

export default MyComponent;

使用示例 (QBC端)

import React, { useEffect, useRef } from 'react';
const { QBC } = require('qunar-react-native');

// 假设这是在 pf_behaviorcenter_rn 项目中
const BehaviorCenterModule = () => {
  const onInitUnsubscribe = useRef(null);
  const inferListeners = useRef(new Map()); // 用于存储不同 sceneId 的 onInfer 取消函数
  const onDestroyUnsubscribe = useRef(null);

  useEffect(() => {
    // QBC端不需要调用 init(),默认即为 QBC 端

    console.log('QBC 端模块启动');

    // 监听所有普通端的初始化请求
    onInitUnsubscribe.current = QBC.onInit(initData => {
      console.log(`收到来自场景 [${initData.sceneId}] 的初始化请求:`, initData.options);
      // 模拟异步处理
      setTimeout(() => {
        // 根据场景ID和选项决定初始化结果
        const initConfig = { someConfig: `config_for_${initData.sceneId}` };
        QBC.notifySceneInitResult(initData.sceneId, { code: 0, data: initConfig, msg: '初始化成功' });
        console.log(`已向场景 [${initData.sceneId}] 发送初始化结果`);

        // 在初始化成功后,为该场景监听推理请求 (如果尚未监听)
        if (!inferListeners.current.has(initData.sceneId)) {
          listenToInferRequests(initData.sceneId);
        }
      }, 500);
    });

    // 监听所有普通端的销毁请求
    onDestroyUnsubscribe.current = QBC.onDestroy(destroyData => {
      console.log(`收到来自场景 [${destroyData.sceneId}] 的销毁请求`);
      // 清理与该场景相关的资源...

      // 取消对该场景推理请求的监听
      const unsubscribeInfer = inferListeners.current.get(destroyData.sceneId);
      if (unsubscribeInfer) {
        unsubscribeInfer();
        inferListeners.current.delete(destroyData.sceneId);
        console.log(`已停止监听场景 [${destroyData.sceneId}] 的推理请求`);
      }

      // 模拟异步处理
      setTimeout(() => {
        QBC.notifySceneDestroyResult(destroyData.sceneId, { code: 0, data: null, msg: '销毁成功' });
        console.log(`已向场景 [${destroyData.sceneId}] 发送销毁结果`);
      }, 200);
    });

    // 组件卸载时清理所有监听
    return () => {
      console.log('QBC 端模块卸载,清理所有监听');
      if (onInitUnsubscribe.current) {
        onInitUnsubscribe.current();
      }
      if (onDestroyUnsubscribe.current) {
        onDestroyUnsubscribe.current();
      }
      inferListeners.current.forEach(unsubscribe => unsubscribe());
      inferListeners.current.clear();
      // QBC.clearAllSubscribers(); // 也可以调用此方法
    };
  }, []);

  // 动态为指定场景添加推理监听
  const listenToInferRequests = (sceneId) => {
    console.log(`开始监听场景 [${sceneId}] 的推理请求`);
    const unsubscribe = QBC.onInfer(sceneId, inferData => {
      console.log(`收到场景 [${sceneId}] 的推理请求:`, inferData.options);
      // 模拟异步推理过程
      setTimeout(() => {
        const inferResult = { prediction: Math.random(), context: inferData.options?.context };
        QBC.notifyInferResult(sceneId, { code: 0, data: inferResult, msg: '推理成功' });
        console.log(`已向场景 [${sceneId}] 发送推理结果`);

        // 可以在这里模拟发送反馈
        // setTimeout(() => {
        //   QBC.notifyFeedBackResult(sceneId, { value: inferResult.prediction > 0.5 ? 1 : -1 });
        //   console.log(`已向场景 [${sceneId}] 发送模拟反馈`);
        // }, 1000);

      }, 800);
    });
    inferListeners.current.set(sceneId, unsubscribe);
  };

  // QBC端通常没有UI,这里返回null
  return null;
};

export default BehaviorCenterModule;