Skip to main content

StructVerify

문서가 규칙을 지켰는지, 수치가 사실인지 코드 한 줄로 검사하는 파이썬 라이브러리입니다. 내 규정집(PDF)이나 내 데이터 소스(CSV · DB · 문서 · 공공통계)를 정답으로 삼아 문서를 대조하고, 결과에서 평범한 True / False를 읽습니다.

PyPI Python License: MIT Providers Docs

StructVerify 데모 - 규정집으로 문서를 검사하고 준수/위반을 판정

import structverify as sv

rules = sv.Ruleset.from_file("safety_standard.pdf", provider="upstage")
v = rules.check("총납 함량은 120mg/kg으로 측정되었다")

v.compliant     # False        <- 평범한 True/False
v.article       # "제3조 (총납) ... 100mg/kg 이하"
v.rule_value, v.claim_value, v.unit   # (100.0, 120.0, 'mg/kg')

공식 문서: 사용법 · 레퍼런스 · 학습 가이드 · 3분 데모 영상


목차


무엇을 하는 라이브러리인가

기업과 기관에서는 시험성적서, 경영 보고서, 공시 자료 같은 문서가 정해진 기준과 실제 데이터에 부합하는지 사람이 규정집과 원본 데이터를 대조하며 수작업으로 확인합니다. StructVerify는 이 대조 작업을 두 갈래의 API로 자동화합니다.

검증 종류 진입점 정답 기준 판정
규정 준수 검사 Ruleset 내 규정집 (PDF/텍스트) compliant / violation / unverifiable
사실 검증 sv.verify · Verifier 내 데이터 소스 (CSV · DB · 문서 · KOSIS 통계) match / mismatch / unverifiable

핵심 설계 원칙은 다음과 같습니다.

  • 내 데이터를 정답으로. 공공 데이터에 고정된 기존 사실검증 도구와 달리, 사용자의 규정 PDF · 참조 CSV · 사내 DB를 그대로 정답 기준으로 삼습니다. 도메인에 독립적입니다.
  • 판정은 코드가, 결정론적으로. LLM은 기준값과 측정값을 추출하고 근거를 수집하는 역할만 합니다. 준수/위반, 일치/불일치 판정은 허용오차와 한도 규칙에 따라 코드가 결정론적으로 계산하므로 같은 입력에는 같은 판정이 나옵니다.
  • 결과가 곧 불리언. .ok · .compliant · .violated, bool(result), 순회(iterable), .to_dict(). 함수에 점을 찍어 부르면 원하는 값이 바로 나옵니다.
  • 원시 테이블만 있어도 검증. 지표 정의가 없는 트랜잭션 테이블이라도 에이전트가 스키마를 조사해 읽기 전용 SQL을 스스로 작성하고, 집계·비율 주장까지 검증합니다.
  • provider에 얽매이지 않음. upstage · openai · gemini · hcx 중 무엇이든 설정 한 줄로 전환하고, 직접 학습한 모델도 주입할 수 있습니다.
  • 감독 학습 루프 내장. 검증에서 축적된 확정 정답으로 자체 모델을 LoRA 파인튜닝하고, 데이터 품질 검사 · 실시간 학습 감독 · 자가평가 후 채택까지 라이브러리가 관리합니다.

설치

pip install structverify              # 코어: 규정 준수 + CSV/문서 사실검증 (의존성 7개)
pip install "structverify[db]"        # + 회사 DB 검증 (SQLAlchemy: sqlite/postgres/Snowflake 등)
pip install "structverify[kosis]"     # + 공공통계(KOSIS) 사실검증
pip install "structverify[training]"  # + 감독 학습 루프 GPU 레시피 (NVIDIA, unsloth QLoRA)
pip install "structverify[training-mac]"  # + Apple Silicon 학습 (MLX)
pip install "structverify[all]"       # 전부

코어는 pydantic · httpx · pyyaml · openai · pdfplumber · python-dotenv · json5만 받습니다. 무거운 의존성은 전부 필요할 때만 extra로 설치되며, import도 지연 로딩이라 가볍습니다. Python 3.10 이상을 지원합니다.

API 키는 인자로 직접 넘기거나(api_key="up_..."), 환경변수 또는 작업 디렉토리의 .env 파일에 두면 자동으로 읽습니다 (UPSTAGE_API_KEY · OPENAI_API_KEY · GEMINI_API_KEY · NCP_API_KEY).

