Skip to content

042. AI 流式更新表单实现

学习目标

这一节把上一节的流式更新原理写成可运行逻辑。

学完后,你应该能理解:

  • 如何收集 AI 每次返回的 chunk;
  • 为什么要从 data_start 之后才开始处理;
  • bufferText 为什么必须放在循环外;
  • 如何只解析已经完整的行;
  • 为什么流式更新时要暂时隐藏预览区;
  • useBufferStreamHandler 如何把复杂逻辑封装起来。

从 chunk 开始理解

流式响应会把内容拆成很多小片段。

前端先监听 AI 消息更新事件,把每次返回的文本片段收集起来。

这一步不是为了马上展示所有内容,而是为了观察真实返回格式:哪些内容是思考、哪些内容是标记、哪些内容才是表单字段和值。

只处理 data_start 之后的内容

AI 返回的文本前面可能包含说明、思考或其他非结构化内容。

真正要写入表单的数据,从约定标记之后开始。

所以解析逻辑需要先判断是否进入数据区域。

还没有进入数据区域时,chunk 只继续累积,不写表单。

bufferText

bufferText 用来保存还没有处理完的文本。

每次收到新的 chunk,都要追加到同一个变量里:

ts
bufferText += chunkText;

这个变量必须放在循环或回调外面。

如果每次收到 chunk 都重新创建一个空字符串,前面的未完成内容就会丢失,后续解析自然不会稳定。

找最后一个换行符

一条字段更新通常按行分隔。

但 chunk 可能只返回半行。

所以处理时要找最后一个换行符:

  • 换行符前面的内容,可以认为是完整行;
  • 换行符后面的内容,可能还没返回完,要继续留在 bufferText

这样就不会把半截字段误解析成完整数据。

解析完整行

完整行再按等号拆成路径和值。

例如:

txt
basicInfo.0.value=13800000000

解析后得到:

  • path: basicInfo.0.value
  • value: 13800000000

然后把 value 写入 path 对应的表单位置。

为什么不要重复解析全部内容

如果每次收到 chunk 都从头解析全部文本,数据越多越慢。

更合理的方式是:

  • 只处理已经完整的新行;
  • 处理完就从 buffer 里移除;
  • 保留最后那段未完成文本。

这也是流式更新能保持顺滑的关键。

常见分隔选择

当前设计用换行符分隔字段。

它的限制是:字段值里不适合再包含换行。

如果后续需要支持多行文本,可以让 AI 在每个字段末尾输出一个特殊结束标记。

分隔符没有绝对标准,重点是前后端和提示词要保持同一套协议。

预览区要暂时隐藏

流式更新时,表单数据处于半成品状态。

例如某个列表项刚生成标题,后续内容还没生成。

如果这时预览组件马上渲染,可能会因为字段缺失报错。

即使不报错,预览区也会频繁重绘,性能会变差。

更稳的做法是:

  • AI 更新开始时,切到表单数据视图;
  • 预览区显示加载状态;
  • 更新完成后,再切回预览视图。

useBufferStreamHandler

useBufferStreamHandler 封装了这套流程。

它负责:

  • 接收 chunk;
  • 维护 buffer;
  • 判断是否进入数据区域;
  • 提取完整行;
  • 解析路径和值;
  • 调用表单更新函数;
  • 在完成时触发收尾逻辑。

这样后续做发票识别、简历翻译、表单生成时,都可以复用同一套流式字段更新能力。

这一节的重点

这一节的核心不是某个 UI,而是流式结构化数据的处理方法。

你需要记住:

  • chunk 不是完整数据;
  • buffer 负责拼接不完整内容;
  • 只处理完整行;
  • 已处理内容要移除;
  • 更新期间不要让复杂预览组件吃半成品数据。

AI Agent 课程学习文档。