sds-converter: Rust와 LLM을 사용하여 안전보건자료(SDS)를 MHLW 표준 JSON으로 변환하기
요약
Rust와 LLM을 활용하여 비정형 안전보건자료(SDS)를 일본 후생노동성(MHLW)의 표준 JSON 스키마로 변환하는 sds-converter 프로젝트를 소개합니다. 규칙 기반 파서의 한계를 극복하기 위해 LLM을 도입하여 복잡한 섹션 구조와 오타가 포함된 공식 스키마를 정확히 처리합니다.
핵심 포인트
- Rust와 LLM을 결합한 고성능 SDS 데이터 변환 도구 구축
- 비정형 문서의 섹션 순서, 레이블링, 값 표현 차이 문제 해결
- MHLW 표준 스키마의 의도적인 오타 및 복잡한 중첩 구조 대응
- 다양한 국가별(GHS, GB/T 등) SDS 형식을 통합 처리 가능
배경
안전보건자료 (Safety Data Sheets, SDS)는 용제, 접착제, 산업용 가스, 세척제와 같은 모든 화학 제품에 필수적인 문서입니다. 유해 화학 물질을 공급하는 모든 제조업체는 반드시 SDS를 제공해야 합니다. 일본의 경우, 화학적 정체성, 유해성 분류, 응급처치, 저장, 운송 정보 등을 다루는 16개 섹션을 정의하는 JIS Z 7253이 관리 표준입니다. 후생노동성 (Ministry of Health, Labour and Welfare, MHLW)은 2025년 3월, 화학 관리 시스템 간의 전자 SDS 데이터 교환을 위해 표준 JSON 스키마 (schema)를 발표했습니다. 이 스키마는 16개 섹션 전체를 아우르는 약 200개의 깊게 중첩된 필드 (fields)로 구성되어 있습니다. 문제는 실제 SDS 문서가 이 스키마에 맞춰 구조화되어 있지 않다는 점입니다.
왜 SDS 문서는 파싱 (parse)하기 어려운가
JIS Z 7253을 준수하는 두 문서라 할지라도, 규칙 기반 파서 (rule-based parsers)를 무력화하는 방식으로 서로 다를 수 있습니다:
- 섹션 순서 — 제조업체는 표준 내에서 16개 섹션을 자유롭게 배치합니다.
- 필드 레이블링 (Field labeling) — 동일한 데이터가 JIS Z 7253, GHS/OSHA HazCom, GB/T 16483, CNS 15030 및 기업별 레이아웃에 따라 서로 다른 제목 아래에 나타납니다.
- 값 표현 (Value representation) — "≥99.5%", "99.5% or higher", "approximately 100%"는 모두 같은 의미를 나타냅니다.
- 언어 혼용 (Language mixing) — 일본어 SDS에는 문장 중간에 영어 화학 명칭과 CAS 번호가 정기적으로 포함됩니다.
- 암묵적 정보 (Implicit information) — 섹션 9 (물리/화학적 특성)는 제조업체가 제품과 관련된 내용만 기입하기 때문에 필드의 절반이 누락되는 경우가 많습니다.
MHLW 스키마는 문제를 더욱 심화시킵니다. 스키마에는 정확하게 재현해야 하는 의도적인 오타가 포함되어 있습니다. HumanExposureAndEmergencyMeasuress는 's'가 두 번 겹쳐 끝납니다. TestGuidline에는 'e'가 빠져 있습니다. Desclaimer는 글자 순서가 바뀌어 있습니다. 이것들은 공식 규격에 포함되어 있으며, 이를 "수정"할 경우 검증 (validation)에 실패합니다.
해외 제조업체(GHS/OSHA 형식)나 중국 공급업체(GB/T 16483 형식)의 SDS를 동일한 파이프라인 (pipeline)에서 처리하려면 각 형식에 대한 별도의 파서가 필요합니다. 이를 직접 작성하고 유지 관리하는 것은 비현실적입니다.
저는 이 문제를 LLM (Large Language Model)을 사용하여 해결하기 위해 sds-converter를 구축했습니다. 16개 섹션 # Schema key JIS Z 7253 section 1 Identification 화학적 정체성 및 회사 정보 2 HazardIdentification 유해성 확인 3 Composition 구성 성분 / 성분에 관한 정보 4 FirstAidMeasures 응급조치 요령 5 FireFightingMeasures 소화 조치 6 AccidentalReleaseMeasures 누출 사고 시 대처 요령 7 HandlingAndStorage 취급 및 저장 방법 8 ExposureControlPersonalProtection 노출 제어 / 개인 보호구 9 PhysicalChemicalProperties 물리화학적 특성 10 StabilityReactivity 안정성 및 반응성 11 ToxicologicalInformation 독성 정보 12 EcologicalInformation 생태 정보 13 DisposalConsiderations 폐기 시 주의사항 14 TransportInformation 운송 정보 15 RegulatoryInformation 규제 정보 16 OtherInformation 기타 정보 설치 및 빠른 시작 cargo install sds-converter # PDF → MHLW 표준 JSON 내보내기 ANTHROPIC_API_KEY = sk-ant-... sds-converter to-json --input input.pdf --output output.json # MHLW JSON → JIS Z 7253 준수 Word 문서 sds-converter to-docx --input output.json --output result.docx --lang ja # 스키마 검증 (Schema validation) sds-converter validate --input output.json # 원문 텍스트 추출 (LLM 호출 없음 — 디버깅에 유용) sds-converter extract-text --input input.pdf 지원되는 입력 형식: PDF, DOCX, XLSX, TXT. 변환 작동 방식 단계 1: 텍스트 추출 텍스트는 PDF 또는 DOCX 파일에서 추출됩니다. extract-text를 사용하여 LLM에 정확히 무엇이 전송되는지 확인할 수 있으며, 이는 추출 품질이 예상보다 낮을 때 유용합니다. 참고: 암호화된 PDF 및 스캔 전용 (이미지) PDF는 지원되지 않습니다 — 텍스트 추출을 위해서는 선택 가능한 텍스트가 필요합니다.
2단계: 병렬 LLM 추출 (Parallel LLM extraction) 16개 섹션은 두 그룹으로 나뉘어 두 번의 병렬 LLM 호출을 통해 추출되며, 이를 통해 파일당 지연 시간 (latency)을 절반으로 줄입니다: GROUP_A (섹션 1–9): 식별 (identification), 유해성 (hazard), 구성 성분 (composition), 응급조치 (first aid), 소화 방법 (fire fighting), 누출 사고 대응 (accidental release), 취급 (handling), 노출 제어 (exposure), 물리화학적 특성 (physical properties) GROUP_B (섹션 10–16): 안정성 및 반응성 (stability), 독성 정보 (toxicology), 환경 영향 (ecological), 폐기 시 주의사항 (disposal), 운송 정보 (transport), 규제 정보 (regulatory), 기타 정보 (other) 두 호출의 결과가 병합됩니다. 첫 번째 패스에서 건너뛴 섹션은 자동으로 재시도됩니다. HTTP 속도 제한 (rate-limit) 응답 (429/529)이 발생하면 지수 백오프 (exponential backoff) 재시도가 트리거됩니다 (2초 → 4초 → 8초, 최대 3회 시도).
3단계: JSON 출력 (JSON output) 병합된 결과는 MHLW SDS 데이터 교환 형식 v1.0 JSON으로 작성됩니다.
LLM 백엔드 및 품질 설정
제공자(Provider) 선택
OpenAI GPT (기본값: gpt-4o-mini)
sds-converter to-json --input input.pdf --output output.json \
--provider openai --api-key $OPENAI_API_KEY
Google Gemini (기본값: gemini-2.0-flash)
sds-converter to-json --input input.pdf --output output.json \
--provider gemini --api-key $GEMINI_API_KEY
Ollama를 통한 로컬 LLM (OpenAI 호환 엔드포인트)
sds-converter to-json --input input.pdf --output output.json \
--provider local --base-url http://localhost:11434/v1 \
--model llama3.2 --api-key dummy
| --provider | 기본 모델 (Default model) | 환경 변수 (Environment variable) |
|---|---|---|
| anthropic | claude-haiku-4-5-20251001 (low/medium) · claude-sonnet-4-6 (high) | ANTHROPIC_API_KEY |
| openai | gpt-4o-mini | OPENAI_API_KEY |
| gemini | gemini-2.0-flash | GEMINI_API_KEY |
| mistral | mistral-small-latest | MISTRAL_API_KEY |
| groq | llama-3.3-70b-versatile | GROQ_API_KEY |
| cohere | command-r-plus | COHERE_API_KEY |
| local | llama3 | LOCAL_LLM_API_KEY (선택 사항) |
품질 프리셋 (Quality preset)
--quality 옵션은 모델과 호출당 LLM으로 전송되는 텍스트 양을 모두 제어합니다:
| --quality | 모델 (Anthropic) | LLM에 입력되는 최대 텍스트 양 | 사용 사례 (Use case) |
|---|---|---|---|
| low | claude-haiku-4-5 | 15,000자 | 속도/비용 우선 |
| medium (default) | claude-haiku-4-5 | 30,000자 | 균형 잡힌 설정 |
| high | claude-sonnet-4-6 | 60,000자 | 정확도 우선 |
high 설정 시, 뒷부분을 포함한 문서 전체 텍스트가...
섹션(운송 정보(transport information), 규제 정보(regulatory))이 포함됩니다. 16개 섹션 전체를 완벽하게 커버하는 것이 중요하다면 --quality high를 사용하세요.
Batch 모드:
sds-converter to-json \ --input-dir ./pdfs/ \ --output-dir ./json/ \ --lang ja \ --concurrency 4
Validation (검증):
validate는 추출된 JSON의 구조적 완전성을 확인하며, 치명적인 오류로 중단하지 않고 경고(warnings)를 반환합니다. 즉, 부분적인 결과물도 여전히 사용할 수 있습니다.
sds-converter validate --input output.json
검증 항목 예시:
- 섹션 1: 제품명(TradeNameJP 또는 TradeNameEN) 없음
- 섹션 1: 공급자 정보(SupplierInformation) 누락
- 섹션 2: 분류(Classification) 또는 위험 표지(HazardLabelling)가 추출되지 않음
- 섹션 3: 성분 및 함량(CompositionAndConcentration) 리스트가 비어 있음
라이브러리로 사용할 경우, convert_to_json은 (SdsRoot, Vec<String>) 튜플을 반환하며, 경고 사항은 인라인(inline)으로 제공됩니다.
출력 JSON 구조:
{
"Datasheet" : {
"IssueDate" : "2024-03-31" ,
"SDS-SchemaVersionNo" : "1.0"
},
"Identification" : {
"TradeProductIdentity" : {
"TradeNameJP" : "Sample Product"
},
"SupplierInformation" : {
"CompanyName" : "Sample Corp" ,
"Phone" : "03-0000-0000"
}
}
}
전체 스키마는 약 200개의 필드를 포함하여 JIS Z 7253의 16개 섹션 전체를 다룹니다. 공식 사양과 개발자 매뉴얼은 후생노동성(MHLW) 웹사이트(일본어)에서 확인할 수 있습니다.
라이브러리로 사용하기
[dependencies]
sds-converter-core = "0.1"
PDF → JSON 사용 예시:
use sds_converter_core::{
converter::{ AnthropicBackend , LlmConfig },
convert_to_json ,
ConvertConfig ,
Language ,
};
#[tokio::main]
async fn main () -> anyhow::Result < () > {
let backend = AnthropicBackend::new(
std::env::var("ANTHROPIC_API_KEY")?,
LlmConfig::default(),
);
let config = ConvertConfig {
source_language: Some(Language::Japanese),
output_language: Language::Japanese,
..Default::default()
};
let (sds, warnings) = convert_to_json(
std::path::Path::new("input.pdf"),
&backend,
&config,
).await?;
for w in &warnings {
eprintln!("WARN: {w}");
}
std::fs::write(
"output.json",
serde_json::to_string_pretty(&sds)?,
)?;
Ok(())
}
; Ok (()) } JSON → Word document use sds_converter_core ::{ convert_from_json , ConvertConfig , Language , SdsRoot }; fn main () -> anyhow :: Result < () > { let sds : SdsRoot = serde_json :: from_str ( & std :: fs :: read_to_string ( "output.json" ) ? ) ? ; let config = ConvertConfig { output_language : Language :: Japanese , .. Default :: default () }; convert_from_json ( & sds , std :: path :: Path :: new ( "result.docx" ), & config ) ? ; Ok (()) } Custom LLM backend use sds_converter_core ::{ LlmBackend , SdsError }; struct MyBackend ; impl LlmBackend for MyBackend { async fn complete ( & self , system : & str , user : & str ) -> Result < String , SdsError > { // Call your LLM API, return the raw JSON string response todo! () } } Language support Language --lang Source standard Output DOCX headings Japanese ja JIS Z 7253 JIS Z 7253 English en GHS/OSHA HazCom GHS Rev.10 / ISO 11014 Simplified Chinese zh-cn GB/T 16483-2012 GB/T 16483-2012 Traditional Chinese zh-tw CNS 15030 CNS 15030 Comparison with alternatives Open-source sds-converter sds_parser tungsten Language Rust Python Python AI/LLM Yes (pluggable) No (regex) No (rule-based) MHLW JSON Yes No No Bidirectional Yes (↔ DOCX) No No Multilingual ja / en / zh-CN / zh-TW Limited English only Commercial (Japan) sds-converter SDS Meister SmartSDS Dr.EHS Chemical AI Yes (your API key) No Yes (translation) AI-OCR MHLW JSON Yes Yes Yes Yes PDF → JSON Yes No (authoring only) Partial (JP only) Yes Open-source MIT/Apache-2.0 No No No sds-converter is the only open-source tool that supports the MHLW schema, runs entirely locally, and handles the full round-trip. Crate structure sds-converter-core — library. LLM extraction, DOCX generation, MHLW schema types. sds-converter — CLI binary. to-json , to-docx , validate , extract-text subcommands. Feedback welcome, especially on section 3 component table extraction and non-Japanese document accuracy. https://github.com/kent-tokyo/sds-converter
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기