본문으로 건너뛰기

포장과 시리얼화: 비전, 추적-추적성, 그리고 이상 탐지

📍 현재 위치: 5부 · 충전-마감 및 출하, 학습됨(Fill-Finish & Release, Learned) — 19장. 앞의 두 장이 원료의약품(drug product)을 출하했습니다. 제형과 충전-마감(formulation and fill-finish)이 카메라 검사 아래에서 그것을 바이알에 담았고, QC와 출하(QC and release)가 그 로트를 승인했습니다. 이제 그 바이알들은 판매 가능한 단위가 됩니다 — 라벨이 붙고, 시리얼화되고, 포장되고, 국가 추적-추적성 시스템에 보고되며 — 그리고 기계학습은 매우 다른 두 모습으로 등장합니다. 바이알 위의 인쇄를 보는 것, 그리고 포장 라인이 내보내는 시리얼 번호 이벤트의 스트림을 추론하는 것.

원료의약품이 만들어지고 출하되었습니다. 그것과 환자 사이에 서 있는 것은 전체 공정에서 가장 화려하지 않고 가장 법적으로 까다로운 구간인 포장입니다. 각 DP-001 바이알 — DP-001 은 러닝 예제의 원료의약품 코드이고, 이 바이알들은 BATCH-2026-001 로 라벨이 붙은 배치의 충전물에서 나옵니다 — 은 인쇄된 라벨, 로트 번호, 유효기한, 그리고 — 이것이 포장을 단지 기계적 문제가 아니라 데이터 문제로 만드는 부분인데 — 2D DataMatrix에 부호화된 고유한 시리얼 번호(serial number) 를 얻으며, 이는 발행되고(단위가 받아들여지는 순간 존재하는 것으로 공식 등록됨) 충전의 순간부터 조제(dispense)의 순간까지 추적됩니다. 두 규제 체제가 이를 강제합니다. 미국의 의약품 공급망 보안법(Drug Supply Chain Security Act, DSCSA) 과 EU의 위조의약품 지침(Falsified Medicines Directive, FMD). 둘 다 모든 판매 가능 단위가 고유하게 식별되고, 그 이동이 보고 가능하며, 공급망이 그 단위가 환자에게 닿기 전에 진품임을 검증(verify) 할 수 있을 것을 요구합니다 [1][2].

기계학습은 이 세계에 두 측면에서 들어옵니다. 물리적 라인에서는 컴퓨터 비전(computer vision) 이 인쇄를 판독하고, 라벨을 점검하며, 분당 수백 단위의 속도로 모든 단위의 2D 코드를 해독합니다 — 17장(Chapter 17)에서 충전된 바이알을 검사했던 바로 그 심층학습 비전 계보가, 이제 미립자가 아니라 텍스트와 코드를 향합니다. 데이터 측면에서는 라인이 시리얼화 이벤트(serialization events) 의 급류를 내보냅니다 — 발행(commissioning), 집합(aggregation), 폐기(decommissioning) — 그리고 이상 탐지(anomaly-detection) 계층이 그 스트림에서 오류와 사기의 구조적 시그니처를 감시합니다. 중복된 시리얼, 발행되지 않은 단위, 선언된 개수와 내용물이 맞지 않는 케이스. 이 장은 양쪽 절반을 모두 학습하고, 그것들을 러닝 예제의 SGTIN-시리얼화된 바이알에 묶습니다. BATCH-2026-001의 480개 바이알, 그중 둘은 라인에서 거부되었고, 나머지는 발행되어 포장되었습니다.

쉽게 말하면

공항을 떠올려 보세요. 두 종류의 점검이 있습니다. 하나는 게이트의 카메라로, 당신의 탑승권을 읽고 당신의 얼굴을 대조합니다 — 빠르고, 물리적이며, 사람마다. 인쇄가 번졌거나 사진이 맞지 않으면 당신은 따로 빼냅니다. 다른 하나는 무대 뒤의 시스템으로, 당신의 표가 다른 도시에서 동시에 사용되어서는 안 된다는 것, 항공편의 탑승자 명단이 실제로 탑승한 사람 수와 맞아야 한다는 것, 타임스탬프가 앞으로 흘러야 한다는 것을 압니다. 포장 ML은 정확히 이 두 가지입니다. 비전 시스템은 모든 바이알의 라벨과 2D 코드를 읽는 카메라입니다. 추적-추적성 이상 계층은 시리얼이 두 번 나타나는 것, 짧게 포장된 케이스, 만들어지기도 전에 출하되었다고 보고된 단위를 잡아내는 후방 사무(back-office) 로직입니다. 하나는 보고, 다른 하나는 추론합니다.

이 장에서 다루는 내용

  • 인쇄 및 라벨 검증을 위한 컴퓨터 비전: 로트/유효기한 텍스트를 위한 OCR, DataMatrix 해독, 그리고 인쇄-품질 등급 매기기 — 라인 속도에서의 단위별 이미지 분류기 겸 판독기.
  • 시리얼화와 SGTIN: 바이알이 어떻게 전 세계적으로 고유한 시리얼화 식별자가 되는지, 그리고 그 식별자가 왜 전체 하류 공급망의 조인 키(join key)인지.
  • 집합 무결성(aggregation integrity): 부모-자식 포장 관계(바이알 → 묶음 → 케이스 → 팔레트)와 그것들을 정직하게 지키는 결정론적 규칙.
  • DSCSA/EPCIS 이벤트 스트림 위의 이상 탐지: 두-계층 설계 — 결정론적 GS1 규칙이 먼저, 이상하지만-합법적인 케이스의 잔차에는 비지도 ML, Isolation-Forest 채점 로직을 평이한 말로 풀어 적으며.
  • 시리얼화 이벤트 한 건의 해부, GMP(Good Manufacturing Practice — 의약품이 그 아래에서 제조되어야 하는, 법적 구속력이 있고 규제자가 점검하는 체제)와 Annex 22 관점, 그리고 ML이 여기서 결정할 수 있는 것과 없는 것의 정직한 한계.

하나의 포장 라인 안에 숨은 두 ML 문제

포장은 하나의 작업처럼 보이지만, 기계학습은 공유하는 바이알 외에 거의 공통점이 없는 두 문제로 깔끔하게 갈라집니다.

첫째는 지각(perception) 입니다. 카메라가 각 단위 — 라벨, 인쇄된 로트와 유효기한, 2D DataMatrix — 를 촬영하고, 소프트웨어는 다음 바이알이 도착하기 전 몇 밀리초 안에 인쇄가 판독 가능하고, 정확하며, 등급을 통과하는지, 그리고 코드가 실제로 무엇을 말하는지를 결정해야 합니다. 이것은 비전 및 판독 작업입니다. 픽셀이 들어가면 결정 하나와 해독된 문자열 하나가 나옵니다. 그것은 자동 외관 검사(automated visual inspection, AVI)를 구동하는, 동일한 합성곱 아키텍처와 점점 더 늘어나는 트랜스포머 아키텍처(두 신경망 계열 — 첫째는 작은 학습된 패턴-필터로 이미지를 훑고, 둘째는 입력의 어느 부분에 주의를 기울일지를 학습합니다)가 지배하며, AVI의 중심적 긴장을 공유합니다 — 좋은 단위를 과잉 거부하는 규칙 기반 판독기 대(對) 인쇄 변동에 걸쳐 일반화하지만 결함 라이브러리에 대해 검증되어야 하는 학습된 판독기 [3][4].

둘째는 무결성 추론(integrity reasoning) 입니다. 어떤 단일 라벨이 어떻게 보이는지와 무관하게, 시리얼 번호 자체 가 이벤트의 그래프를 이룹니다 — 이 시리얼은 여기서 발행되었고, 저 케이스에 포장되었으며, 그 케이스는 이 팔레트에 실렸다 — 그리고 질문은 그 전체 그래프가 내부적으로 일관되고 현실과도 일관되는가입니다. 이것은 전혀 비전 문제가 아닙니다. 그것은 구조화된 이벤트 로그 위의 이상 탐지입니다. 두 문제는 서로 다른 모델, 서로 다른 데이터, 서로 다른 검증 증거를 요구하며, 그들을 뒤섞는 것이 첫 번째 실수입니다. 이 장의 나머지는 그들을 차례로 다룹니다.

두 번째 구조적 차이가 검증에 중요합니다. 지각 모델은 단위별이며 무상태(stateless) 입니다 — 그것은 하나의 이미지를 학습된 클래스 경계에 대해 판단하고 잊습니다. 무결성 모델은 관계적이며 누적적(cumulative) 입니다 — 한 케이스에 대한 그 판정은 그 이전에 발행된 모든 시리얼과 그것이 보유한다고 선언된 개수에 달려 있습니다. 그 차이가, 지각 모델은 계측기처럼(민감도, 특이도, 결함-라이브러리 챌린지 세트) 검증되고 무결성 모델은 공정 제어처럼(심어 둔 위반을 표시하는가, 그리고 오직 그것만을 표시하는가) 검증되는 이유입니다. 그들은 같은 라인 위에 있지만, 같은 종류의 소프트웨어가 아닙니다.

라인에서의 비전: OCR, DataMatrix, 그리고 인쇄 등급

포장 카메라는 모든 단위에 세 가지 일을 하며, 각각은 별개의 ML 작업에 대응합니다. 이미지 센서를 우연히 공유하는 세 개의 서로 다른 스택으로 이해하세요.

