• HTML Ingest 레이어는 원문 HTML을 LLM-wiki Ingest flow가 다루는 claim/concept 파이프라인에 넣기 전, 본문만 추출·정규화하는 단일 전처리 계층 — 인터페이스(HTML in → 정규화 Markdown + 해시 out)만 고정이고 내부 구현체는 교체 가능
  • 기존 LLM-wiki Ingest flow.md가 이미 markdown(A.md, B.md)부터 시작하는 claim 추적을 다루므로, 이 레이어는 그 앞 단계(HTML → 정규화된 markdown)만 담당하는 상보적 구조
  • Karpathy의 raw→wiki→schema 3계층 패턴과 Glean의 하이브리드 검색 구조 중 레드팀에서 사실로 확인된 부분만 근거로 채택하고, 미검증 벤치마크 수치는 배제한 설계 기준

해당 개념이 필요한 이유

  • LLM-wiki Ingest flow의 예시(A.md, B.md)는 이미 깨끗한 markdown이라고 가정한다. 실제 원문이 HTML(공지사항, 고시, 게시판)일 때는 네비게이션·광고·사이드바가 chunk에 섞이거나 표·각주가 boilerplate와 함께 유실되는 문제가 그 앞 단계에서 먼저 발생한다
  • 이 문제를 claim/concept 레이어 안에서 고치려 하면 stableChunkId, sourceHash 같은 기존 추적 규칙과 충돌한다. HTML 정규화는 별도 레이어로 분리해 기존 pipeline은 그대로 두고 입력만 깨끗하게 만드는 것이 맞다
  • Andrej Karpathy gist와 nashsu/llm_wiki 저장소(레드팀 검증 완료)가 공통으로 Readability.js + Turndown.js 조합을 쓰는 것이 확인됐다 — 이 조합을 기본 구현체로 채택하되, 레이어 자체가 이 두 라이브러리에 종속되지 않도록 인터페이스만 고정한다

AS-IS

flowchart TD
    H["HTML 원문<br/>(네비게이션·광고·사이드바 포함)"] --> S1["step1 Discover/Classify<br/>(LLM-wiki Ingest flow.md)"]
    S1 --> S2["step2 Parse/Chunk<br/>heading 기준 분할"]
    S2 --> P["정제되지 않은 chunk"]

이 상태로 넘기면 생기는 문제: nav/ads가 chunk에 섞이고, 표·각주가 boilerplate와 함께 유실되며, heading 구조가 HTML DOM 순서에 그대로 종속된다.

TO-BE

flowchart TD
    subgraph NEW["HTML Ingest 레이어 (신규, 이 문서의 범위)"]
        H["HTML 원문"] --> N["본문 추출 + Markdown 정규화"]
        N --> HS["정규화 해시 계산"]
    end
    HS --> S1["step1 Discover/Classify<br/>(기존 LLM-wiki Ingest flow.md)"]
    S1 --> S2["step2 Parse/Chunk"]
    S2 --> S3["step3 Queue Wiki work"]
    S3 --> S4["step4 이후 동일<br/>(claim 생성 → concept wiki)"]

    classDef pluggable fill:#FEF3C7,stroke:#D97706,stroke-width:2px,stroke-dasharray: 5 5
    class N pluggable

🟧 점선·주황 노드 = 구현체를 자유롭게 교체할 수 있는 지점(인터페이스만 고정). 나머지 실선 노드는 이 문서·기존 문서가 고정한 단계다.

HTML Ingest 레이어 상세

이 레이어의 책임은 하나다 — HTML을 받아 정규화된 Markdown과 해시를 낸다. 내부를 본문 추출/Markdown 변환 2단계로 나눌지 단일 구현체로 합칠지는 구현 선택이고, 레이어 경계와는 무관하다.

  • 인터페이스: 입력은 HTML, 출력은 정규화된 Markdown 문자열 + sourceHash(sha256) 하나뿐이다. 이 두 값만 맞으면 LLM-wiki Ingest flow의 stableChunkId(sourcePath, sourceHash, ordinal, heading) 규칙에 그대로 올라탄다 — 별도의 ID 체계를 만들 필요가 없다
  • 기본 구현체: Readability.js(본문 추출) + Turndown.js(Markdown 변환) 조합. nashsu/llm_wiki가 웹클리퍼에서 동일 조합을 쓰는 것이 레드팀 검증에서 확인됐다
  • 처리 못 하는 것 (명시적 한계): JS로 렌더링되는 동적 페이지(헤드리스 브라우저 렌더링 필요), 페이지네이션된 목록(별도 크롤링 정책 필요)은 이 레이어의 책임 밖이며, 상위 수집기(크롤러/웹클리퍼)에서 먼저 해결돼야 한다

