首页 > 教程攻略 > ai资讯 >AIGCDesign 开放式跨端 AI 组件解决方案

AIGCDesign 开放式跨端 AI 组件解决方案

来源:互联网 时间:2026-06-09 14:17:49

一、我们为什么要做这样的一件事情?

如果说2022年11月30日发生了什么值得标记的事,那一定是OpenAI团队发布了全新的ChatGPT模型。一个简洁的聊天交互界面,就能完成回答问题、撰写文本、翻译语言、编写代码等多种任务——这种能力跃迁,直接给整个AI行业带来了一场巨变。搜索热度的持续攀升,也从侧面印证了这一点。

AIGC搜索热度-数据来自Google Trends

能力跃升的背后,必然伴随着新产品、新模式的爆发机遇。作为一线的业务研发,我们需要思考的是:如何承接住这股技术革新带来的业务需求激增?过往的经验告诉我们,如果要快速交付大量同类型应用,关键在于分层抽象的、类型丰富的组件沉淀。有了这些组件的复用能力,再结合LowCode/NoCode平台,就能通过“搭积木”的方式快速产出应用。

基于这个判断,我们调研了业界已经初具规模的6类AIGC组件库,梳理了它们的共性与差异,同时也盘点了京东内部现有的平台能力。最终,在京东零售前端通道的支持下,我们启动了一个基于内源共建的开放式跨端AI组件解决方案项目——给它取了个名字:

AIGCDesign

。接下来的内容,我会把这套方案的设计开发理念,以及对未来的思考,详细地讲一遍。

二、前期调研:当前AIGC行业内前端AI组件库的进展

项目启动之初,我们对行业内开源的高Star组件和应用做了一次摸底。从可拓展性、组件覆盖度、端支持、框架支持等多个维度进行了评测,具体如下表:

从这些对比里,我们提炼出几个关键能力项:

  • 轻量、快速开发、开箱即用
  • 覆盖TailWind、React、Vue、Native
  • 会话组件、多模态录入
  • 响应式布局

结合京东内部多种多样的业务形态,以及灵活支持定制的需求,我们的组件库必须具备Native、Web、MP、PC等多端能力,同时要支持React、Vue、Android、iOS等多种技术框架。综合以上考量,我们最终明确了方案的核心定位和目标:

三、AIGCDesign的技术实现

有了核心目标,接下来就是技术选型、技术架构和具体实现细节的落地。

3.1 整体技术架构

组件库借助Taro的跨端能力,输出MP和H5组件。通过Web端的响应式方案,同时支持H5和PC端的内容输出,单React应用也能跑得起来。

在内部,组件库集成了AI接口请求能力(京东言犀)。开发者只需要引用容器组件,做几项简单的配置,就能“开箱即用”地输出一个AI应用。当然,如果某些组件的功能不足以覆盖业务形态,组件库也预留了大量的自定义接口,开发者可以进行高定制化开发,灵活对接私域大模型服务。

整体架构分为三层:

  • 核心层

    :提供AI平台对接相关功能,包括各类基础模块和API。可以在容器或者组件中引用,也可以在项目中独立使用。
  • 容器层

    :支持多端多框架的应用容器,内部对接大模型平台,提供基础的AI会话交互,并且开放会话区域的高度自定义能力。
  • 组件层

    :集合基础组件、业务组件和自定义组件,供容器层渲染使用。通过组件映射的方式,在容器组件中完成渲染。

在原生实现方面,我们采用的是基于JDHybrid的混合架构:

  1. 对经常变更的业务组件或模块,通过H5接入;
  2. 对不经常变更的容器组件、基础组件,通过原生开发;
  3. 业务侧的Taro组件,可以快速复用到Native项目中。

核心实现因此拆分成三部分:

  1. 原生基础组件

    :包含弹层、语音交互、Toast提示、自定义头部、底部输入框、工具箱等。
  2. 原生容器组件

    :负责整体事件、UI、接口请求等配置,是AIGC组件的核心模块。
  3. JDHybrid扩展协议和AIGC JSSDK

    :负责H5与原生容器组件的交互和消息通信。

3.2 应用生命周期

