欢迎光临
我们一直在努力

流式数据 Chunk 合并算法:像搭积木一样拼凑完整内容

引言:为什么我们需要 Chunk 合并?

在现代 Web 开发中,接入大语言模型(LLM)已经成为一种常态。为了让用户能够实时看到 AI 的思考过程,我们通常会采用流式传输(Streaming)技术,例如 Server-Sent Events (SSE)。在这种模式下,服务端不会等所有内容生成完毕再一次性返回,而是像打字机一样,将内容切割成无数个微小的数据块(Chunk)源源不断地推送到前端。

然而,这种\”碎片化\”的传输方式给前端渲染带来了不小的挑战。AI 返回的内容往往包含复杂的排版,比如 Markdown 代码块、表格等。如果前端不做任何处理,直接将这些零散的 Chunk 拼接渲染,用户就会看到代码块在生成过程中频繁闪烁,或者表格的边框被硬生生地拆开。为了解决这个问题,我们需要一种机制,能够在数据流动的过程中,智能地识别并\”拼凑\”出完整的结构化内容。这就是 Chunk 合并算法的核心价值所在。

通俗解释:看标签的快递分拣法

想象一下,你正在接收一个特殊的快递。但这位快递员非常调皮,他不是一次性把整个包裹交给你,而是把包裹拆成无数个小碎片,随机地扔给你。

更麻烦的是,这些碎片里混杂着两种不同的物品:“乐高积木”(代表代码块、表格等结构化内容)和普通的\”拼图碎片\”(代表纯文本)。而且,同一个乐高积木可能被分成了三次才扔给你。面对满地狼藉,你怎么知道哪几块属于同一个乐高积木呢?

最聪明的解决方案是\”看标签\”法,也就是边界检测。我们可以给每种东西定个规矩:比如乐高积木的盒子上明确写着\”开始\”和\”结束\”的标签。当你收到一块碎片时,只需要看一眼:

  • 如果碎片上有\”开始\”标签,说明一个新的乐高积木来了,你需要拿一个全新的空盒子来装它。
  • 如果碎片上有\”结束\”标签,说明这个积木已经拼完了,你可以把这个盒子封好,放到旁边的\”已完成\”堆里。
  • 如果碎片上什么标签都没有,说明它是刚才那个还没装完的积木的一部分,你只需要把它直接塞进当前正在使用的盒子里即可。
  • 通过这种简单的状态流转,我们就能在混乱的碎片中,有条不紊地组装出完整的物品。

    算法步骤详解

    将上述通俗的逻辑转化为严谨的算法,主要分为以下四个核心步骤:

  • 定义规则:首先需要明确不同内容类型的边界标记。例如,Markdown 代码块的开始标记和结束标记都是三个反引号(“`),而表格可能有特定的起始和结束符号。

  • 维护状态:在内存中,我们需要始终维护一个\”当前正在组装的盒子\”,在算法中通常称为\”当前活跃片段(Active Chunk)\”。

  • 处理新碎片(Chunk):每当接收到一个新的数据块时,执行以下判断逻辑:

    • 检测开始标记:如果当前没有活跃片段,且新数据包含开始符号,则创建一个新的片段对象,并将其设为活跃状态。
    • 检测结束标记:如果当前存在活跃片段,且新数据包含结束符号,则将数据追加进该片段,随后将其标记为\”完成\”,移入已完成列表,并清空活跃状态。
    • 默认情况:如果没有检测到任何特殊标记,则将数据直接追加到\”当前活跃片段\”的内容中。
  • 状态流转:整个算法的状态机非常清晰:初始状态(无活跃片段) -> 检测到开始标记 -> 活跃状态(接收中) -> 检测到结束标记 -> 完成状态(归档)。

  • 代码实现

    下面我们通过 Vue 3 结合 TypeScript 的 Setup 语法糖,来实现这个流式数据合并算法。

    <script setup lang=\”ts\”>
    import {

    ref } from \’vue\’;

    // 1. 类型定义
    enum ChunkType {


    TEXT = \’text\’,
    CODE = \’code\’,
    TABLE = \’table\’,
    }

    interface ContentChunk {


    id: string;
    type

    赞(0)
    未经允许不得转载:171主机测评 » 流式数据 Chunk 合并算法:像搭积木一样拼凑完整内容
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址