빠른 시작

규정 준수 검사: 내 규정집으로

PDF/텍스트 규정집(안전기준 · 사내정책 · 표시기준 등)을 조항 단위로 색인하고, 문장이 그 규정을 지켰는지 판정합니다. 규정집만 있으면 외부 데이터 없이 바로 동작합니다.

import structverify as sv

rules = sv.Ruleset.from_file("safety_standard.pdf", provider="upstage")
len(rules)                   # 색인된 조항 수

v = rules.check("총납 함량은 120mg/kg으로 측정되었다")
v.compliant                  # False
v.violated                   # True
v.article                    # "제3조 (총납) ... 100mg/kg 이하"
v.rule_value, v.claim_value, v.unit   # (100.0, 120.0, 'mg/kg')
v.reason                     # 판정 근거 (자연어)

# 문서 전체: 측정값이 있는 줄마다 자동 판정
for v in rules.check_file("시험성적서.pdf"):
    print("준수" if v.compliant else "위반", v.article, v.rule_value, v.claim_value)

조항이 많은 큰 규정집은 agent=True로 ReAct 에이전트 루프를 켭니다. 한 번의 검색으로 적용 조항을 놓칠 수 있을 때, 검색 - 판정 - 쿼리 재구성 - 재검색을 판정이 확정될 때까지 스스로 반복합니다.

rules = sv.Ruleset.from_file("big_rulebook.pdf", provider="upstage", agent=True)
v = rules.check("화장품 납 함량은 30㎍/g으로 측정되었다")
v.violated      # True
v.iterations    # 몇 바퀴 만에 확정했는지 (1이면 한 번에, 2 이상이면 재검색함)

사실 검증: 데이터 소스와 대조

문서의 수치 주장을 설정된 데이터 소스와 대조합니다.

import structverify as sv

# 한 줄 검증
report = sv.verify("과수농가 65세 이상 비율은 64.2%다", provider="upstage")
report.ok                    # 거짓 주장이 없으면 True
if report:                   # Report 자체가 True/False로 동작
    print("거짓 주장 없음")

# 엔진 재사용 (여러 문서를 검증할 때)
engine = sv.Verifier(provider="upstage", data=sv.DataSource.csv("reference.csv"))
report = engine.verify(long_text)
report.mismatches            # 반박된 주장만
for r in report:             # 순회 가능, len(report) == 주장 수
    print(r.verdict, r.confidence, r.value, r.reason)

PDF 파일도 그대로 넣을 수 있습니다: engine.verify_document("경영실적보고서.pdf"). 모든 동기 메서드는 a 접두사의 비동기 쌍을 가집니다 (check/acheck, verify/averify).

데이터 소스: 무엇이든 정답으로

DataSource 팩토리로 정답 기준을 연결합니다. 경로 문자열만 넘겨도 확장자로 추론합니다.

sv.DataSource.csv("부채비율.csv")                          # 참조 통계 CSV
sv.DataSource.csv("t.csv", columns={"value": "amount"})    # 컬럼명 매핑
sv.DataSource.docs("policies/")                            # 회사 문서 폴더 (의미검색)
sv.DataSource.db("postgresql://...", table="kpi")          # 정돈된 지표 표
sv.DataSource.kosis()                                      # 내장 KOSIS 공공통계

에이전틱 DB 검증: 원시 테이블 그대로

지표 정의가 없는 원시 트랜잭션 테이블은 agentic=True 하나로 검증합니다. 에이전트가 스키마와 표본을 조사해 주장마다 읽기 전용 집계 SELECT를 자동 생성하며, 합계 · 평균 · 비중 같은 집계/비율 주장까지 대조합니다. SQLAlchemy DSN이면 어떤 DB든 연결됩니다 (sqlite · PostgreSQL · MySQL · Snowflake 등).

# 원시 주문 테이블에서 직접 검증
raw = sv.DataSource.db("snowflake://user:pw@account/DB/SCHEMA?warehouse=WH",
                       agentic=True, tables=["ORDERS", "LINEITEM"])
report = sv.verify("1998년 연간 순매출은 3.2조 달러를 기록했다", provider="upstage", data=raw)
report[0].verdict            # 'mismatch'  (실제 집계값과 대조한 결과)

# 지표가 수백 개인 대형 표는 임베딩 의미검색으로 자동 전환
sv.DataSource.db(dsn, table="BIG_KPI", use_embedding="auto", embed_threshold=200)

모든 SQL은 읽기 전용으로만 실행되며, 쓰기 구문은 실행 전에 차단됩니다.

동작 구조

StructVerify 동작 구조

  • 문서에서 수치 주장을 탐지하면, 소스 프로파일러가 기준 자료를 먼저 조사해 검색 전략을 수립하고, 주장 하나마다 RuntimeAgent(ReAct 루프)가 독립 실행됩니다.
  • 에이전트는 Planner - 도구 실행(의미 검색 · 에이전틱 SQL · 검색어 재구성 · 표 샘플 조사) - Reflect를 반복하며 근거를 확보합니다. 근거가 부족하면 재계획하고, 최대 10회 반복하며, 신뢰도 0.9 이상이면 조기 종료합니다.
  • 시도 이력은 워크스페이스(./agent_workspace)의 작업 메모리에 기록되어 중복 검색을 방지하고, 확정된 값은 verified_facts 캐시로 다음 주장에서 재사용됩니다.
  • 준수/사실 판정은 LLM이 아닌 코드가 허용오차 · 한도 규칙으로 결정론적으로 계산합니다.
  • 검증에서 축적된 확정 정답은 감독 학습 루프를 거쳐 개선된 모델로 파이프라인에 다시 주입됩니다.

파이프라인 내부 구현(에이전트 루프 · 도구 11종 · 워크스페이스 캐시 · 설정 스키마)은 docs/architecture-internals.md에 정리되어 있습니다.

감독 학습 루프: 쓸수록 정확해지는 검증

검증에서 나온 확정 정답으로 자체 7B 모델을 LoRA 파인튜닝합니다. 단순한 학습 스크립트가 아니라 감독 3종이 학습의 앞 · 중간 · 뒤를 지킵니다.

감독 시점 역할
DataCurator 학습 전 중복 · 라벨 오류 · 태스크 편중을 격리하고 사유를 기록
TrainDoctor 학습 중 · 후 실시간 손실 감독(터미널 한 줄 UI). 수렴 정체나 발산이면 스스로 조기 종료하고, 학습 후 수렴 스텝 진단과 처방 제공
EvalGate 학습 후 학습 전/후 엔진을 같은 평가셋으로 채점해 개선된 경우에만 채택 (회귀 방지)
from structverify.training import LearningLoop

loop = LearningLoop(engine, base_model="unsloth/Qwen2.5-7B-Instruct")
loop.add_seed().add_reports(reports).add_jsonl("corrections.jsonl")   # 데이터 수집 (체이닝)
ds, curation = loop.prepare("train.jsonl")            # DataCurator: 품질검사 후 clean 데이터셋
loop.train(ds, "./adapter", backend="auto",           # NVIDIA는 QLoRA, Apple Silicon은 MLX
           run=True, early_stop=True, patience=200)   # 수렴하면 스스로 멈춤
loop.diagnose("./adapter/trainer_state.json")         # 사후 진단과 처방
gate = loop.evaluate(eval_set, tuned_engine=tuned)    # 개선 확인 후에만 채택

학습 중 터미널에는 감독 상태 한 줄만 갱신됩니다 (색상은 tty 자동 감지, NO_COLOR / SV_COLOR 지원):

🧠 336/2496 ▓░░░░░░░  13% · loss 0.108 ▆█▄▄▁▁ · lr 1.5e-04 · ETA 2:29 · ⚡1 · 🩺 수렴 유지
✂ step 336: 200스텝 동안 이동평균 개선 없음. 더 학습해도 이득이 없어 조기 종료합니다.

GPU 레시피는 extra로 제공됩니다. [training]은 NVIDIA(RTX 3060 · Colab T4/L4, unsloth QLoRA 4bit), [training-mac]은 Apple Silicon(MLX)용입니다. 수집 · 품질검사 · 진단 · 평가 등 코어 기능은 GPU 없이 동작합니다. 학습 결과는 python -m structverify.training.recipe.sample --adapter ./adapter로 바로 확인합니다.

학습된 모델 주입

어댑터를 Ollama나 vLLM으로 서빙하고, base_url과 티어별 모델 오버라이드로 파이프라인에 주입합니다. 전체 교체가 아니라 학습된 자리만 점진적으로 전환할 수 있습니다.