광학 문자 인식(Optical character recognition, OCR) 은 사람이 읽을 수 있는 텍스트 — 로트 번호, 유효기한, 제품명 — 를 판독하고, 배치 기록이 인쇄되어야 한다고 말하는 것과 대조합니다. 현대 제약 OCR은 학습된 시퀀스 모델입니다. 정전적(canonical) 아키텍처는 CRNN(Convolutional Recurrent Neural Network) 입니다 — 세 개의 신경망 단계를 쌓은 것입니다. 먼저, 합성곱 특징 추출기(작은 CNN, 즉 합성곱 신경망 — 바이알 검사기(vial inspector)에서 쓰인 같은 이미지-패턴 계층)가 잘라낸 텍스트 띠를 좌-우 방향의 열 단위 특징 벡터 시퀀스로 바꿉니다. 다음으로, 양방향 순환 계층 — LSTM 또는 GRU(맥락을 스캔하며 실어 나르는 메모리-셀 시퀀스 네트워크) — 가 그 시퀀스를 좌-우와 우-좌 양방향으로 읽으므로, 각 문자가 이웃의 맥락 속에서 읽힙니다. 마지막으로, CTC(Connectionist Temporal Classification) 디코더가 가변 길이 문자 시퀀스를 고정된 특징 열의 격자에 문자별 경계 상자(문자를 읽기 전에 각 문자 둘레에 그린 표시된 직사각형) 없이 정렬합니다.

CTC가 푸는 문제는 정렬(alignment) 문제입니다. 네트워크는 이미지 열당 하나의 예측을 내놓지만(가령 40개 열), 텍스트는 그와 다른, 가변적인 개수의 문자(가령 7개)를 가지며, 어느 열이 어느 문자에 속하는지 아무도 표시해 두지 않았습니다 — 그리고 대안인, 먼저 각 문자 둘레에 상자를 그리는 것은 깨지기 쉽습니다. CTC는 이것을 자동으로 처리합니다. 그것은 (반복을 병합하고 공백 기호를 제거한 후) 표적 문자열로 무너지는 모든 열-대-문자 정렬에 대해 확률을 합산함으로써 작동하며, 훈련은 그 합 아래에서 올바른 문자열의 로그우도를 최대화하므로, 네트워크는 문자를 학습하는 부산물로 정렬을 학습합니다. 더 새로운 패턴은 RNN-플러스-CTC 꼬리를, 띠 전체에 주의를 기울이며 문자를 자기회귀적으로 내보내는 작은 비전 트랜스포머(vision transformer) 로 대체하는데, 이는 곡선이거나 간격이 고르지 않은 인쇄를 더 견고하게 읽습니다.

제약 특유의 어려움은 깨끗한 텍스트를 읽는 것이 아니라 — 그것은 본질적으로 해결되었습니다 — 실패 모드(failure modes) 입니다. 색이 바래는 리본에서 온 절반만 인쇄된 문자, 번짐, 이중 인쇄, 잘못된 형식의 올바른 날짜. 모델은 단지 가장 그럴듯한 문자열을 내보내서는 안 됩니다. 그것은 문자별 신뢰도(per-character confidence)(CTC의 경우, 각 단계에서 선택된 기호가 옳을 것이라고 모델 스스로가 추정한 확률)를 드러내야, 신뢰도가 낮은 판독이 조용히 신뢰되는 대신 표시되도록 해야 합니다. 확신에 차서 잘못 읽은 유효기한은 명백히 읽을 수 없는 것보다 훨씬 위험하므로, 작동점(operating point)은 원시 판독 정확도를 최대화하는 것이 아니라 의심 구간으로 거부하도록 조율됩니다.

DataMatrix 해독(DataMatrix decoding) 은 이 장 전체에서 쓰이는 GTIN, SGTIN, EPCIS를 정의하는 전 세계 공급망 표준 기구인 GS1 의 응용 식별자(application identifiers)를 담은 2D 코드를 판독합니다 — GTIN(응용 식별자 01, AI 01로 표기 — 여기서 이 "AI"는 GS1 응용 식별자(application identifier) 를 뜻하지 인공지능이 아닙니다), 시리얼(AI 21), 로트(AI 10), 유효기한(AI 17), 모두가 흑백 모듈(코드를 이루는, 각각 검거나 흰 작은 인쇄 셀)의 정사각형 하나 안에. 깨끗한 DataMatrix를 해독하는 것은 해결된, 결정론적 알고리즘 입니다. L자 모양 파인더 패턴과 점선 클록 트랙을 찾고, 모듈 격자를 표본화한 뒤, 리드-솔로몬 오류 정정(Reed-Solomon error correction) 을 실행하는데, 이는 ECC 200 심볼로지(현대 DataMatrix 부호화 표준)에 내장되어 있으며 모듈의 의미 있는 분획이 손상되어도 페이로드를 복원할 수 있습니다. 해독 자체에는 ML이 없으며, 있어서도 안 됩니다 — 법적 구속력이 있는 시리얼의 확률론적 디코더는 부채(liability)일 것입니다. 비전이 제 몫을 하는 곳은 인쇄-품질 등급 매기기(print-quality grading) 입니다. 인쇄된 코드를 ISO/IEC 15415 파라미터 — 인쇄가 저하될 수 있는 한 가지 방식씩을 각각 재는 것으로, 심볼 대비(흑-대-백 분리), 변조(각 모듈이 검정 또는 흰색으로 얼마나 깨끗하게 읽히는지), 고정-패턴 손상(디코더가 의존하는 파인더와 클록 패턴의 마모), 축 및 격자 비균일성(셀이 정사각형 격자에서 늘어나거나 비틀린 것), 그리고 사용되지 않은 오류 정정(리드-솔로몬의 복구 여유가 얼마나 남았는지) — 에 대해 채점하고, A(최고, 4.0점)부터 F(불합격, 0.0)까지 학교식 척도로 등급을 매기는 것입니다. 등급의 요점은 예측 입니다. 오늘 티 없이 깨끗하고 잘 조명된 검증기에서 해독되는 코드가, 몇 달 후 형광등 아래 약사의 더 값싼 휴대용 스캐너에서는 실패할 수 있으며, 사용되지 않은-오류-정정 파라미터는 그 일이 일어나기 전에 얼마나 여유가 남았는지의 직접적 척도입니다. 학습된 등급기는 인쇄된 이미지로부터 해독-견고성을 예측하여, 한계선상의 인쇄를 현장에서 검증 실패가 표면화된 뒤가 아니라 출하 전에 잡아냅니다. 평평한 라벨이 아니라 곡선이거나 반사하는 바이알에 직접 마킹된 코드의 경우, 관련 등급은 흔히 ISO/IEC TR 29158(직접-부품-마킹 지침)로도 보고되는데, 이는 조명 각도를 고정하여 등급이 검증기들에 걸쳐 재현 가능하게 합니다 — 바로 이 절이 경고하는 그 판독기-의존성의 표준 차원 표현입니다.

라벨 및 인쇄 검증(Label and print verification) 은 분류기 그 자체입니다. 올바른 라벨이 올바른 제품 위에, 똑바로 붙어 있고, 주름, 찢김, 기포, 잘못된 언어의 삽입물이 없는가? 이것은 AVI에 가장 가까운 사촌입니다 — 단위별 이미지 분류기로, 전형적으로는 검사 영역 위에 작은 헤드를 얹은 합성곱 백본(ResNet 부류) — 그리고 그것은 AVI의 경제학을 물려받습니다. 규칙 기반 라벨 검사는 과잉 거부 — 거짓 거부(false rejects), 즉 실수로 버려진 좋은 단위 — 로 악명이 높습니다. 규칙 기반 AVI는 좋은 단위를 대략 20%까지 거부한다고 널리 인용되는데(Amgen에 귀속된 학회/전문가 추정치이며, 학회 보고, 동료심사 아님), 심층학습 비전은 바로 그 거짓-거부 부담의 해법으로 판매됩니다 [3][4]. 훈련 규율은 17장(Chapter 17)이 AVI에 대해 고집하는 바로 그것입니다. 챌린지 세트로서의 정선되고 버전이 매겨진 결함 라이브러리(defect library), 막연한 "괜찮아 보임" 베이스라인이 아니라 심어 둔 알려진 결함에 대해 측정된 재현율, 그리고 운영 중에 아무것도 학습하지 않도록 검증 시점에 잠긴(locked at validation) 모델(고정된 가중치, eval()만). 조용히 스스로를 갱신하는 라벨 분류기는 GMP 아래에서 검증되지 않은 변경입니다.

증거

충전-마감 및 포장에서 학습된 비전의 가장 강력한 상용급 닻은 바이알과 주사기의 심층학습 검사입니다. Stevanato Group의 Vision AI 플랫폼은 최대 99.9%의 탐지 정확도와 대략 10배 적은 거짓 거부를 주장하고, Syntegon의 AIM 은 약 70% 더 많은 미립자 탐지와 약 60% 적은 거짓 거부를 보고하며, Brevetti CEA / Brevetti AI, Antares Vision, Cognex, Körber 가 견줄 만한 심층학습 검사를 판매합니다((상용) 성숙도). 여기 모든 표제 숫자는 벤더 / 자체보고 이며(증거 등급: 벤더 자료, 동료심사 아님) — 99.9%와 10배는 벤더 자료이고 대략 20% 거짓-거부 베이스라인은 학회 전문가 추정치입니다 — 기록상 완전히 검증된 단 하나의 Amgen/Syntegon 개조(retrofit)는 바이알이 아니라 주사기 라인이었습니다 [3][4]. 능력(capability) 은 실재하는 것으로, 특정 백분율 은 마케팅으로 다루세요. DataMatrix 해독(리드-솔로몬)과 ISO/IEC 15415 등급 매기기는, 대조적으로, 모든 시리얼화된 라인에서 표준화된 (상용) 관행이며 ML-신뢰성 단서를 전혀 달지 않습니다.

