Skip to main content
Glama
README.md
# clausegraph

보험 표준약관을 지식그래프로 만들고, 그 위에서 지급심사를 보조하는 시스템.
청구 건을 넣으면 **판정과 근거 약관 조항**을 함께 낸다.

```
청구: "충치가 심해 임플란트를 했습니다. 비급여 1,200,000원 청구합니다."
가입: 2026-07-01, 실손의료보험 특별약관1(중증 비급여)

판정 DENIED
사유  진단코드 K02가 약관이 정한 면책 범위에 든다
근거  20260506/실손의료보험 특별약관1(중증 비급여 실손의료비)/제4조#(3)3대비급여#4-1
      제4조(보상하지 않는 사항) 치과치료(K00∼K08, 다만, 안면부 골절로 발생한
      의료비는 치아관련 치료를 제외하고 보상합니다)ㆍ한방치료(…)
```

## 왜 그래프인가

벡터 검색으로 구조적으로 안 되는 것이 셋 있다. 셋 다 숫자로 확인했다.

### 1. 면책은 부정 조건이라 벡터가 놓친다

청구자 말투 18문항으로 재 봤다.

| 전략 | hit@10 | recall@10 | recall@30 | recall@100 | 후보 수 |
|---|---|---|---|---|---|
| **vector** | **50.0%** | **32.9%** | 55.1% | 88.0% | k |
| graph | 100% | **100%** | 100% | 100% | 106 |
| hybrid | 88.9% | 86.1% | **100%** | 100% | 285~388 |

**벡터는 k를 열 배로 늘려야 88%에 닿는다.** 후보 100개는 색인 1,689청크의
6%다. 그래프는 k와 무관하게 100%인데, 순위를 매기는 대신 **그 상품·그
판본의 면책 사유를 빠짐없이 세우기** 때문이다. hybrid는 두 후보를 섞느라
k=10에서는 오히려 그래프보다 낮고 k=30부터 100%가 된다.

이유는 어휘가 겹치지 않기 때문이다. *"충치가 심해 임플란트를 했습니다"* 와
의미상 가장 가까운 글은 **보장** 조항이다. 지급을 뒤집는 `치과치료(K00~K08)`는
질문의 어떤 표현과도 닮지 않았다 — 임플란트라는 낱말이 약관에 없으니까.

> **면책 조회는 랭킹 문제가 아니라 열거 문제다.**

→ [notes/008](notes/008-exclusion-recall.md)

### 2. 약관에는 시점 축이 있다

보험은 **가입 당시** 약관이 적용된다. 같은 조문 번호가 시점에 따라 다른 내용이다.

수집한 4개 버전에서 상품이 **16개** 나온다. 최신본은 14개다. 2026-05-06
5세대 실손 개편으로 `실손의료보험 특별약관`이 중증/비중증 둘로 갈리면서
원래 상품이 **사라졌다.**

> 2025년 가입자가 "실손 특별약관"이라고 말하면 지금 문서에 없는 상품을
> 가리킨다. 현행 약관만 벡터로 색인하면 특별약관1이나 2가 걸려 나오지만
> 그 계약에는 둘 다 적용되지 않는다.

더 미묘한 것도 있다. **세칙 시행일과 약관 적용일이 다르다.**

| 세칙 시행일 | 약관 적용일 |
|---|---|
| 20260506 | **20260606** |

부칙이 *"[별표15] 표준약관(개인실손의료보험은 제외한다) 개정내용은 2026년
6월 6일 이후 체결되는 보험계약부터 적용한다"* 고 정했다.

괄호가 결정적이다. **적용일이 상품마다 다르다.** 같은 날 가입해도 실손은
새 약관, 생명·질병상해는 옛 약관이다.

| 가입일 | 기본형 실손(급여) | 생명보험 | 질병·상해보험 |
|---|---|---|---|
| **2026-05-20** | **20260506** | **20250901** | **20250901** |
| 2026-06-10 | 20260506 | 20260506 | 20260506 |

그리고 **부칙은 조문마다 시행일을 따로 정한다.**

```
다만 [별표 15]의 <자동차보험> 제9조, 제11조의 개정사항은 2020년 10월 22일부터
시행하고, … 제1조, 제20조, 제27조 … 의 개정사항은 2020년 11월 10일부터 시행한다.
```

부칙 26건을 **적용 단위 30개**로 쪼갰다. 19개는 상품 전체에 걸리고 **11개는
조문·별표 일부만** 바꾼다. 일부만 바꾼 부칙으로는 **버전을 옮기지 않는다** —
옮기면 그 상품의 나머지 조문까지 새 판본으로 끌려간다. 대신 그 사실을 답에
실어, 조문을 단정해서 인용하지 못하게 한다.

→ [notes/006](notes/006-graph-load.md) · [notes/015](notes/015-appendix-provisions.md) · [notes/030](notes/030-appendix-scopes.md)
· [notes/016](notes/016-product-scoped-provisions.md)

### 3. 면책의 예외는 다른 조문에 있다

면책 조항의 상당수가 예외를 달고 있고, **그 예외가 다른 조문을 가리킨다.**

> 산재보험에서 보상받는 의료비. **다만**, 본인부담의료비(…)는
> **제3조(보장종목별 보상내용) … 에 따라 보상합니다.**

면책이면서 동시에 보상의 근거를 가리킨다. 참조를 따라가지 않으면 "면책에
걸렸다"까지만 말하고 끝난다 — 청구인에게는 그 뒤가 중요하다.

`제N조` 표기의 42%는 약관 **밖**(「국민건강보험법」 제42조, 동법 제3조의3,
민법 제768조)을 가리켜서, 내부로 잘못 읽으면 번호만 같은 엉뚱한 조문에
엣지가 생긴다. 앞을 보고 가르고, 가르지 못하면 엣지를 만들지 않는다.
내부 참조 해석률 **98.3%**, 못 만든 엣지는 적재 로그에 수로 남긴다.

**참조 해석률이 파서 검사기이기도 했다.** 처음 80.5%가 나와 남은 20%를
들여다보다가, 조문 파서가 **제목을 대괄호로 묶은 조문 60개를 통째로
버리고** 있던 것을 찾았다(`제27조[… 납입최고(독촉)와 계약의 해지]` —
제목 안에 괄호가 겹치면 바깥을 대괄호로 바꿔 쓴다). 조문이 사라진 것은
조문 수를 세도 보이지 않는다. **약관이 자기 자신을 가리키는 것을 이용해서야
빈칸이 드러났다.** 고친 뒤 조문 1,774 → 1,798, 해석률 → 98.3%.

→ [notes/022](notes/022-reference-edges.md)

## 어디까지 되는가

앞의 셋은 **이 구조가 무엇을 할 수 있는지**다. 그것만 쓰면 절반이다.

금감원 분쟁조정사례 중 **청구 분쟁이면서 표준약관 범위인 68건**의 쟁점을
유형별로 세었다.

| | 유형 | 건수 |
|---|---|---:|
| ✗ | **DEFINITION** — 약관 용어(수술·입원·장해)의 범위 해석 | **21 (30.9%)** |
| ✓ | EXCLUSION — 보상하지 않는 사항에 걸리는가 | 13 (19.1%) |
| ✓ | TIMING — 보장개시·면책기간·적용 판본 | 10 (14.7%) |
| ✓ | DUPLICATE — 건보 상한액·산재에서 받은 돈 | 5 (7.4%) |
| ✗ | 나머지(고지·입증·절차·계약·미상) | 17 (25.0%) |
| ✓ | SCOPE — 그 특약에 가입했는가 | 2 (2.9%) |

> **답할 수 있는 유형 30/68 (44.1%). 가장 큰 덩어리는 못 푼다.**

*"IPL시술이 약관이 정하는 수술의 정의와 범위에 포함되는지"* 는 **조문을
찾아 주는 문제가 아니라 조문을 해석하는 문제다.** 그래프는 조문을 정확히
가져다주지만 그 판단을 대신하지 않는다.

**LLM으로 덮으려다 21건을 전부 읽고 그만뒀다.** 병목이 모델이 아니었다.