cfg = sv.build_config(provider="upstage", api_key="none", data=data)
cfg["llm"]["base_url"] = "http://localhost:11434/v1"   # 자체 서빙 주소
cfg["llm"]["models"] = {"structured": "sv-tuned"}      # 판정·추출 자리만 교체
tuned = sv.Verifier(config=cfg)

gate = EvalGate(base).evaluate(eval_set, tuned_engine=tuned)
if gate.accepted:
    engine = tuned            # 나빠졌으면 자동 거부

자세한 절차는 학습 가이드를 참조하세요.

결과 객체

객체 핵심 불리언 주요 필드
Verdict (규정 준수) .compliant · .violated · bool(v) .article .rule_value .claim_value .unit .reason .iterations
Report (문서 단위) .ok · bool(report) .results .matches .mismatches .unverifiable (순회 가능, len())
Result (주장 단위) .ok · .is_match · bool(r) .verdict .claim .reason .confidence .value .source

모든 결과 객체는 .to_dict()(JSON 직렬화)와 사람이 읽기 좋은 repr을 지원합니다. 확인이 불가능한 주장은 억지로 판정하지 않고 unverifiable(보류)로 남깁니다. 근거 없이 일치/불일치를 보고하는 경우는 코드 단계에서 보류로 강등됩니다.

설정 · 로깅 · 진행 대시보드

import structverify as sv

# 로깅: 콘솔 + 파일, verbose로 상세도 제어
sv.configure_logging("verification.log", level="INFO", verbose=False)

# config를 미리 만들어 재사용. 세부 키는 dict로 직접 조정
cfg = sv.build_config(
    provider="upstage",              # upstage | openai | gemini | hcx
    tolerance=2.0,                   # 수치 허용오차(%)
    data="reference.csv",
)
cfg["llm"]["max_concurrency"] = 2          # 429(rate limit)가 나면 낮추기
cfg["agent"]["loop"]["max_iterations"] = 6 # 주장당 에이전트 반복 상한
engine = sv.Verifier(config=cfg)

# 진행상황: 로컬 웹 대시보드 + 터미널 진행바
#   환경변수로도 제어 가능: SV_PROGRESS=off|terminal|web
with sv.progress_dashboard():              # 웹 대시보드가 브라우저로 열림
    report = engine.verify(text)

검증 실적

완성본 기준으로 실제 데이터에서 end-to-end 검증을 마쳤습니다.

에이전틱 DB 검증 (Snowflake TPCH_SF10, 약 6천만 행 원장)

원시 테이블(고객 150만 · 주문 1,500만 · 라인아이템 5,998만 행)을 정답으로, 오류 5건을 심어 둔 공식 경영실적 보고서 PDF의 수치 주장 20건을 검증했습니다.

판정 건수 내용
일치 (match) 9 총매출 · 지역별 매출 · 고객 수 등 집계 주장
불일치 (mismatch) 3 심어 둔 오류를 실제 집계값과 함께 적발
보류 (unverifiable) 8 원장에서 확인 불가능한 주장을 무리하게 판정하지 않고 보류
오탐 (거짓 경보) 0 맞는 수치를 틀렸다고 판정한 사례 없음

감독 학습 루프 (Google Colab L4 GPU)

학습 데이터 1만 건으로 전체 루프(수집 - DataCurator - QLoRA 학습 - TrainDoctor - 어댑터 검증)를 실행했습니다. 실시간 감독의 조기 종료로 2,496스텝 예정 학습이 516스텝에 완료되었고, 산출 어댑터의 품질이 동일함을 확인했습니다.

이 외에 어린이제품 안전기준 · 화장품 안전기준 · 식품 영양표시 기준 등 실제 규정집으로 규정 준수 검사를 검증했습니다. pytest 테스트 226개가 통과합니다.

예제

시연 데이터가 동봉되어 있어 바로 실행됩니다. 각 파일 상단에 필요한 extra와 실행법이 적혀 있습니다.

예제 내용
01_quickstart_conformance.py 규정 준수 검사 빠른 시작 (Ruleset, 에이전트 모드)
02_factcheck_csv.py CSV를 정답으로 사실 검증
03_database_agentic.py 회사 DB 검증: 정돈된 표와 에이전틱 모드
04_config_logging_progress.py 설정 · 로깅 · 진행 대시보드
05_training_loop.py 감독 학습 루프 전체 흐름
06_custom_model_injection.py 학습된 모델 주입과 EvalGate 채택
python examples/01_quickstart_conformance.py