시리얼화: 바이알이 어떻게 SGTIN이 되는가

무결성 추론이 말이 되기에 앞서, 한 바이알이 자신의 정체성을 획득하는 과정을 따라가 보세요. 러닝 예제는 BATCH-2026-001의 480개 바이알을 충전하고, 데이터셋은 각각을 00361414000017.0000153 같은 시리얼로 기록합니다. 그 문자열은 SGTIN시리얼화된(Serialized) 글로벌 거래 품목 번호(Global Trade Item Number) — 으로, 두 부분으로 되어 있습니다.

  • 00361414000017GTIN-14 입니다. 이 제형에서의 제품 mAb-A 에 대한 전 세계적으로 등록된 식별자(세계 어디서나 이 제품의 모든 바이알에 붙는 같은 번호)입니다.1 그것은 DataMatrix 안에서 GS1 응용 식별자 AI 01 아래에 실립니다.

  • 0000153시리얼(serial) 입니다. 이 한 바이알 에 고유하며, AI 21 아래에 실리므로, GTIN-플러스-시리얼 쌍이 이 개별 단위를 식별하고 다른 어떤 것도 식별하지 않습니다.

바이알 위의 DataMatrix는 이 SGTIN을 로트(BATCH-2026-001, AI 10) 및 유효기한(AI 17)과 함께, 위의 GS1 응용 식별자로 부호화하여 담습니다. 바이알이 공정 중 중량 점검(checkweigh)을 통과하는 순간, 그 SGTIN은 발행(commissioned) 됩니다. 라인이 "이 시리얼은 이제 존재하며, 이 실제 단위에 부착되었다"고 선언하는 것입니다. 러닝 예제에서는 IPC 중량 점검이 발행 트리거를 대신하여, 데모가 하나로 다루는 두 스테이션을 압축합니다. 실제 라인에서는 시리얼화된 DataMatrix가 포장 라인의 인쇄-및-부착(print-and-apply) 스테이션에서 인쇄되고 발행되며, 흔히 무균 충전과 그 중량 점검의 한참 하류입니다 — 그러나 무결성 로직은 발행 행위가 어디에 앉든 동일합니다. 그 단 한 번의 행위가 전체 추적-추적성 기록의 씨앗입니다 — 그리고 그것은 또한 첫 번째 무결성 규칙이기도 한데, 라인이 거부한 단위에 대해 발행된 시리얼은 정의상, 결코 태어나지 말았어야 할 유령이기 때문입니다. 러닝 예제에서 두 바이알 — 시리얼 00001520000342 — 은 low_fill 로 라인에서 거부되어 결코 발행되지 않으며, 480개 중 478개가 실제이고 포장 가능한 SGTIN이 됩니다. 그 빠진 두 시리얼은 그 외에는 연속적인 시리얼 범위에 한-단위 간극을 남기고, 그 간극은 이상 계층이 나중에 보게 될, 작지만 실제이며 구조적인 신호입니다.