容器组件提供了完整的应用生命周期方法。开发者可以在每一个流程节点进行事件监听,实时获取最新的应用状态。结合生命周期函数和容器属性,可以进行定制化逻辑开发,灵活支持各类业务形态。生命周期的主要特性包括:

  • 容器组件提供全流程生命周期事件,调用方可以随时获取最新的应用上下文和数据
  • 默认提供了京东言犀平台的对接模块,基础配置即可解锁完整的AI会话交互流程
  • 通过容器组件属性配置,可以灵活添加自定义流程控制:模型检索、会话渲染、生命周期等

主要支持以下生命周期Hooks:

  • beforeLaunch

    :容器组件加载前执行
  • onLaunch

    :容器组件加载完成后执行
  • onSubmit

    :用户点击发送按钮后,请求大模型前执行
  • onLLMResult

    :大模型数据返回后执行,用于在组件外部获取返回数据
  • onChatUpdate

    :组件更新完成后执行,代表本次会话更新完成

3.3 用户交互和数据流转流程

交互界面和数据流转流程如下图所示:

3.4 最小化配置和自定义配置方案

组件库内置了AI聊天全流程的交互,少量入参就能实现基础功能。当然,也可以结合生命周期事件和相关属性做定制化配置。

调用方引入容器组件,配置言犀平台的apiKey和大模型平台路径,就可以输出聊天记录界面:

import AiContainer from "@aigcui/container";
...
// 言犀平台apiKey
apiKey='xxx'
// 大模型接口的路径
aiPath='/ChatRhino/api/v1/chat/completions'
/>
...

结合生命周期事件和相关属性配置,可以自定义以下功能:

  • 大模型请求

    :调用方可以自行发起大模型接口请求,并将会话数据注入容器,容器根据注入的数据进行会话区域渲染
  • 会话区域渲染

    :会话区域可以完全交由调用方自定义渲染
  • 会话输入区域扩展图标

    :支持自定义配置,还能实现展开收起功能
  • 快捷操作区域

    :输入框上方支持快捷操作区域的自定义渲染
  • 会话卡片头尾区域

    :会话卡片的头部和底部都支持自定义渲染

3.5 Web平台多框架支持方案

为了实现对多开发框架的支持,除了借助Taro跨端解决方案,组件库还提供了UMD产物。通过加载JS文件的方式,可以将组件渲染到指定DOM节点,同时结合AutoBots平台能力,进行AI应用的输出。

UMD组件基于React开发框架。如果项目内已经全局挂载了React环境,可以引用纯组件代码包;如果全局没有React环境,则可以引用组件库全包进行渲染。全包内部集成了React框架代码,会自动处理React应用和组件的初始化流程,接入方直接在项目内调用组件渲染方法就能输出应用。

全包引用的代码示例如下:


<script src="https://storage.jd.com/taro/aigc-ui/1.0.6/aigcjdfe-autobots-full.umd.js"></script>


window['autobots-full'].renderAiChatBubble({
  width: 500,
  height: 500,
  chatInfo: {
    agentId: 'xxx',
    token: 'xxxxxx',
  }
}, 'app')

四、业务接入案例

基于上述共建形式,目前已经有多端案例接入:

五、AIGCDesign长期努力的方向和价值

组件库目前已经支持MP、Web、Hybrid、Android的AI会话基础能力。通过自定义配置,可以覆盖大部分AI聊天交互场景。最新版本为1.0.6,提供了MP端8个会话组件和Web端14个业务组件。Autobots组件除了NPM包引入方式,还支持UMD方式接入,实现了技术栈无关的全量适配能力。

接下来的时间,我们将在以下两个方面加大对AIGCDesign的投入:

1、根据架构设计,持续完善核心能力

  • 平台能力建设:支持高度灵活的配置化能力,提供便捷的组件产出和搭建能力
  • 多端多框架能力建设:提供NPM/UMD等多种形式产物,输出多端容器和组件,实现技术栈无关的接入能力
  • 底层能力扩充:逐步融合OCR、ASR/TTS、Agent、知识库等多种底层能力

2、2B端/2C端多业务形态支持,多场景交互形式拓展

  • 场景化能力扩展:支持B/C端通用的场景化AI交互能力和组件,极低成本快速接入
  • 通用能力支持:结合AI能力,拓展非对话框场景的交互能力。提供高度可配置化交互组件,支持数据源配置和交互定制化,配合投放平台,满足营销、办公等各类场景

