feat: P&ID 연결 분석, LLM 에이전트 모드, KB 확장, MCP 서버 리팩토링
- P&ID: 연결 분석 API, Prefix 규칙 관리, 카테고리 분류, DXF 그래프 빌드 - LLM: 대화 요약, tool card 영구 보존, 시계열 차트(uPlot), 에이전트 모드 - KB: 청크 미리보기, Field Instrument Inference, 인증/Qdrant 클라이언트 - MCP: 서버 기능 확장, 파이프라인 수정, timeout 개선 - Frontend: P&ID UI, LLM UI, KB UI, OPC UA Write 탭 추가 - 설정: AGENTS.md, plant_context, README, opencode.json 업데이트 - 정리: 진단 체크리스트 문서 삭제
This commit is contained in:
52
prompts/instrument_inference.yaml
Normal file
52
prompts/instrument_inference.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
measurement:
|
||||
f: flow
|
||||
p: pressure
|
||||
t: temperature
|
||||
l: level
|
||||
a: analysis
|
||||
s: speed
|
||||
w: weight
|
||||
d: density
|
||||
j: power
|
||||
h: moisture
|
||||
|
||||
modifiers:
|
||||
i: { role: indicator, virtual: true }
|
||||
r: { role: recorder, virtual: true }
|
||||
t: { role: transmitter, data_points: [.pv] }
|
||||
c: { role: controller, data_points: [.sp, .op] }
|
||||
q: { role: totalizer, data_points: [.qv, "qv.value"] }
|
||||
s: { role: switch, data_points: [.instate0, .instate1] }
|
||||
a: { role: alarm }
|
||||
y: { role: interlock-relay }
|
||||
z: { role: positioner }
|
||||
|
||||
auto_pair:
|
||||
- if_role: controller
|
||||
create:
|
||||
role: control-valve
|
||||
id_pattern: "{meas}cv-{loop}"
|
||||
display_pattern: "{MEAS}CV-{loop}"
|
||||
|
||||
special_prefixes:
|
||||
xv: { role: shutdown-valve, measures: null }
|
||||
sdv: { role: shutdown-valve, measures: null }
|
||||
fy: { role: interlock-relay, measures: flow }
|
||||
fz: { role: positioner, measures: flow }
|
||||
p: { role: power_equipment, measures: null, equipment_type: pump }
|
||||
k: { role: power_equipment, measures: null, equipment_type: compressor }
|
||||
ag: { role: power_equipment, measures: null, equipment_type: agitator }
|
||||
b: { role: power_equipment, measures: null, equipment_type: blower }
|
||||
f: { role: power_equipment, measures: null, equipment_type: fan }
|
||||
|
||||
confidence:
|
||||
high_when:
|
||||
- prefix matches measurement OR special_prefixes
|
||||
- all modifiers resolved
|
||||
- data_points present and consistent
|
||||
medium_when:
|
||||
- prefix matches but some data_points missing
|
||||
- modifiers contain unknown letter
|
||||
low_when:
|
||||
- special_prefixes only AND data_points unusual
|
||||
- first letter not in measurement table
|
||||
@@ -3,25 +3,153 @@
|
||||
> 본 파일은 LLM 채팅의 시스템 프롬프트에 자동 주입됩니다.
|
||||
> 운영 환경에 맞춰 단위(Area / Unit), 계기 prefix, 태그 명명 규칙, 예시 질문 등을 채워주세요.
|
||||
|
||||
## 단위(Area / Unit)
|
||||
## 단위(Area / Unit) 명명
|
||||
|
||||
<!-- 예: Unit A — 압축 -->
|
||||
<!-- 예: Unit B — 분리 -->
|
||||
DB의 area 컬럼은 두 가지 표기가 혼재합니다 — 도구 호출 시 표기를 구분해서 사용해야 합니다.
|
||||
|
||||
- **event_history_table.area** — 정규화된 짧은 이름. 예: `P6`, `UTIL`, `PACKING`
|
||||
- **v_tag_summary.area** — Experion 원본 형식. 예: `{12 | P6 | }`, `{11 | UTIL | }`
|
||||
|
||||
사용자가 한국어로 "N차 플랜트", "N차" 라고 부르면 → area 코드 **`P{N}`** 로 변환하세요.
|
||||
|
||||
| 한국어 호칭 | event_history_table.area | v_tag_summary.area | 태그 수(참고) |
|
||||
|---|---|---|---|
|
||||
| 1차 플랜트 | `P1` | `{7 \| P1 \| }` | 87 |
|
||||
| 2차 플랜트 | `P2` | `{8 \| P2 \| }` | 142 |
|
||||
| 3차 플랜트 | `P3` | `{9 \| P3 \| }` | 50 |
|
||||
| 4차 플랜트 | `P4` | `{17 \| P4 \| }` | 13 |
|
||||
| 5차 플랜트 | `P5` | `{10 \| P5 \| }` | 40 |
|
||||
| 6차 플랜트 | `P6` | `{12 \| P6 \| }` | 121 |
|
||||
| 8차 플랜트 | `P8` | `{13 \| P8 \| }` | 43 |
|
||||
| 9차 플랜트 | `P9` | `{14 \| P9 \| }` | 98 |
|
||||
| 10차 플랜트 | `P10` | `{15 \| P10 \| }` | 79 |
|
||||
| 유틸리티 | `UTIL` | `{11 \| UTIL \| }` | 1 |
|
||||
| 포장 | `PACKING` | `{16 \| PACKING \| }` | 7 |
|
||||
|
||||
(7차 플랜트는 존재하지 않습니다.)
|
||||
|
||||
이벤트/알람 도구(`active_alarms`, `query_events`, `summarize_events`, `generate_status_report`)는
|
||||
**짧은 형식**(`P6`)을 받습니다. `find_tags`/`run_sql`에서 `v_tag_summary`를 직접 조회할 때만 LIKE 매칭이 필요할 수 있습니다.
|
||||
|
||||
`unit-6`, `Unit 6`, `6번 유닛` 같은 표현은 area 코드가 아닙니다. 위 표의 정규 코드만 사용하세요.
|
||||
|
||||
## 계기 명명 약어
|
||||
|
||||
<!-- 예: FIC: Flow Indicator Controller -->
|
||||
<!-- 예: PT: Pressure Transmitter -->
|
||||
- `FIC` / `FT` — Flow Indicator Controller / Transmitter
|
||||
- `PIC` / `PT` — Pressure Indicator Controller / Transmitter
|
||||
- `TIC` / `TI` / `TE` — Temperature Indicator Controller / Indicator / Element
|
||||
- `LIC` / `LT` — Level Indicator Controller / Transmitter
|
||||
- `AIC` / `AT` — Analyzer Indicator Controller / Transmitter
|
||||
- `XV` — On/Off Valve (Open/Close)
|
||||
- `PSV` — Pressure Safety Valve
|
||||
- `P` — Pump (장비), `T` — Tank, `F` — Filter, `C` — Column, `E` — Heat Exchanger
|
||||
- `R` — Reactor, `S` — Separator, `V` — Vessel, `D` — Drum
|
||||
|
||||
## 태그 명명 규칙
|
||||
|
||||
<!-- 예: 모두 소문자 (ficq-6113.pv) -->
|
||||
<!-- 예: 접미사 .pv/.sp/.op/.instate0..7 -->
|
||||
- 태그는 모두 **소문자**입니다 (예: `ficq-6113.pv`, `ti-6101.pv`).
|
||||
- 접미사로 신호 종류를 구분: `.pv`(현재값), `.sp`(설정값), `.op`(출력값), `.instate0..7`(디지털 상태).
|
||||
- base_tag(접미사 없는 형태) 예: `p-6102`, `xv-6105`.
|
||||
- 4번째~6번째 자리의 첫 숫자가 area를 시사하는 경우가 많지만(예: `6xxx` ≈ P6), 절대 규칙은 아닙니다.
|
||||
area를 확정하려면 `find_tags` / `v_tag_summary` 조회로 확인하세요.
|
||||
|
||||
## 시간대
|
||||
## 펌프 운전 상태 판정 (중요)
|
||||
|
||||
<!-- 예: DB 저장 UTC, 사용자 입력 KST -->
|
||||
펌프 디지털 포인트는 `p-NNNN.pv` 태그의 **값(livevalue)이 enumerated 상태**로 표현됩니다.
|
||||
숫자 ordinal과 라벨이 함께 `{ordinal | label | }` 형식.
|
||||
|
||||
## 예시 질문 / 의도 라우팅
|
||||
### 알려진 상태 enum
|
||||
|
||||
<!-- 자유 작성 -->
|
||||
| 값 | 의미 | 운전 중? |
|
||||
|---|---|---|
|
||||
| `{? \| L-RUN \| }` | 로컬 운전 (Local Run) | **✅ 운전 중** |
|
||||
| `{5 \| R-RUN \| }` | 원격 운전 (Remote Run) | **✅ 운전 중** |
|
||||
| `{0 \| L-STOP \| }` | 로컬 정지 | ❌ 정지 |
|
||||
| `{4 \| R-STOP \| }` | 원격 정지 | ❌ 정지 |
|
||||
| `{0 \| STOP \| }` | 정지 (모드 미구분) | ❌ 정지 |
|
||||
| `{0 \| OFF \| }` | OFF | ❌ 정지 |
|
||||
| `{2 \| L-TRIP \| }` | 로컬 트립 | ❌ 트립 |
|
||||
| `{6 \| R-TRIP \| }` | 원격 트립 | ❌ 트립 |
|
||||
| `{0 \| NORMAL \| }`, `{0 \| PNL \| }`, `{0 \| A \| }` | 펌프가 아닌 다른 디지털 포인트 (panel/alarm 등) — 운전 판정에서 제외 |
|
||||
|
||||
(L-RUN의 ordinal 값은 현재 환경 데이터에 흔적이 없어 미확정. enum 정의상 존재하므로 매칭에 포함)
|
||||
|
||||
### "운전 중" 판정 SQL (안전 매칭)
|
||||
|
||||
```sql
|
||||
-- realtime_table 기준 — R-RUN, L-RUN 둘 다 운전 중
|
||||
WHERE livevalue ~ '\|\s*[LR]-RUN\s*\|'
|
||||
|
||||
-- 트립 판정
|
||||
WHERE livevalue ~ '\|\s*[LR]-TRIP\s*\|'
|
||||
|
||||
-- 정지 판정 (모든 STOP 변형)
|
||||
WHERE livevalue ~ '\|\s*(L-STOP|R-STOP|STOP|OFF)\s*\|'
|
||||
```
|
||||
|
||||
### ⚠️ p-prefix 주의사항
|
||||
|
||||
`p-NNNN` prefix는 펌프 전용이 아닙니다. panel point, alarm point 등 다른 디지털 포인트도 같은 prefix를 공유합니다.
|
||||
- 운전 판정 시 enum이 위 6종(L-STOP/L-RUN/L-TRIP/R-STOP/R-RUN/R-TRIP) 중 하나인 태그만 펌프로 취급.
|
||||
- 또는 `node_map_master.description` / `v_tag_summary.description`으로 펌프 여부 추가 확인.
|
||||
|
||||
### "운전 중인 플랜트" 판정 — `v_plant_running_state` 뷰 사용 (1순위)
|
||||
|
||||
❌ **데이터 갱신 중 = 운전 중** 으로 해석 금지. 컨트롤러 1대가 여러 플랜트를 서빙하므로 태그 데이터가 갱신되어도 실제 공정은 정지 상태일 수 있음.
|
||||
|
||||
✅ 진짜 운전 중 판정 = **해당 area의 펌프 중 1대 이상이 R-RUN 또는 L-RUN**.
|
||||
|
||||
이 판정을 매번 직접 SQL로 짜지 말고 **`v_plant_running_state` 뷰를 그대로 사용**하세요:
|
||||
|
||||
```sql
|
||||
SELECT area_code, status, running_pumps, tripped_pumps, stopped_pumps, total_pumps, running_pump_tags
|
||||
FROM v_plant_running_state
|
||||
ORDER BY area_code;
|
||||
```
|
||||
|
||||
#### 뷰 컬럼
|
||||
|
||||
| 컬럼 | 의미 |
|
||||
|---|---|
|
||||
| `area_code` | 정규화된 area (P3, P4, P5, P6, P8 등) |
|
||||
| `status` | `RUNNING` / `TRIPPED` / `STOPPED` (펌프 1대라도 RUN이면 RUNNING) |
|
||||
| `running_pumps` | R-RUN 또는 L-RUN 펌프 수 |
|
||||
| `tripped_pumps` | R-TRIP 또는 L-TRIP 펌프 수 |
|
||||
| `stopped_pumps` | R-STOP 또는 L-STOP 펌프 수 |
|
||||
| `total_pumps` | 펌프 enum 가진 태그 전체 수 |
|
||||
| `running_pump_tags` | 현재 RUN 상태인 펌프 base_tag 배열 (예: `['p-6102','p-6116']`) |
|
||||
|
||||
#### 결과에 안 나오는 area의 의미
|
||||
|
||||
뷰 결과에 area가 없으면 그 area는 **펌프 enum을 가진 태그가 0개** — 펌프 미등록 또는 panel/alarm point만 있는 경우.
|
||||
"운전 판정 불가" / "펌프 데이터 없음"으로 답하세요. **"정지 상태"로 추정 금지.**
|
||||
|
||||
(예: P1, P2, P7, P9, P10, UTIL, PACKING은 펌프 데이터 미등록 — 운전 여부 단정 불가)
|
||||
|
||||
#### 사용자 의도 매핑
|
||||
|
||||
- "지금 어떤 플랜트가 운전 중이야?" → `SELECT area_code, status FROM v_plant_running_state WHERE status='RUNNING'`
|
||||
- "P6 펌프 어떤 게 돌아가?" → `SELECT running_pump_tags FROM v_plant_running_state WHERE area_code='P6'`
|
||||
- "트립 펌프 있어?" → `SELECT area_code, tripped_pumps FROM v_plant_running_state WHERE tripped_pumps > 0`
|
||||
|
||||
## 시간대 및 날짜 처리
|
||||
|
||||
- DB 저장은 **UTC** 입니다 (`recorded_at`, `event_time` 모두 TIMESTAMPTZ).
|
||||
- 사용자 입력은 **KST(UTC+9)** 로 가정합니다.
|
||||
- KST → UTC 변환 예: KST 2026-05-12 00:00 = UTC 2026-05-11T15:00:00Z.
|
||||
- "5월 12일" 같이 연도 생략된 경우, 시스템 프롬프트의 "현재 시각" 블록에 적힌 **현재 연도**를 사용하세요. 학습 시점의 연도로 추정하지 마세요.
|
||||
|
||||
## 의도별 권장 도구
|
||||
|
||||
| 사용자 의도 (예시) | 권장 도구 |
|
||||
|---|---|
|
||||
| "지금 알람 뭐 있어?", "활성 트립" | `active_alarms` |
|
||||
| "5월 12일 6차 플랜트 이상 상황 보고", "어제 P3 이벤트 요약" | `summarize_events` (since/until + area) |
|
||||
| "교대 보고", "운전 상태 보고서", "지난 24시간 종합" | `generate_status_report` (area + hours) |
|
||||
| "지금 어떤 플랜트가 운전 중이야?", "P6 펌프 RUN 상태", "운전 중인 펌프 목록" | `run_sql` (위 "펌프 운전 상태 판정" 섹션의 SQL 사용. ⚠️ "데이터 갱신 중"으로 판단 금지) |
|
||||
| "온도 태그 찾아줘", "P6 펌프 어떤 게 있어" | `find_tags` |
|
||||
| "FIC-6113 최근 1시간 PV 추이" | `query_pv_history` 또는 `query_with_nl` |
|
||||
| "특정 SQL 결과" | `run_sql` |
|
||||
| "절차서/매뉴얼/설계서 검색" | `search_kb` |
|
||||
|
||||
도구 인자는 raw JSON으로 답변하지 말고, 표/요약으로 정리해 운전원이 바로 읽을 수 있게 답변하세요.
|
||||
|
||||
Reference in New Issue
Block a user