Skip to content

export-llm: HWP/HWPX → LLM-ready RAG 청크 출력 축 신설 (#4869) - #4871

Open
kevin9327 wants to merge 1 commit into
edwardkim:develfrom
kevin9327:gym_llm_export
Open

export-llm: HWP/HWPX → LLM-ready RAG 청크 출력 축 신설 (#4869)#4871
kevin9327 wants to merge 1 commit into
edwardkim:develfrom
kevin9327:gym_llm_export

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

이슈 #4869 — HWP/HWPX → LLM-ready RAG 출력 축을 신설한다.

왜 (축의 논지)

2025–2026 문서-AI 프런티어(PDF 영역의 Docling·LlamaParse·MarkItDown·Marker·Unstructured 등)는
문서를 RAG-ready 로 바꿔 준다 — 토큰 예산 청킹, 표 선형화, 출처 앵커. 그러나 어느 것도
HWP/HWPX 를 읽지 못한다.
한국 공공·법령·행정 문서 표준이 프런티어의 사각지대에 남아 있다.

rhwp 는 이 공백을 남들보다 정확하게 채울 수 있다. PDF 도구가 좌표로 읽기 순서·표 셀 경계를
추측하는 반면, rhwp 는 이미 이진 구조를 파싱해 그것을 실측으로 갖고 있다. 이 PR 은 재파싱
없이 기존 IR 위에 LLM 패키징 계층만 얹는다:

  • 제목 계층 → queries::structure::build_structure
  • 표 격자(앵커 셀 + 병합 span) → queries::table_extract::extract_tables

무엇을 (새 명령 export-llm)

rhwp export-llm <파일.hwp|파일.hwpx> [--max-tokens <N>] [--format jsonl|json] \
                [--mode auto|outline|clause] [-o <출력>]
  1. 구조 인지 청킹 — 자연 경계(제목/문단/표)에서만 분할, --max-tokens(기본 512) 예산 목표.
    토큰 수는 실제 토크나이저가 아니라 추정이라 필드 이름도 tokenEstimate, 추정기 이름은
    tokenEstimator: "cjk1-latin4-v1"(CJK 1글자=1토큰, 그 밖 4글자=1토큰)로 명시한다.
  2. 자기완결 표 — 표를 Markdown 으로 선형화(머리 행 보존·병합 셀 [병합 R×C] 주석). 예산을
    넘는 큰 표는 행 단위로만 쪼개고 파트마다 머리 행을 되풀이한다(행 중간 절단 없음).
  3. 출처 앵커 — 청크별 headingPath(루트→제목)·section·paragraph.
  4. untrusted 표지 — RAG 청크는 프롬프트 주입면 그 자체다. 봉투 출처 계약
    (mydocs/tech/envelope_provenance.md)대로 청크 텍스트를 문서 파생(신뢰 불가)으로 표지한다.
  5. 에이전트 친화 산출 — 기본 NDJSON(스트림·grep·재개), --format json 단일 봉투. 결정론.

실제 산출 (직접 실행)

NDJSON 한 줄rhwp export-llm samples/hwp3-sample.hwp --max-tokens 256(발췌·정리):

{"chunkIndex":0,"headingPath":[],"kind":"text","tokenEstimate":195,"part":1,"partCount":56,
 "text":"…Creating Linux Virtual Servers\n\nWensong Zhang, …","schemaVersion":"1.0",
 "source":"samples/hwp3-sample.hwp","untrustedContent":true,"untrustedFields":["text"]}

중첩 제목 + 병합 표 청크2025 행정업무운영 편람(최종).hwpx(발췌):

headingPath: ["제5장 질의 및 답변\t 269", "라. 결문(규칙 제4조제6항)"]
kind: mixed   tokenEstimate: 291
tables: [{"index":38,"section":2,"paragraph":492,"rows":2,"cols":5,
          "headerRowCount":1,"part":1,"partCount":1,"headerRepeated":false}]
--- text (끝부분) ---
…(본문 문단들)…

| <예시> [병합 2×1] | 행정안전부장관 직무대리 | ○○○ [병합 2×1] | 서울특별시장 권한대행 | ○○○ [병합 2×1] |
| --- | --- | --- | --- | --- |
|  | 차관 |  | 행정1부시장 |  |

표가 청크 안에서 자기완결로 읽히고(머리 행 + 병합 주석), 제목 경로가 청크를 페이지 밖에서도
문맥 있게 만든다.

스키마

청크 객체: chunkIndex, headingPath[], headingLevel, section?, paragraph?, kind
(text|table|mixed), tokenEstimate, part, partCount, text, tables[]
(index·section·paragraph·rows·cols·headerRowCount·part·partCount·headerRepeated).

NDJSON 줄은 위 청크에 schemaVersion·source·untrustedContent·untrustedFields 를 더한
자기서술 레코드다. --format json 봉투: schemaVersion·source·maxTokens·mode·
tokenEstimator·chunkCount·chunks[]·untrustedContent·untrustedFields(chunks[].text 등).

정직한 한계 (IR 이 모델하지 않는 것은 지어내지 않는다)

  • 본문 문단 주소: 재사용하는 구조 IR 은 제목의 주소만 남기고 본문 문단 각각의 주소는
    접는다 → 청크 인용 앵커는 소속 제목의 (section, paragraph) 다.
  • 문단↔표 정밀 인터리브: 같은 이유로 세그먼트 안에서 본문이 표보다 앞서고 표는 문서 위치
    순으로 뒤에 온다. 정확한 끼워넣기는 후속.
  • 페이지 번호·다단 읽기 순서: IR 이 주는 것만 쓴다(지어내지 않는다). 위 편람 예의
    headingPath 에 붙은 \t 269 는 목차형 제목 문단의 원문 그대로다(export-structure 와 동일).
  • 커버리지가 100% 가 아닐 수 있음: export-text 는 page-표면(머리말/꼬리말·쪽번호를 쪽마다
    반복)이고 청크는 section-표면이라 표면 차이가 있다. 본문 손실은 없다(아래 라운드트립 참조).

충돌 회피 / 후속

  • 로직은 새 파일(src/rag/)에. CLI 디스패치는 한 줄 추가.
  • src/capabilities_schema.rs·MCP 서버·export-provenance-map 등재는 후속(형제 에이전트
    소유 영역). 명령은 standalone 으로 동작하며, 출처 표지는 계약을 직접 소비해 붙인다
    (등재 시 src/provenance.rs MAP 에 export-llm 항목 1건 추가가 후속 작업이다).
  • mydocs/manual/cli_commands.md 반영도 후속(명령 계약이 안정된 뒤).

검증 (모두 실행함)

  • cargo build --bin rhwp ✓, 실샘플 end-to-end ✓(위 산출은 실제 실행 결과).
  • cargo test --lib3715 passed, 0 failed(회귀 없음). 신규 rag 유닛 13 passed:
    제목 경계·표 행 무절단·머리 반복·병합 주석·예산 준수·모든 청크 untrusted 표지·결정론
    (바이트 동일)·빈/degenerate 문서 무패닉·서문 표 배치·라운드트립 무손실.
  • tests/llm_export_contract.rs11 passed(실바이너리×실샘플): NDJSON 표지·JSON 봉투·
    바이트 결정론·예산 준수·중첩 제목 경로·표 선형화·큰 표 머리 반복·본문 커버리지
    (논문 100%, 편람 96%+)·사용법/런타임 종료코드·모드 옵션.
  • cargo clippy --workspace --all-targets -- -D warnings ✓, wasm-lib clippy ✓.
  • 드리프트 가드 무영향 확인: provenance_contract(10)·capabilities_subcommands_contract(4)·
    skills_contract(2)·agent_toolkit_contract(13)·cli_json_contract(31) 전부 pass —
    등재하지 않았으므로 출처 지도 가드가 이 명령을 건드리지 않는다(설계 의도대로).

포맷: 신규 leaf(chunker.rs·tests/llm_export_contract.rs)만 rustfmt --edition 2021.
mod.rs(하위모듈 선언)·lib.rs 는 손대지 않고 한 줄만 Edit.

)

세계 문서-AI 도구들(PDF 영역의 Docling·LlamaParse·MarkItDown 등)이 HWP엔
못 해 주는 RAG 출력 축을 정확 구조(픽셀 추측 아님) 위에 신설한다. 재파싱하지
않고 build_structure(제목 계층)와 extract_tables(표 격자·병합 span)를 소비한다.

- 구조 인지 청킹: 자연 경계(제목/문단/표)에서만 분할, --max-tokens 예산 목표
- 자기완결 표: 머리 행 보존·병합 주석·행 단위 분할(파트마다 머리 반복)
- 출처 앵커: 청크별 headingPath·section·paragraph
- untrusted 표지: 청크 텍스트를 문서 파생(신뢰 불가)으로 표지(주입면 방어)
- 산출: 기본 NDJSON, --format json 단일 봉투, 결정론(바이트 동일)

capabilities/MCP/provenance-map 등재는 후속. 설계·한계는 src/rag/mod.rs에 문서화.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant