feat(policy): domain_policy.yaml v1 (safety_health + news)
PR-A 의 Single Source of Truth. subject_domains 9개 (safety_reference/ safety_operational/msds/hazard_specific/incident_report/health_record/ safety_video/news_item/news_digest_request) + fallback_domain + risk_flags 10개 + forbidden_for_4b 6 카테고리 + escalation 임계값 + observability. Axis 원칙 (feedback_category_vs_ai_domain_axis.md): - subject_domain 매칭 키 = source_channel/keywords/tags/ai_domain - documents.category 는 UI 축 (매칭 키로 사용 금지) - suggested_ui_category 는 OUTPUT 매핑 (분류 제안용) Scope: safety_health + news 만. 소설은 별도 정책으로 분리. plan: ~/.claude/plans/wise-gliding-hippo.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
# domain_policy.yaml
|
||||
# ============================================================================
|
||||
# Single Source of Truth for AI routing/escalation/forbidden rules.
|
||||
#
|
||||
# - 코드가 이 파일을 로드한다 (app/policy/loader.py).
|
||||
# - 프롬프트는 이 yaml 에서 excerpt 를 runtime 에 렌더링 받는다.
|
||||
# - 규칙을 프롬프트에 직접 하드코딩하지 않는다 (drift 방지).
|
||||
# - 변경 시 policy_version (sha256(yaml+template)[:12]) 자동 bump.
|
||||
#
|
||||
# Axis separation (feedback_category_vs_ai_domain_axis.md):
|
||||
# - subject_domain 매칭 키 = source_channel / keywords(본문) / tags / ai_domain
|
||||
# (documents.category 는 **매칭 키로 사용 금지** — UI 축)
|
||||
# - suggested_ui_category = classify_worker 가 사용자에게 제시할 UI 카테고리 **제안**
|
||||
# (실제 저장·전이는 PR-B 의 ai_suggestion 승인 플로우에서 결정)
|
||||
#
|
||||
# Scope v1: safety_health + news. 소설은 별도 정책으로 분리 (도메인 미확정).
|
||||
# ============================================================================
|
||||
|
||||
version: 1
|
||||
last_updated: "2026-04-24"
|
||||
scope: [safety_health, news]
|
||||
self_declare_semantics: additive_trigger_only # 4B self-declare 는 ADD only, OFF 불가
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# subject_domains — 라우팅·정책 축
|
||||
# ---------------------------------------------------------------------------
|
||||
# 매칭 방법 (routing.py 에서 upstream 이 결정):
|
||||
# - keywords: 본문 첫 N chars 내 키워드 매칭 (대소문자 무시)
|
||||
# - source_channel: 외부 수집 경로 (`law_monitor`, `news_collector` 등)
|
||||
# - tags: ai_domain tags / user tags
|
||||
# **category (UI 축) 매칭 금지** — feedback_category_vs_ai_domain_axis.md
|
||||
#
|
||||
# suggested_ui_category: 실측 doc_category enum ∈ {document,library,news,memo,audio,video,law}
|
||||
# ---------------------------------------------------------------------------
|
||||
subject_domains:
|
||||
|
||||
safety_reference:
|
||||
description: "산업안전보건법·중대재해 관련 법령·기준 문서 (사용자 업로드분)"
|
||||
suggested_ui_category: document
|
||||
high_impact: true
|
||||
default_risk_flags: [safety_legal_interpretation]
|
||||
keywords: [산업안전보건법, 중대재해, 안전보건관리체계, 유해위험방지계획서]
|
||||
note: "law_monitor 자동 유입 법령은 source_channel=law_monitor 로 별도 처리 (classify skip), 여기는 사용자 업로드 PDF/DOC 대상"
|
||||
|
||||
safety_operational:
|
||||
description: "현장 운영 문서 — 위험성평가·작업허가·JSA·SOP"
|
||||
suggested_ui_category: document
|
||||
high_impact: true
|
||||
default_risk_flags: [safety_operational_decision]
|
||||
keywords: [위험성평가, 작업허가서, JSA, 안전작업지침, 보호구, SOP]
|
||||
|
||||
msds:
|
||||
description: "MSDS / SDS / 화학물질 안전자료"
|
||||
suggested_ui_category: document
|
||||
high_impact: true
|
||||
default_risk_flags: [chemical_hazard, safety_legal_interpretation]
|
||||
keywords: [MSDS, SDS, 물질안전보건자료, 화학물질, 유해화학물질]
|
||||
|
||||
hazard_specific:
|
||||
description: "위험 유형별 자료 (추락·끼임·감전·밀폐공간·화재폭발)"
|
||||
suggested_ui_category: document
|
||||
high_impact: true
|
||||
default_risk_flags: [safety_operational_decision]
|
||||
keywords: [밀폐공간, 추락, 끼임, 감전, 화재, 폭발, 중독, 질식]
|
||||
|
||||
incident_report:
|
||||
description: "사고·재해 보고서"
|
||||
suggested_ui_category: document
|
||||
high_impact: true
|
||||
default_risk_flags: [incident_causation]
|
||||
keywords: [사고보고, 재해조사, 원인분석, 재발방지, 중대재해]
|
||||
|
||||
health_record:
|
||||
description: "건강검진·작업환경측정·보건관리"
|
||||
suggested_ui_category: document
|
||||
high_impact: true
|
||||
default_risk_flags: [medical_health_judgment]
|
||||
keywords: [건강검진, 작업환경측정, 보건관리, 특수건강진단]
|
||||
|
||||
safety_video:
|
||||
description: "안전·보건 교육/현장 영상 (STT 대상)"
|
||||
suggested_ui_category: video
|
||||
high_impact: false # 분류/챕터분리는 4B 가능. 깊은 요약 단계에서 승격
|
||||
deep_summary_risk_flags: [safety_operational_decision, safety_legal_interpretation]
|
||||
keywords: [] # 본문 텍스트가 없음. filename/source_channel 기반 매칭
|
||||
|
||||
news_item:
|
||||
description: "뉴스 기사 단건"
|
||||
suggested_ui_category: news
|
||||
high_impact: false
|
||||
default_risk_flags: []
|
||||
keywords: [] # source_channel=news_collector 로 매칭
|
||||
|
||||
news_digest_request:
|
||||
description: "다출처·다국가 뉴스 종합 요청 (Phase 4 digest 연장선)"
|
||||
suggested_ui_category: news
|
||||
high_impact: true
|
||||
default_risk_flags: [news_cross_source, multi_reference_synthesis]
|
||||
keywords: [] # 사용자 요청 의도로 판별 (upstream)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# fallback_domain — 매칭 실패 시 안전 착지점 (INV-6)
|
||||
# ---------------------------------------------------------------------------
|
||||
fallback_domain:
|
||||
name: generic
|
||||
description: "매칭 실패 시 기본 도메인 — 사람 리뷰 큐로 안내"
|
||||
suggested_ui_category: document
|
||||
high_impact: false
|
||||
default_risk_flags: [low_confidence_reasoning] # 이미 "모른다" 신호
|
||||
requires_human_review: true
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# risk_flags — 26B 승격 조건 + synthesis directive
|
||||
# ---------------------------------------------------------------------------
|
||||
risk_flags:
|
||||
|
||||
safety_legal_interpretation:
|
||||
description: "법령·기준 조문의 특정 상황 적용 해석"
|
||||
requires_26b: true
|
||||
synthesis_directive: "조문 원문 인용 필수. 해석은 '일반적 취지' 선에서만. 특정 상황 적용 단정 금지."
|
||||
|
||||
safety_operational_decision:
|
||||
description: "현장 안전조치 결정·적정성 판단"
|
||||
requires_26b: true
|
||||
synthesis_directive: "조치 나열 OK. '충분/적법' 단정 금지. '검토 사항' 형태로 서술."
|
||||
|
||||
chemical_hazard:
|
||||
description: "MSDS / 화학물질 취급·노출"
|
||||
requires_26b: true
|
||||
synthesis_directive: "MSDS 원문 인용 우선. 대체물질·취급법은 레퍼런스 나열까지만."
|
||||
|
||||
medical_health_judgment:
|
||||
description: "건강검진 결과 해석, 노출 영향 추정, 증상 원인"
|
||||
requires_26b: true
|
||||
synthesis_directive: "의학 판단 거부. '전문의 상담 권장' 문구 포함."
|
||||
|
||||
incident_causation:
|
||||
description: "사고·재해 원인 귀속"
|
||||
requires_26b: true
|
||||
synthesis_directive: "'원인은 ~' 금지. '관련 요인으로 ~가 기록됨' 수동태만."
|
||||
|
||||
multi_reference_synthesis:
|
||||
description: "여러 레퍼런스 종합 가이드 작성"
|
||||
requires_26b: true
|
||||
synthesis_directive: "레퍼런스별 입장 분리 기술. 대조표 권장. 최종 권고 금지."
|
||||
|
||||
news_cross_source:
|
||||
description: "다출처·다국가 뉴스 종합"
|
||||
requires_26b: true
|
||||
synthesis_directive: "출처별 보도 차이 명시. 중립 서술."
|
||||
|
||||
multi_doc_dependency:
|
||||
description: "문서 3개 이상 교차 참조 필요 (INV-4 derived)"
|
||||
requires_26b: true
|
||||
|
||||
low_confidence_reasoning:
|
||||
description: "4B 자체 confidence < 0.7 (derived)"
|
||||
requires_26b: true
|
||||
|
||||
pii_present:
|
||||
description: "개인정보 포함 (주민번호·계좌 등)"
|
||||
requires_26b: false # 판단 위험 아님, 출력 마스킹 의무만
|
||||
output_mask_required: true
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# forbidden_for_4b — 4B 가 절대 수행하면 안 되는 작업
|
||||
# ---------------------------------------------------------------------------
|
||||
# detection_patterns: Python re.search() 엔진. Postgres regex 아님.
|
||||
# ---------------------------------------------------------------------------
|
||||
forbidden_for_4b:
|
||||
|
||||
- id: legal_interpretation
|
||||
description: "법령·고시·안전보건기준의 특정 상황 적용 해석"
|
||||
applies_when_subject_in: [safety_reference, safety_operational, msds]
|
||||
detection_patterns: [] # 구조적 감지 (조문번호 + 단정 표현), 별도 휴리스틱
|
||||
|
||||
- id: safety_sufficiency_assertion
|
||||
description: "안전조치 충분성·적법성 판단"
|
||||
applies_when_subject_in: [safety_operational, hazard_specific, msds]
|
||||
detection_patterns:
|
||||
- '(이대로|이렇게)\s*하면\s*(됩니다|된다|괜찮)'
|
||||
- '(충분합니다|적법합니다|문제\s*없)'
|
||||
- '걱정\s*(없|안)'
|
||||
|
||||
- id: medical_health_judgment
|
||||
description: "보건·의학적 판단"
|
||||
applies_when_subject_in: [health_record]
|
||||
detection_patterns:
|
||||
- '(증상|노출)[은는이가]\s+[가-힣]+\s*(입니다|이다)'
|
||||
- '(건강상|의학적으로)\s+.*(우려|문제)\s*(없|있)'
|
||||
|
||||
- id: incident_causation_assertion
|
||||
description: "사고 원인 단정"
|
||||
applies_when_subject_in: [incident_report]
|
||||
detection_patterns:
|
||||
# "원인은 ~ 입니다/이다/임" (공백 포함 명사구 허용)
|
||||
- '원인은\s+[가-힣A-Za-z0-9\s]+?(입니다|이다|임)'
|
||||
# "~ 때문에 발생" / "~ 으로 인해 발생" (앞 명사 뒤 공백 허용)
|
||||
- '[가-힣]+\s*(때문에|으로\s*인해)\s+발생'
|
||||
|
||||
- id: multi_reference_synthesis
|
||||
description: "다중 레퍼런스 종합 공식 가이드 작성"
|
||||
applies_when_subject_in: [safety_reference, safety_operational, hazard_specific]
|
||||
detection_patterns: [] # 구조적 (evidence docs >= 3 AND 결론형 문단)
|
||||
|
||||
- id: news_multi_source_synthesis
|
||||
description: "2출처 이상 뉴스 최종 종합"
|
||||
applies_when_subject_in: [news_item]
|
||||
detection_patterns: []
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# escalation — 결정론 임계값 (INV-3/INV-4)
|
||||
# ---------------------------------------------------------------------------
|
||||
escalation:
|
||||
confidence_threshold: 0.7 # < 이면 escalate
|
||||
context_char_cap_4b: 120000 # INV-3: 초과 시 강제 escalate
|
||||
context_char_cap_26b: 260000
|
||||
escalate_on_multi_doc_count: 3 # INV-4: >= 이면 escalate
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# observability — analyze_events 기록 필수 필드 + 건강 범위
|
||||
# ---------------------------------------------------------------------------
|
||||
observability:
|
||||
required_event_fields:
|
||||
- prompt_version
|
||||
- model_name
|
||||
- subject_domain
|
||||
- risk_flags
|
||||
- high_impact_task
|
||||
- confidence
|
||||
- escalated_to_26b
|
||||
- escalation_reasons
|
||||
- policy_violation
|
||||
- policy_version
|
||||
|
||||
health_ranges:
|
||||
escalation_ratio_24h: {min: 0.10, max: 0.35}
|
||||
high_impact_26b_coverage: {min: 1.00, max: 1.00} # 100% 고정
|
||||
over_escalation_ratio: {max: 0.15}
|
||||
summary_quality_low_ratio: {max: 0.03}
|
||||
answerability_insufficient: {max: 0.20}
|
||||
policy_violation_24h: {max: 0}
|
||||
Reference in New Issue
Block a user