RxJS for LLM 流式架构

结论:复杂状态流中,一边接收一边解析一边分流一边传递上下文做状态管理又要有错误处理,RxJS 能起到一定程度的作用

什么场景会用到 RxJS?

  • 异步流
  • 多协议解析 (vx, markdown, json, bash script)
  • 分发 (解析之后需要执行)
  • 解耦
  • Scheduler 控制流的调度机制

AI 输出解析的本质

  • 从 HTTP Stream 数据流检测并 分发子语义段落
  • 按照语言类型 分支处理
  • 每个处理器有自己的解析和消费逻辑

RxJS 应用场景

  • 事件驱动,异步解耦,多路流合并 / 拆分
  • 每一段子流可以 filter / groupBy / switchMap / mergeMap
  • 自然支持 取消, 中断, 错误恢复

RxJS 工具功能

  • 操作符 - scan 构造状态机, bufferWhen 拆段, groupBy 语言分发
  • 天然流式 - HTTP Chunk 到一部分处理一部分
  • 高度解耦 - 每个语言逻辑放在单独 pipe() 里面
  • 动态分流 - 在 runtime 动态按照内容格式分给不同分支
  • 中间态可观察 - debug log 状态可视化 (意味着测试驱动,问题可溯源,业务领域分隔)
  • 类型安全 - 符合 TS 设计, 团队成员提效

Q1 - RxJS 过时了吧?

即使操作符复杂,类型安全和 lazy execution 也值得使用 RxJS

Q2 - RxJS 并不适合做状态管理了

of course, 但 RxJS 仍然是最适合在当前 use-case 下大放异彩的

在简单情况下当然不如 mobx, zustand 甚至 signals

Q3 - RxJS 团队不可维护

stackoverflow.com/questions/7...

架构设计中参考 Facade 设计,以简洁形式或 observable 形式暴露,隐藏底层复杂管线

RxJS 的难度本质在于 operator 模式产生的高心智成本 → 认识到问题 → 结合现有 use-case 进行针对性降低维护门槛

RxJS 在这个场景的优势

优势 为什么重要
操作符丰富 scan 构造状态机,bufferWhen 拆段,groupBy 按语言分发
天然流式处理 HTTP chunk 到达一部分就可以处理一部分
高度解耦 每种语言处理逻辑放在单独的 pipe()
动态分流 可以在 runtime 动态按内容格式分给不同分支
中间态可观察 debug、log、状态可视化都很方便

1. 将 stream 转为 Observable

ts 复制代码
import { fromEvent, Observable } from 'rxjs';

function createTextStream(response: ReadableStream<Uint8Array>): Observable<string> {
return new Observable(observer => {
  const reader = response.getReader();
  const decoder = new TextDecoder();

  (async () => {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        observer.complete();
        break;
      }
      observer.next(decoder.decode(value, { stream: true }));
    }
  })();
});
}

2. 使用 scan 构造语言块解析器(Markdown / HTML / JSON / Git log)

ini 复制代码
stream$.pipe(
  scan((state, chunk) => {
    state.buffer += chunk;

    const blocks = extractLanguageBlocks(state.buffer); // 返回 [{type: 'json', content: '...'}]
    state.buffer = getRemainingBuffer(state.buffer); // 剩下没处理完的内容

    blocks.forEach(block => state.blocks.push(block));

    return state;
  }, { buffer: '', blocks: [] }),
  mergeMap(state => from(state.blocks)), // 把 blocks 变成 stream
)

3. 使用 groupBy + 各自的解析逻辑处理

less 复制代码
.pipe(
  groupBy(block => block.type),
  mergeMap(group$ =>
    group$.pipe(
      map(block => parseAndConsume(block)) // 每种语言自己内部 parser + 消费逻辑
    )
  )
)

4. parseAndConsume(block) 结构建议

typescript 复制代码
function parseAndConsume(block: { type: string, content: string }) {
  switch (block.type) {
    case 'json':
      try {
        const obj = JSON.parse(block.content);
        return handleJson(obj); // 解耦的消费者
      } catch {}
      break;
    case 'markdown':
      return renderMarkdown(block.content);
    case 'html':
      return renderHtml(block.content);
    case 'gitlog':
      return parseGitLog(block.content);
    default:
      return null;
  }
}
相关推荐
亚里随笔4 分钟前
稳定且高效:GSPO如何革新大型语言模型的强化学习训练?
人工智能·机器学习·语言模型·自然语言处理·llm·rlhf
smileNicky33 分钟前
SpringBoot系列之从繁琐配置到一键启动之旅
java·spring boot·后端
David爱编程1 小时前
为什么必须学并发编程?一文带你看懂从单线程到多线程的演进史
java·后端
long3162 小时前
java 策略模式 demo
java·开发语言·后端·spring·设计模式
rannn_1113 小时前
【Javaweb学习|黑马笔记|Day1】初识,入门网页,HTML-CSS|常见的标签和样式|标题排版和样式、正文排版和样式
css·后端·学习·html·javaweb
柏油3 小时前
Spring @Cacheable 解读
redis·后端·spring
柏油4 小时前
Spring @TransactionalEventListener 解读
spring boot·后端·spring
SuperherRo4 小时前
Web攻防-大模型应用&LLM安全&提示词注入&不安全输出&代码注入&直接间接&数据投毒
大模型·llm·提示词注入·不安全输出·直接·间接
两码事5 小时前
告别繁琐的飞书表格API调用,让飞书表格操作像操作Java对象一样简单!
java·后端
shark_chili6 小时前
面试官再问synchronized底层原理,这样回答让他眼前一亮!
后端