Show HN: サーバーまたはクライアントでLLM Markdownストリームをインクリメンタルに解析する
ストリーム対応のMarkdownパーサーで、LLMが生成するMarkdownストリームをインクリメンタルに解析し、確定したブロックのみを段階的に出力します。
大規模言語モデル(LLM)がストリーム出力を行う際、Markdown形式のテキストを段階的に生成することがよくあります。従来のMarkdownパーサーは完全な入力を必要とするため、ストリーム処理には適していません。この問題を解決するために、開発者のnimeshnayaju氏はTypeScript製のライブラリ「markdown-parser」を公開しました。このパーサーはストリームモードで動作し、LLMが生成するMarkdownをインクリメンタルに解析しながら、確定したブロックのみを出力します。
このパーサーはCommonMark仕様に完全準拠しており、GitHub Flavored Markdown(GFM)テーブルもサポートしています。サーバーサイドでもクライアントサイドでも利用可能で、内部状態を保持しながらparse()メソッドが呼ばれるたびに新たに確定したブロックだけを返します。ストリームが終了したら、全てのオープンブロックを閉じて完全なASTを得ることができます。
インストールはnpm install markdown-parserで完了し、基本的な使用方法はMarkdownParserインスタンスを作成してparse()メソッドを呼び出すだけです。ストリームモードでは、テキストを連続的に渡すことで段階的な解析結果を取得できます。例えば以下のように使用します:
import { MarkdownParser } from "markdown-parser";
const parser = new MarkdownParser();
let nodes = parser.parse("# Hello World\nThis", { stream: true });
// 見出しノードのみ返され、段落はまだ未完了
nodes = parser.parse(" is a paragraph\n\nThis is another paragraph.", { stream: true });
// 段落ノードが返されるまた、実験的な機能としてexperimental_openNodeプロパティが用意されており、現在解析中の開いているブロックをプレビューできます。これにより、ストリーミング中に部分的な内容を事前に表示することが可能ですが、このノードはまだ確定していないため、追加の入力によって変更される可能性があります。
内部実装では、commonmark.js、markdown-it、marked.jsなどのパーサーから影響を受けており、構造的にはcommonmark.jsに似ています。主な違いは、ストリームモードでどの行を解析するかの判断方法です。開発者は当初、よりシンプルで読みやすい実装を試みましたが、ブロックコンテナー(引用ブロックやリスト)のサポートを追加する際に複雑さが増し、最終的により堅牢で拡張性のあるアプローチを採用しました。
CommonMark仕様では、リンク参照定義がそれを使用するリンクの後に現れることを許容しています。そのため、ストリーム解析時には、リンク参照が即座に解決できない可能性があることを考慮する必要があります。定義が後続の入力チャンクに含まれるかもしれないからです。
markdown-parserはCommonMark仕様のすべてのブロックノードとインラインノードをサポートしており、見出し、段落、コードブロック、水平線、HTMLブロック、引用ブロック、リスト、リンク参照定義、GFMテーブルなどをカバーしています。インラインノードとしては、テキスト、コードスパン、改行、インラインHTML、自動リンク、リンク、画像、強調、強い強調などがあります。
ストリーム対応Markdownパーサーとして、markdown-parserはLLM出力のリアルタイムレンダリングに効率的で標準準拠のソリューションを提供します。チャットボットやコード生成、その他のストリーミングテキストアプリケーションにおいて、インクリメンタルなMarkdownコンテンツを適切に処理するのに役立ちます。このプロジェクトは完全にオープンソースでMITライセンスの下で公開されており、ソースコードはGitHubでホストされ、オンラインデモページも提供されています。