| | |
|---|---|
| 판정 쏠림 | OUT 19 / IN 2 — **"전부 OUT"이 90.5%를 받는다** |
| 상품 약관의 정의 문구만으로 갈린 사례 | **5건 (24%)** |
| 나머지가 요구한 것 | 의무기록 38% · 판례 33% · 상품분류표 29% |
| 표준약관에 `수술`·`입원`의 정의 | **없다** (제2조는 계약 용어만 정의) |
| `장해분류표` | 조문이 **32번 가리키는데 표가 없다** |

없는 문서는 모델 급을 올려도 읽을 수 없다. 붙였다면 모델이 표준약관의 다른
조문으로 답을 지어냈을 것이고, 채점하면 쏠림 덕에 90%가 나왔을 것이다.

**대신 판정하지 않고 "무엇이 있어야 하는지"를 답한다.** 용어를 가리고
(21/21), 표준약관에 그 정의가 있는지를 **조회로** 확인하고, 없으면 무엇을
가져와야 하는지 이름으로 돌려준다. 금액에서 쓴 것과 같은 방법이다.

정의를 셋으로 나눠 센다 — **있다 / 비었다 / 없다**. 가운데가 중요하다.
`장해`는 표준약관이 정의하지만 그 정의가 `<부표 3>`을 가리키고 그 표가
수집본에 없다. "정의가 있으니 그 조문을 보라"고 답하면 빈 곳으로 보낸다.

**판례가 필요한지는 말하지 않는다.** 쟁점 문장만으로는 알 수 없고, 예측하는
척하면 사후 지식을 쓰는 것이 된다. 넷 중 셋만 답하고 하나를 비워 두는 쪽이
낫다. → [notes/034](notes/034-definition-anatomy.md) · [notes/035](notes/035-definition-triage.md)

이 표가 있어야 위의 "면책 recall 100%"가 무엇의 100%인지 말이 된다.
**실제 분쟁의 19%가 면책 다툼이고, 그 19%에서 열거 방식이 100%를 낸다.**

→ [notes/024](notes/024-dispute-types.md)

## 구조

```
                     ┌─ 국가법령정보 API ──→ 표준약관 조문·부칙
데이터 수집 ─────────┼─ 금감원 분쟁조정사례 ─→ 평가셋
                     └─ 심평원 상병마스터 ──→ KCD 코드 사전

지식그래프 (Neo4j)   Product · Version · Article · Item · Coverage · Provision
                     조문 간 참조 1,592엣지 (면책의 예외가 보상 조문을 가리킨다)
벡터 색인 (pgvector) 조문·호 1,689청크, bge-m3 ONNX INT8 CPU

심사 에이전트        사실추출 → 보장탐색 → 면책검증 → 금액산정 → 검증/심판
가드레일             grounding · 금액 미계산 · 금액 상한 · 금액 하한 · 불확실 면책
                     · PII 마스킹
노출                 MCP 서버 도구 10개 (심사 7 + 후속 질문·재심사 2 + 용어 트리아지 1)
```

## 설계에서 갈렸던 지점

**LLM을 어디에 쓰는가.** 용어→코드 변환 하나에만 쓸 수 있고, 그것도
**기본 경로에서는 뺐다.** 4B(llama.cpp CPU)는 코드 생성 3/10에 틀리는 방식도
나빴다 — 치핵에 `G00.1`(뇌수막염), 발목 골절에 `L84.0`(티눈)처럼 **형식은
맞고 챕터가 틀린** 코드를 냈다.

그래서 "4B라서 그런 것 아닌가"를 재 봤다. **맞다.** 모델 급만 바꾸면 달라진다.

| | 생성 적중 | 선택 헛짚음 | p50 | 온프렘 |
|---|---|---|---|---|
| 규칙 표 | 7/10 | — | **0.8ms** | 예 |
| 로컬 4B | 3/10 | 3/3 | 2,438ms | 예 |
| 오픈웨이트 120B | **8/10** | **0/3** | 2,524ms | 예 (80GB급 필요) |
| 프론티어 flash | **8/10** | *측정 못 함* | 9,138ms | **아니오** |

