SchemaLinter-OneShot: LLM JSON 스키마 유효성 검사 및 자체 복구 강제화를 위한 CLI 도구 구축
요약
SchemaLinter-OneShot은 파이썬 표준 라이브러리만을 사용하여 LLM이 생성한 JSON 스키마를 유효성 검사하고 오류 발생 시 자체 복구 프롬프트를 즉시 생성하는 CLI 도구입니다. 이 도구는 외부 의존성을 최소화하여 가볍고 효율적이며, 재귀적 타입 검사와 정규 표현식을 활용해 LLM의 출력 노이즈 문제를 해결합니다.
핵심 포인트
- LLM JSON 스키마 유효성 검사 및 복구를 위한 CLI 도구입니다.
- 외부 라이브러리 의존성을 최소화하여 가볍고 효율적으로 설계되었습니다.
- 정규 표현식과 재귀적 타입 검사를 통해 LLM 출력의 노이즈를 처리합니다.
- Python argparse 모듈의 생명주기 관련 아키텍처적 한계를 분석했습니다.
SchemaLinter-OneShot: LLM JSON 스키마 유효성 검사 및 자체 복구 강제화를 위한 CLI 도구 구축
1. 도구의 목표 아키텍처
"SchemaLinter-OneShot"은 파이썬 표준 라이브러리만을 사용하여 완전히 구축된, 가벼운 원샷(one-shot) linter로 설계되었으며, 무거운 외부 유효성 검사 라이브러리와 같은 과도한 의존성을 의도적으로 제거했습니다.
핵심 구성 요소 설계 철학
- 유연한 JSON 추출 (
_extract_json)- LLM이 자주 생성하는 노이즈와 Markdown 형식 지정 문제를 처리하기 위해, 이 도구는 다음 우선순위 목록에 따라 정규 표현식을 사용하여 JSON 후보를 식별합니다:
json ...으로 감싸진 코드 블록 추출.- 첫 번째
{부터 마지막}까지의 범위 추출. - 전체 원본 텍스트를 직접 파싱하는 폴백(fallback) 방식.
- LLM이 자주 생성하는 노이즈와 Markdown 형식 지정 문제를 처리하기 위해, 이 도구는 다음 우선순위 목록에 따라 정규 표현식을 사용하여 JSON 후보를 식별합니다:
- 재귀적 타입 유효성 검사 (
_validate_types)jsonschema와 같은 패키지의 막대한 오버헤드를 피하기 위해, 페이로드(payload)를 재귀적으로 스캔하여 필수 키의 존재 여부를 확인하고 최소한의 엄격한 타입 검사를 수행합니다.
- 자체 복구 프롬프트 즉시 생성
- 감지된 구문 오류와 타입 불일치 목록을 구조화하고, 이를 LLM에게 다시 전송할 치유(healing) 프롬프트를 즉시 구성합니다. 이 구조화된 피드백 루프는 표준 출력으로 바로 파이프됩니다.
2. 개발의 난관: QA 테스트 중 노출된 치명적인 명세 충돌
구현은 아름답게 응집되어 보였습니다. 하지만 QA 단계에서, "인수가 누락되었을 때 오류 처리를 JSON 형식으로 포맷하는" 요구 사항을 구현하던 중, 표준 프레임워크의 내부 명세로 인해 깊은 난관에 빠졌습니다.
발생한 오류
스크립트를 인수 없이 실행했을 때, 의도했던 JSON 형식의 오류 대신 argparse의 기본 일반 텍스트 사용 오류가 표준 에러 스트림으로 유출되었습니다.
실패 분석: 왜 이를 포착하지 못했을까?
개발 측면에서, 저는 try...except SystemExit: 블록을 사용하여 오류를 가로채고 종료 전에 JSON 페이로드로 변환하는 방식으로 접근했습니다. 아래에 보여드리겠습니다:
try:
args = parser.parse_args()
except SystemExit:
...
하지만 이 방식에는 Python argparse 모듈의 생명주기와 관련된 두 가지 치명적인 간과가 있었습니다:
- 예외 전파 전에 표준 에러(Standard Error)에 직접 쓰기
argparse는 필수 인자 누락 또는 유효하지 않은 옵션을 감지하면, 예외(SystemExit)를 발생시키기 직전에 내부error()메서드를 통해 사용법 메시지를sys.stderr로 직접 출력합니다.- 따라서 실행 흐름이 JSON 페이로드를 출력하기 위해
except블록에 도달하기도 전에, 일반 텍스트 오류 메시지가 이미 표준 에러 스트림으로 플러시(flushed)된 상태였습니다.
--help(-h)와 유효성 검사 오류 혼동- 사용자가 의도적으로
--help플래그를 지정하더라도,argparse는 도움말 메시지를 성공적으로 표시한 후SystemExit(0)을 발생시킵니다. - 위의 단순한
except SystemExit:구현으로는, 유효한 도움말 요청조차 오류로 포착되어 JSON 형식의 오류 메시지로 덮어쓰여지므로, CLI 도구의 사용자 경험(UX)이 치명적으로 손상됩니다.
- 사용자가 의도적으로
3. 구현 한계 및 프로젝트 동결 결정
QA의 피드백에 따라, argparse 내에서 예외 후킹(exception hooking)에 의존하는 것의 아키텍처적 한계를 인정해야 했습니다. 진정으로 견고한 JSON 전용 CLI를 구축하려면 광범위한 리팩토링이 필요할 것입니다:
argparse.ArgumentParser클래스의error()메서드를 완전히 오버라이딩(overriding)하는 것.- 파싱 전에
sys.argv를 독립적으로 스캔하여 명시적이고 분리된 검증 계층을 선행 배치하는 것.
하지만 이 도구의 초기 요구사항은 **"CI/CD 파이프라인 건전성을 보장하기 위해 1초 이내에 안정적으로 작동하는 가볍고 일회성(one-shot) 도구"**였습니다. CLI 인자 파싱의 원시적인 계층에서 표준 프레임워크를 해킹하는 데 지속적으로 엔지니어링 노력을 투입하는 것은 프로젝트의 투자 대비 수익률(ROI)을 심각하게 저하시킬 것입니다.
종합적인 아키텍처적 판단에 따라, 이번 버전(V2)에서는 코드베이스를 취약한 패치로 복잡하게 만들지 않기로 결정했습니다. 결과적으로, 기술 부채를 추출하고 축적된 지식을 미래 설계에 전달하기 위해 프로젝트를 임시로 [개발 미완료] 상태로 종료하는 것을 선택했습니다.
4. 차세대 설계를 향하여: 배운 점 (안티 패턴)
이 도전을 통해 얻은 아키텍처적 통찰력은 미래 CLI 도구 개발을 위한 귀중한 안티 패턴(anti-patterns)으로 작용할 것입니다.
- 표준 라이브러리의 암묵적인 동작을 과대평가하지 마라
argparse와 같이 성숙하고 검증된 모듈이라 할지라도, 소스 코드 수준에서 "예외가 발생할 때의 순서"와 "텍스트가 I/O 스트림으로 플러시될 때의 순서"를 검사하지 못한 것은 설계 초기 단계에서의 결정적인 검증 부족이었습니다.
- CLI 인터페이스 디자인은 처음부터 엄격하게 분리되어야 한다
- "표준 입력(stdin)으로부터 데이터 처리"와 "명령줄 인자를 통한 구성"을 혼합하는 도구의 경우, 프레임워크의 라이프사이클 오류 처리를 커스텀 JSON 형식으로 강제하려는 접근 방식 자체가 프레임워크의 핵심 철학과 본질적으로 충돌했습니다.
이 엔지니어링 로그가 귀하의 프로덕션 서버(그리고 정신 건강)을 지켜주었다면, GitHub Sponsors를 통해 저희 아키텍처를 후원하는 것을 고려해 주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기