프로젝트 구조

디렉토리 역할
structverify/core 파이프라인 · 데이터 모델 · 설정 로더
structverify/preprocessing PDF/DOCX/URL/텍스트 추출, 문장 분리
structverify/detection 수치 주장 탐지, 스키마 추출
structverify/agent RuntimeAgent ReAct 루프, 도구, 워크스페이스
structverify/retrieval 데이터 소스(CSV · DB · 문서 · KOSIS), 카탈로그 의미검색
structverify/verification 결정론 판정 (허용오차 · 한도 규칙 · 단위 계열 가드)
structverify/training 감독 학습 루프 (DataCurator · TrainDoctor · EvalGate · GPU 레시피)
structverify/library 고수준 API (Ruleset · Verifier · DataSource · build_config)
sv_platform/ FastAPI 플랫폼 (REST API · 인증 · Job). structverify를 감싸는 선택 구성요소

내부 구현 상세는 docs/architecture-internals.md, 플랫폼은 sv_platform/README.md를 참조하세요.

테스트

pip install -e ".[dev]"
pytest                              # 전체 (226개 통과)
pytest structverify/agent/          # 모듈 단위
pytest -k "schema_inductor"         # 키워드 필터

알려진 한계

  • 확인할 수 없는 주장은 보류(unverifiable)로 남기는 안전 우선 설계라, 근거가 부족한 환경에서는 보류 비율이 높아질 수 있습니다.
  • KOSIS 공공통계는 응답이 1~2년 지연되는 경우가 있어 최신 시점 주장은 보류될 수 있습니다.
  • 행정구역 개명("강원도"와 "강원특별자치도" 등)이나 아주 오래된 통계 시리즈는 카탈로그 매칭에 실패할 수 있습니다.
  • 순위 · 예측 · 주관적 표현은 검증 가능한 수치가 없어 의도적으로 탐지 대상에서 제외합니다.

라이선스

StructVerify는 MIT 라이선스입니다. 자유롭게 사용 · 수정 · 배포할 수 있습니다.

의존성도 모두 permissive 라이선스만 사용합니다.

범위 패키지 라이선스
코어 pydantic, pyyaml · httpx, python-dotenv, uvicorn · openai, json5, asyncpg, trafilatura, neo4j, mlflow, boto3, snowflake · pdfplumber, kss, redis, fastapi, sqlalchemy, langfuse, python-docx MIT · BSD-3 · Apache-2.0
격리(opt-in) PyMuPDF ([pdf-ocr] extra) AGPL-3.0

유일한 copyleft인 PyMuPDF(AGPL)는 고급 OCR PDF 파이프라인 전용으로 [pdf-ocr] extra에 격리했습니다. 기본 PDF 처리는 pdfplumber(MIT)를 사용하므로 pip install structverify와 [all] 어떤 경로로도 AGPL이 설치되지 않습니다.

Release files for structverify 0.3.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for structverify 0.3.5
File Size Uploaded
structverify-0.3.5.tar.gz 487.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for structverify 0.3.5
File Interpreter ABI Platform
structverify-0.3.5-py3-none-any.whl Python 3 none any Details

Total release size: 1.0 MB

Release files / structverify-0.3.5.tar.gz

Download URL structverify-0.3.5.tar.gz
Size 487.1 kB
Tags Source
SHA-256 checksum
How to use checksums
e6aa334ff91a549660ec3c401795f6ed1d60fff49c5a2b57ffba1018f8a5a038
BLAKE2b-256 checksum
How to use checksums
ba7710a887b7cffbdbe01298936e095f12434041a21454bdd8527143c91327bb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / structverify-0.3.5-py3-none-any.whl

Download URL structverify-0.3.5-py3-none-any.whl
Size 544.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
697cc6e85fb81b0b5f98c0d24ce3d9242ff038934d3659349da1bc044c4f8e40
BLAKE2b-256 checksum
How to use checksums
ea47b45ca8e87ce12e4b5086a9a3d25f3a965e9010a9b9426abeb9250c0da782
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

0.3.7

2 release files

0.3.6

2 release files

This release

0.3.5 This release

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page