**그래도 안 넣는다. 근거가 바뀌었을 뿐이다** — 규칙 표와 한 건 차이인데
**3,000배** 느리고 가속기가 필요하다. 대신 바뀌는 조건이 확정됐다: 폐쇄망에
80GB급 가속기가 있고 심사 한 건에 2~3초를 쓸 수 있다면, 선택 방식의 120B를
불확실 버킷으로 넣는 것이 낫다. 프론티어가 오픈웨이트를 못 이겼으므로
**망분리 제약은 이 과제에서 비용을 물리지 않는다.**
→ [notes/012](notes/012-local-llm.md) · [notes/031](notes/031-model-tier.md)

**multi-turn에서 위험한 것은 잊는 것이 아니라 낡은 것을 말하는 것이다.**

```
턴1  "충치 임플란트 120만원"        -> DENIED  (근거: 치과치료 K00~K08)
턴2  "아 작년에 이미 300만원 받았어요"
```

턴2는 판정의 **입력**을 바꾼다. 기억해 둔 DENIED로 답하면 이미 틀린 결론에
근거 조항까지 붙여 설명하게 된다 — 틀린 답 중 제일 나쁜 종류다. 그래서 새
사실 검사가 다른 모든 분류보다 **먼저** 온다. *"작년에 300만원 받았는데 왜
부지급이죠"* 는 `왜`가 들어 있어도 `WHY`가 아니라 `NEW_FACTS`이고, 답하지
않고 재심사로 보낸다.

숫자가 있다고 새 사실은 아니다. *"120만원이 왜 안 나와요"* 의 120만원은 이미
청구에 있는 값이다. **지금 아는 값과 달라야** 새 사실로 센다 — 아니면 같은
답을 두 번 주면서 매번 "다시 심사했다"고 말하게 된다.

그리고 후속 답변은 **앞 턴의 답변 문장이 아니라 저장된 `Adjudication`에서**
낸다. 답변을 이어 쓰면 두 턴 만에 인용이 원본에서 떠내려간다.
→ [notes/032](notes/032-multi-turn.md) · [notes/033](notes/033-followup-eval.md)

**금액산정은 자동 파싱하지 않는다.** 산식은 약관에 적혀 있지만 값이 표 안의
표에 중첩되고 보장종목·입원/통원·의료기관마다 다르다. 정규식으로 긁으면
조용히 틀린 숫자가 나오고, 틀린 숫자는 곧 틀린 지급액이다. 값을 손으로 적되
**조항 uid를 함께** 적고, 확인 못 한 값은 비워 사람에게 넘긴다.
→ [notes/014](notes/014-amount.md) · [notes/017](notes/017-amount-parameters.md)

**모르는 값이 있으면 지급액이 아니라 상한을 말한다.** 급여 통원 공제는
`max(정액, 의료비의 20%, 의료비 × 건강보험 본인부담률)`인데, 마지막 항의
비율은 **영수증에서 오는 값이라 약관에 없다.** 빠진 항은 공제를 키우는
쪽으로만 작용하므로, 그 항 없이 계산한 값은 실제 지급액의 **상한**이다.
법정 요율로 추정해 채우지 않고 상한이라고 말하고, 가드레일이 상한의 지급을
막는다. 무엇이 없어서 못 정했는지 이름까지 돌려준다 — 심사자가 할 일이
"판단"이 아니라 "값 두 개 확인"이 된다. → [notes/018](notes/018-deductible-terms.md)

**표에서 숫자 하나를 찾은 순간이 가장 위험하다.** 금액 오류 셋을 내가
직접 만들고 직접 잡았다. 한 칸만 읽어 공제 항을 빼먹어 상급종합병원 통원을
**2배 과다지급**했고, 한 행만 읽어 입원 비율을 통원에 돌려써 특약2 통원을
**정확히 반**만 줬고, 표준약관에 없는 감액기간(730일 50%)을 하드코딩해 가입
2년 미만 청구를 전부 반으로 깎았다. 셋 다 "틀릴 때만 조용히" 틀렸다.
그래서 규칙마다 `source_articles`를 달아 근거 조항을 되짚을 수 있게 했다 —
감액기간은 규칙 밖의 모듈 상수여서 그 검사를 통째로 빠져나갔다.
→ [notes/019](notes/019-rate-and-reduction.md)

