# 작업지시서 — NL2SQL 스키마 갭 수정 (플랜트 뷰 추가) > 대상: 코딩 LLM. 이 문서만 보고 독립 수행 가능하도록 작성됨. > 예상 분량: 단일 파일의 문자열 상수 1곳 편집 + 검증. 로직 변경 없음. ## 1. 배경 (왜) Phase 0 골든 평가에서 **Qwen3-8B가 전체 85%인데 nl2sql만 50%(5/10)** 로 떨어짐. 실패 5건(nl2sql-02~06)은 **전부 플랜트 전용 뷰**(`v_plant_running_state`, `v_plant_running_state_corroborated`, `v_instrument_range`)를 써야 하는 질문인데, NL2SQL 프롬프트의 스키마(`DB_SCHEMA`)에 **그 뷰들이 문서화돼 있지 않아** 모델이 모르는 뷰를 쓸 수 없었음. 기본 테이블 질문(nl2sql-01,07~10)은 모두 통과 → **모델·채점 문제 아님, 스키마 문서 갭**. 이 갭은 production NL2SQL(`query_with_nl`/`run_sql` 생성기)도 동일하게 가짐. 프롬프트가 단일 소스(`worker/sql_prompt.py`)라 **여기만 고치면 eval·production 동시 개선**. ## 2. 수정 대상 (딱 하나) `mcp-server/worker/sql_prompt.py` 의 **`DB_SCHEMA` 문자열 상수** 한 곳. - ⚠️ `nl2sql_worker.py`는 이 상수를 import만 함 — **건드리지 말 것**. - ⚠️ `SQL_SYSTEM_PROMPT`은 자동으로 `DB_SCHEMA`를 포함하므로 별도 수정 불필요. ## 3. 추가할 내용 (정확히 이 텍스트를 DB_SCHEMA에 삽입) `DB_SCHEMA` 안에서 **`뷰: v_tag_summary ...` 블록 바로 다음, `새로운 태그 타입:` 줄 앞**에 아래 블록을 그대로 삽입한다 (기존 서술 스타일·들여쓰기 유지): ``` 뷰: v_plant_running_state (area별 펌프 운전 판정 — "어떤 플랜트가 운전 중" 질문 1순위) area_code TEXT - 정규화 area (예: P3, P4, P5, P6, P8) status TEXT - 'RUNNING' / 'TRIPPED' / 'STOPPED' (펌프 1대라도 RUN이면 RUNNING) running_pumps INT - R-RUN/L-RUN 펌프 수 tripped_pumps INT - R-TRIP/L-TRIP 펌프 수 stopped_pumps INT - R-STOP/L-STOP 펌프 수 total_pumps INT - 펌프 enum 보유 태그 수 running_pump_tags TEXT[] - 현재 RUN 상태 펌프 base_tag 배열 ※ "운전 중인 플랜트/펌프", "트립 펌프" 류 질문은 이 뷰를 직접 SELECT (펌프 상태 SQL 직접 작성 금지) ※ 결과에 없는 area = 펌프 미등록 → 운전 여부 단정 금지. 이 뷰는 area 레벨(sub_area 없음) 뷰: v_plant_running_state_corroborated (펌프별 실질 운전 — 유량/진공 교차검증, sub_area 지원) base_tag TEXT - 펌프 base_tag (예: 'p-6102', 'vp-6117') area_code TEXT - 정규화 area sub_area TEXT - 세부 area (예: 'P6-1'; 공용은 'P6-1,P6-2'). 필터는 LIKE '%P6-1%' corroborated_status TEXT - CONFIRMED_RUNNING / SUSPICIOUS_RUNNING / STALE / INDETERMINATE_RUNNING / STOPPED / TRIPPED flow_kg_hr DOUBLE PRECISION - 연결 유량(kg/hr) vacuum_torr DOUBLE PRECISION - 연결 진공압(torr=mmHg) ※ "6-1차/6-2차" 등 sub_area 필터가 필요한 질문은 **반드시 이 뷰** 사용 (아래 agg/기본뷰는 sub_area 없음) 뷰: v_instrument_range (계기 단위/레인지 — tag_metadata에서 추출) base_tag TEXT - 기본 태그명, 접미사 없음 (예: 'ficq-6113', 'pica-6111') unit TEXT - 단위 (예: 'kg/hr', 'mmHg') eu_lo DOUBLE PRECISION - 레인지 하한 eu_hi DOUBLE PRECISION - 레인지 상한 ※ 계기 레인지/상하한/단위 질문에 사용. base_tag는 '.pv' 등 접미사를 떼고 매칭 참고(직접 쓰지 말 것): v_plant_running_state_agg 도 있으나 area 레벨 집계라 sub_area가 없음. sub_area 질문엔 위 v_plant_running_state_corroborated 를 사용. ``` > 컬럼/뷰 정의 출처: `src/Infrastructure/Database/ExperionDbContext.cs` (boot DDL). > 변경 전 그 파일에서 위 3개 뷰의 SELECT를 한 번 대조해 컬럼명이 위와 일치하는지 확인할 것. ## 4. 검증 (순서대로) ```bash cd mcp-server # 1) 컴파일 — 프롬프트 단일소스/워커 둘 다 python3 -m py_compile worker/sql_prompt.py worker/nl2sql_worker.py # 2) 모델 서빙 (표준 FP8만! FP8-dynamic은 출력 손상되니 금지) cd .. bash scripts/run-vllm-eval-model.sh Qwen/Qwen3-8B-FP8 Qwen3-8B 0.30 32768 8001 # 3) nl2sql 카테고리만 재실행 (Qwen3는 --no-think 필수) cd mcp-server/eval ../.venv/bin/python run_eval.py --model Qwen3-8B --no-think --categories nl2sql # 4) 회귀 확인 — 전체 재실행 + 이전 결과 대비 ../.venv/bin/python run_eval.py --model Qwen3-8B --no-think \ --baseline results/Qwen3-8B_20260526_103459.json ``` ## 5. 수용 기준 (Acceptance) - [ ] `py_compile` 통과 (sql_prompt.py, nl2sql_worker.py) - [ ] **nl2sql ≥ 9/10** (목표: 02~06 통과. 특히 06은 `v_plant_running_state_corroborated`+`p6-1` 포함, `v_plant_running_state_agg` 미포함이어야 PASS) - [ ] 다른 카테고리(abstain/scaffold/tool_call/grounding) **회귀 없음** (`--baseline` 비교에서 PASS→FAIL 0건) - [ ] `DB_SCHEMA` 외 다른 코드(워커 로직·채점기·골든셋) 변경 없음 ## 6. 하지 말 것 (금지) - ❌ 골든셋(`golden.jsonl`)이나 채점기(`run_eval.py`)를 고쳐서 점수를 맞추기 — 측정자를 왜곡함 - ❌ 존재하지 않는 뷰/컬럼을 스키마에 추가 (반드시 ExperionDbContext.cs DDL과 대조) - ❌ `nl2sql_worker.py`의 생성 로직·`SQL_SYSTEM_PROMPT` 규칙 변경 (스키마 문서만 보강) - ❌ FP8-dynamic 양자화 모델 사용 (이 스택에서 출력 문자 손상 — 표준 FP8/​bf16만) ## 7. 산출물 - 변경 파일: `mcp-server/worker/sql_prompt.py` (DB_SCHEMA 뷰 3개 추가) 1개 - 새 eval 결과: `mcp-server/eval/results/Qwen3-8B_*.json` (nl2sql 개선 확인) - 한 줄 보고: 변경 전/후 nl2sql 점수, 회귀 유무