[Open WebUI] MultiResponseMessages에 O(1) Fast-path 비교 추가
PR 링크: open-webui/open-webui#22100 상태: Merged | 변경: +7 / -2
들어가며
Open WebUI의 MultiResponseMessages 컴포넌트는 여러 모델의 응답을 동시에 표시합니다. 메시지가 업데이트될 때마다 변경 여부를 감지하기 위해 JSON.stringify()로 전체 메시지 객체를 직렬화하여 비교하고 있었습니다. 스트리밍 중에는 content 필드만 변경되는 경우가 대부분임에도, 매번 전체 객체를 직렬화하는 비용이 발생했습니다.
핵심 코드 분석
Before: 매번 전체 JSON 직렬화 비교
$: if (history.messages) {
if (JSON.stringify(message) !== JSON.stringify(history.messages[messageId])) {
message = structuredClone(history.messages[messageId]);
}
}
Svelte의 반응성 구문($:)은 history.messages가 변경될 때마다 실행됩니다. 스트리밍 중 토큰이 하나 추가될 때마다 전체 메시지 객체를 두 번 직렬화(JSON.stringify)하고 문자열을 비교합니다.
After: Fast-path + Fallback 패턴
$: if (history.messages) {
const source = history.messages[messageId];
if (source) {
if (message.content !== source.content || message.done !== source.done) {
message = structuredClone(source);
} else if (JSON.stringify(message) !== JSON.stringify(source)) {
message = structuredClone(source);
}
}
}
스트리밍 중 가장 빈번하게 변경되는 content와 done 필드를 먼저 비교합니다. 이 두 필드가 같으면 대부분 변경이 없으므로, 그때만 비용이 큰 JSON.stringify 비교로 폴백합니다.
왜 이게 좋은가
- O(1) 비교: 스트리밍 중 대부분의 업데이트는
content변경이므로, 문자열 비교 한 번으로 변경을 감지합니다. - 정확성 보장:
content와done외의 필드(예: 메타데이터)가 변경되는 드문 경우에도JSON.stringify폴백으로 정확하게 감지합니다. - null 체크 추가:
source존재 여부를 먼저 확인하여 삭제된 메시지에 대한 안전성도 개선했습니다.
이 패턴은 "저비용 검사를 먼저 수행하고, 필요할 때만 고비용 검사로 전환"하는 최적화의 교과서적 사례입니다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [Open WebUI] JSON.parse(JSON.stringify()) 를 structuredClone으로 교체
- 현재글 : [Open WebUI] MultiResponseMessages에 O(1) Fast-path 비교 추가
- 다음글 [Open WebUI] buildMessages에서 불필요한 객체 스프레드 제거
댓글