**평가셋을 내가 쓰면 내 말투가 배어 있다.** 위 면책 recall 18문항은 내가
약관을 읽고 만든 것이라 약관의 어휘가 그대로 들어가 있다. 그래서 Tier B가
`EXCLUSION`으로 분류한 **실제 분쟁 13건의 쟁점 문장을 그대로** 넣어 봤다.

처음 나온 숫자는 **13/13**이었다. 무엇을 짚었는지 읽어 보니 이랬다.

| 쟁점 | 걸린 조항 | 걸린 낱말 |
|---|---|---|
| **보조기** 구입비용이 보장 대상인지 | **HIV 감염 치료비** | `대상에` |
| **치과치료** 비급여가 지급사유인지 | **정신 및 행동장애** | `치료에서` |

**변별어 4,528개의 46.6%가 조사 붙은 어절**이었다. `대상`은 흔해서 걸러지는데
`대상에`는 희귀어로 통과한다. 어절이 아니라 어간으로 세도록 고쳤다.

고치고 나니 **확실(certain) 히트**가 하나 남았다 — 부담보 해제를 묻는 쟁점에
정신질환 면책이 걸렸다. 확실 히트는 가드레일이 막지 않는다. 따라가 보니
KCD 사전에 `'특정'`이라는 열쇠가 있었고, 그건 `특정(개별) 공포증`을
**첫 괄호에서 잘라** 만든 조각이었다. `만성 (소아기) 육아종성 질환` → `만성`,
`급성, 재발성 또는 …` → `급성`도 같았다. 괄호를 자르지 않고 덜어 내도록
고쳤다.

| | 어간화 이전 | 이후 |
|---|---:|---:|
| 정답 조항을 짚은 사례 | 9/10 | **8/10** |
| **총 히트** | **178** | **74** |
| 사례당 평균 히트 | 13.7 | **5.7** |

**정답률만 보면 나빠 보인다.** 이전의 9/10은 아무 데나 다 걸려서 그 안에
정답이 섞여 있던 것이다. 사례 하나에 "걸릴 수도 있다"를 열네 건 내놓으면
심사자에게 준 것이 없다. 그래서 이 평가는 **정답률과 히트 수를 함께 낸다.**

그리고 어간화가 **원래 있던 논리 오류를 드러냈다.** 발목 골절 청구가
`치과치료` 면책에 걸렸는데, `골절`이 그 조항의 **`다만` 뒤**에 있었기
때문이다 — "안면부 골절로 발생한 의료비는 보상합니다", 즉 예외를 적은
자리다. `다만`이 든 괄호를 표현 일치에서 빼자 합성 청구 195건의
`PARTIAL`이 18 → **28**로 늘고 오발동 가드레일이 0이 됐다.

→ [notes/025](notes/025-real-disputes.md) · [notes/026](notes/026-proviso-tokens.md)

**인용문이 곧 산출물이다.** 근거로 보여 줄 문장의 앞머리를
`^.*?제\d+조\([^)]*\)\s*`로 다듬고 있었다. 조문 제목을 떼려던 것인데,
조문도 호도 제목으로 시작하지 않는다 — 파서가 이미 뗀다. 그래서 이 정규식이
실제로 지운 것은 **본문 안의 조문 참조와 그 앞의 모든 글자**, 즉 면책의
주어였다. 면책 항목 1,446개 중 116개(8.0%)가 잘렸고 최악은 11자
`"에 따라 보상합니다."`였다 — **부지급의 근거로 "보상합니다"를 인용했다.**
지우고 나니 표현 일치도 옳은 쪽으로 붙었다(`치과치료`, `치료관계비`를 새로
잡는다). → [notes/020](notes/020-citation-integrity.md)

같은 문제가 보장 쪽에 더 심하게 있었다 — 보장 조문 88개 중 40개(45.5%)의
인용문이 `┏━━━━┳`로 채워져 있었고 심한 것은 127자 중 59자가 테두리였다.
자르는 코드가 세 군데(보장·면책·MCP)에 각자 다르게 있어서, 020에서 면책만
고친 것이 고친 게 아니었다. 한 함수로 모으고 **표가 시작되는 곳에서 끊어
`…(표)`로 표시한다** — 괘선을 지우고 이어 붙이면 셀이 뒤엉켜 읽을 수 없고,
읽을 수 없는 인용문은 근거가 아니다. → [notes/021](notes/021-prose-quotes.md)