구현체는 교체 가능 — 성능에 직접 영향

레이어 인터페이스만 고정하고 내부 구현체를 바꾸면 본문 추출 정확도·표/각주 보존율·처리 속도가 달라진다. 표가 깨지면 A조 2항 같은 정확한 키워드 검색이 RAG, LLM wiki 관계의 FTS 레이어에서 무력화되므로, 구현체를 바꿀 때는 표 보존율을 회귀 확인 대상으로 삼아야 한다.

구현체특징비고
Readability.js + Turndown.js본문 추출/Markdown 변환이 분리된 JS 2단계 조합nashsu/llm_wiki에서 실사용 검증됨 (기본값)
trafilatura본문 추출+Markdown 변환을 한 번에 처리하는 Python 단일 라이브러리언어 감지·boilerplate 제거 내장
unstructured.ioHTML 외 PDF/DOCX 등도 함께 처리하는 통합 파서파이프라인은 무거워지지만 포맷 커버리지가 넓음

구현체를 바꾸더라도 위 인터페이스(HTML in → 정규화 Markdown + 해시 out)만 지키면 이후 LLM-wiki Ingest flow 단계는 전혀 수정할 필요가 없다.

전체 레이어 Wrap-up

기존 두 문서의 내부 로직은 그대로 두고, HTML Ingest 레이어를 맨 앞에 붙여 전체를 한 그림으로 정리하면 다음과 같다.

flowchart TD
    subgraph L_HTML["HTML Ingest 레이어 (신규 · 이 문서)"]
        H1[HTML 원문] --> H2["본문 추출 + Markdown 정규화"] --> H4[정규화된 Markdown + 해시]
    end

    subgraph L_CLAIM["Claim/Concept 레이어 (기존 · LLM-wiki Ingest flow.md)"]
        C1["step1~2<br/>Discover/Parse/Chunk"] --> C1Q["step3<br/>Queue Wiki work"]
        C1Q --> C2["🤖 step4~5<br/>LLM Generate/Validate"]
        C2 --> C3["step6~7<br/>wiki page + claims.json"]
        C3 --> C4["step8<br/>concept wiki 생성"]
    end

    subgraph L_INDEX["검색 인덱스 레이어 (기존 · RAG, LLM wiki 관계.md)"]
        I1[(Vector DB)]
        I2[(FTS 인덱스)]
        I3[(Graph DB)]
    end

    subgraph L_RAG["RAG 질의 응답 레이어 (기존)"]
        Q[사용자 질문] --> RT[Retriever] --> CTX[관련 Context 선택] --> ANS["🤖 LLM 답변 생성"]
    end

    H4 --> C1
    C1 -. chunk/claim 텍스트 .-> I2
    C2 -. claim 임베딩 .-> I1
    C4 -. concept/관계 .-> I3
    I1 --> RT
    I2 --> RT
    I3 --> RT
    CTX --> ANS

    classDef pluggable fill:#FEF3C7,stroke:#D97706,stroke-width:2px,stroke-dasharray: 5 5
    classDef llmUsed fill:#DBEAFE,stroke:#2563EB,stroke-width:2px
    class H2 pluggable
    class C2,ANS llmUsed
  • 🟧 점선·주황 노드(H2)는 위 TO-BE 다이어그램과 같은 의미 — 구현체 교체 가능 지점이다

  • 🤖 파란 노드(C2, ANS)는 로컬 LLM(Gemma/Qwen)이 실제로 호출되는 단계다. 나머지는 청킹·큐잉·파일 쓰기·그룹핑처럼 결정론적 코드 처리이며, I1(Vector DB)의 임베딩 계산도 별도의 임베딩 모델을 쓰는 것이라 이 뱃지 대상이 아니다

  • 왼쪽 두 subgraph(L_HTML, L_CLAIM)가 “지식 구축” 축이고, 오른쪽 두 subgraph(L_INDEX, L_RAG)가 “질의 응답” 축이다 — 이 구분은 RAG, LLM wiki 관계에 이미 있던 구조를 그대로 따른 것이다

  • L_HTML은 이 문서가 추가하는 유일한 신규 박스이고, 나머지 3개는 기존 문서를 참조만 한다 — 내부 단계(step1~8, claim 병합 로직, concept grouping)는 LLM-wiki Ingest flow를 그대로 본다

  • step3 Queue Wiki work는 LLM-wiki Ingest flow 원본에서 “backend 전용 내부 큐 단계”로 설명된다 — chunk가 바로 LLM 호출로 이어지지 않고 이 큐를 거쳐 순차 처리·크래시 복구가 가능해진다. 원본 문서는 visualizer 설명을 단순화하려 이 단계를 생략했지만, 이 문서는 첫 독자가 번호 순서만 보고도 흐름을 따라갈 수 있도록 그대로 표시했다

