인포시즈
경력근거: 고객사 경영진·실무진과 직접 소통하며, 비즈니스와 기술 사이의 인터페이스 역할을 합니다
인포시즈 FDE 는 고객의 문제와 가장 가까운 곳에서 운영 구조를 이해하고 데이터를 해석해 기술이 실제 현장에서 작동하도록 잇는 역할이고, 공고는 '고객의 업무 흐름과 데이터 구조를 빠르게 이해하고 모델링합니다'와 '단순 기능 구현이 아니라, 고객의 운영 방식과 의사결정 구조 자체를 개선합니다'를 주요 업무로 적어 두었습니다. 이 도구는 고객사 담당자가 숫자 하나를 확인하려고 파견 나온 엔지니어를 기다리던 흐름을 담당자가 직접 묻고 근거를 확인하는 흐름으로 바꿉니다. 공고가 우대하는 '실제 사용자에게 쓰이는 Agent 또는 AI 제품을 만들어본 경험'이 여기서 정확히 같은 지점을 가리키고, 자유 질의 생성 대신 승인된 템플릿에 조건 값만 채우게 좁힌 설계는 '데모가 아니라 실제 현장에서 작동하는 AI 제품'을 만들려면 무엇을 포기해야 하는지에 대한 판단으로 그대로 설명됩니다. 다만 이 포트폴리오가 보여주는 것은 자연어를 승인된 질의로 옮기는 변환 설계와 실행 가드와 근거 출력 기술이며, 인포시즈 고객사가 속한 산업의 물류 운영 실무 지식이나 위탁 계약·정산 구조 같은 도메인 전문성은 주장하지 않습니다. 그 깊이는 면접에서 모르면 모른다고 말하는 편이 낫습니다.
고객의 업무 흐름과 데이터 구조를 빠르게 이해해 모델링하는 일이 이 역할의 출발점입니다. 고객사 추출본을 질의가 먹을 수 있는 형태로 올리고 담당자가 실제로 묻는 질문을 템플릿으로 뽑아내는 작업이 직접 정렬됩니다.
'LLM 기반 Agent·AI 솔루션을 실제 운영 환경에 적용하고, 프로덕션 수준의 안정성으로 정착시킵니다'. 데모가 아니라 현장에서 도는 도구가 목표입니다.
'고객사 경영진·실무진과 직접 소통하며, 비즈니스와 기술 사이의 인터페이스 역할을 합니다'. 담당자가 쓰던 말을 그대로 받는 자리입니다.
고객사에서 받은 추출본 두 벌(출고·배송 기록과 위탁사 마스터)을 질의 대상으로 올리고, 고객사 담당자가 한국어 한 문장으로 물으면 그 문장을 FDE 가 미리 써 둔 질의 템플릿 번호와 조건 값으로 바꿔 실행하는 CLI입니다. LLM 이 하는 일은 문장을 템플릿 번호와 조건 값으로 옮기는 변환 하나뿐이고, 실행되는 질의문은 사람이 손으로 쓴 템플릿에서만 나옵니다. LLM 이 템플릿 목록 밖을 가리키거나 조건 값이 형식 검사를 통과하지 못하면 질의를 실행하지 않고 되물을 문장을 냅니다. 답과 실행한 질의문과 근거가 된 행 번호를 항상 같이 내보내, 담당자가 숫자만 믿지 않고 어디서 나온 값인지 확인합니다. 조회 계열 질의만 화이트리스트로 허용해 값을 고치는 요청은 형식 검사 단계에서 막습니다. 질의 템플릿 목록은 그날 받은 추출본을 보고 한 사람이 쓰는 파일이라, 고객사와 합의해야 나오는 표준 체계나 용어 사전을 전제하지 않습니다. 화면은 만들지 않습니다. 터미널에서 질문 한 줄로 시작해 터미널 출력으로 끝납니다.
인포시즈가 들어간 고객사 물류센터의 운영 담당자입니다. 출고 지연 건수와 위탁사별 사고 비율을 매일 확인해야 하는데 창고 관리 시스템 화면의 고정 조회 조건으로는 원하는 기간과 조합이 나오지 않아, 그때마다 파견 나온 엔지니어에게 부탁하고 반나절을 기다리던 사람입니다. 쓰던 말 그대로 물어 그 자리에서 숫자와 근거 행을 받고 싶어 합니다.
질문을 자유 질의로 짜게 두지 않고 승인된 템플릿 번호와 조건 값으로만 옮기면, (a) 담당자가 쓰던 말 그대로 물어도 실행되는 질의는 사람이 검토한 것 하나이며, (b) 답에 붙은 질의문과 근거 행으로 숫자의 출처를 그 자리에서 확인하고, (c) 템플릿 밖 질문과 값을 고치려는 요청은 실행 전에 걸러 답을 지어내지 않습니다.
고객사 추출본을 가정한 합성 파일 두 벌과 질의 템플릿 목록을 넣으면, 질문 한 줄에 답과 실행한 질의문과 근거 행이 터미널로 돌아오는 CLI입니다. 만드는 덩어리는 문장을 템플릿 번호와 조건 값으로 옮기는 변환기와 화이트리스트 질의 실행·출력기 둘이고, 템플릿 밖 질문과 값을 고치려는 요청은 실행 전에 되묻기와 거절로 갈립니다. 평일 5일에 혼자 끝나는 범위이며 그 자체로 제출 가능한 완결품입니다.
실무자가 실제로 물을 법한 질문 120건에 심어 둔 정답 템플릿과 조건 값을 대조해 템플릿 선택 정확도와 조건 값 정확도를 내고, 되묻기로 보내야 할 질문을 실행해 버린 사례와 실행해도 될 질문을 되물은 사례를 유형별로 정리한 상태입니다.
코드 수정 없이 질의 템플릿 목록과 표기 정규화 표 교체만으로 다른 고객사 추출본에 질문이 도는 걸 보이고, Docker 이미지 하나와 템플릿 변경 시 심은 질문 세트를 다시 채점하는 회귀 검사를 붙인 재사용 패키지입니다.
고객사 추출본을 가정한 합성 파일 두 벌을 올려 두고 질문 한 줄을 치면, 답과 실행한 질의문과 근거 행이 몇 초 안에 터미널로 돌아오는 걸 시연합니다
일부러 만든 악성·모호 질문 30종(기간이 없는 질문, 마스터에 없는 위탁사, 한 번에 둘을 묻는 질문, 값을 고쳐 달라는 요청, 템플릿에 없는 원인 분석 요청)을 넣어도 도구가 중간에 죽지 않고 실행·되묻기·거절 중 하나로 반드시 갈리며, 거절과 되묻기에는 사유가 붙습니다
2주차 자가채점에서 심은 질문 120건 중 템플릿을 맞게 고른 게 111건(약 93%)이고 조건 값까지 정확히 맞은 게 104건(약 87%)입니다. 단, 질문과 정답을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작임을 명시합니다
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 전부 작성자가 만든 더미데이터 자가채점이며, 실제 변환 정확도는 인포시즈 고객사 담당자가 실제로 던지는 질문과 실 추출본이 있어야 측정 가능합니다. 이 도구는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다
수치는 합성 데이터 자가채점이라 성능 증명이 아닙니다. 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다
질문과 정답을 작성자가 만들었으니 잘 맞는 것이 당연합니다. 기간이 빠진 질문, 표기가 흔들리는 센터명, 마스터에 없는 위탁사 코드, 한 번에 두 가지를 묻는 질문을 질문 세트에 일부러 섞어, 반듯한 질문만 통과시키는 게 아님을 보여줍니다
LLM 이 질의문을 직접 쓰면 숫자를 그럴듯하게 지어냅니다. 실행되는 질의문은 사람이 쓴 템플릿에서만 나오게 하고, LLM 은 템플릿 번호와 조건 값만 채우며, 목록 밖 번호나 형식이 어긋난 값은 실행 전에 되묻기로 돌립니다. 조회 계열 밖의 구문은 실행 직전 검사에서 막습니다
이 포트폴리오가 보여주는 것은 자연어를 승인된 질의로 옮기는 변환 설계와 실행 가드와 근거 출력 기술입니다. 인포시즈 고객사가 속한 산업의 물류 운영 실무 지식이나 위탁 계약·정산 구조 같은 도메인 전문성은 주장하지 않으며, 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다
템플릿 목록에 없는 질문은 이 도구가 답하지 못합니다. 그걸 감추지 않고 어느 템플릿에도 닿지 않았다는 사유를 붙여 알리며, 자주 거절된 질문을 모아 다음 템플릿 후보로 남깁니다. 담당자가 원하는 질문의 범위를 넓히는 일은 이 도구가 줄여 주는 대상이지 없애 주는 대상이 아닙니다
실제 고객사 추출본은 열 이름과 표기 규칙이 더미와 다릅니다. 고객사별 템플릿 목록과 표기 정규화 표를 새로 쓰는 일은 도입 단계 과제로 분리해 잡고, 그 작업량을 템플릿 개수와 표기 변형 수로 미리 견적 냅니다
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
고객사 창고 관리 시스템에서 내려받은 출고·배송 기록 추출본을 흉내 낸 행입니다. 질의 템플릿 대부분이 가장 먼저 읽는 표이며, 센터명 표기 흔들림·마스터에 없는 위탁사 코드·출고일 결측·수량 결측·날짜 역전·추출 기간 밖 행을 일부러 섞었습니다.
| ship_id | center_raw | carrier_code | order_date | ship_date | arrive_date | qty | status | delay_reason | damaged |
|---|---|---|---|---|---|---|---|---|---|
| sh_001 | 부산센터 | HK01 | 2026-03-02 | 2026-03-02 | 2026-03-04 | 120 | 출고완료 | — | false |
| sh_002 | 부산센터 | HK01 | 2026-03-02 | 2026-03-04 | 2026-03-06 | 80 | 출고지연 | 차량 배차 지연 | false |
| sh_003 | 부산 센터 | DY02 | 2026-03-03 | 2026-03-05 | 2026-03-08 | 200 | 출고지연 | 재고 부족 | false |
| sh_004 | BUSAN | DY02 | 2026-03-04 | 2026-03-04 | 2026-03-07 | 60 | 출고완료 | — | true |
| sh_005 | 광주센터 | NR03 | 2026-03-05 | — | — | 150 | 출고지연 | 출고 지시 누락 | false |
아래 JSON Schema 에 맞는 고객사 출고·배송 기록 80행을 JSON 배열로 생성합니다. 센터는 부산센터·광주센터·대전센터 세 곳, 위탁사 코드는 HK01·DY02·NR03·SB04·GM05 위주, order_date 는 2026-03-01 부터 2026-03-31 사이로 만들고, status 는 출고완료를 다수로 두되 출고지연·반품·취소를 섞습니다. delay_reason 은 status 가 출고지연·반품·취소일 때만 채우고 나머지는 null 로 둡니다.
{"type":"object","properties":{"ship_id":{"type":"string"},"center_raw":{"type":"string"},"carrier_code":{"type":"string"},"order_date":{"type":"string"},"ship_date":{"type":["string","null"]},"arrive_date":{"type":["string","null"]},"qty":{"type":["integer","null"]},"status":{"type":"string","enum":["출고완료","출고지연","반품","취소"]},"delay_reason":{"type":["string","null"]},"damaged":{"type":"boolean"}},"required":["ship_id","center_raw","carrier_code","order_date","status","damaged"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어 주세요(반듯한 행만 통과시키는 함정 회피): (1) 같은 센터의 표기 흔들림('부산센터'/'부산 센터'/'BUSAN' 처럼 정규화 표로 묶여야 하는 표기) 6건 이상, (2) 위탁사 마스터에 없는 코드를 쓴 행 3건, (3) ship_date 가 null 인 출고지연·취소 행 5건 이상, (4) qty 가 null 인 행 2건, (5) arrive_date 가 ship_date 보다 앞서는 날짜 역전 2건, (6) order_date 가 추출 기간(2026-03-01~2026-03-31) 밖인 행 3건, (7) damaged 가 true 인 행 6건 안팎. JSON 배열만 출력합니다.{"type":"object","properties":{"ship_id":{"type":"string"},"center_raw":{"type":"string"},"carrier_code":{"type":"string"},"order_date":{"type":"string"},"ship_date":{"type":["string","null"]},"arrive_date":{"type":["string","null"]},"qty":{"type":["integer","null"]},"status":{"type":"string","enum":["출고완료","출고지연","반품","취소"]},"delay_reason":{"type":["string","null"]},"damaged":{"type":"boolean"}},"required":["ship_id","center_raw","carrier_code","order_date","status","damaged"]}고객사에서 함께 받은 배송 위탁사 마스터 추출본입니다. 질문에 나온 위탁사 이름을 코드로 옮기고 약속 기한 초과를 판정할 때 참조하며, 같은 회사가 코드 둘을 갖는 경우와 약속 기한이 비어 있어 판정할 수 없는 경우와 계약이 끝난 코드를 함께 담았습니다.
| carrier_code | carrier_name | contract_type | sla_days | active |
|---|---|---|---|---|
| HK01 | 한결택배 | 일반계약 | 2 | true |
| HK09 | 한결택배 | 일반계약 | 2 | false |
| DY02 | 대영로지스 | 권역계약 | 3 | true |
| DY12 | 대영로지스 | 일반계약 | 3 | true |
| NR03 | 누리운송 | — | — | true |
아래 JSON Schema 에 맞는 배송 위탁사 마스터 18행을 JSON 배열로 생성합니다. carrier_code 는 영문 두 글자와 숫자 두 자리 형식이고, carrier_name 은 실제 회사가 아닌 가상의 물류사 이름으로 만들며, contract_type 은 일반계약·권역계약·스팟계약 중 하나이거나 null, sla_days 는 1 에서 5 사이의 정수이거나 null 입니다.
{"type":"object","properties":{"carrier_code":{"type":"string"},"carrier_name":{"type":"string"},"contract_type":{"type":["string","null"]},"sla_days":{"type":["integer","null"]},"active":{"type":"boolean"}},"required":["carrier_code","carrier_name","active"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어 주세요: (1) 같은 carrier_name 에 코드가 둘 이상 붙은 회사 3곳(이름으로 물으면 코드를 모두 묶어야 함), (2) sla_days 가 null 이라 약속 기한 초과를 판정할 수 없는 위탁사 3건, (3) active 가 false 인 계약 종료 코드 3건, (4) contract_type 이 null 인 행 2건, (5) 출고 기록에는 한 번도 등장하지 않는 위탁사 3건. JSON 배열만 출력합니다.{"type":"object","properties":{"carrier_code":{"type":"string"},"carrier_name":{"type":"string"},"contract_type":{"type":["string","null"]},"sla_days":{"type":["integer","null"]},"active":{"type":"boolean"}},"required":["carrier_code","carrier_name","active"]}고객사 담당자가 실제로 물을 법한 한국어 질문과 심은 정답입니다. 정답은 템플릿 번호와 조건 값과 처리 구분(실행·되묻기·거절)으로 이뤄져 규칙으로 채점되며, 2주차 변환 정확도 자가채점과 3주차 회귀 검사가 이 표를 씁니다. 기준일은 2026-03-16 으로 고정합니다.
| q_id | question_ko | gt_action | gt_template_id | gt_params | note |
|---|---|---|---|---|---|
| q_001 | 이번 달 들어 부산센터에서 하루 넘게 늦게 나간 건이 몇 건이야? | run | t_delay_count | {"period_from":"2026-03-01","period_to":"2026-03-15","center":"부산센터","min_delay_days":1} | 부산 센터·BUSAN 표기까지 정규화 표로 묶어야 합니다 |
| q_002 | 3월 위탁사별 출고 지연율 알려줘 | run | t_delay_rate_by_carrier | {"period_from":"2026-03-01","period_to":"2026-03-31"} | — |
| q_003 | 광주센터 반품 건수 알려줘 | clarify | t_return_count | {"center":"광주센터"} | 기간이 빠져 있어 실행하지 않고 기간을 되물어야 합니다 |
| q_004 | 대영로지스 파손 신고 비율이 얼마야? 이번 달 기준으로 | run | t_damage_rate | {"period_from":"2026-03-01","period_to":"2026-03-15","carrier_name":"대영로지스"} | 대영로지스는 코드가 DY02·DY12 둘이라 함께 묶어야 합니다 |
| q_005 | 3월 한결택배 약속 기한 넘긴 건 목록 뽑아줘 | run | t_sla_breach | {"period_from":"2026-03-01","period_to":"2026-03-31","carrier_name":"한결택배"} | 계약이 끝난 HK09 코드도 기간 안 기록이 있으면 포함합니다 |
아래 JSON Schema 에 맞는 고객사 담당자 질문 120건을 JSON 배열로 생성합니다. 기준일은 2026-03-16 이고, 템플릿 목록은 t_delay_count(기간·센터·지연 기준 일수), t_delay_rate_by_carrier(기간), t_return_count(기간·센터), t_damage_rate(기간·위탁사), t_sla_breach(기간·위탁사), t_center_volume(기간·센터 선택) 여섯 개입니다. question_ko 는 실무자가 말하듯 짧고 구어체로 쓰고, gt_params 는 그 템플릿이 요구하는 조건 값만 담습니다.
{"type":"object","properties":{"q_id":{"type":"string"},"question_ko":{"type":"string"},"gt_action":{"type":"string","enum":["run","clarify","refuse"]},"gt_template_id":{"type":["string","null"]},"gt_params":{"type":"object"},"note":{"type":["string","null"]}},"required":["q_id","question_ko","gt_action","gt_params"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어 주세요(반듯한 질문만 통과시키는 함정 회피): (1) 기간이 빠져 되물어야 하는 질문 12건, (2) '이번 달'·'지난주'·'요즘'처럼 기준일 없이는 기간이 정해지지 않는 표현 15건(이 중 '요즘'처럼 끝내 정할 수 없는 표현은 clarify), (3) 센터명이 'BUSAN'·'부산 센터'처럼 흔들리는 질문 10건, (4) 마스터에 없는 위탁사 코드나 이름을 쓴 질문 6건은 clarify, (5) 한 번에 두 가지를 묻는 질문 8건은 clarify, (6) 원인 분석·예측·의견을 요구해 템플릿에 닿지 않는 질문 10건은 refuse, (7) 값을 고치거나 지워 달라는 요청 5건은 refuse, (8) 약속 기한이 비어 있는 위탁사를 대상으로 한 t_sla_breach 질문 4건은 clarify. gt_action 과 gt_params 는 위 규칙대로 정직하게 채우고, JSON 배열만 출력합니다.{"type":"object","properties":{"q_id":{"type":"string"},"question_ko":{"type":"string"},"gt_action":{"type":"string","enum":["run","clarify","refuse"]},"gt_template_id":{"type":["string","null"]},"gt_params":{"type":"object"},"note":{"type":["string","null"]}},"required":["q_id","question_ko","gt_action","gt_params"]}| Python | 추출본 적재기와 질문 변환기와 질의 실행기와 채점기를 모두 구현하는 언어입니다 |
| DuckDB | 고객사 CSV·엑셀 추출본을 옮겨 담지 않고 그대로 읽어 질의하는 실행 엔진이며, 파일 하나로 끝나 고객사 장비에 설치가 필요 없습니다 |
| sqlglot | 템플릿에서 만들어진 질의문을 실행 전에 구문 분석해 조회 계열인지 확인하고, 값을 고치는 구문이 섞이면 실행을 막습니다 |
| Pydantic | LLM 이 내놓은 템플릿 번호와 조건 값을 JSON Schema 로 검사해, 목록 밖 번호나 형식이 어긋난 값은 실행 전에 되묻기로 돌립니다 |
| Typer | 질문 한 줄로 시작해 터미널 출력으로 끝나는 CLI 인터페이스와 옵션을 만듭니다 |
| pytest | 표기 흔들림·미등록 코드·기간 미지정 같은 경계 질문을 회귀 테스트로 고정합니다 |
| Docker | 고객사 사내 장비에서 설치 없이 같은 결과가 나오도록 실행 환경을 이미지 하나에 담습니다 |
| Claude Haiku 4.5 | 문장을 템플릿 번호와 조건 값으로 옮기는 변환만 맡고 숫자에는 개입하지 않는 보조 LLM 입니다 |
✓ pass → 그대로 멈춰도 완결입니다. 템플릿을 늘리고 싶어도 여기서 참습니다. 변환이 얼마나 맞는지 재는 채점 장치가 없으면 템플릿 수가 늘수록 어디서 틀렸는지 알 수 없다는 판단이고, 이 잘라내기가 범위 설정의 근거입니다. 더 키우려면 2주차(변환 정확도 자가채점)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(템플릿 목록 교체만으로 두 번째 고객사 질의와 패키지화)로 진행합니다.
질문 1건에 대한 응답 카드입니다. 처리 구분과 고른 템플릿과 조건 값과 실제로 실행한 질의문과 답과 근거 행을 한 스키마에 담아 터미널 출력과 자가채점에 함께 씁니다. 답의 숫자는 전부 질의가 정하고 LLM 은 템플릿 번호와 조건 값만 채웁니다.
{"type":"object","properties":{"q_id":{"type":"string"},"question_ko":{"type":"string"},"action":{"type":"string","enum":["run","clarify","refuse"]},"template_id":{"type":["string","null"]},"params":{"type":"object"},"executed_sql":{"type":["string","null"]},"answer":{"type":["string","null"]},"row_count":{"type":["integer","null"]},"evidence_rows":{"type":"array","items":{"type":"string"}},"param_trace":{"type":"array","items":{"type":"string"}},"clarify_question":{"type":["string","null"]},"reject_reason":{"type":["string","null"],"enum":["no_matching_template","missing_period","unknown_center","unknown_carrier","multi_intent","missing_sla","write_intent",null]},"hedge":{"type":["string","null"]}},"required":["q_id","question_ko","action","params","evidence_rows","param_trace"]}[
{
"input_ref": "q_001 · 이번 달 들어 부산센터에서 하루 넘게 늦게 나간 건 (기준일 2026-03-16)",
"output": {
"q_id": "q_001",
"question_ko": "이번 달 들어 부산센터에서 하루 넘게 늦게 나간 건이 몇 건이야?",
"action": "run",
"template_id": "t_delay_count",
"params": {
"period_from": "2026-03-01",
"period_to": "2026-03-15",
"center": "부산센터",
"min_delay_days": 1
},
"executed_sql": "SELECT count(*) AS delayed_cnt FROM shipments s JOIN center_map m ON s.center_raw = m.center_raw WHERE m.center_id = '부산센터' AND s.status = '출고지연' AND s.order_date BETWEEN DATE '2026-03-01' AND DATE '2026-03-15' AND date_diff('day', s.order_date, coalesce(s.ship_date, DATE '2026-03-16')) >= 1",
"answer": "3건입니다",
"row_count": 3,
"evidence_rows": [
"sh_002",
"sh_003",
"sh_009"
],
"param_trace": [
"이번 달 들어 → period_from=2026-03-01, period_to=2026-03-15 (기준일 2026-03-16)",
"부산센터 → center=부산센터 (부산 센터·BUSAN 표기 포함)",
"하루 넘게 → min_delay_days=1"
],
"clarify_question": null,
"reject_reason": null,
"hedge": "출고일이 비어 있는 지연 건은 기준일까지 지연된 것으로 셌습니다"
}
},
{
"input_ref": "q_003 · 광주센터 반품 건수 (기간이 빠진 질문)",
"output": {
"q_id": "q_003",
"question_ko": "광주센터 반품 건수 알려줘",
"action": "clarify",
"template_id": "t_return_count",
"params": {
"center": "광주센터"
},
"executed_sql": null,
"answer": null,
"row_count": null,
"evidence_rows": [],
"param_trace": [
"광주센터 → center=광주센터",
"기간에 해당하는 구절이 질문에 없습니다"
],
"clarify_question": "어느 기간으로 볼까요? 이번 달(2026-03-01부터 2026-03-15까지)로 잡을지, 최근 30일로 잡을지 알려 주시면 바로 실행합니다.",
"reject_reason": "missing_period",
"hedge": null
}
},
{
"input_ref": "q_010 · 마스터에 없는 위탁사 코드를 쓴 질문",
"output": {
"q_id": "q_010",
"question_ko": "3월에 ZZ99 위탁사 건수 얼마나 돼?",
"action": "clarify",
"template_id": null,
"params": {
"period_from": "2026-03-01",
"period_to": "2026-03-31",
"carrier_code": "ZZ99"
},
"executed_sql": null,
"answer": null,
"row_count": null,
"evidence_rows": [
"sh_007"
],
"param_trace": [
"3월 → period_from=2026-03-01, period_to=2026-03-31",
"ZZ99 → carrier_code=ZZ99 (위탁사 마스터에 없는 코드입니다)"
],
"clarify_question": "ZZ99 는 위탁사 마스터에 없는 코드입니다. 출고 기록에는 1건이 남아 있는데, 어느 위탁사로 볼지 알려 주시면 그 기준으로 실행합니다.",
"reject_reason": "unknown_carrier",
"hedge": "임의로 다른 위탁사에 붙이지 않았습니다"
}
},
{
"input_ref": "q_012 · 값을 고쳐 달라는 요청",
"output": {
"q_id": "q_012",
"question_ko": "출고지연으로 잘못 찍힌 건들 상태를 출고완료로 바꿔줘",
"action": "refuse",
"template_id": null,
"params": {},
"executed_sql": null,
"answer": null,
"row_count": null,
"evidence_rows": [],
"param_trace": [
"상태를 바꿔 달라는 요청이라 조회 계열 템플릿에 닿지 않습니다"
],
"clarify_question": null,
"reject_reason": "write_intent",
"hedge": "이 도구는 추출본을 읽기만 합니다. 상태 정정은 창고 관리 시스템에서 처리해 주세요"
}
}
][자동 검증] 1. 응답 카드가 JSON Schema(필드·enum·필수값)를 통과하는지 확인합니다. 2. action 이 run 인 카드에만 executed_sql 과 answer 가 있고, clarify·refuse 카드에는 둘 다 비어 있으며 reject_reason 이 반드시 채워져 있는지 봅니다. 3. executed_sql 이 승인된 템플릿에 조건 값을 끼운 결과와 문자열로 일치하는지 대조하고, sqlglot 구문 분석으로 조회 계열인지 다시 확인합니다. 4. evidence_rows 의 모든 행 번호가 추출본에 실재하고 질의 결과 집합에 포함되는지 대조합니다. 5. template_id 와 params 를 질문 세트의 심은 정답과 비교해 템플릿 선택 정확도와 조건 값 정확도를 계산하고, 템플릿 목록이 바뀔 때마다 회귀 검사로 다시 채점합니다. [수동 검증] 1. clarify 카드 20건을 뽑아 되물을 문장이 담당자가 바로 답할 수 있는 질문인지 점검합니다. 2. 전체의 5% 를 사람이 직접 점검합니다.