**노출 계층도 로직이다.** MCP 도구가 버전을 고를 때 **상품을 무시하고**
세칙 시행일만 보고 있었다. 심사 에이전트는 부칙의 상품별 적용일을 반영하는데
도구는 그 함수를 지나쳐 갔다 — 같은 청구에 두 답이 나왔다. 가입일×상품
1,472쌍 중 32쌍(2.2%)이 어긋났고, 어긋나는 구간이 하필 **개정 직후 한 달**
이었다. 감싸는 줄 알았던 것이 두 번째 구현이었다.
→ [notes/023](notes/023-mcp-drift.md)

**기본값은 조용한 가정이다.** 연간한도를 깎을 `already_paid_this_year`가
매개변수로 있었는데 **오케스트레이터가 한 번도 넘기지 않아** 언제나 0이
들어갔다. `0`은 "모른다"가 아니라 "올해 아무것도 안 받았다"는 주장이고,
한도를 다 쓴 계약에도 한도가 통째로 남은 것처럼 계산했다. 계약의 올해
누적은 약관에도 청구서에도 없는 **보험사 시스템의 값**이라, 저장소를 만드는
대신 청구가 들고 오게 하고 **없으면 지급액 대신 상한**을 말한다.
→ [notes/027](notes/027-claim-history.md)

**"보수적"은 누구에게 안전한지를 정해야 뜻이 생긴다.** 지금까지 찾은 금액
누락은 전부 한 방향이었다 — 공제 항을 빼먹거나 한도를 모르면 **더** 주게
된다. 그래서 "모르면 상한"이라는 한 문장으로 덮였다. 그런데 제5조 ④의
자기부담 연 200만원 상한은 **알수록 더 주는** 조항이라, 모르면 우리 계산이
실제보다 **작다**. 깃발을 나눠 `amount_lower_bound` 가드레일을 더했다 —
다섯이 보험사가 더 주는 위험을 막는다면, 이건 **청구인이 덜 받는 위험**을
막는다. 부지급도 사고지만 과소지급도 사고다.
→ [notes/028](notes/028-lower-bound.md)

**가드레일은 한 방향으로만 움직인다.** 여섯 다 판정을 보수적인 쪽으로만
바꾼다. 방향을 한 번 뒤집었다 — "불확실한 면책으로 부지급을 내지 않는다"로
걸었더니 코드로 확정된 부지급까지 사람에게 넘어갔다. 위험한 방향은 반대다.
→ [notes/009](notes/009-agent-orchestration.md)

**지연은 캐시를 비싼 호출에 걸어 잡았다.** 청구 1건당 15.8ms → 1.3ms(-92%).
변별어 사전 계산은 이미 캐시돼 있었는데 그 앞의 조회가 캐시 밖이라, 청구마다
조문 452개를 Neo4j에서 다시 긁어 왔다. → [notes/011](notes/011-latency.md)

## 규모

| | |
|---|---|
| 약관 조문 | 1,798 (버전 4 × 상품 16) |
| 면책 조문 / 사유 | 68 / 1,446 |
| 조문 간 참조 | 1,592 (해석률 98.3%) |
| 벡터 청크 | 1,689 |
| KCD 코드 / 용어 열쇠 | 21,299 / 27,113 |
| 평가셋 | 면책 recall 18문항, 실제 분쟁 13건, Tier A 라벨 50건, Tier B 분쟁 유형 68건 |
| 테스트 | 315 |

## 돌려 보기