SGTIN은 모든 하류의 조인 키입니다. 그것은 도매상이 수령 시 스캔하는 것, 약국이 조제 전에 검증하는 것, 그리고 — 이 장에 결정적으로 — 공급망의 이벤트 로그가 그 둘레로 조직되는 식별자입니다. Book 4의 온톨로지(Book 4's ontology)에서 바이알은 전 세계적으로 고유한 IRI(그 노드에 대한 웹-고유 식별자)로 식별되는 노드이고, 그 SGTIN은 그 노드에 대해 기록된 GS1 품목 키입니다 — 하나의 바이알에 대한 두 개의 정당한 정체성 체계이며, 여기서는 SGTIN이 ML 계층이 정직하게 유지해야 할 이벤트 스트림의 닻이 됩니다.

이벤트 로그는 지식 그래프이고, 규칙은 SHACL 셰이프이다

이 장의 무결성 추론이 단지 if 문 더미가 아니라 접지(grounded) 된 이유는, 공급망을 조인하는 바로 그 SGTIN이 Book 4의 용어로는 IRI 이기 때문입니다 — 그래서 추가-전용 이벤트 로그는 우연히 시리얼 열을 가진 CSV가 아니라, 문자 그대로 타입화된 RDF 삼중항의 지식 그래프(knowledge graph)입니다. 발행 이벤트는 bp:DP-001-0000153 bp:commissionedAt "…"^^xsd:dateTime 가 되고, 포장 이벤트는 bp:CASE-003 bp:contains bp:DP-001-0000153 가 됩니다. 이벤트가 삼중항이 되면, 이 장의 나머지가 기대는 두 구별이 관행이기를 멈추고 모델링된 사실 이 됩니다. 첫째, 연속자(continuant)(시간을 통해 지속하는 바이알)와 발생자(occurrent)(한순간에 일어나는 발행 이벤트) 사이의 BFO 절단이 단위와 그것을 등록하는 행위를 별개의 노드로 유지합니다 — 그래서 평평한 행이 둘을 뒤섞는 식으로 "그 바이알"과 "언제 발행되었는가"가 조용히 혼동될 수 없습니다. 둘째, 계보 간선 bp:derivedFrom(바이알은 DP-001 에서, 그것은 원료의약품 로트에서 왔다)과 포장 간선 bp:contains(바이알은 지금 CASE-003 안에 있다)는 의도적으로 구별됩니다. 담음은 가변적이고 — 케이스를 다시 포장하면 바뀝니다 — 계보는 영속적이며, 바로 그것이 bp:derivedFrom 으로 범위를 잡은 리콜이 결코 bp:contains 간선을 따라 배송 상자로 걸어 들어가서는 안 되는 이유입니다.

이렇게 모델링하면, 결정론적 규칙 계층은 임시 코드가 아니라 — Book 4의 출하 게이트 bp:ReleaseShape(release gate)의 시리얼화 유사물입니다. 같은 닫힌-세계 발상이 적용됩니다. bp:CaseShape 는 케이스당 자식에 sh:minCount 48sh:maxCount 48(정확한-개수 불변식), 포장된 자식당 발행 이벤트에 sh:minCount 1(발행되지 않은 자식 금지), 한 GTIN 안의 어떤 시리얼의 출현에도 sh:maxCount 1(중복 금지)을 요구할 수 있습니다. SHACL(Shapes Constraint Language — 그래프가 갖춰야 할 구조를 가졌는지에 대한 닫힌-세계 검증)은 빠진 필수 발행 이벤트를 지금의 실패로 다루며, 이는 정확히 출하 게이트가 빠진 무균 결과를 다루는 방식입니다 — 반면 열린-세계로 작동하는 OWL 추론기는 그것을 단지 "미지"로 여기고 어깨를 으쓱할 것입니다. 그것이 규칙이 핵심 결정을 나르고 ML은 조언만 하는 깊은 이유입니다. SHACL 셰이프는 학습된 점수가 그럴 수 없는 방식으로 감사 가능하고, 설명 가능하며, 구성상-완전하며, 이것이 정확히 Annex 22 초안이 핵심-결정 로직에 요구하는 것입니다. 그리고 팔레트 스캔이 그 아래의 모든 바이알을 함의하게 하는 집합 워크는 하나의 SPARQL(RDF 그래프를 위한 표준 질의 언어) 속성 경로입니다 — bp:contains+(+ 는 "이 간선을 한 홉 이상 따라가라"는 뜻) — 이 장의 공급망 "추론"을 그래프 순회로 문자 그대로 만든 것입니다. 바로 그 접지가, GraphRAG 어시스턴트(GraphRAG assistant)가 "CASE-003 안에 무엇이 있는가?"에, 그럴듯한 명세서를 환각하는 대신 검증된 bp:contains 간선을 순회하고 인용함 으로써 답하게 해 주는 것입니다. 온톨로지는 모델이 책임을 지는 스키마입니다.

집합: 포장 위계와 그것을 보호하는 규칙

약국은 바이알 하나를 주문하지 않습니다. 케이스를 주문합니다. 그래서 시리얼화된 단위는 위계 — 바이알 → 묶음 → 케이스 → 팔레트 — 를 따라 집합(aggregated) 되고, 각 집합은 그 자체로 기록된 관계입니다. 시리얼들이 케이스의 자식들이고, 그 케이스는 그 자체로 팔레트의 자식이다. 이 부모-자식 구조가, 창고가 팔레트 코드 하나를 스캔하고 단 하나의 상자도 열지 않은 채 그 아래의 모든 케이스와 바이알 시리얼을 추론하게 해 주는 것입니다(ML적 의미가 아니라 공급망적 의미의 "추론").

집합은 무결성 규칙이 집중되는 곳인데, 그 관계가 정확해야 하고 기계적으로 깨지기 쉽기 때문입니다. 발행과 포장 사이에 라인에서 떨어진 바이알, 한 단위 부족하게 봉인된 케이스, 부모를 갱신하지 않고 한 단위를 새 케이스로 옮긴 재작업. 이것들은 추적-추적성 시스템이 강제하는 결정론적 불변식(invariants)이며, 기계학습이 아닙니다 — 그것은 GS1 / EPCIS 비즈니스 규칙입니다. 어떤 것이 법적 효력을 갖는지 정확히 짚어 둘 가치가 있습니다. 고유 식별, 중복 시리얼 금지, 조제-시-폐기(decommission-at-dispense)는 DSCSA와 FMD가 의무화하지만, 완전한 케이스 수준 집합은 연방 요구사항이 아니라 거래-파트너 기대이자 추론 편의입니다(FDA는 집합 요구를 명시적으로 거부했습니다). 바로 이것이 사슬을 가로질러 집합 데이터 품질이 그토록 천차만별인 이유입니다.

  • 발행되지 않은 자식 금지. 케이스에 포장된 모든 시리얼은 먼저 발행되었어야 합니다.
  • 발행된 거부품 금지. 라인이 거부한 단위에 부착된 시리얼은 결코 케이스의 자식으로 나타나서는 안 됩니다.
  • 정확한 집합 개수. 48개 바이알을 담는다고 선언된 케이스는 정확히 48개의 자식 시리얼을 담아야 합니다.
  • 중복 시리얼 금지. 한 GTIN 안에서 시리얼은 정확히 한 번 나타납니다. 두 번째 출현은 복제(cloning)이거나 재입력입니다.
  • 고아 자식 금지. 모든 자식은 정확히 하나의 부모를 가져야 합니다. 두 케이스에 든 한 단위는 불가능합니다.
  • 타임스탬프 역전 금지. 한 단위는 발행되기 전에 집합될 수 없고, 포장되기 전에 출하될 수 없습니다.

이 규칙들이 — 어떤 ML보다도 — 먼저 오는 이유는 규제적인 동시에 실용적입니다. 그것들은 결정론적이고, 감사 가능하며, 설명 가능합니다. 심사자가 각각을 읽을 수 있고 규제자는 어떤 단위가 왜 보류되었는지를 정확히 볼 수 있습니다. EU/PIC/S(Pharmaceutical Inspection Co-operation Scheme — 규제자들에 걸쳐 GMP 점검 표준을 조율하는 기구) GMP Annex 22(GMP 제조에서의 AI에 특화된 규제 지침 초안) 초안 아래에서, GMP 시스템의 핵심-결정 로직은 정확히 이런 종류의 정적이고 결정론적인 규칙이어야 합니다 — 그 부속서는 핵심 용도에 정적이고 결정론적인 모델만을 허용하며, 동적이고 연속 학습하며 확률론적이고 생성적인 AI를 그러한 결정에서 배제합니다 [5]. 따라서 이 장에서 기계학습은 규칙이 부호화할 수 없는 것에 국한됩니다. 어떤 규칙도 깨지 않지만 그럼에도 통계적으로 이상한 케이스의 잔차(residual).

EPCIS 이벤트 스트림과 이상 탐지가 사는 곳

그 행위들 하나하나 — 발행, 집합, 폐기, 출하, 수령 — 는 EPCIS 이벤트(Electronic Product Code Information Services, 공급망 가시성 데이터를 공유하기 위한 GS1 표준)로 보고됩니다. EPCIS 이벤트는 다음 질문에 답합니다. 무엇(what)(시리얼들의 epcList), 언제(when)(이벤트 시각), 어디서(where)(서로 구별되는 두 필드 — 스캔된 곳인 readPoint 와 지금 머무는 곳인 bizLocation), 그리고 왜(why)(비즈니스 단계 — 발행, 포장, 출하 — 와 함께 in_progressin_transit 같은 처분(disposition)). 그 처분 필드가 바로 "포장-전-출하" 규칙이 실제로 읽는 것입니다. 발행 이벤트는 비즈니스 단계가 발행ObjectEvent 이고, 포장 이벤트는 parentID 와 자식 epcList 를 명명하는 AggregationEvent 입니다. DSCSA와 EU 허브는 모두 이 이벤트 어휘를 소비하며, 그 결과는 SGTIN으로 키가 매겨진, 대용량의 추가-전용(append-only) 구조화 이벤트 로그입니다 [1][2].

이 스트림 위의 이상 탐지는 자연스러운 ML 문제이며, 모델 선택을 결정짓는 매우 독특한 모양을 가집니다.

  • 그것은 압도적으로 정상적(normal) 입니다. 이벤트의 압도적 다수가 정당하므로, 지도 분류를 할 균형 잡힌 라벨 달린 "사기" 훈련 세트가 없습니다. 이상은 드물고, 다양하며, 부분적으로 적대적입니다.
  • 그것은 잘해야 약하게 라벨링(weakly labelled) 됩니다. 확인된 사기나 리콜은 드문, 사후의 라벨입니다. 그것을 수천 개 기다릴 수는 없습니다.
  • 그것은 구조화되어 있고 특징이 풍부합니다(feature-rich). 각 집합은 그 "모양"을 묘사하는 개수, 타이밍, 시리얼-연속성, 거부 통계를 담습니다.

네 번째 속성은 거버넌스적인 것이며, 방어 가능한 이상 계층과 오도하는 계층을 가르는 것입니다. 스트림은 추가-전용이고 출처가 남으며, 결측 자체가 신호입니다(append-only and provenanced, with missingness that is itself a signal). EPCIS 이벤트는 제자리에서 결코 편집되지 않으므로 — 정정은 덮어쓰기가 아니라 새로운 이벤트입니다 — 로그는 구성상 ALCOA+-친화적 기록입니다. 모든 이벤트는 귀속 가능(recordTime 과 보고 당사자)하고, 동시적(eventTime)이며, 영속적 입니다. 그것이 ML에 중요한 이유는, 이 스트림에 적합된 모델이 그 출처를 물려받기 때문입니다. 각 케이스별 특징 행은 SGTIN으로, 라인의 데이터 그림자(data-shadow)가 내보낸 바로 그 fill_events.csv 행들까지 거슬러 추적되므로, 표시된 케이스는 블랙박스의 판정이 아니라 그 원천 이벤트까지 설명 가능 합니다. 그것은 또한 결측 데이터가 다뤄져야 하는 방식을 다시 틀잡습니다. 빈 commissioning 이벤트는 대치(impute)할 값이 아닙니다 — 닫힌-세계 규칙 계층 아래에서 그것은 위반, 즉 발행되지 않은-자식 실패 그 자체입니다. 그러므로 무결성 계층은 빠진 필수 이벤트를 존재하지만-0인 것과 구별되게 유지해야 합니다. "발행 행 없음"을 조용히 대치된 정상으로 다루는 것은 정확히 결정론적 SHACL-식 완전성 점검이 막으려고 존재하는 데이터-거버넌스 실패이며, 이것이 이벤트가 부재 하는지에 대한 질문을 Isolation Forest가 아니라 규칙 계층이 소유하는 이유입니다.

이것은 비지도 이상 탐지(unsupervised anomaly detection) 의 교과서적 체제이며 — 특히 Isolation Forest 같은 트리 기반 격리 방법의 체제로, 이는 무작위 분할이 한 점을 격리하는 데 몇 번이나 걸리는지로 그 점을 채점하여, 라벨을 요구하지 않고 이상의 "드물고-이상한" 정의를 직접 다룹니다. 같은 Isolation-Forest-플러스-Random-Forest 계보가 바이오 제조 다른 곳의 동료심사된 CPV(Continued Process Verification — 검증된 공정이 통제를 유지하는지 확인하기 위한 지속적 감시) 작업에 등장하며(CSL Behring과 Aizon의 "미래의 CPV(CPV of the Future)", 완전한 mAb 런을 대신하는 더 단순한 미생물-기반 공정인 미생물 모델 시스템 위의 개념 증명), 그것이 여기서 이국적인 것이 아니라 방어 가능하고 잘 이해된 선택인 이유입니다 [6].

Isolation Forest가 케이스를 채점하는 법

이 방법을, 수식이 아니라 산문으로 풀어 적으면, 그것이 이 체제에 들어맞는 이유가 됩니다. Isolation Forest는 많은 무작위 이진 트리(여기서는 200개)를 만듭니다. 각 트리는 특징을 무작위로 고르고 그 특징의 최솟값과 최댓값 사이에서 분할 값을 무작위로 고르며, 점들을 분할하고, 모든 점이 잎(leaf)에 홀로 앉을 때까지 재귀함으로써 자랍니다. 핵심 관찰은, 대다수와 다른 점은 짧은 분할 사슬로 격리되는 반면, 빽빽한 군집 안에 묻힌 점은 이웃들에서 떼어내는 데 많은 분할이 필요하다는 것입니다. 그래서 경로 길이(path length) — 한 점을 담은 잎까지 뿌리로부터의 간선 수, 200개 트리에 걸쳐 평균한 것 — 는 이상점에는 짧고 정상점에는 깁니다.

경로 길이를 비교 가능한 점수로 바꾸기 위해, 평균 경로 길이는 그 크기의 트리에서 평균적인 한 점에 기대되는 경로 길이 — 천천히(대략 표본 크기의 로그에 따라) 자라는 베이스라인 — 로 정규화됩니다. 정규화가 중요한 이유는, 케이스의 더미가 더 클수록 정상점조차 자연히 격리하는 데 분할이 몇 번 더 필요하기 때문입니다. 그 크기 효과를 나눠 빼지 않으면, 더 큰 데이터셋은 모든 점을 더 정상으로 보이게 만들고, 크기가 다른 실행에서 나온 점수는 비교할 수 없게 됩니다. 그러면 점수는 0과 1 사이를 달리도록 정의됩니다. 정규화된 경로 길이가 기대 길이와 같은 점은 약 0.5를 받고, 기대보다 훨씬 빠르게 격리되는 점은 1을 향해 밀려 이상으로 표시되며, 기대보다 훨씬 오래 걸리는 점은 0.5보다 한참 아래에 앉아 깊은 정상(deep normal)입니다. 예제 모듈은 부정된(negated) score_samples 값을 보고합니다(sklearn의 score_samples더 정상적인 점에 대해 더 높은 숫자를 돌려주므로, 부호를 뒤집으면 높을수록 더 이상함 이 됩니다) — 이 부정된 값은 위의 정전적 0-에서-1 점수와 함께 오르내리지만(그것에 대해 단조(monotonic)) 문자 그대로 같지는 않으므로, 출력된 열을 "이상함으로 가는 비율"이 아니라 순위와 플래그로 읽으세요. 별도의 contamination 파라미터가 모델에게 이상치로 기대하라고 알려 주는 점의 비율을 설정하는데, 이것이 그 점수 위로 flag 가 참이 되는 임계값을 고정합니다. 세 가지 속성이 이것을 여기 알맞은 도구로 만듭니다. 그것은 라벨이 필요 없고, 점 개수에 대해 거의 선형(near-linear) 이라 국가 단위 이벤트 양으로 확장되며, 임계를 매겨야 할 밀도를 적합하는 대신 "드물고 구조적으로 이상한 것"을 직접 채점합니다.

그 결과로 나오는 아키텍처는 두 계층이며, 그 계층화 자체 가 설계입니다. 결정론적 규칙 계층이 먼저 돌아 완전한 감사 가능성으로 실제 결함의 대부분을 잡고, 비지도 ML 계층은 살아남은 것 위에서만 돌며, 합법적이지만 캠페인과 다른 케이스 — 약간 짧게 포장된 케이스, 발행 기간이 이상하게 긴 케이스, 시리얼 범위의 가장자리에 앉은 케이스 — 를 채점합니다. ML 점수는 조언적(advisory) 입니다. 그것은 사람이 검토하도록 플래그를 올릴 뿐, 자율적으로 단위를 보류하거나 출하하지 않습니다. 그 구분이 정확히 FDA의 2023년 의약품 제조에서의 인공지능(Artificial Intelligence in Drug Manufacturing) 논의 문서와 Annex 22 초안이 모두 품질-관련 결정에 닿는 ML에 기대하는 것입니다 [5][7].

포장-및-시리얼화 ML 스택의 히어로 도해: 왼쪽에 바이알 DP-001이 세 가지 판독을 수행하는 비전 카메라를 지나는 포장 라인 — 로트와 유효기한 텍스트의 OCR, SGTIN 00361414000017 점 0000153의 DataMatrix 해독, 그리고 라벨 또는 인쇄-등급 합격-또는-거부 분류기; 발행된 SGTIN들이 오른쪽으로 흘러 48개 바이알이 한 케이스로 한 팔레트로 들어가는 트리로 그려진 집합 위계로; 위계 아래에는 수평 EPCIS 이벤트 스트림 띠가 시리얼로 키가 매겨진 발행, 포장, 출하 이벤트를 보여 주며; 그 이벤트 스트림이 결정론적 규칙 계층 상자(발행되지 않은 자식, 중복 시리얼, 개수 불일치, 타임스탬프 역전)를 잔차의 이상하지만-합법적인 케이스를 채점하는 비지도 Isolation Forest 상자 앞에 둔 두-계층 이상 엔진에 입력되고; 오른쪽에는 인간-결정으로 표시된 녹색 조언-플래그 출력과, 시리얼 범위에 한-단위 간극을 남기며 떠나는 두 거부 바이알이 보인다. 포장의 두 ML 문제를 나란히: 물리적 라인 위의 단위별 비전 판독기(OCR, DataMatrix 해독, 라벨 등급), 그리고 시리얼화된 EPCIS 이벤트 스트림 위의 두-계층 무결성 엔진 — 결정론적 GS1 규칙이 먼저, 잔차에는 비지도 Isolation Forest, ML 점수는 조언적이고 결정은 사람이. 저자가 AI의 도움을 받아 직접 제작한 그림입니다.

실행 가능한 모델: serialization_anomaly.py

예제 모듈 examples/platform/ml/serialization_anomaly.py 는 커밋된 데이터셋 examples/datasets/fill_events.csv 위에 전체 무결성 스택을 만듭니다. 그것은 BATCH-2026-001 의 충전된 480개 바이알에서 실제 SGTIN을 발행하고(pandas — 표준 파이썬 표 라이브러리 — 가 그러지 않으면 파괴할 선행 0을 유지하면서. 열 타입을 추측하게 내버려 두면 그것은 00361414 같은 시리얼을 숫자 361414로 읽어 선행 0이 사라지므로, 코드는 그것을 텍스트로 읽도록 강제합니다), 두 low_fill 거부품을 제외하여 그것들이 결코 발행되지 않게 하며, 생존자들을 48개 케이스로 집합하고, 결정론적 GS1 규칙 계층을 돌린 다음, 케이스별 특징 표를 Isolation Forest로 채점합니다. 그것은 서비스 없이 단독으로 실행됩니다.

케이스별 특징 표가 ML 절반의 핵심이므로, 필드 하나하나 읽으세요. 각 케이스는 다섯 개의 특징을 가진 한 행이 됩니다. n_vials 는 자식 개수입니다. commission_span_s 는 케이스 안의 첫 발행 타임스탬프와 마지막 발행 타임스탬프 사이의 벽-시계(wall-clock) 초로, 그 케이스가 채워지는 동안 라인이 얼마나 매끄럽게 돌았는지의 대리물입니다. mean_fill_g 는 케이스 바이알들의 평균 중량 점검 충전 무게로, 포장을 충전-제어(fill-control) 중량 점검에 도로 묶습니다. fill_ration_vials 를 선언된 48로 나눈 것이므로, 가득 찬 케이스는 정확히 1.0이고 짧은 케이스는 1 미만입니다. serial_jump 는 연속성 검사입니다. 깨끗한 케이스에서는 최대 시리얼 빼기 최소 시리얼이 n_vials 빼기 1과 같아야 하므로, 양수인 serial_jump 는 시리얼 범위 안의 간극을 뜻합니다 — 정확히 두 거부 바이알이 남기는 발자국입니다. Isolation Forest는 이 5차원 공간에서 행을 채점합니다. 그것이 표시하는 모든 것은 케이스의 모양(shape) 에 대한 진술이지, 결코 단일 라벨 이미지에 대한 것이 아닙니다.

mean_fill_g 는 곱씹어 볼 가치가 있는데, 그것이 시리얼 그래프가 아니라 바이오공정 본체로 거슬러 닿는 유일한 특징이기 때문입니다. 실제 무균 충전 라인에서 공정 중 중량 점검(in-process checkweigh)(각 충전된 바이알을 중량으로 점검하는 100%-칭량 스테이션)은 그 자체로 충전중량 관리도(fill-weight control chart) 가 규율하는 검증된 단위공정입니다. 목표 충전은 제형화된 용량에 작은 의도적 과충전을 더한 것이고, 조치 및 경고 한계(action and warning limits) 는 라인의 적격성 평가된 충전중량 표준편차에서 설정되며, 거부 한계를 벗어난 바이알이 두 시리얼이 결코 발행되지 않게 막는 low_fill 거부입니다. 그 바이알별 무게를 케이스별 mean_fill_g 로 집계하면 무결성 계층이 거친 공정능력(process-capability) 센서가 됩니다. 평균이 관리 한계로 표류하거나 바이알-대-바이알 산포가 넓어지는 케이스는, 펌프나 중량 점검이 공정능력 밖으로 추세를 보이는 동안 충전된 케이스입니다 — 충전-마감 장(fill-finish chapter)이 바이알 하나하나에 적용하는 바로 그 Cpk(공정능력지수: 충전의 산포가 규격 창 안에 얼마나 여유 있게 앉는지) 사고를, 이제 한 포장 단계 위에서 읽는 것입니다. Isolation Forest는 단일 무게를 결코 보지 않습니다. 그 케이스가 조립되는 동안 통제 안에 있었거나 밖에 있었던 충전 공정의 케이스-수준 시그니처 를 보는데, 이것이 충전중량 일탈과 시리얼화 이상이 같은 표시된 케이스로 표면화될 수 있는 이유입니다.

# examples/platform/ml/serialization_anomaly.py (excerpt)
from pathlib import Path
import pandas as pd
from sklearn.ensemble import IsolationForest

DATA = Path(__file__).resolve().parents[3] / "examples" / "datasets"
VIALS_PER_CASE = 48 # vial -> case aggregation (illustrative hierarchy)


def commission_serials():
"""Each filled, NON-rejected vial is commissioned as an SGTIN at the fill line."""
fe = pd.read_csv(DATA / "fill_events.csv", parse_dates=["ts"],
dtype={"vial_serial": str}) # keep GTIN/serial leading zeros
fe["reject"] = fe["reject"].astype(str).str.strip().eq("True")
fe[["gtin", "serial"]] = fe["vial_serial"].str.split(".", expand=True)
commissioned = fe[~fe["reject"]].sort_values("ts").reset_index(drop=True)
return fe, commissioned


def aggregate_cases(commissioned):
"""Roll commissioned vials into cases of 48 and build the per-case feature table."""
c = commissioned.copy()
c["case_idx"] = c.index // VIALS_PER_CASE
g = c.groupby("case_idx")
cases = pd.DataFrame({
"case_id": ["CASE-%03d" % i for i in g.size().index],
"n_vials": g.size().to_numpy(),
"mean_fill_g": g["fill_weight_g"].mean().to_numpy(),
"min_serial": g["serial"].min().to_numpy(),
"max_serial": g["serial"].max().to_numpy(),
})
cases["fill_ratio"] = cases["n_vials"] / VIALS_PER_CASE
# serial contiguity: a clean case has max-min == n_vials-1 (no gaps/jumps)
cases["serial_jump"] = (cases["max_serial"].astype(int)
- cases["min_serial"].astype(int)
- (cases["n_vials"] - 1))
return cases


def rule_checks(fe, cases):
"""Deterministic GS1/EPCIS invariants — NOT machine learning, and audited first."""
findings = []
if fe.loc[~fe.reject, "vial_serial"].duplicated().any():
findings.append("duplicate_serial")
phantom = set(fe.loc[fe.reject, "vial_serial"]) & set(fe.loc[~fe.reject, "vial_serial"])
if phantom:
findings.append(f"commissioned_rejected_unit x{len(phantom)}")
short = cases[cases.n_vials != VIALS_PER_CASE]
if len(short):
findings.append(f"aggregation_count_mismatch x{len(short)} "
f"(e.g. {short.iloc[-1].case_id}={int(short.iloc[-1].n_vials)})")
return findings or ["none"]


def score_anomalies(cases, contamination=0.08):
"""IsolationForest over per-case features -> advisory score for legal-but-strange cases."""
feats = ["n_vials", "commission_span_s", "mean_fill_g", "fill_ratio", "serial_jump"]
iso = IsolationForest(n_estimators=200, contamination=contamination, random_state=2026)
X = cases[feats].to_numpy(float)
iso.fit(X)
cases = cases.copy()
cases["anomaly_score"] = -iso.score_samples(X) # higher = more anomalous
cases["flag"] = iso.predict(X) == -1 # -1 = outlier
return cases.sort_values("anomaly_score", ascending=False)

python platform/ml/serialization_anomaly.py 를 실행하면 다음 블록을 출력합니다. 여기 모든 숫자는 실제 fill_events.csv 위의 그대로의 실행 출력(verbatim run output) 입니다 — GTIN, 480/478 발행 개수, 두 low_fill 거부품, 그리고 짧은 마지막 케이스 — 단, Isolation-Forest 점수는 예외로, 그것은 시드(seed)가 주어지면 결정론적이지만 깨끗한 캠페인 위의 예시용(illustrative) 이상 모델이지 학습된 사기 탐지기가 아닙니다.

serialization / track-and-trace anomaly layer
GTIN-14 : 00361414000017
vials filled : 480
IPC rejects (not commissioned): 2 (['low_fill', 'low_fill'])
serials commissioned: 478
cases (48/case): 10 (last case is short: 46 vials)

-- rule layer (deterministic GS1/EPCIS invariants) --
n_commissioned: 478
n_rejected_not_commissioned: 2
rule_findings: ['aggregation_count_mismatch x1 (e.g. CASE-009=46)']

-- ML layer (IsolationForest, advisory) — top scored cases --
case_id n_vials fill_ratio serial_jump anomaly_score flag
CASE-009 46 0.958 0 0.735 True
CASE-007 48 1.000 1 0.582 False
CASE-003 48 1.000 1 0.576 False
CASE-001 48 1.000 0 0.529 False
CASE-000 48 1.000 0 0.437 False

NOTE: rule findings are deterministic and auditable; the IsolationForest score is ADVISORY only. Real vendor detection accuracy (e.g. Stevanato ~99.9% on the VISION half) is vendor/self-reported.

이 출력을 시리얼화 분석가가 읽듯이 읽으세요. 결정론적 계층이 먼저 실제 작업을 합니다. 480개 중 478개 바이알이 발행되고, 두 low_fill 거부품은 올바르게 발행되지 않으며(그래서 그것들은 유령 단위가 될 수 없습니다), 그리고 정확히-48 불변식을 깨는 단 하나의 개수 — 478이 48개 케이스로 고르게 나뉘지 않기에 48 대신 46개 바이알을 담은 마지막 케이스 CASE-009 — 은 정확하고 감사 가능한 aggregation_count_mismatch 규칙에 잡힙니다. (이 짧은 마지막 케이스는 라인의 결함이 아니라 예상된 나머지입니다. 그럼에도 규칙이 발화하는 것은, 그것의 일이 개수가 어긋난 어떤 케이스든 보고하여 사람이 그 이유를 — 여기서는 무해한 산술을 — 확인하게 하는 것이기 때문입니다.) 그러고 나서야 Isolation Forest가 돌고, 그것은 같은 CASE-009 를 최고점, 표시된 이상치(anomaly_score 0.735, flag true)로 독립적으로 표면화합니다 — 규칙과 일치하되 논리가 아니라 통계를 거쳐 그것에 도달하는데, 그 짧은 케이스가 fill_ratio 1.000 대신 0.958을 가진 외로운 점이고 단 몇 번의 무작위 분할로 격리되기 때문입니다.

serial_jump 가 1인 두 케이스(CASE-007, CASE-003)는 가득 차고 연속적인 동료들보다 약간 더 높은 점수를 받습니다(0.582와 0.576 대 0.529와 0.437). 거부된 시리얼 00001520000342 가 한-단위 간극을 남겨 그 케이스들 안의 시리얼 연속성을 깼기 때문입니다. 이것이 정확히 ML 계층이 알아채라고 존재하는 종류의 약한 구조적 신호이며 — 주목할 것은 그중 어느 것도 contamination 임계값을 넘어 플래그가 되지 않는다는 점입니다. 이것이 전체 설계의 축소판입니다. 규칙이 확실한 것을 잡고, ML이 의심스러운 것을 채점하며, 사람이 플래그를 읽습니다.

이 데모가 구체화하는 정직한 단서 하나: 이 포레스트는 단일 골든 런(golden run)의 열 개 케이스 위에 적합되며, N=10에서는 분포를 학습하기보다는 열 개 점을 외우는 데 더 가깝습니다 — sklearn은 모든 트리를 그 열 개 전부에서 뽑기까지 합니다. 메커니즘은 실재하지만, 일반화는 그렇지 않으며, 그것은 오직 수백 개 캠페인에 걸친 훈련에서만 옵니다. 그 간극이, 공장의 마지막 문제에서 마지막으로 한 번 더 모습을 드러내는 소-데이터 천장입니다.

시리얼화 이벤트 한 건의 해부

시리얼화 이벤트는, 이 시리즈의 모든 산출물처럼, 헐벗은 시리얼 번호가 아닙니다 — 그것은 그 단위에 무슨 일이, 어디서, 언제, 왜 일어났는지에 그것을 묶는 구조화된 EPCIS 기록이며, 거기에 그것과 함께 따라가는 모델 출력과 무결성 판정이 더해집니다. 추적-추적성 심사자가 하듯이 발행-그다음-포장 이벤트 하나를 해부하세요.

BATCH-2026-001의 바이알 시리얼 0000153에 대한 시리얼화 이벤트 한 건의 해부 신원 카드: 이벤트 유형 ObjectEvent 발행 그다음 AggregationEvent 포장과 SGTIN 00361414000017 점 0000153을 명명하는 인디고 헤더; 네 개의 WWWW 필드를 나열하는 EPCIS 핵심 블록 — 무엇 SGTIN epc 리스트, 언제 이벤트 타임스탬프, 어디서 사업장 위치 FILL-A 라인, 왜 비즈니스 단계 발행 그다음 포장; OCR로 읽은 로트 BATCH-2026-001과 유효기한을 판독 신뢰도와 함께, 해독된 DataMatrix 페이로드, 그리고 ISO 15415 코드-품질 등급 문자를 동반한 라벨 또는 인쇄 등급 합격을 담은 비전 블록; parentID CASE-003과 그것이 속한 48-자식 개수를 보여 주는 집합 블록; 결정론적 규칙 판정을 나열하는 무결성 블록 — 포장-전-발행 true, 거부-아님 true, 개수-정확 true, 중복-없음 true — 각각 결정론적으로 표시됨; 부모 케이스에 대한 Isolation Forest 이상 점수를 예시용이며 조언적으로 표시하고 인간-검토 플래그 false를 담은 조언 블록; 이벤트를 DP-001에서 derivedFrom, CASE-003의 child-of, DSCSA와 EU 허브에 reported-to, 조제에서 verified-at으로 잇는 보라색 관계 패널; 규칙 판정은 핵심-결정 로직이고 ML 점수는 Annex 22 아래에서 조언적임을 짚는 캡션. 완전히 풀어낸 시리얼화 이벤트 한 건: EPCIS의 무엇-언제-어디서-왜 핵심, 단위를 물리적으로 검증한 비전 판독(신뢰도를 가진 OCR 텍스트, 해독된 DataMatrix, 인쇄 등급), 그것이 속한 집합 부모, 핵심-결정 로직인 결정론적 무결성 판정, 그것이 아닌 조언적 Isolation-Forest 이상 점수, 그리고 이벤트를 DP-001, 그 케이스, 그것이 보고되는 국가 허브에 잇는 계보. 저자가 AI의 도움을 받아 직접 제작한 그림입니다.

카드를 위에서 아래로 읽으면 이 장이 필드로 펼쳐집니다.

EPCIS 핵심 — 이벤트 그 자체. 네 필드. 무엇epcList, 이벤트가 다루는 SGTIN(들)(여기서는 00361414000017.0000153). 언제 는 이벤트 타임스탬프로, 시간대 오프셋과 함께 기록되어 관할 구역을 가로지르는 이벤트도 순서를 유지합니다. 어디서 는 판독 지점 사업장 위치(FILL-A 라인). 는 비즈니스 단계 — ObjectEvent 의 경우 commissioning, 그다음 AggregationEvent 의 경우 packing. 이 넷은 GS1이 의무화한 최소이며, 또한 정확히 규칙 계층이 읽는 열입니다.

비전 블록 — 카메라가 물리적으로 검증한 것. 세 개의 하위 필드, 각각 위 세 비전 작업 중 하나에서 옵니다. OCR로 읽은 로트(BATCH-2026-001)와 유효기한은 판독 신뢰도와 함께 따라가므로, 신뢰도가 낮은 판독은 조용히 신뢰되는 대신 표시됩니다 — 실패-모드 규율이 필드가 된 것입니다. 해독된 DataMatrix 페이로드는 2D 코드의 결정론적 리드-솔로몬 해독입니다(신뢰도 불필요. 해독되거나 안 되거나입니다). 라벨/인쇄 등급은 그 ISO/IEC 15415 문자 등급, 즉 단지 합격 비트가 아니라 예측된 해독-견고성을 나릅니다.

집합 블록 — 부모. parentID(CASE-003)와 선언된 48-자식 개수로, 부모-자식 관계를 명시적이고 점검 가능하게 만듭니다. 이것이 aggregation_count_mismatch 와 고아-자식 규칙이 작동하는 필드입니다.

무결성 블록 — 핵심-결정 로직. 결정론적 규칙 판정. 포장-전-발행(true), 거부-아님(true), 개수-정확(true), 중복-없음(true). 각각은 결정론적 으로 표시되는데, 이것들이 규제자가 읽는 판정이고 Annex 22 아래에서 단위를 게이트할 수 있도록 허용된 유일한 것이기 때문입니다.

조언 블록 — 게이트할 수 없는 부분. 부모 케이스 에 대한 Isolation-Forest 이상 점수로, 조언적 이고 예시용 으로 표시되며, 더하기 인간-검토 플래그(false). 그 점수가 카드 위에 사는 것은 바로, 심사자가 그것이 고려되었으나 결정을 내리지는 않았음을 볼 수 있도록 하기 위함입니다 — "ML이 채점하고, 사람이 결정한다"의 감사-추적적 표현이자, ALCOA+ 데이터-무결성 원칙(기록은 귀속 가능(Attributable), 판독 가능(Legible), 동시적(Contemporaneous), 원본(Original), 정확(Accurate)해야 한다 — ALCOA 다섯 — 더하기 네 개의 "+" 속성: 완전(Complete), 일관(Consistent), 영속(Enduring), 가용(Available))을 구체화한 것입니다. 조언 점수가 동시적이고 귀속 가능하게 기록되어 결정이 재구성 가능하게 유지됩니다.

관계(보라색) — 계보와 담음. 여기서 DP-001 에서의 derivedFrom계보(lineage) 간선(단위가 어디서 왔는가)인 반면, CASE-003contained-in 은 별개의 포장-담음(packing-containment) 간선입니다 — Book 4는 이 두 위계를 의도적으로 구별합니다(담음은 가변적이며 계보가 아닙니다). 이 이벤트는 또한 DSCSA와 EU 검증 허브에 reported-to 이고, 조제에서 verified-at 입니다 — 러닝 예제의 계보에서 마지막 지점으로, 충전에서 시작된 SGTIN이 환자가 용량을 받기 전에 마침내 제조사의 기록과 대조됩니다.

미해결 과제: 드물고, 적대적이며, 포화 문제

시리얼화 이상 탐지가 깔끔한 데모가 시사하는 것보다 왜 더 어려운지에 대해 정직하세요. 첫 번째 어려움은 실제 이상이 드물고 적대적(rare and adversarial) 이라는 것입니다. 표류하는 소프트 센서와 달리, 가장 위험한 시리얼화 이상 — 유효한 시리얼의 위조 복제, 정당한 사슬로 재투입된 우회된 제품(정당한 경로에서 빼낸 단위, 예를 들어 회색 시장으로) — 은 적극적으로 정상으로 보이려 애쓰는 적대자가 만들어 냅니다. 정당한 트래픽에서 훈련된 Isolation Forest는 정상이 어떻게 생겼는지를 학습하지만, 정교한 위조자는 같은 분포를 연구하여 자신의 가짜를 그 안에 편안히 앉도록 포장합니다. 여기에는 단지 경험적인 이유가 아니라 구조적인 이유가 있습니다. 비지도 탐지기는 자신이 관측한 분포에 적합되고, 유능한 적대자는 바로 그 같은 분포에 맞서 최적화하므로, 그 방법은 견고성 보장을 전혀 제공하지 못합니다. 그래서 "플래그 없음"은 결코 "진품"으로 읽힐 수 없으며, 적대자-독립적인 결정론적 규칙이 — 모델이 아니라 — 진품성 결정을 나르야 합니다. 정전적 복제를 실제로 잡는 것은 모델이 아니라 결정론적 중복-시리얼 규칙이며 — 이것이 규칙이 핵심 부하를 나르는 더 깊은 이유입니다.

두 번째 어려움은 경보 피로 / 포화 문제(alert-fatigue / saturation problem), AVI 과잉 거부의 공급망 사촌입니다. 너무 공격적으로 표시하는 추적-추적성 시스템은 양성(benign)인 이상함의 홍수 아래에 실제 신호를 묻습니다 — 정당하게 짧은 마지막 케이스(데모가 정확하지만 무해하게 표시한 바로 그 CASE-009), 부모를 정확히 갱신했으나 이례적으로 갱신한 재작업, EPCIS 시계가 몇 초 어긋난 파트너. Isolation Forest의 contamination 을 너무 높게 조율하면 인간 심사자가 플래그를 신뢰하기를 멈추고, 너무 낮게 조율하면 드문 진짜 사기가 빠져나갑니다. 깨끗한 작동점은 없으며 — 출하 예측(release-prediction) 작동점이 구체화하는 같은 재현율-대-정밀도 긴장입니다 — 유일하게 지속 가능한 답은 이 장이 고집하는 두-계층 분할입니다. 확실하고 감사 가능한 규칙이 부하를 나르게 하고, ML 점수는 인간 주의를 위한 우선순위 결정기(prioritizer) 로 쓰되, 결코 게이트로 쓰지 않는 것.

세 번째 어려움은 단편화(fragmentation) 입니다. DSCSA와 EU FMD는 서로 다른 이벤트 모델, 서로 다른 허브, 서로 다른 검증 흐름을 가진 다른 체제이며, 단일한 글로벌 제품은 둘 다를 가로지릅니다. 한 관할 구역의 이벤트 모양에서 훈련된 이상 모델은 다른 쪽으로 깨끗하게 전이되지 않으며, 가장 흥미로운 이상 — 두 나라의 시스템에 동시에 나타나는 단위 — 은 정확히 어떤 단일 관할 구역의 데이터도 볼 수 없는 것입니다. 관할 구역 간 이상 탐지는 경쟁과 프라이버시 압력이 진정으로 어렵게 만드는 데이터 공유를 요구하며, 이것이 오늘날 대부분의 배포된 이상 작업이 사슬을 가로질러서가 아니라 한 제조사의 시리얼화 저장소 안에 사는 이유입니다. 이것이 또한 학습된 시리얼화 이상 탐지의 정직한 성숙도 라벨이 (상용)이 아니라 (파일럿)/(연구) 인 이유입니다. 방법 은 건전하고 동료심사된 CPV 작업에 닻을 내렸지만, 배포 표면은 단편화되어 있고 검증 증거는 얇습니다 [6].

이 장이 모델 모음에 더하는 것

이 장은 Book 5 예제 모음에 examples/platform/ml/serialization_anomaly.py 를 기여합니다. fill_events.csv 에서 실제 SGTIN을 발행하고(GTIN-14와 시리얼 선행 0을 올바르게 보존하며), 두 low_fill IPC 거부품을 발행에서 제외하고, 생존자들을 케이스로 집합하며, 결정론적 GS1/EPCIS 규칙 계층(발행되지 않은 자식, 발행된 거부품, 집합-개수 불일치, 중복 시리얼, 타임스탬프 역전)을 돌리고, 케이스별 특징 표를 비지도 Isolation Forest로 채점하는 단독 모듈입니다. 그것은 비전 AVI 스케치(vision AVI sketch)(vision_avi.py)와 협조하며 — 그리고 의도적으로 중복하지 않으며 — 그쪽은 포장의 지각 절반(바이알별 이미지 분류기)을 다루고, 이 모듈은 무결성-추론 절반(시리얼화된 이벤트 스트림)을 다룹니다. 발행 개수, GTIN, 두 거부품, 그리고 짧은 마지막 케이스는 실제 커밋된-데이터셋 사실이고, Isolation-Forest 점수는 예시용으로 명확히 라벨링되어 있습니다 — 그것들은 확인된 사기에서 훈련된 학습된 사기 탐지기가 아니라 깨끗한 캠페인 위의 방어 가능한 이상 모델을 운동시킵니다.

왜 중요한가

포장은 디지털 스레드가 제품에 닿는 마지막 장소이며, 두 규제 체제가 제조의 관심사를 공공-안전의 관심사로 바꾸는 곳입니다. 비전을 제대로 잡으면 라인이 운영자를 거짓 거부로 묻지 않고 속도로 인쇄와 코드를 자동 검증하고, 무결성 추론을 제대로 잡으면 위조, 우회, 또는 단순한 포장 오류가 약국 선반에 닿기 전에 잡힙니다. 두 종류의 소프트웨어가 그 라인을 공유하며, 둘은 서로 다른 두 방식으로 검증됩니다. 계측기처럼 검증하는 단위별 판독기, 그리고 공정 제어처럼 검증하는 관계적 무결성 엔진. 이 장이 고집하는 규율 — 결정론적 규칙이 핵심 결정을 나르고, ML은 잔차만을, 그것도 조언으로만 채점하는 것 — 은 사과해야 할 한계가 아닙니다. 그것은 정확히 규제자들이 수렴하고 있는 아키텍처이며, 제조사가 단위의 출하 경로에 확률론적 모델을 두지 않고도 여기서 기계학습을 배포할 수 있게 해 주는 것입니다. 충전에서 BATCH-2026-001 의 바이알 위에 시작된 SGTIN은 약사가 환자가 용량을 받기 전에 스캔하는 바로 그 식별자입니다. 그 식별자를 정직하게 유지하는 법을 배우는 것이 공정의 제조 절반의 조용한 피날레입니다.

실제 현장에서는

포장의 비전 절반은 진정으로 (상용) 입니다. 라벨, 인쇄, 코드의 심층학습 검사는 Stevanato, Syntegon, Brevetti CEA, Antares Vision, Cognex, Körber가 판매하고 배포하며, 전체 충전-마감-및-포장 영역에서 가장 강력한 상용 ML 이야기입니다 — 모든 표제 정확도와 거짓-거부 숫자가 벤더 / 자체보고 이고 완전히 검증된 단 하나의 공개 개조가 주사기 라인이었다는 상존하는 단서와 함께 [3][4]. DataMatrix 해독(리드-솔로몬)과 ISO/IEC 15415에 대한 인쇄 등급 매기기는 모든 시리얼화된 라인에서 성숙하고 표준화된 관행이며, ML 단서를 달지 않습니다 — 그것들은 결정론적이고 합격하거나 하지 않거나입니다.

추적-추적성 이상(anomaly) 절반은 더 상용화된 ML이라기보다 파일럿 에 가깝습니다. DSCSA와 EU FMD 시리얼화 그 자체는 완전히 상용이며 — 모든 제조사가 오늘날 EPCIS 이벤트를 발행하고, 집합하고, 보고합니다 — 그러나 결정론적 규칙 계층이 거의 모든 운영 작업을 하고, 이벤트 스트림 위의 학습된 이상 탐지는 시리얼화-플랫폼 벤더들이 더하기 시작하는 응용 (파일럿) 발상이지 정착된, 검증된 능력이 아닙니다. 이 장이 쓰는 비지도-이상 계보(Isolation Forest, random forests)는 동료심사된 바이오 제조 CPV 작업에 등장하는 같은 것 — CSL Behring과 Aizon의 "미래의 CPV(CPV of the Future)" 개념 증명 — 이며, 그 작업이 시리얼화 스트림이 아니라 미생물 모델 시스템 위였음에도 방법 을 닻 내립니다(증거 등급: 자체 저자 동료심사) [6]. 더 넓은 틀은 이 책 전체가 거듭 돌아오는 것입니다. ISPE(International Society for Pharmaceutical Engineering — 제약-공학 전문가 단체)의 Pharma 4.0(제약 제조를 위한 그것의 디지털-성숙도 프레임워크) 현실은, 상용 ML이 자율 품질 결정이 아니라 인간 개입을 동반한 비전 검사와 감시에 군집한다는 것이며, 시리얼화 이상 점수는 FDA의 2023년 의약품 제조에서의 인공지능(Artificial Intelligence in Drug Manufacturing) 논의 문서와 Annex 22 초안 아래에서 명백히 조언적입니다 [5][7]. 그리고 경고적 사례는 한 체제 건너에 앉아 있습니다. 2026년 4월 Purolea cGMP(current GMP — 오늘날 시행 중인 GMP) 경고 서한(warning letter)(점검에서 GMP 위반이 발견될 때 FDA가 발부하는 집행 통지) — AI를 인용한 최초의 것 — 은 품질 부서의 검토 없이 AI 에이전트를 써서 규격과 마스터 생산 기록을 생성하던 회사를 지적했는데, 이는 이 장이 주장하는 규칙-우선, ML-조언 규율의 정확한 반대입니다 [8].

핵심 용어

  • 시리얼화(serialization) — 모든 판매 가능 단위에 전 세계적으로 고유한 시리얼 번호를 할당하고 공급망을 거쳐 추적하는 것; DSCSA(미국)와 FMD(EU)가 의무화함.
  • SGTIN(시리얼화된 GTIN)(SGTIN (Serialized GTIN)) — 단위 식별자: GTIN-14(제품, AI 01) 플러스 시리얼(개별 단위, AI 21), 예: 00361414000017.0000153; 전체 추적-추적성 기록의 조인 키.
  • DataMatrix — 바이알 위에 SGTIN, 로트, 유효기한을 나르는 2D 바코드(ECC 200) 심볼로지; 리드-솔로몬 오류 정정으로 결정론적으로 해독됨.
  • OCR(광학 문자 인식)(OCR (optical character recognition)) — 사람이 읽을 수 있는 로트와 유효기한 텍스트를 읽는 학습된 비전 작업(CTC 디코더를 동반한 CRNN, 또는 비전 트랜스포머); 깨끗한 텍스트를 읽는 것보다 신뢰도가 낮은 판독을 표시하는 것이 더 중요함.
  • 인쇄-품질 등급 매기기(print-quality grading) — 인쇄된 코드를 ISO/IEC 15415 파라미터(대비, 변조, 고정-패턴 손상, 사용되지 않은 오류 정정)에 대해 채점하고 A–F로 등급을 매겨 하류에서도 여전히 해독될지를 예측하는 것.
  • 발행(commissioning) — 시리얼이 실제이고 승인된 단위에 부착되어 존재한다고 선언하는 행위; 거부된 단위에 대해 발행된 시리얼은 유령임.
  • 집합(aggregation) — 부모-자식 포장 관계(바이알 → 묶음 → 케이스 → 팔레트)를 기록하여 팔레트 스캔이 그 아래의 시리얼을 함의하게 하는 것.
  • EPCIS — 공급망 이벤트를 공유하기 위한 GS1 표준; 각 이벤트는 시리얼 집합에 대한 무엇, 언제, 어디서, 왜 를 기록함(발행에는 ObjectEvent, 포장에는 AggregationEvent).
  • DSCSA / FMD — 시리얼화와 검증을 구동하는 미국과 EU의 추적-추적성 규정.
  • Isolation Forest — 한 점을 무작위 분할의 사슬이 얼마나 짧게 격리하는지로 채점하는(짧은 경로 = 이상) 비지도, 라벨 없는 이상 탐지기; 드물고, 대부분 정상이며, 약하게 라벨링된 시리얼화 체제에 잘 맞음.
  • 두-계층 무결성 설계(two-layer integrity design) — 감사 가능한 핵심 결정에는 결정론적 GS1/EPCIS 규칙, 이상하지만-합법적인 케이스의 잔차에만 조언적 ML 이상 점수.
  • 경보 포화(alert saturation) — 양성 플래그 아래에 실제 신호를 묻어 심사자 신뢰를 침식하는 과욕적 이상 탐지기의 실패 모드.
  • SHACL 셰이프(시리얼화)(SHACL shape (serialization))빠진 필수 이벤트를 지금의 실패로 다루는 닫힌-세계 제약(예: 중복 없이 정확히 48개의 발행된 자식을 요구하는 bp:CaseShape)으로, 결정론적 규칙 계층을 Book 4 출하 게이트의 시리얼화 유사물로 만듦.
  • 연속자 대 발생자(BFO)(continuant vs occurrent (BFO)) — 바이알(지속하는 연속자)을 발행 이벤트(일어나는 발생자)와 구별되게 유지하는 상위-온톨로지 절단으로, 이벤트 그래프가 단위를 그것을 등록하는 행위와 결코 혼동하지 않게 함.
  • 충전중량 관리 / Cpk(fill-weight control / Cpk)low_fill 거부를 결정하는 공정 중 중량-점검 관리도; mean_fill_g 로 집계되면 무결성 계층을 한 포장 단계 위 충전 작업에 대한 거친 공정능력 센서로 만듦.

다음 이야기

제품이 만들어지고, 출하되고, 포장되고, 시리얼화되었습니다. BATCH-2026-001 의 모든 바이알은 이제 사슬 어디서나 검증될 수 있는 SGTIN을 나릅니다. 남은 것은 그것을 환자에게 온전히 전달하는 것입니다. 다음 장 유통: 콜드체인 예측과 수요 예보(Distribution: Cold-Chain Prediction and Demand Forecasting)는 공장을 완전히 떠나 공급망 그 자체를 학습합니다 — 배송 구간에서 온도 일탈이 일어나기 전에 예측하고, 경로와 파트너 위험을 채점하며, 애초에 올바른 수의 용량이 만들어지도록 수요를 예보하는 것 — 제조 척추가 마침내 세계와 만나는 곳에서 그것을 닫습니다.

Footnotes

  1. 러닝 예제 전반에서 쓰인 GTIN-14는 예시용이며 등록된 GS1 식별자가 아닙니다. 실제 단위에서는 마지막 자리가 앞의 열세 자리로부터 계산된 mod-10 검사 숫자(check digit)로, 하류 스캐너가 스스로 검증할 수 있는 유일한 필드입니다.