라이넨스는 산업용 세탁공장을 직접 운영하며 생산·품질·운송·설비 데이터로 공장 운영의 표준화와 AI 전환을 추진하고, AX Engineer 는 그 공장에 들어가 공장장과 작업자가 경험으로 하던 판단을 구조화합니다. 아침 반입 물량을 어느 세탁기에 어떤 코스로 넣을지는 세탁기 용량과 코스 제한, 병원과 호텔을 섞지 않는 금지 조합, 배송 회차 마감이 한꺼번에 걸리는 판단이라, 이 조건표를 가진 직영 공장을 운영하지 않는 회사에서는 같은 도구가 성립하지 않습니다. 계산 엔진과 공장별 규칙표를 나눠 둔 구조는 한 공장에서 푼 문제를 다른 공장으로 넓히는 멀티사이트 표준화와 곧바로 이어집니다. 다만 이 포트폴리오가 보여주는 것은 현장의 말로 된 판단을 규칙으로 옮겨 결정론적으로 계산하고 LLM 을 규칙 후보 추출 보조로만 가두는 기술이며, 산업용 세탁 공정이나 설비 보전 도메인 전문성은 주장하지 않고 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
공장장과 작업자가 경험으로 내리던 판단을 데이터와 시스템의 문제로 다시 세우는 일이 이 직무의 출발점입니다. 머릿속 배분 감각을 세탁기 용량·혼합 금지·회차 마감이라는 규칙표로 꺼내 놓은 이 도구가 그 지점에 직접 붙습니다.
현장 문제를 푸는 웹 도구와 자동화 워크플로를 직접 설계하고, LLM 같은 기술을 조합해 빠르게 완결품을 냅니다. 계획 계산은 규칙 엔진이 맡고 LLM 은 공장장 메모를 규칙 후보로 바꾸는 보조만 맡는 이 구성이 그 요구와 맞물립니다.
한 공장에서 푼 문제를 다른 공장에도 적용되게 표준화하고, 공장마다 다른 조건과 공통 구조를 나눠 재사용 가능한 제품으로 키웁니다. 계산 엔진과 공장별 규칙표를 처음부터 분리해 둔 설계가 그 방향을 따릅니다.
그날 아침 공장에 반입된 거래처별 수거 로트 목록과 공장 규칙표(세탁기 용량·세탁 코스·혼합 금지 조합·배송 회차 마감)를 입력으로 받아, 거래처와 품목 표기를 규칙표 별칭으로 맞추고 품목과 오염도로 세탁 코스를 확정한 뒤 같은 코스와 같은 회차의 로트를 세탁기 용량 이하로 묶어 투입 계획표를 만들고, 인쇄해 라인에 붙이는 작업지시표와 미배정 로트 목록을 냅니다. 계량이 빠졌거나 대장에 없는 거래처거나 한 로트가 가장 큰 세탁기 용량을 넘는 경우처럼 규칙으로 하나가 정해지지 않으면 배치를 억지로 만들지 않고 사유를 적어 미배정으로 가려냅니다. 세탁기 배정·코스 확정·용량 검사는 전부 규칙 엔진이 결정하고, LLM 은 공장장이 메모로 남긴 문장을 규칙 후보 카드로 바꾸는 보조만 맡으며 그 카드는 원문 구절을 그대로 달고 나와 사람이 승인해야 규칙표에 들어갑니다.
라이넨스 직영 세탁공장의 생산관리 담당자입니다. 매일 아침 반입 전표를 보며 공장장 옆에서 '가운은 따로 돌려야 한다', '이 호텔 건은 1시 차에 실어야 한다' 같은 말을 받아 적어 화이트보드에 배치를 손으로 짜던 사람으로, 공장장이 자리를 비우면 같은 판단을 아무도 재현하지 못하는 게 늘 불안합니다. 오늘 들어온 물량을 넣으면 세탁기별 투입 계획이 계산돼 나오고, 애매한 물량은 왜 못 넣었는지가 같이 보이길 바랍니다.
반입 로트 목록과 공장 규칙표를 함께 넣으면, (a) 거래처·품목 표기 흔들림을 별칭 사전으로 맞추고 계량이 빠진 로트는 품목 단위중량으로 환산해 물량을 세우고, (b) 품목과 오염도로 세탁 코스를 확정한 뒤 같은 코스·같은 회차 로트를 세탁기 용량 이하로 묶어 투입 계획표를 만들며, (c) 규칙으로 하나가 정해지지 않는 로트는 추측하지 않고 사유를 적어 미배정으로 가려냅니다.
그날 반입 로트 엑셀과 공장 규칙표를 올리면 거래처·품목 표기를 맞추고 세탁 코스를 확정해 세탁기별 배치 계획과 적재율을 화면에 띄우고, 라인에 붙이는 작업지시표와 미배정 로트 목록을 파일로 내려받는 웹 도구입니다. 여기에 공장장 메모 문장을 규칙 후보 카드로 바꿔 사람이 승인하면 규칙표에 반영되는 화면을 포함합니다. 데이터는 반입 전표를 받았다고 가정한 합성 로트와 규칙표로 시작하며, 설비 가동 로그 연동과 세탁물 사진 판독은 3주차 과제로 둡니다.
같은 날 물량을 두고 공장장 역할 검수자 2명이 손으로 짠 배치와 도구가 낸 배치를 맞대어 세탁기 배정 일치율과 제약 위반 건수를 재고, 어긋난 로트를 사유 유형별로 묶어 규칙표를 보강한 결과를 리포트로 냅니다.
규칙표만 갈아끼워 두 번째 공장 프로필로 같은 계획을 돌리고, 세탁기 가동 로그를 실적으로 받아 계획 대비 실제 투입 시각과 적재율의 차이를 회차별로 대조하는 화면을 붙입니다.
반입 로트 60건과 공장 규칙표를 올리면 세탁기 4대 기준 배치 계획과 적재율이 몇 초 안에 화면에 뜨고, 작업지시표와 미배정 목록이 파일로 떨어지는 걸 시연합니다
일부러 만든 지저분한 입력 30종(계량 누락·미등록 거래처·한 칸에 품목 둘·가장 큰 세탁기 용량을 넘는 단일 로트·이미 지난 회차·오염도 미기재)을 넣어도 출력 형식이 한 번도 안 깨지고, 용량 상한과 금지 조합과 회차 마감을 어기는 배치는 한 건도 만들지 않으며 정할 수 없는 로트는 사유를 적어 미배정으로 가려냅니다
더미 로트 120건 중 거래처·품목·세탁 코스 확정이 심은 정답과 모두 일치한 게 104건(약 87%)이고, 만들어진 배치의 제약 위반은 0건이며 평균 적재율은 82%입니다. 단, 로트와 규칙표와 정답을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작임을 명시합니다
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 전부 작성자가 만든 더미 반입 전표와 규칙표 자가채점이며, 실제 배치 정확도는 라이넨스 직영 공장의 실 반입 전표와 실 세탁기 사양, 공장장 검수가 있어야 측정 가능합니다. 이 도구는 그 검증을 규칙표만 갈아끼워 바로 돌릴 수 있는 상태로 만듭니다
이건 실제 공장 데이터 없이 혼자 만든 포트폴리오입니다. 모든 수치는 합성 반입 전표와 규칙표 자가채점이라 성능 증명이 아닙니다. 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명하는 편이 신뢰를 얻습니다
이 포트폴리오가 보여주는 것은 현장의 말로 된 판단을 규칙표로 꺼내 결정론적 계산 엔진으로 옮기고, LLM 을 규칙 후보 추출 보조로만 가둔 설계입니다. 산업용 세탁 공정 자체의 전문성, 세탁기 제어와 설비 보전, 세탁물 오염 판독 같은 깊이는 이 포트폴리오로 증명되지 않으므로 주장하지 않으며, 모르는 부분은 면접에서 모른다고 말하는 편이 낫습니다
정답을 작성자가 만들었으니 잘 맞는 것이 당연합니다. 계량 누락, 미등록 거래처, 한 칸에 적힌 품목 둘, 가장 큰 세탁기 용량을 넘는 단일 로트, 이미 지난 회차, 오염도 미기재 같은 케이스를 더미에 일부러 섞어 깨끗한 전표만 통과시키는 게 아님을 보여줍니다
별칭 매칭은 표기가 조금만 달라도 놓치고 반대로 엉뚱한 거래처를 걸 위험이 있습니다. 후보가 0건이면 미배정으로 돌리고 2건 이상이면 하나를 고르지 않고 후보를 사유에 적어 내보내며, 무엇을 더 등록해야 하는지가 미배정 목록에 그대로 드러나게 둡니다
배치 묶기는 용량을 채우는 방향으로 계산하지만 공장장은 세탁기 고장 이력이나 그날 인력 배치처럼 전표에 없는 사정을 함께 봅니다. 계획을 확정으로 밀지 않고 화면에서 손으로 옮길 수 있게 두며, 실제 도입 때는 설비 가동 로그와 실 검수자 판단을 붙이는 것을 도입 단계 과제로 분리합니다
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
그날 아침 공장에 반입된 거래처별 수거 로트를 전표에서 읽은 원시 데이터입니다. 계획 엔진이 가장 먼저 다루는 입력이라 계량 누락, 거래처 표기 흔들림, 한 칸에 적힌 품목 둘, 지난 회차 표기를 일부러 섞고 gold_ 필드로 정답을 심어 자가채점합니다.
| lot_no | received_at | client_raw | item_raw | soil_raw | weight_kg | piece_count | due_run_raw | memo | gold_client_id | gold_item_code | gold_program | gold_weight_kg | gold_status | gold_reason |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 101 | 2026-08-05T06:40 | 그랜드호텔 | 시트 | 보통 | 38.5 | 96 | 2회차 | — | CL-GRH | ITM-SHT | P-WHT | 38.5 | planned | — |
| 102 | 2026-08-05T06:42 | 그랜드 호텔 서울 | 타월 | 보통 | 22 | 140 | 2회차 | — | CL-GRH | ITM-TWL | P-WHT | 22 | planned | — |
| 103 | 2026-08-05T06:55 | 중앙병원 | 환자 가운 | — | 31 | 88 | 3회차 | 3층 병동분입니다 | CL-JAH | ITM-GWN | P-INF | 31 | planned | — |
| 104 | 2026-08-05T07:02 | 중앙병원 | 침대 시트 | — | 26.4 | 70 | 3회차 | — | CL-JAH | ITM-SHT | — | 26.4 | needs_check | 오염도 칸이 비어 있어 일반 코스와 감염성 코스 중 하나를 정하지 못… |
| 105 | 2026-08-05T07:10 | GH-SEOUL | 베개커버 | 낮음 | — | 210 | 2회차 | 계량기 점검 중이라 장수만 셌습니다 | CL-GRH | ITM-PWC | P-WHT | 25.2 | planned | — |
아래 JSON Schema 에 맞는 세탁공장 반입 로트 120건을 JSON 배열로 생성합니다. 거래처는 호텔 2~3곳, 병원 1~2곳, 공장 1곳으로 두고 품목은 시트·타월·베개커버·환자 가운·수술포·작업복을 섞습니다.
{"type":"object","properties":{"lot_no":{"type":"integer"},"received_at":{"type":"string"},"client_raw":{"type":["string","null"]},"item_raw":{"type":["string","null"]},"soil_raw":{"type":["string","null"]},"weight_kg":{"type":["number","null"]},"piece_count":{"type":["integer","null"]},"due_run_raw":{"type":["string","null"]},"memo":{"type":["string","null"]},"gold_client_id":{"type":["string","null"]},"gold_item_code":{"type":["string","null"]},"gold_program":{"type":["string","null"]},"gold_weight_kg":{"type":["number","null"]},"gold_status":{"enum":["planned","needs_check"]},"gold_reason":{"type":["string","null"]}},"required":["lot_no","received_at","client_raw","item_raw","due_run_raw","gold_status"]}
gold 규칙(위에서부터 먼저 맞는 것을 적용): (1) client_raw 가 plant_rules 의 client 항목 aliases 에 정확히 하나 걸리면 그 code, 0건이거나 2건 이상이면 gold_client_id=null 이고 gold_status=needs_check. (2) item_raw 도 같은 방식으로 매칭하되 후보가 0건이거나 2건 이상이면 gold_item_code=null·gold_program=null 이고 needs_check. (3) gold_weight_kg 는 weight_kg 이 있으면 그 값, 없으면 piece_count × 품목 단위중량을 소수 첫째 자리까지 계산하고, 둘 다 null 이면 gold_weight_kg=null 이고 needs_check. (4) 중량과 장수가 모두 0 이면 needs_check. (5) gold_program 은 품목이 ITM-GWN·ITM-SRG 면 오염도와 무관하게 P-INF, 품목이 ITM-UNF 면 P-OIL, 그 밖의 품목은 soil_raw 가 '높음' 이면 P-STN, '낮음'·'보통' 이면 P-WHT, soil_raw 가 null 이면 코스를 정하지 못해 null 이고 needs_check. (6) due_run_raw 가 규칙표의 run 항목에 없거나 그 회차 출발 시각이 received_at 보다 앞서면 needs_check. (7) gold_weight_kg 가 가장 큰 세탁기 용량을 넘으면 needs_check. (8) 미확정 사유가 하나도 없으면 gold_status=planned 이고 gold_reason=null, 있으면 그 사유를 한 문장으로 gold_reason 에 적습니다.
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(깨끗한 전표만 통과시키는 함정 회피): (1) 같은 거래처의 표기 별칭('그랜드호텔'·'그랜드 호텔 서울'·'GH-SEOUL')이 고르게 섞인 로트 12건 이상, (2) weight_kg 이 null 이고 piece_count 만 있는 로트 10건과 둘 다 null 인 로트 3건, (3) 별칭 사전에 없는 신규 거래처 3건과 사전에 없는 품목 3건, (4) 한 칸에 품목 두 개가 적힌 로트 2건, (5) 오염도 칸이 빈 로트 8건(그중 절반은 가운·수술포라 코스가 확정되고 절반은 needs_check), (6) 가장 큰 세탁기 용량을 넘는 단일 로트 2건과 중량·장수가 0 인 휴무 로트 2건, (7) 이미 지난 회차를 적어 온 로트 3건. gold_ 필드는 위 규칙대로 정직하게 채웁니다. JSON 배열만.{"type":"object","properties":{"lot_no":{"type":"integer"},"received_at":{"type":"string"},"client_raw":{"type":["string","null"]},"item_raw":{"type":["string","null"]},"soil_raw":{"type":["string","null"]},"weight_kg":{"type":["number","null"]},"piece_count":{"type":["integer","null"]},"due_run_raw":{"type":["string","null"]},"memo":{"type":["string","null"]},"gold_client_id":{"type":["string","null"]},"gold_item_code":{"type":["string","null"]},"gold_program":{"type":["string","null"]},"gold_weight_kg":{"type":["number","null"]},"gold_status":{"enum":["planned","needs_check"]},"gold_reason":{"type":["string","null"]}},"required":["lot_no","received_at","client_raw","item_raw","due_run_raw","gold_status"]}공장장이 머릿속과 메모로 지켜 온 배분 규칙을 한 표로 꺼내 놓은 공장 규칙표입니다. 거래처·품목 별칭, 세탁기 사양, 세탁 코스 조건, 같은 배치에 넣으면 안 되는 조합, 배송 회차 출발 시각을 담아 계획 결과를 규칙으로 확정하는 유일한 근거가 됩니다. 새 표준을 제정하지 않고 공장이 이미 쓰는 표기와 회차를 그대로 받습니다.
| entry_kind | code | label | aliases | capacity_kg | unit_weight_kg | applies_to | banned_with | depart_at | source_memo | approved_by |
|---|---|---|---|---|---|---|---|---|---|---|
| client | CL-GRH | 그랜드호텔 서울 | ["그랜드호텔","그랜드 호텔 서울","GH-SEOUL","그랜드"] | — | — | — | — | — | — | 공장장 |
| client | CL-JAH | 중앙병원 | ["중앙병원","중앙 병원","JAH"] | — | — | — | — | — | — | 공장장 |
| client | CL-HBH | 한빛호텔 | ["한빛호텔","한빛"] | — | — | — | — | — | 별칭이 아직 두 개뿐이라 전표에 다르게 적혀 오면 놓칩니다 | 공장장 |
| client | CL-WSG | 우성기공 | ["우성기공","우성 기공","WSG"] | — | — | — | — | — | — | 공장장 |
| item | ITM-SHT | 시트 | ["시트","침대 시트","베드시트"] | — | 0.4 | — | — | — | — | 생산관리 |
아래 JSON Schema 에 맞는 세탁공장 규칙표 항목 40개를 JSON 배열로 생성합니다. 거래처(client)·품목(item)·세탁기(machine)·세탁 코스(program)·혼합 금지(mix_ban)·배송 회차(run) 항목을 고르게 섞습니다.
{"type":"object","properties":{"entry_kind":{"enum":["client","item","machine","program","mix_ban","run"]},"code":{"type":"string"},"label":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"capacity_kg":{"type":["number","null"]},"unit_weight_kg":{"type":["number","null"]},"applies_to":{"type":["array","null"],"items":{"type":"string"}},"banned_with":{"type":["array","null"],"items":{"type":"string"}},"depart_at":{"type":["string","null"]},"source_memo":{"type":["string","null"]},"approved_by":{"type":["string","null"]}},"required":["entry_kind","code","label","aliases"]}
코드 규칙: 거래처는 CL- 접두, 품목은 ITM- 접두, 세탁기는 용량과 일련 기호를 붙인 W-80A 형식, 코스는 P- 접두, 혼합 금지는 MB- 접두, 회차는 R 과 번호를 씁니다. capacity_kg 는 machine 에만, unit_weight_kg 는 item 에만, depart_at 은 run 에만 채우고 나머지는 null 로 둡니다. aliases 에는 전표에 실제로 적혀 오는 한글 표기와 영문 약칭을 함께 넣어 intake_lots 의 client_raw·item_raw 가 여기서 매칭되게 맞춥니다.
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(규칙표가 완전하다는 착각 회피): (1) 별칭이 하나뿐이라 전표 표기를 못 잡는 거래처 2건과 품목 2건, (2) 한 품목의 별칭이 다른 품목 별칭의 부분 문자열인 쌍('가운'과 '환자 가운') 1쌍, (3) 코스가 같아도 함께 돌리면 안 되는 조합 3건을 source_memo 에 공장장 말투 그대로 적기, (4) 특정 코스만 받는 전용 세탁기 2대와 여러 코스를 받는 범용 세탁기 2대, (5) 회차 출발 시각이 두 시간밖에 안 벌어져 물량이 몰리는 회차 1건, (6) approved_by 가 null 이라 아직 승인되지 않은 규칙 후보 3건. JSON 배열만.{"type":"object","properties":{"entry_kind":{"enum":["client","item","machine","program","mix_ban","run"]},"code":{"type":"string"},"label":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"capacity_kg":{"type":["number","null"]},"unit_weight_kg":{"type":["number","null"]},"applies_to":{"type":["array","null"],"items":{"type":"string"}},"banned_with":{"type":["array","null"],"items":{"type":"string"}},"depart_at":{"type":["string","null"]},"source_memo":{"type":["string","null"]},"approved_by":{"type":["string","null"]}},"required":["entry_kind","code","label","aliases"]}| Python | 로트 정규화, 세탁 코스 확정과 용량·혼합 금지 검사, 배치 묶기 계산과 작업지시표 생성을 맡는 대표 언어입니다 |
| TypeScript | 반입 물량 업로드, 배치 계획표와 미배정 목록, 규칙 후보 승인 화면을 만드는 웹 도구의 언어입니다 |
| SQL | 로트·규칙표·배치 결과를 저장하고 회차별 적재율과 미배정 사유 분포를 집계하는 질의 계층입니다 |
| API | 계획 계산을 웹 화면과 분리해 호출하는 경계이자, 공장 운영 시스템이 반입 물량을 밀어 넣을 수 있게 열어 두는 입력구입니다 |
| 데이터베이스 | 공장별 규칙표를 버전으로 남겨 어느 날 어떤 규칙으로 계획이 나왔는지 되짚을 수 있게 하는 저장 계층입니다 |
| 클라우드 | 공장 사무실 PC 와 현장 태블릿에서 같은 화면을 열 수 있게 웹 도구를 올려 두는 실행 환경입니다 |
| LLM | 공장장이 남긴 메모 문장을 규칙 후보 카드로 바꾸는 보조 모델입니다(규칙 확정은 사람 승인과 규칙 엔진이 합니다) |
| RAG | 규칙표가 수백 항목으로 늘면 전부 프롬프트에 넣을 수 없어, 메모 문장과 가까운 기존 규칙 항목만 찾아 넣어 중복 규칙을 걸러내는 검색 계층입니다 |
| Workflow Automation | 반입 전표 업로드부터 계획 계산, 작업지시표 배포까지를 아침 한 번의 실행으로 잇는 자동화 흐름입니다 |
| MES | 공장 실행 시스템이 남기는 세탁기 가동 시작·종료 기록을 계획 대비 실적 대조의 입력으로 받는 연동 지점입니다(3주차) |
| IoT | 세탁기·건조기의 가동 로그를 회차별 실적으로 끌어와 계획한 투입 시각과 벌어진 차이를 보여 주는 설비 데이터원입니다(3주차) |
| 컴퓨터 비전 | 반입 전표를 사진으로만 받는 날을 대비해 촬영본에서 표를 읽어 같은 로트 스키마로 옮기는 문서 판독 어댑터입니다(3주차 확장 수단) |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우려면 2주차(공장장 판단과 맞았는지 확인)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(두 번째 공장 프로필과 설비 실적 대조)로 진행합니다.
투입 계획표의 한 행입니다. 같은 코스와 같은 회차의 로트를 세탁기 용량 이하로 묶은 배치 하나를 담고, 어떤 규칙을 적용해 그렇게 묶였는지 근거를 함께 답니다. 규칙으로 배치가 정해지지 않은 로트는 machine_code 를 비운 채 사유를 달아 미배정 목록으로 나갑니다.
{"type":"object","properties":{"batch_no":{"type":["integer","null"]},"machine_code":{"type":["string","null"]},"program_code":{"type":["string","null"]},"lot_nos":{"type":"array","items":{"type":"integer"}},"total_weight_kg":{"type":["number","null"]},"fill_rate":{"type":["number","null"]},"depart_run":{"type":["string","null"]},"status":{"enum":["planned","needs_check"]},"reason":{"type":["string","null"]},"evidence":{"type":"array","items":{"type":"object","properties":{"rule_code":{"type":"string"},"quote":{"type":"string"}},"required":["rule_code","quote"]}},"hedge":{"type":["string","null"]}},"required":["lot_nos","machine_code","program_code","status","evidence"]}[
{
"input_ref": "lot 101·102·105 (그랜드호텔 백색 린넨, 2회차)",
"output": {
"batch_no": 1,
"machine_code": "W-50B",
"program_code": "P-WHT",
"lot_nos": [
101,
102,
105
],
"total_weight_kg": 85.7,
"fill_rate": null,
"depart_run": "R2",
"status": "needs_check",
"reason": "묶은 중량 85.7kg 이 W-50B 용량 50kg 을 넘어 한 배치로 만들지 못했습니다. 회차를 나누거나 대형기 배정을 사람이 정해야 합니다",
"evidence": [
{
"rule_code": "W-50B",
"quote": "50kg 중형 워셔"
},
{
"rule_code": "P-WHT",
"quote": "백색 표준 코스"
}
],
"hedge": "합성 로트 기준이라 실제 반입량 분포에서는 나뉘는 지점이 달라집니다"
}
},
{
"input_ref": "lot 101·102 (그랜드호텔 백색 린넨, 2회차)",
"output": {
"batch_no": 2,
"machine_code": "W-50B",
"program_code": "P-WHT",
"lot_nos": [
101,
102
],
"total_weight_kg": 60.5,
"fill_rate": null,
"depart_run": "R2",
"status": "needs_check",
"reason": "묶은 중량 60.5kg 이 W-50B 용량 50kg 을 넘어 시트 로트를 대형기로 옮겨야 합니다",
"evidence": [
{
"rule_code": "W-50B",
"quote": "50kg 중형 워셔"
}
],
"hedge": null
}
},
{
"input_ref": "lot 102·105 (그랜드호텔 타월·베개커버, 2회차)",
"output": {
"batch_no": 3,
"machine_code": "W-50B",
"program_code": "P-WHT",
"lot_nos": [
102,
105
],
"total_weight_kg": 47.2,
"fill_rate": 0.94,
"depart_run": "R2",
"status": "planned",
"reason": null,
"evidence": [
{
"rule_code": "P-WHT",
"quote": "백색 표준 코스"
},
{
"rule_code": "R2",
"quote": "2회차 배송"
},
{
"rule_code": "ITM-PWC",
"quote": "베개커버"
}
],
"hedge": "lot 105 중량은 장수 210 에 베개커버 단위중량 0.12kg 을 곱해 세운 합성 기준 환산값입니다"
}
},
{
"input_ref": "lot 103·115 (중앙병원 가운, 3회차)",
"output": {
"batch_no": 4,
"machine_code": "W-50C",
"program_code": "P-INF",
"lot_nos": [
103,
115
],
"total_weight_kg": 55.8,
"fill_rate": null,
"depart_run": "R3",
"status": "needs_check",
"reason": "감염성 전용기 W-50C 용량 50kg 을 5.8kg 넘겨 두 번 돌릴지 순서를 사람이 정해야 합니다",
"evidence": [
{
"rule_code": "P-INF",
"quote": "병원 가운과 수술포는 오염도가 어떻게 적혀 있든 이 코스입니다"
},
{
"rule_code": "W-50C",
"quote": "병원 물량은 이 기계에서만 돌립니다"
},
{
"rule_code": "MB-01",
"quote": "병원 건은 코스가 같아도 호텔 시트랑 절대 같이 돌리지 마세요"
}
],
"hedge": null
}
},
{
"input_ref": "lot 106 (별칭 사전에 없는 신규 거래처)",
"output": {
"batch_no": null,
"machine_code": null,
"program_code": "P-INF",
"lot_nos": [
106
],
"total_weight_kg": 18,
"fill_rate": null,
"depart_run": "R3",
"status": "needs_check",
"reason": "거래처 별칭 사전에 '행복요양원' 이 없어 혼합 금지 조합을 판단하지 못했습니다",
"evidence": [
{
"rule_code": "P-INF",
"quote": "감염성 고온 코스"
}
],
"hedge": "요양원 물량이 병원과 같은 취급인지는 공장장 확인이 필요합니다"
}
}
][자동 검증] 1. 출력 형식(필드와 enum)이 JSON Schema 를 통과하는지 확인합니다. 2. status 가 planned 인 배치의 total_weight_kg 이 machine_code 의 capacity_kg 이하인지 재계산해 대조하고, 넘으면 계획으로 내보내지 못하게 막습니다. 3. 한 배치의 로트들이 mix_ban 항목의 금지 조합에 걸리지 않는지, 같은 program_code 와 같은 depart_run 인지 검사합니다. 4. machine_code 의 applies_to 에 그 program_code 가 들어 있는지 확인합니다. 5. evidence 의 rule_code 가 규칙표에 실제로 있는 코드인지, quote 가 그 항목의 label 이나 source_memo 의 substring 인지 대조합니다. 6. status 가 needs_check 인 행은 reason 이 비어 있지 않은지 강제하고, gold_ 필드와 견줘 거래처·품목·코스 확정 일치율을 계산합니다. [수동 검증] 1. 공장장 역할 검수자 2명이 같은 날 물량을 각자 손으로 배치해 세탁기 배정 일치율과 bootstrap Cohen's κ(두 사람 판단이 우연 이상으로 겹치는 정도, 0~1) 하한 0.6 이상을 봅니다. 2. 계획 배치의 5% 를 사람이 직접 훑어 현장에서 실제로 돌릴 수 있는 묶음인지 확인합니다.