Docker와 [uv](https://docs.astral.sh/uv/)가 필요하다.

```bash
docker compose up -d                                          # Neo4j 7475, pgvector 5434
cp .env.example .env                                          # LAW_API_OC를 채운다
uv run python -m clausegraph.law.collect --limit 10           # 표준약관 수집
uv run --extra graph python -m clausegraph.graph.load_cli     # 그래프 적재
uv run --extra graph python -m clausegraph.agents.cli         # 심사 데모
```

`LAW_API_OC`는 [국가법령정보 공동활용](https://open.law.go.kr)에서 무료로
발급한다(승인 1~2일). 자세한 실행 방법은 `docs/`를 본다.

- [docs/mcp-setup.md](docs/mcp-setup.md) — MCP 서버를 Claude Desktop에 붙이기
- [docs/local-llm.md](docs/local-llm.md) — 로컬 LLM 서빙
- [docs/data-sources.md](docs/data-sources.md) — 데이터 출처와 이용조건

## 데이터 출처

**수집한 데이터는 리포에 담지 않는다.** `data/`와 `models/`는 git에서
제외돼 있고, 아래 출처에서 직접 받는 수집기만 들어 있다. 리포에 있는 것은
평가에 쓴 **라벨 파일**(직접 판독한 것)과 사례 목록뿐이다.

| 데이터 | 출처 | 이용조건 |
|---|---|---|
| 보험 표준약관 | [국가법령정보 공동활용](https://open.law.go.kr) — 보험업감독업무시행세칙 별표15 | 비상업적 이용, 출처표시 |
| 분쟁조정사례 | [금융감독원](https://www.fss.or.kr/fss/job/fncCnflCase/list.do?menuNo=201195) | 출처표시 |
| KCD 코드표 | [공공데이터포털](https://www.data.go.kr/data/15067467/fileData.do) — 건강보험심사평가원 상병마스터 | 공공저작물 제1유형(출처표시) |

임베딩은 [BAAI/bge-m3](https://huggingface.co/BAAI/bge-m3), 로컬 LLM은
[Qwen3-4B](https://huggingface.co/Qwen/Qwen3-4B-GGUF)(Apache-2.0)를 쓴다.
모델 파일도 리포에 담지 않는다.

## 한계

포트폴리오로 만든 것이고, 실제 지급심사에 쓸 수 있는 상태가 아니다.

- **판정은 보조다.** 근거 조항을 특정하지 못하면 결론을 내지 않고, 확인 못 한
  면책이 남으면 지급하지 않는다. 최종 결정은 사람이 한다.
- 약관을 **최근 4개 버전**만 수집했다. 그 전 가입자는 판정하지 않고 거절한다.
- 금액산정은 급여 실손과 비급여 특약1·2(3대비급여·MRI 포함)까지 채웠다.
  올해 기지급액과 통원 횟수는 **청구가 들고 와야** 하고, 없으면 지급액이
  아니라 상한만 답한다. 약관 값이 비어 있는 자리는 이제 없고, 남은 것은
  **계약별 청구 이력을 시계열로 들고 있어야 판정되는 한도**다 — 3대비급여
  연 50회, 통원 "1회"의 정의, 제5조 ⑥의 계속 통원 180일·90회.
- **조문 단위 판본이 없다.** 부칙이 조문마다 시행일을 따로 정하는 경우
  (수집한 26건 중 11개 적용 단위)에는 한 계약에 두 판본이 걸리는데, 조문을
  판본에 매어 둔 구조로는 "제11조만 옛 것"을 표현할 수 없다. 버전을 옮기지
  않고 그 사실을 답에 실어 사람에게 넘긴다.
- 실제 분쟁 13건에서 정답 조항을 짚은 것은 8/10이고, 면책이 아닌 3건 중
  2건에 오발동한다. 못 잡는 둘은 청구서의 말(`한방병원`)과 약관의 말
  (`한방치료`)이 달라서, 그리고 면책 세부 항목이 조문 본문이 아니라 `목`에
  있어서다.
- 용어→코드 변환이 면책 적중 5/8이다. 못 잡는 셋은 청구서의 말과 KCD 공식
  표기가 달라서다.
- Tier A 라벨 50건은 세션 안에서 판독한 것이며 재검수 전이다. Tier B는
  검수하면서 규칙을 고쳤으므로 "규칙 정확도"를 주장하지 않는다 — 무엇을
  고쳤는지만 남겼다.
- 표준약관은 **표준**이다. 실제 상품 약관은 회사마다 다르다.

전체 설계 근거와 측정 기록은 `notes/`에 035번까지 있다.

## 라이선스

코드는 [MIT](LICENSE). 위 데이터 출처의 이용조건은 각 기관의 것을 따른다.