중복된 Markdown 파싱 제거: 일반적으로 2-10배 빠른 AI 스트리밍
Source: Dev.to
번역을 진행하려면 번역하고자 하는 전체 텍스트(코드 블록 및 URL을 제외한 본문)를 제공해 주시겠어요? 텍스트를 주시면 요청하신 대로 한국어로 번역해 드리겠습니다.
문제
AI가 새로운 텍스트 청크를 스트리밍할 때, 기존 마크다운 파서는 처음부터 전체 문서를 다시 파싱하여 이미 렌더링된 내용에 CPU 사이클을 낭비합니다. Incremark는 문서의 새로운 부분만 파싱함으로써 이를 해결합니다.
벤치마크 결과 – 직접 확인해 보세요
짧은 Markdown 문서
긴 Markdown 문서
참고: 청크 전략에 따라 성능 향상 배수는 실행마다 달라질 수 있습니다.
데모 페이지는 무작위 청크 길이를 사용합니다:
const chunks = content.match(/[\s\S]{1,20}/g) || []
이는 청크가 이전 또는 다음 청크의 내용을 포함할 수 있는 실제 시나리오를 시뮬레이션합니다. 콘텐츠가 어떻게 청크되든 성능 향상은 보장됩니다. 데모는 결과를 부풀리기 위해 인위적인 청크를 사용하지 않습니다.
실시간 데모
- Vue 데모:
- React 데모:
- 문서:
매우 긴 markdown 문서의 경우 이득이 더욱 극적입니다. 20 KB markdown 벤치마크에서 46배의 속도 향상을 달성했습니다. 콘텐츠가 길어질수록 가속도는 커지며, 이론적인 상한선은 없습니다.
주요 장점
| ✅ | 장점 |
|---|---|
| ⚡ | 일반적으로 AI 스트리밍 시나리오에서 2–10× 빠름 |
| 🚀 | 더 긴 문서에 대해 더 큰 속도 향상 (테스트에서 최대 46×) |
| 🎯 | 중복 파싱 없음 – 각 문자를 한 번만 파싱 |
| ✨ | AI 스트리밍에서 점진적 업데이트에 최적화 |
| 💪 | 일반 마크다운에서도 작동 |
| 🔧 | 프레임워크 지원 – 바로 사용할 수 있는 React 및 Vue 컴포넌트 |
Source: …
왜 이렇게 빠른가?
기존 파서의 문제점
AI 채팅 앱을 만들 때, AI는 작은 청크 단위로 출력을 스트리밍합니다. 각 청크가 도착할 때마다 전체 마크다운 문자열을 파서(예: remark, marked.js, markdown‑it)에 전달합니다. 이러한 파서는 매번 전체 문서를 다시 파싱합니다. 이미 렌더링된 안정적인 부분도 다시 파싱하게 되죠. 이 때문에 성능이 크게 낭비됩니다.
vue‑stream‑markdown 같은 도구는 렌더링 레이어에서 안정적인 컴포넌트를 재사용해 개선하지만, 마크다운 텍스트의 반복 파싱—실제 CPU 병목—은 해결하지 못합니다.
Incremark의 핵심 성능 최적화
Incremark의 혁신은 파싱 단계에 있습니다. 불안정한 마크다운 블록만 파싱하고, 안정적인 블록은 절대 다시 파싱하지 않습니다. 이 덕분에 파싱 복잡도가 **O(n²)**에서 **O(n)**으로 감소합니다. 즉, 출력이 길어질수록 성능 향상이 커집니다.
1. 증분 파싱 – O(n²) → O(n)
전통적인 파서는 매 업데이트마다 전체 문서를 다시 파싱해 이차적인 작업량이 늘어납니다. Incremark의 IncremarkParser 클래스는 증분 전략을 구현합니다(IncremarkParser.ts 참고).
// Design Philosophy:
// 1. Maintain a text buffer to receive streaming input
// 2. Identify "stable boundaries" and mark completed blocks as 'completed'
// 3. For blocks currently being received, re-parse only that block's content
// 4. Complex nested nodes are treated as a whole until confirmed complete
2. 지능형 경계 감지
append() 내부의 findStableBoundary() 메서드가 핵심 최적화 포인트입니다.
append(chunk: string): IncrementalUpdate {
this.buffer += chunk
this.updateLines()
const { line: stableBoundary, contextAtLine } = this.findStableBoundary()
if (stableBoundary >= this.pendingStartLine && stableBoundary >= 0) {
// Only parse newly completed blocks, never re-parse already completed content
const stableText = this.lines
.slice(this.pendingStartLine, stableBoundary + 1)
.join('\n')
const ast = this.parse(stableText)
// …
}
}
3. 중복 연산을 방지하는 상태 관리
파서는 중복 작업을 막기 위해 여러 상태를 유지합니다.
| 상태 | 목적 |
|---|---|
buffer | 아직 파싱되지 않은 누적 내용 |
completedBlocks | 절대 다시 파싱되지 않는 블록 배열 |
lineOffsets | 라인 길이의 누적 합으로 O(1) 라인‑오프셋 조회 가능 |
pendingStartLine | 현재 수신 중인 블록의 첫 번째 라인 인덱스 |
stableBoundary | 안정적이라고 보장되는 마지막 라인 |
새롭게 안정화된 영역만 업데이트함으로써 Incremark은 선형 시간 증분 파싱을 구현합니다.
시작하기
# Install the core library
npm i incremark
# For Vue
npm i incremark-vue
# For React
npm i incremark-react
// React example
import { IncremarkRenderer } from 'incremark-react'
function ChatMessage({ stream }) {
return <IncremarkRenderer markdown={stream} />
}
<script setup>
import { IncremarkRenderer } from 'incremark-vue'
defineProps({ stream: String })
</script>
<template>
<IncremarkRenderer :markdown="stream" />
</template>
License
Incremark는 MIT 라이선스에 따라 배포됩니다. 자유롭게 사용하고, 수정하며, 기여하세요!
점진적 계산
context: 코드 블록, 리스트 등 의 중첩 상태를 추적합니다.
4. Incremental Line Update Optimization
updateLines() 메서드는 전체 split 작업을 수행하지 않고 새로운 내용만 처리합니다:
private updateLines(): void {
// Find the last incomplete line (which may be continued by a new chunk)
const lastLineStart = this.lineOffsets[prevLineCount - 1];
const textFromLastLine = this.buffer.slice(lastLineStart);
// Re‑split only the last line and subsequent content
const newLines = textFromLastLine.split('\n');
// Only update the changed portions
}
성능 비교
| 문서 크기 | 전통 파서 (문자) | Incremark (문자) | 감소율 |
|---|---|---|---|
| 1 KB | 1,010,000 | 20,000 | 98 % |
| 5 KB | 25,050,000 | 100,000 | 99.6 % |
| 20 KB | 400,200,000 | 400,000 | 99.9 % |
핵심 불변식
Incremark의 성능 이점은 핵심 불변식에서 비롯됩니다: 블록이 완료된 것으로 표시되면 다시 파싱되지 않습니다. 이는 각 문자가 최대 한 번만 파싱되도록 보장하여 O(n) 시간 복잡도를 달성합니다.
🚀 지금 시작하세요
불필요한 파싱에 CPU 사이클을 낭비하지 마세요. 오늘 Incremark를 사용해 보세요:
빠른 설치
npm install @incremark/core
# For React
npm install @incremark/react
# For Vue
npm install @incremark/vue
리소스
- 📚 문서
- 🎮 실시간 데모 (Vue)
- 🎮 실시간 데모 (React)
- 💻 GitHub 저장소
사용 사례
다음에 적합합니다:
- 🤖 스트리밍 응답을 지원하는 AI 채팅 애플리케이션
- ✍️ 실시간 마크다운 에디터
- 📝 실시간 협업 문서
- 📊 마크다운 콘텐츠가 포함된 스트리밍 데이터 대시보드
- 🎓 인터랙티브 학습 플랫폼
AI 인터페이스를 구축하든, 더 빠른 마크다운 렌더링을 원하든, Incremark는 필요한 성능을 제공합니다.
💬 Try It Out & Show Your Support
I’d love for you to try Incremark in your projects and see the performance difference for yourself! The live demos are the best way to experience the speed improvements in action.
If you find Incremark useful, please consider giving it a ⭐ star on GitHub—it really helps the project gain visibility and motivates me to keep improving it. Your feedback, issues, and contributions are also highly welcome!
- 🌟 Star on GitHub
- 💡 Report Issues or Ideas
- 🤝 Contribute: Pull requests are welcome!
Thank you for your interest in Incremark! Let’s make markdown rendering faster together. 🚀