可以确定的是,在京东零售前端通道内源共建小组的努力、内外部贡献者的协同建设,以及京东丰富业务场景的加持下,AIGCDesign一定能够交付更多优秀的能力和组件,为研发提效和业务赋能带来更大的价值。

附、流式处理技术点扩展

1、流式数据接收和处理

1.1 在与AI对话的过程中,比较常用的方式是通过请求支持流式数据的API来获取数据。这种方式的优势很明显——用户可以更快地看到响应数据和输入过程。

1.2 在前端,通过fetch实现流式接口数据请求,依赖的是ReadableStream接口。逐块读取数据并进行处理,可以实现对流式数据的高效处理。同时,使用AbortController可以实现请求的中止,提供更灵活的控制。

async function fetchStream(url, params) {
  const { onmessage, onclose, ...otherParams } = params;
  const response = await fetch(url, otherParams);
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let result = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) {
      onclose?.();
      break;
    };
    result = decoder.decode(value, { stream: true });
    // 处理接收到的数据块
    onmessage?.(result);
  }

  console.log('Stream complete');
}

const controller = new AbortController();
const signal = controller.signal;
fetchStream('https://example.com/stream-endpoint', {
  signal,
  onmessage: (text) => { console.log(text); }
  onclose: () => { console.log('Stream abort'); }
});

// 如果需要提前结束输入,通过调用以下中止请求和修改输入结束状态实现
controller.abort();

流式处理数据的方式主要有两种:

  • 正常按照流式的方式处理

    :触发onmessage时,把拼装好的数据传入handleData方法,实时调用
  • 按非流式的方式处理

    :等流式接口返回已完成标识后,再把拼装好的数据一次性调用handleData

2、流式Markdown渲染

AIGC Web端组件库已经实现了流式Markdown渲染。通过react-markdown组件包裹输入内容,配合rehype-highlight等工具实现markdown格式的内容展示。通过components属性,可以自定义markdown标签的渲染方式。

const BubbleMarkdown: React.FC<{ children?: string }> = ({ children }) => {

  return (
    

{ const href = aProps?.href || ""; const isInternal = /^/#/i.test(href); const target = isInternal ? "_self" : aProps?.target ?? "_blank"; return ; }, }} > {children}

); };

对话框支持以下几种接口返回和渲染方式。无论是流式还是非流式返回,都支持打字机和全量渲染效果:

流式数据处理方式会持续渲染对话框,因此需要对以下几点交互做单独的优化处理:

  1. 对话渲染过程中,不要引起父组件重新渲染
  2. 建议使用模拟输入效果,平缓地控制输入节奏
  3. 当对话内容超出屏幕时,需要向上滚动页面。这种情况需要通过节流控制滚动节奏,避免页面闪动
  4. 对话输入过程中,要禁止用户的输入行为。如果需要继续对话,可以点击中止后再进行用户输入
useEffect(() => {
  if (!isEnd) {
    // 如果服务端返回数据结束,且当前展示文本等于服务端返回文本,则停止输入
    setEntering(!(responseEnded && content === text));
    // 如果是模拟输入,且当前展示文本不等于服务端返回文本,则继续输入
    if (
      simulate &&
      content &&
      content !== text &&
      // 以下逻辑解决流式数据接入且为模拟输入时,文本长度重复触发文本更新问题
      text.length === len.current
    ) {
      const { time, char } = getInputTimeAndChar(
        content,
        simulateSpeed,
        inputTimeAndCharMap,
      );
      const randomLen = getRandomInt(
        char?.[0] || 2,
        char?.[1] || 6
      );
      len.current +=
        len.current + randomLen > content.length
          ? content.length - len.current
          : randomLen;
      timeout.current = setTimeout(() => {
        setText(content?.slice(0, len.current) || "");
      }, getRandomInt(time?.[0] || 60, time?.[1] || 200));
    }
    // 非模拟输入,直接展示服务端返回文本
    if (!simulate) {
      setText(content || "");
    }
  }
}, [
  responseEnded,
  text,
  content,
  simulate,
  isEnd,
  simulateSpeed,
  inputTimeAndCharMap,
]);

相关下载