모델 업그레이드 시 재처리 범위와 기존 한계의 연결

LLM-wiki Ingest flow의 “13. 현재 방식의 한계”는 A.md의 chunk 1개만 바뀌어도 source 전체 claim이 재생성된다는 문제를 다루고, 해결 방향으로 dependsOnChunks 필드를 제안했다. 로컬 LLM을 Gemma4 → Gemma5로 교체하는 상황도 구조적으로 동일한 문제다 — “내용이 바뀐 것”이 아니라 “그 내용을 합성한 모델이 바뀐 것”이 무효화 조건이 된다는 점만 다르다.

flowchart LR
    M["모델 교체<br/>gemma4 → gemma5"] --> V{"claim.synthModelVersion<br/>== 신규 모델?"}
    V -->|예: 이미 최신| K[claim 유지, 재처리 스킵]
    V -->|아니오: 구버전| S[claim stale 처리]
    S --> P["해당 claim만 LLM 재생성"]
    P --> U["wiki/claims.json 갱신<br/>synthModelVersion=gemma5"]
  • HTML Ingest 레이어(L_HTML)는 모델과 무관하므로 Gemma5로 바뀌어도 100% 캐시 재사용 — 재처리 대상이 아니다
  • dependsOnChunks와 동급으로 claim에 synthModelVersion 필드를 추가하면, source-hash 교체(내용 변경)와 model-version 교체(품질 개선)를 같은 무효화 메커니즘으로 처리할 수 있다 — 이전 대화에서 나온 “버전 태깅” 권고가 실제로는 이미 설계된 chunk dependency 구조의 확장판인 셈이다

검증된 사실 vs 미검증 주장 (레드팀 필터)

이 레이어 설계에서 실제로 근거로 쓴 것과 배제한 것을 구분해 둔다 — 인용 시 이 표를 기준으로 한다.

주장판정이 설계에서의 사용
Karpathy raw→wiki→schema 3계층, ingest/query/lint 연산사실 (gist 원문 확인)L_HTML→L_CLAIM 분리의 이론적 근거로 채택
llm_wiki(nashsu)가 Readability.js+Turndown.js+MCP 사용사실 (README 원문 확인)HTML Ingest 레이어의 기본 구현체 선택 근거로 채택 (교체 가능)
Glean 하이브리드 검색(벡터+어휘) + 권한 인지 크롤링사실 (공식 블로그 확인)L_INDEX가 Vector+FTS+Graph 3종을 유지하는 근거로 채택
Qwen3-30B RAGAS faithfulness 0.91검증 불가 (출처 불명 마케팅 글)모델 선택 근거로 사용 금지 — 골든셋 자체 측정으로 대체
Kairntech Qwen-2.5 온프레미스 사례부분 사실 (자사 SEO 블로그 한 줄)“사례가 있다”는 정도로만 인용, 효과 수치로 인용 금지
온프레미스 손익분기 가동률 50~83%부분 사실 (AWS 한정 벤더 블로그)TCO 논의의 참고치로만 사용, 확정 수치로 인용 금지

참고 문서