今天发布了 Incremark 0.3.0:双引擎架构 + 完整插件生态, AI 流式渲染的终极方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
1244943563
V2EX    程序员

今天发布了 Incremark 0.3.0:双引擎架构 + 完整插件生态, AI 流式渲染的终极方案

  •  
  •   1244943563 10 天前 1025 次点击

    Incremark 0.3.0 发布:双引擎架构 + 完整插件生态,AI 流式渲染的终极方案

    距离上次发帖已经过了一段时间,这段时间我一直在打磨 incremark ,今天正式发布 0.3.0 版本。这次更新的核心是双引擎架构你可以在极速的 marked 和稳定的 micromark 之间自由切换,同时享受完整的插件生态。

    先说结论

    md 来源:本地随机抽取的 38 个文件,最大只有 18kb ,文件更大的时候,这个差距只会随指数拉大,没有专门写测试 markdown 文件,就拉了文档中的一些 md 以及使用 cursor 时候生成的一些文档。可查看文档看详细数据 详细数据

    对比方案 平均优势 最大差距
    vs Streamdown 6.1 倍 16.4x
    vs ant-design-x 7.2 倍 18.9x
    vs markstream-vue 28.3 倍 65.6x

    基于 38 个真实 markdown 文档( 6,484 行,128.55 KB )的基准测试结果。

    在线体验:

    为什么要做双引擎?

    上次发帖后收到很多反馈,主要集中在两个方向:

    1. "能不能更快?" 性能党
    2. "能不能支持 xxx 语法?" 功能党

    这两个需求看似矛盾,但我找到了一个优雅的解决方案:双引擎架构

    Marked 引擎(默认) 极速派

    // 默认使用 marked ,可以省略 <IncremarkContent :cOntent="content" :is-finished="isFinished" :incremark-optiOns="{ engine: 'marked' }" /> 

    特点:

    • 极速:针对流式场景深度优化
    • 自研扩展:我们为 marked 补齐了脚注、数学公式、自定义容器、内联 HTML 解析
    • Tree-shaking 友好:只打包你用到的功能

    Micromark 引擎 稳定派

    <IncremarkContent :cOntent="content" :is-finished="isFinished" :incremark-optiOns="{ engine: 'micromark' }" /> 

    特点:

    • 严格 CommonMark:100% 规范兼容
    • 丰富生态:直接使用 micromark/mdast 社区的所有插件
    • 稳定可靠:久经考验的解析器

    Tree-shaking 优化

    为了打包体积,我们做了 tree-shaking 优化:

    // 默认只打包 marked (极速模式) import { createIncremarkParser } from '@incremark/core' const parser = createIncremarkParser({ gfm: true }) // 如果需要 micromark ,单独导入 import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true }) 

    这样你的项目只会打包你实际使用的引擎,不用担心 bundle 体积问题。

    我们为 Marked 做了什么增强?

    原生 marked 不支持很多 AI 场景常用的语法,我们通过自研扩展补齐了这些能力:

    功能 原生 Marked Incremark Marked Streamdown
    脚注 完整 GFM 脚注
    数学公式 $...$$$...$$ 部分
    自定义容器 :::tip:::warning
    内联 HTML 解析 基础 完整 HTML 树 基础

    这解释了为什么在某些基准测试中 Incremark 看起来"更慢"因为我们在做更多的事情

    文件 Incremark Streamdown 说明
    footnotes.md 1.7 ms 0.2 ms Streamdown 跳过了脚注解析
    FOOTNOTE_FIX_SUMMARY.md 22.7 ms 0.5 ms 同上

    这是功能差异,不是性能问题。 Streamdown 跳过不支持的语法所以看起来更快,而 Incremark 完整解析了所有内容。

    完整基准测试数据

    为了让大家心里有底,我把 38 个测试文件的完整数据都放出来:

    文件 行数 大小 Incremark Streamdown ant-design-x markstream-vue
    introduction.md 34 1.57 KB 5.6 ms 4.5 ms 12.8 ms 57.5 ms
    quick-start.md 71 3.14 KB 12.8 ms 26.7 ms 37.9 ms 214.2 ms
    concepts.md 91 4.38 KB 12.0 ms 50.5 ms 51.5 ms 287.5 ms
    comparison.md 109 5.39 KB 20.5 ms 94.9 ms 85.2 ms 418.9 ms
    OPTIMIZATION_SUMMARY.md 391 8.90 KB 19.1 ms 208.4 ms 340.3 ms 1685.7 ms
    BLOCK_TRANSFORMER.md 489 9.24 KB 75.7 ms 320.9 ms 619.9 ms 2268.7 ms
    test-md-01.md 916 17.67 KB 87.7 ms 1441.1 ms 1656.9 ms 7927.9 ms

    规律很明显:文档越长,Incremark 的优势越大。 这就是 O(n) vs O(n) 的威力。

    核心架构一览

    ┌─────────────────────────────────────────────────────────────────┐ │ IncremarkContent │ │ (声明式组件,处理 content/stream 输入) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ IncremarkParser │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ 双引擎 AST 构建器 │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ │ MarkedAstBuilder│ │MicromarkAstBuilder│ │ │ │ │ (默认,极速) │ │ (稳定,严格) │ │ │ │ └──────────────────┘ └──────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ BlockTransformer │ │ (打字机效果,字符级增量渲染) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Vue │ │ React │ │ Svelte │ │ │ │ 组件库 │ │ 组件库 │ │ 组件库 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────┘ 

    最简使用方式

    我们推荐使用 IncremarkContent 组件,这是最简单的方式:

    <script setup> import { ref } from 'vue' import { IncremarkContent } from '@incremark/vue' const cOntent= ref('') const isFinished = ref(false) // 处理 AI 流式输出 async function handleStream(stream) { content.value = '' isFinished.value = false for await (const chunk of stream) { content.value += chunk } isFinished.value = true } </script> <template> <IncremarkContent :cOntent="content" :is-finished="isFinished" :incremark-optiOns="{ gfm: true, math: true }" /> </template> 

    新增 Svelte 支持

    应社区要求,我们新增了 Svelte 5 支持:

    pnpm add @incremark/svelte 
    <script lang="ts"> import { IncremarkContent } from '@incremark/svelte' let cOntent= $state('') let isFinished = $state(false) </script> <IncremarkContent {content} {isFinished} /> 

    致 V2EX 社区

    说实话,这个项目的 star 大部分应该都是 V2EX 的朋友们贡献的。上次发帖后收到了很多有价值的反馈:

    • @Leon6868 提的淡入动画 → 已实现 effect: 'fade-in'
    • @weareoutman 提的 memo render → 我们的 BlockTransformer 就是干这个的
    • 还有很多关于性能、兼容性的讨论

    感谢大家的支持和反馈,让这个项目越来越好。

    资源链接


    如果觉得有用,欢迎 star

    有任何问题或建议,欢迎在评论区讨论,或者直接提 issue 。

    lizhenda
        1
    lizhenda  
       10 天前
    体验了下很棒,性能很强
    1244943563
        2
    1244943563  
    OP
       9 天前
    @lizhenda 感谢感谢,今天因为这个 issue https://github.com/kingshuaishuai/incremark/issues/4 做了性能优化,在渲染上保持最少的更新,性能也拉满了。

    目前算是接近稳定了,社区再跑一段时间修修 bug 再发 1.x
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2779 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 13:00 PVG 21:00 LAX 05:00 JFK 08:00
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86