- 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 업데이트 - 정리: 진단 체크리스트 문서 삭제
34 KiB
P&ID 추출 데이터 이용방안 플랜
작성일: 2026-05-14
배경: pid_equipment 테이블에 No-10_Plant_PID.dxf로부터 460건의 구조화 데이터(태그·라인번호·fluid·종류·area) 적재 완료. Experion realtime_table과의 자동 매핑(exact + prefix only, false positive 제거)도 동작 중. 다음 단계로 이 데이터를 무엇에 쓸지 결정.
현재 보유 데이터
| 컬럼 | 의미 | 예시 |
|---|---|---|
tag_no |
추출된 원본 태그/라인번호 | P-10138-600A-F2A-H100, PSV-10217, FCV-6113 |
instrument_type |
prefix 분류 | FCV, PSV, P, T, BT, LIA |
line_number |
LineNo 식별번호 (pipe만) | 10138, 6203 |
confidence |
추출 신뢰도 | 0.95~0.99 |
experion_tag_id |
realtime_table FK (매핑 시) | NULL or int |
is_active |
활성 여부 | true/false |
서버 내부 사전(코드)으로 _PID_FLUID_DICT(P=PROCESS, CWS=COOLING WATER SUPPLY 등 19종), _PID_EQUIPMENT_PREFIX(P=Pump, T=Tank, F=Filter 등 14종), _PID_INSTRUMENT_FIRST/_PID_INSTRUMENT_MODIFIER(ISA letter 코드)도 함께 보유.
갈래 1 — 채팅 컨텍스트 보강 (최우선 추천)
가치: 운전원이 즉시 체감. 작업량 최소. 작업량: 0.5~1일.
구현
MCP 도구 2개 추가 (mcp-server/server.py):
@mcp.tool()
async def find_pid_equipment(query: str, kind: str | None = None,
area: str | None = None, limit: int = 20) -> str:
"""P&ID 장비/계기 검색. tag_no ILIKE 매칭 + kind/area 필터.
kind: 'pipe'|'equipment'|'instrument' (없으면 전체)
area: 6-1 → tag_no가 P-61XX/T-61XX 등 6+1로 시작
"""
@mcp.tool()
async def get_pid_equipment_info(tag_no: str) -> str:
"""단일 태그 상세. 매핑된 Experion 태그도 함께 반환.
응답: {tag_no, type(fluid 또는 장비종류), instrument_type, line_number,
experion_tag, latest_value (있으면)}
"""
ToolGuideKo(OllamaController.cs)에 새 도구 설명 추가 → LLM이 자동 활용.
효과 예시
- "PSV-10217이 뭐야?" → "Pressure Safety Valve (mechanical, OPC 신호 없음). 10차 area"
- "10차에 펌프 몇 대?" →
find_pid_equipment(kind='equipment', area='10')→ 카운트 + 리스트 - "P-10138 어떤 fluid?" → "PROCESS FLUID, 600A, F2A spec, H100 단열"
- "FCV-6113 지금 값은?" → 매핑된 experion 태그로 자동 join → 실시간값
갈래 2 — 알람·이벤트 컨텍스트 자동 주입
가치: 알람 보고서가 풍부해짐. 운전원이 태그 코드만 보고 의미 파악 가능.
작업량: 0.5일. 기존 summarize_events/generate_status_report에 join 추가.
구현
query_events결과를pid_equipment와 LEFT JOIN해서 각 이벤트에 PID 컨텍스트 첨부- 예: ALARM event
tagname=fcv-6113.pv→ 컨텍스트 "FCV-6113, Flow Control Valve, 6-1 area, P-10138 라인의 PROCESS 흐름 제어" generate_status_report마크다운 출력에 "## 영향 장비" 섹션 추가 (해당 area의 PID 인벤토리 요약)
효과
- 알람 요약 LLM이 "단순 태그 나열" → "공정 맥락 포함된 운전 보고서"로 격상
- KB 문서에서 같은 area의 절차서 자동 인용 (search_kb area 필터 + PID 데이터 연동)
갈래 3 — P&ID 다이어그램 시각화 (UI)
가치: 시각적 자산 파악. 도면 없이도 area별 장비 구조 한눈에 보기. 작업량: UI 작업 중심. 그래프 보기까지 가려면 from-to 추출 추가 필요.
Phase 3a (즉시 가능)
현재 데이터만으로 — area별·종류별 트리뷰/리스트뷰:
└─ 10차 area
├─ 펌프 (15) P-10101, P-10116, …
├─ 탱크 (19) T-10101, T-10102, …
├─ 필터 (4) F-10101A, F-10101B, …
├─ 안전밸브 (18) PSV-10101, PSV-10103, …
└─ 라인 (172) P-10138, CWS-10612, …
14번 P&ID 탭 또는 신규 탭에서 구현.
Phase 3b (확장, 작업 큼)
DXF에서 라인 끝점 좌표 + 장비 좌표 추출 후 KD-tree로 from-to 추정 → cytoscape/d3로 노드 그래프. 사용자 이미 결정한 "위치좌표 계산 없이" 방향과 상충 — 추후 필요해질 때만 착수.
갈래 4 — 자산 마스터 + KB 통합 (장기 그림)
가치: 단순 검색을 넘어 정비·운영 데이터 통합 플랫폼. 작업량: 큼. 다른 데이터 소스 통합 필요.
구성요소
- equipment_registry.yaml (이전 논의) — Experion htm에서 추출한 좌표·area + PID 추출 데이터 머지
- 정비/점검 일정 테이블 — 종류별 주기 정의 (PSV 1년, FCV 6개월, …) → 다음 점검일 자동 계산
- 누락 검출 리포트 —
pid_equipment(P&ID 기준) vsrealtime_table(Experion 기준) 양방향 차집합- P&ID에만 있는 것 → 측정 누락 (or mechanical/지표 없는 장비)
- Experion에만 있는 것 → 도면 누락 (or 시스템 신호)
- KB 문서 자동 인용 —
search_kb에 PID 태그 정보 자동 추가해서 검색 품질 향상
의존성
- equipment_registry yaml 구축이 선결 (이전 결정: htm 파서 추가)
- 정비 일정은 별도 사용자 입력 또는 기존 정비 시스템 연동 필요
갈래 5 — 기존 infer_field_instruments와의 통합 (보완 관계, 죽이지 않음)
배경: RAG 관리 → Field Instrument 탭의 기존 기능(infer_field_instruments → Excel 초안 다운로드)이 parse_pid_dxf 등장 후 의미를 잃었는지 의문 제기됨. 결론: 의미 없어지지 않음, 오히려 통합 가치가 생김.
두 기능의 본질적 차이
| 구분 | infer_field_instruments (기존) |
parse_pid_dxf (신규) |
|---|---|---|
| 입력 소스 | Experion DB의 OPC 태그 (v_tag_summary) |
DXF 도면 파일 |
| 추론 방향 | "실제 측정점이 있다 → 현장에 계기 있을 것" | "도면에 그려져 있다 → 자산으로 존재" |
ficq-6101 처리 |
base 보고 FT-6101 / FIC-6101 / FCV-6101 3개로 분해 | 도면에 그려진 그대로 (보통 FCV-6101, FIC-6101 등) 인식 |
| PSV-10217 (mechanical, 신호 없음) | ❌ 못 만듦 | ✅ 도면에 있으면 추출 |
| 추가된 임시 계기 (OPC 신호만 존재) | ✅ 추론 가능 | ❌ 도면에 없으면 못 잡음 |
| 출력 | Excel 초안 (운전원 수동 검수 후 KB 업로드) | pid_equipment 테이블 |
| 동력기기 | power_equipment role로 별도 분류 |
Pump prefix(P) 등으로 분류 |
잡는 누락이 정반대 — 단독으로는 불완전
- OPC 신호 있지만 도면 미반영:
infer_field_instruments만 잡음 (도면 업데이트 누락 케이스) - 도면엔 있지만 OPC 신호 없음:
parse_pid_dxf만 잡음 (PSV/수동밸브/게이지/파이프 등 mechanical 자산) - 둘 다 존재:
match_pid_tags가 자동 연결 (exact + prefix)
통합으로 새로 가능해지는 작업
-
infer_field_instruments출력 자동 검증- infer가 추론한 FT-6101이 실제 도면(
pid_equipment)에 있는지 즉시 대조 - 추론 정확도 자동 측정 → 추론 룰 개선 피드백 루프 가능
- infer가 추론한 FT-6101이 실제 도면(
-
Excel 초안 자동 라벨링 보강
- 도면에는 PSV-10217이 있는데 infer는 못 만들었음 → "OPC 신호 없는 mechanical" 라벨로 Excel에 자동 행 추가
- 도면 LineNo 정보(
P-10138-600A-F2A-H100)로 fluid/size/material 컬럼 자동 채움 - infer가 만든 row와 P&ID에서만 보이는 row를 한 Excel에 합쳐서 운전원이 한 번에 검수
-
양방향 차집합 리포트 (갈래 4의 핵심 산출물)
차집합 의미 운영 액션 pid_equipment−realtime_table(도면 ⊖ 실제)도면엔 있는데 측정 없는 자산 (a) mechanical → 정상, "OPC 신호 없음" 라벨로 마스터에 등록
(b) 측정 누락 → 신호 추가 검토realtime_table−pid_equipment(실제 ⊖ 도면)측정은 있는데 도면 없는 신호 도면 업데이트 누락 → P&ID 도면 보완 요청 양쪽 모두 정상 매핑 UI에서 ✅ 표시 (현재 상태)
구현 (작업량 적음)
infer_field_instruments의 dedup 단계 뒤에pid_equipmentLEFT JOIN 한 번- infer 결과 row마다
in_pid_drawing: bool,pid_line_number,pid_drawing_no컬럼 추가 - infer가 만들지 못한
pid_equipmentrow를 별도 시트(Pid_Only_Mechanical)로 Excel에 추가
- infer 결과 row마다
parse_pid_dxf는 손대지 않음. infer 쪽에만 join 추가- 운전원이 다운받는 Excel이 그대로 더 풍부해짐 — 추가 UI 변경 불필요
의존성
- 갈래 1·2 없어도 가능. 단독 진행 가능
infer_field_instruments의 출력 Excel 포맷 일부 변경 (시트 추가) — 기존 운영 흐름에 영향 적음
갈래 6 — PID 추출 → 옵시디언 노트 부트스트랩 → 하이브리드 RAG
배경: plans/옵시디언-구조적용-플랜.md는 마크다운 노트 + [[wikilinks]] + frontmatter 기반 그래프 RAG를 제안하지만 아직 미구현 (notes/ 디렉토리·DB 테이블 없음, 위키링크가 들어있는 .md는 계획 문서 자체뿐). 옵시디언 노트 시스템을 0에서 시작하면 "초기 비어있음" 문제가 큰데, PID 추출 결과를 활용하면 첫날부터 460개 anchor 노트로 부트스트랩 가능.
역할 분담
| 영역 | PID 추출 (pid_equipment) |
옵시디언 노트 (planned) |
|---|---|---|
| 채우는 것 | 뼈대 — 모든 태그/라인/장비 자동 인벤토리 | 살 — 절차, 루프 의미, 트러블슈팅, 벤더 정보, 운전 노하우 |
| 입력 | 도면 1번 + 자동 | 운전원/엔지니어 수기 + 채팅 저장 |
| 갱신 | 도면 바뀌면 재추출 | 사람이 알게 될 때마다 |
| 핵심 식별자 | tag_no (FCV-6113, P-10101) |
노트 ID tag/fcv-6113, loop/compression-a |
공통 anchor가 tag ID — PID가 만든 모든 태그는 곧 노트 ID가 되고, 사람이 쓴 노트는 [[tag/fcv-6113]] 위키링크로 PID 인벤토리에 자동 연결.
구현 단계
Step 1 — PID stub 노트 자동 생성
pid_equipment 460건을 각각 frontmatter-only .md 파일로 발행:
---
id: tag/fcv-6113
kind: tag
prefix: FCV
type: Flow Control Valve
area: 6-1
line_number: 6113
experion_tag: fcv-6113.pv
source_drawing: No-10_Plant_PID.dxf
source: pid_equipment.id=42
generated_at: 2026-05-14
---
<!-- 본문은 비어둠 — 운전원이 채움 -->
- 디렉토리:
notes/tag/,notes/area/,notes/drawing/등 - 한 파일 = 한 노트 =
pid_equipment1행 - 본문 비어있어도 anchor 역할 → 위키링크 타깃으로 즉시 사용 가능
Step 2 — 사람 노트는 위에 자라남
운전원/엔지니어가 만드는 손 노트는 별도 kind:
notes/loop/compression-a.md— "이 루프는 tag/fcv-6113 tag/pt-6111 tag/ft-6113로 구성됨"notes/procedure/start-up-a.md— "기동 시 loop/compression-a 먼저 안정화"notes/event-pattern/surge-recovery.md— "tag/fcv-6113 surge 발생 시 procedure/anti-surge 적용"
원칙: 사람은 신규 마크다운만 쓰고 PID stub은 안 건드림. 재추출 시 stub 안전하게 덮어쓰기 가능.
Step 3 — Stub 갱신 정책
PID 재추출 시:
- frontmatter는 항상 최신
pid_equipment값으로 덮어씀 - 본문(
<!-- comment -->아래)에 운전원이 추가한 텍스트가 있으면 보존 (merge 로직) - 새로 등장한 tag → 신규 stub 생성
- 사라진 tag →
archived: truefrontmatter 추가 (파일 삭제 안 함, 위키링크 깨짐 방지)
Step 4 — KB 인덱싱 + 그래프 엣지 추출
notes/ 디렉토리를 KbIngestWorker가 별도 컬렉션(예: kb_notes)으로 처리:
- 노트 1개 = 1 청크 (헤딩으로 자르지 않음 — 작은 단위 유지)
- frontmatter → Qdrant payload (area, kind, prefix 필터링 가능)
- 본문에서
[[note-id]]정규식 추출 → 신규 테이블kb_note_edges (source_id, target_id, link_type)에 적재
Step 5 — 채팅 RAG에 그래프 1-hop 결합
search_kb가 top-k 청크 검색 → 각 청크가 노트면 kb_note_edges에서 1-hop 위키링크 타깃 조회 → 그 타깃 노트들의 frontmatter+첫 200자를 컨텍스트에 함께 주입.
# 의사 코드
chunks = search_kb(query, top_k=5)
extra_context = []
for chunk in chunks:
if chunk.note_id:
targets = db.fetch_edges(chunk.note_id, depth=1)
extra_context.extend(targets) # 5개 청크 + N개 1-hop 노트
return chunks + extra_context # LLM에 함께 전달
LLM은 청크 5개만이 아니라 "이 청크와 명시적으로 연결된 절차/루프/이벤트 패턴"까지 함께 보고 답변.
트레이드오프
- (+) 옵시디언 시스템의 "초기 비어있음" 문제 해결 — 첫날부터 460개 anchor 보유
- (+) 운전원이 채팅에서 받은 답변을
loop/surge-recovery.md한 줄로 영구화 가능 → 지식 자산이 자라남 - (+) 마크다운이라 외부 옵시디언 앱으로 열어 편집해도 호환 (부수효과)
- (−) stub 갱신 시 본문 보존 머지 로직 필요 (text diff 충돌 검출)
- (−) 운전원이 위키링크 작성 습관 안 들이면 anchor만 잔뜩에 살이 없는 상태 → 저진입 UX 필수:
- 채팅에서 "이 답변을 loop/compression-a에 저장" 같은 한 클릭 액션
- 노트 작성 시
[[입력하면 자동완성 드롭다운으로 PID stub 추천
의존성
- 갈래 1 권장 선결 — PID 데이터 조회 인프라가 있어야 stub 생성 스크립트 작성이 쉬움
옵시디언-구조적용-플랜.md의 데이터 모델 결정사항 따름 (note ID 규칙, kind 9종, frontmatter 스키마)- KbIngestWorker에 notes 디렉토리 전용 처리 분기 추가
작업 분할
| 단계 | 산출물 | 작업량 |
|---|---|---|
| Step 1 | mcp-server/notes_sync.py — pid_equipment → notes/tag/*.md stub 생성기 |
0.5일 |
| Step 3 | 머지 보존 로직 + archived 처리 | 0.5일 |
| Step 4 | KbIngestWorker notes 분기 + kb_note_edges 테이블 + 위키링크 파서 |
1일 |
| Step 5 | search_kb 그래프 1-hop 보강 + 채팅 통합 |
0.5일 |
| 사람 노트 저진입 UX | "답변 → 노트 저장" 버튼, [[ 자동완성 |
1일 (UI) |
| 합계 | 3.5일 |
갈래 7 — Excel 라운드트립으로 service/role 메타데이터 보강 (마지막 연결고리)
배경: DXF 파서는 tag·LineNo·fluid(파이프 한정)·prefix 분류는 자동 추출하지만, 장비의 실질 정보(service, role, contents, from-to)는 도면에 텍스트로 없음. 예: T-201이 원료탱크인지 폐액탱크인지, 무슨 fluid를 담는지, 어디로 보내는지 — LLM이 답할 컨텍스트가 없음. 운전원이 가장 익숙한 도구(Excel)로 한 번에 채우는 round-trip이 가장 실용적인 해결책.
갈래 5와의 차이: 갈래 5는 infer_field_instruments Excel(현장 계기 초안, 다운로드 전용)에 PID 정보를 합치는 것. 갈래 7은 PID 메타데이터를 사람이 채워 다시 시스템에 반영하는 round-trip — 편집 가능한 마스터 시트.
시트 구성 (장비 종류별 분리)
| 시트 | 자동 채워진 컬럼 | 사용자가 채울 컬럼 |
|---|---|---|
Tanks (T-XXX) |
tag_no, area, source_drawing | service, role(feed/buffer/product/waste), contents(PGMEA/HBM/...), capacity, notes |
Drums (D-XXX) |
위와 동일 | service, role, contents |
Filters (F-XXX) |
tag_no, area | service, medium, from_tag, to_tag |
Heat Exchangers (E-XXX) |
tag_no, area | service, hot_side, cold_side, duty |
Columns (C-XXX) |
tag_no, area | service, product, overhead, bottom |
Pumps (P-XXX) |
tag_no, area, mapped_experion_tag | service, driver(motor/turbine), from_tag, to_tag, power_kw |
Compressors / Fans |
tag_no, area | service, driver, power_kw |
Cooling Towers |
tag_no, area | service, capacity |
Manual Valves (BV/GV/XV) |
tag_no, area | service, normal_position(open/closed), purpose |
Pipes (LineNo) |
service, fluid, size, spec, insul (이미 파싱됨) | from_tag, to_tag (오직 이거만) |
Legend |
dropdown 후보 (role 종류, fluid 코드, position 등) | — |
Index |
시트별 완성도 (채워진 비율) | — |
Round-trip 흐름
[다운로드]
pid_equipment → 장비 종류별 그룹핑 → 시트별 분리 → Excel 생성
(자동 채운 컬럼 + 빈 컬럼 + dropdown legend)
↓
[운전원이 채움 (며칠~몇 주, 영역별 분할 가능)]
↓
[업로드]
Excel 파싱 → 검증 (dropdown 값, 필수 필드, 참조 tag_no 존재 여부)
→ pid_equipment에 신규 컬럼들(service, role, contents, from_tag, to_tag, …) UPDATE
→ 변경 diff 리포트 (몇 건 채워졌는지, 무효 값 몇 건)
→ (갈래 6 도입 후) tag stub 노트 frontmatter 자동 갱신
데이터 모델 확장
pid_equipment 테이블에 컬럼 추가:
ALTER TABLE pid_equipment
ADD COLUMN service TEXT, -- 운전원 입력 fluid/용도 (P=PROCESS와 별개로 자유 텍스트)
ADD COLUMN role TEXT, -- feed_tank, buffer_tank, waste_tank, transfer_pump, ...
ADD COLUMN contents TEXT, -- PGMEA, HBM, CITY_WATER, ...
ADD COLUMN from_tag TEXT, -- 흐름 상류 tag (수동 입력)
ADD COLUMN to_tag TEXT, -- 흐름 하류 tag
ADD COLUMN driver TEXT, -- motor / turbine / electric / steam
ADD COLUMN capacity TEXT, -- 자유 텍스트 (단위 포함)
ADD COLUMN power_kw NUMERIC,
ADD COLUMN user_notes TEXT, -- 운전원 자유 메모
ADD COLUMN metadata_filled_at TIMESTAMPTZ; -- 마지막 사용자 갱신 시각
갈래 5/6과의 관계 — 같은 그림의 다른 단계
| 단계 | 역할 | 갈래 |
|---|---|---|
| 자동 추출 | 뼈대 (모든 태그 자동 인벤토리) | PID 파서 (완료) |
| 자동 검증 Excel | mechanical/누락 자산 검출 (read-only) | 갈래 5 |
| 수기 보강 round-trip | 구조화 슬롯 일괄 채우기 (service/role/from-to) | 갈래 7 (이 항목) |
| 노트 자동 생성 | tag stub frontmatter에 갈래 7 데이터 자동 반영 | 갈래 6 Step 1 |
| 채팅 RAG 강화 | 위 모두 통합 검색 | 갈래 1+2+6 |
→ 갈래 7이 진짜 마지막 연결고리. 이게 없으면 갈래 6 stub의 frontmatter가 빈약하고, 채팅도 "T-201이 뭐 담는지" 답을 못 함.
트레이드오프
- (+) Excel은 운전원이 가장 자연스럽게 다루는 도구 — 마크다운 학습 비용 0
- (+) 한 번 다운로드받아 오프라인에서도 채울 수 있음
- (+) 시트별 분리로 "오늘은 펌프만, 내일은 탱크만" 같은 분할 작업 가능
- (+) dropdown legend로 데이터 일관성 자동 확보
- (−) Excel은 discrete batch — 동시에 여러 사람이 채우면 머지 충돌 위험. 한 번에 한 사람 권장
- (−) 다운로드 받은 파일이 오래되면 사이에 PID 재추출로 신규 tag 생긴 경우 머지 필요 — 업로드 시 "신규 tag는 이번 Excel에 없음" 경고
- (−) 한 번에 460건 다 채우라 하면 부담 → 영역별/종류별 분할 가이드 필요 ("이번 주는 6-1 area Pump만")
구현 (작업량)
| 단계 | 산출물 | 작업량 |
|---|---|---|
| DB 마이그레이션 | pid_equipment 신규 컬럼 ALTER + InitializeAsync DDL 갱신 |
0.3일 |
| 다운로드 엔드포인트 | GET /api/pid/metadata/excel — 시트별 분리 Excel 생성 (openpyxl) |
0.5일 |
| 업로드 엔드포인트 | POST /api/pid/metadata/excel — 파싱+검증+UPDATE+diff 리포트 |
1일 |
| UI (RAG 관리 또는 P&ID 탭) | 다운로드/업로드 버튼 + 진행률 + diff 표시 | 0.5일 |
| Legend dropdown 사전 | role/contents/driver 등 유효값 정의 + 운영 후 확장 가능하게 | 0.2일 |
| 합계 | 2.5일 |
의존성
- 갈래 1·5와 독립적으로 진행 가능
- 갈래 6보다 먼저 끝나야 stub frontmatter가 풍부해짐 → Phase B 또는 Phase C 초반에 진행 권장
갈래 8 — LineNo 파생 정보 컬럼 추가 (작지만 모든 갈래에 가치 전파)
배경: 현업 통찰 — 운영 부서는 LineNo(P-10138, 16456 등 시공·단관 제작용 번호)로 파이프를 부르지 않음. 가치 있는 건 거기서 파생되는 {service, fluid, size, material, flange_rating, insulation}. LineNo 자체는 시공·정비 참조용으로 보존하되, 파생 정보를 별도 컬럼으로 저장해야 운영 검색·통계·일관성 검증이 가능해짐.
현재 상태: _parse_pid_lineno가 MCP 응답에 7개 필드를 다 담고 있지만, C# 측이 line_number 하나만 DB에 저장하고 나머지는 버리고 있음. 추출은 되는데 활용이 안 됨.
구현
-- pid_equipment 컬럼 추가 (line_number는 그대로 유지)
ALTER TABLE pid_equipment
ADD COLUMN service_code TEXT, -- 'P', 'CWS', 'ST', 'VG', ...
ADD COLUMN fluid_name TEXT, -- 'PROCESS FLUID', 'STEAM' (legend 변환)
ADD COLUMN pipe_size TEXT, -- '25A', '600A'
ADD COLUMN material_spec TEXT, -- 'F', 'S'
ADD COLUMN flange_rating INT, -- 1=150#, 2=300#
ADD COLUMN insul_code TEXT, -- 'A', 'B'
ADD COLUMN insul_thickness TEXT; -- 'H50', 'H100', 'E50', 'n'
장비/계기 행은 이 컬럼들이 NULL — 정상. 한 테이블 유지, 정규화 분리 안 함.
변경 파일
| 파일 | 변경 |
|---|---|
ExperionDbContext.InitializeAsync |
ALTER TABLE 7개 컬럼 추가 (또는 새 설치용 CREATE TABLE 갱신) |
PidEquipment 엔티티 |
7개 속성 + [Column("snake_case")] 매핑 |
ExtractedItem DTO |
7개 필드 추가 (PipeService/FluidName/PipeSize/...) |
PidExtractorService.ParseJson |
MCP 응답의 pipe 필드를 ExtractedItem에 매핑 |
PidExtractorService.ExtractFromStreamAsync |
save 시 7개 컬럼 채움 (pipe 행만, instrument/equipment는 null) |
MCP extract_pid_tags / parse_pid_dxf |
이미 7개 필드 응답 중 — 변경 불필요 |
활용은 자동으로 따라옴
컬럼만 채워지면 기존 갈래들이 즉시 더 풍부해짐:
- 갈래 1 채팅 검색: "CWS 25A 이상 라인", "스팀 H100 단열 라인" 같은 속성 조합 검색 즉시 가능
- 갈래 6 stub frontmatter: pipe 노트에
service: P,fluid: PROCESS FLUID,pipe_size: 25A,insul_thickness: H50자동 반영 → 노트가 빈약하지 않음 - 갈래 7 Pipes 시트: 자동 채워진 컬럼이 7개로 늘어남, 사용자는 from_tag/to_tag/서비스별칭만 채우면 됨
- (부수효과) 사양 분포 리포트, 일관성 검증 같은 분석이 가능해짐 — 필요할 때 별도 도구로 노출하면 됨 (지금은 컬럼만 추가)
작업량
| 단계 | 산출물 | 작업량 |
|---|---|---|
| DB 컬럼 추가 | ALTER TABLE + InitializeAsync DDL 갱신 | 0.2일 |
PidEquipment 엔티티 + [Column] 매핑 |
7개 속성 추가 | 0.1일 |
ExtractedItem 7개 필드 + ParseJson 매핑 |
DTO 확장 | 0.2일 |
PidExtractorService save 경로 |
7개 컬럼 INSERT | 0.2일 |
| 기존 460건 재추출 (또는 in-place UPDATE 스크립트) | truncate 후 재추출이 간단 | 0.1일 |
| 합계 | 0.8일 |
의존성
- 없음. 단독 진행 가능
- 갈래 1·6·7의 가치를 증폭시키므로 가장 먼저 배치 권장
갈래 9 — 추출 결과 저장·폐기 선택 UX (실수 방지)
배경: 현재 P&ID 추출 UI는 "추출 시작" 클릭 시 MCP 추출 → pid_equipment 즉시 INSERT가 자동으로 이뤄짐. 운전원이 실수로 다른 파일(다른 플랜트, 구버전 도면 등)을 추출해도 되돌릴 방법이 없음. TRUNCATE는 정상 데이터까지 날아가서 사용 불가. 추출 전/후에 사용자가 검토·취사선택할 수 있어야 함.
결정 보류: 아래 3개 옵션 중 어느 방향으로 갈지 사용자 결정 필요.
옵션 비교
옵션 A — Dry-run + 저장 버튼 (사전 검토)
[추출 시작] → MCP 추출만 (DB 저장 X) → "미리보기 460건" 표시
├── [✅ DB에 저장] → INSERT 수행
└── [🗑️ 폐기] → 결과 버림
| 항목 | 내용 |
|---|---|
| 장점 | 가장 안전 — DB 들어가기 전 검토 가능. 운전원 의도 명확 ("이걸 저장할까?") |
| 단점 | UI 흐름 2단계로 늘어남. 결과를 서버 임시 캐시 또는 클라이언트 메모리에 보관 필요. 사용자가 검토 중 페이지 떠나면 데이터 잃음 |
| 작업량 | 약 1일 |
| 구현 | PidExtractorService.ExtractWithoutSaveAsync 추가, IMemoryCache 결과 보관, UI에 미리보기 + 저장/폐기 버튼 |
옵션 B — 자동 저장 + 즉시 취소 버튼 (사후 롤백)
[추출 시작] → MCP 추출 → DB 저장 (extraction_batch_id 부여)
→ "✅ 추출 완료: 460건" + [🗑️ 이번 추출 취소] 버튼
↓
batch_id WHERE 절로 일괄 삭제
| 항목 | 내용 |
|---|---|
| 장점 | 기존 UX 거의 그대로. 추출 이력 자체가 자동으로 남아 추후 분석 가능 |
| 단점 | 저장 후 후속 작업(confidence 수정 등)이 일어났으면 일괄 삭제가 그 작업까지 날림 → "최근 N분만 취소 가능" 같은 가드 필요. 다른 사용자가 잠깐 잘못된 데이터 볼 수 있음 |
| 작업량 | 약 0.5일 |
| 구현 | pid_equipment.extraction_batch_id (UUID) 컬럼 추가, 추출 시 부여, UI에 "이번 추출 취소" 버튼 + 시간 가드 |
옵션 C — A + 영구 batch_id 보존 (절충)
[추출 시작] → MCP 추출 (DB 저장 X, staging 보관)
├── [저장] → batch_id와 함께 INSERT
│ → 이후에도 "추출 이력" 페이지에서 batch_id로 일괄 삭제 가능
└── [폐기] → staging만 버림
| 항목 | 내용 |
|---|---|
| 장점 | A의 안전성 + B의 사후 롤백 모두 확보. "추출 이력" 페이지에서 과거 batch 단위 관리 가능 |
| 단점 | 작업량 가장 큼. UI도 가장 복잡 (미리보기 + 저장 + 이력 관리) |
| 작업량 | 약 1.5~2일 |
| 구현 | 옵션 A + 옵션 B 합친 형태. staging 캐시 + batch_id 컬럼 + 이력 페이지 |
추천 (결정 보류 상태)
| 우선 고려 | 추천 옵션 |
|---|---|
| 안전성 우선 | 옵션 A |
| 작업량 최소 | 옵션 B |
| 장기 운영 (감사·이력) | 옵션 C |
운전원이 자주 추출하는 운영 환경이면 옵션 A의 사전 검토가 정신적 부담 적고 안전 — 기본 추천은 옵션 A. 단, "추출 이력 관리" 같은 요구가 미래에 나올 가능성이 크면 옵션 C가 미리 대응됨.
의존성
- 옵션 A:
IMemoryCache또는 클라이언트 세션 — 표준 ASP.NET Core 기능 - 옵션 B/C:
pid_equipment.extraction_batch_id컬럼 (UUID) — 갈래 8 컬럼 추가와 함께 ALTER 묶어 처리하면 효율적 - 어느 옵션이든 갈래 8과 같은 시점에 진행하면 마이그레이션 1번으로 끝낼 수 있음
결정 시점
- 갈래 1~5 진행 중 사용 패턴 보면서 결정 가능 (당장 결정 안 해도 됨)
- 단, 옵션 B/C를 선택한다면 갈래 8 마이그레이션 시
extraction_batch_id컬럼을 함께 추가하는 게 효율적 → 갈래 8 착수 전에 한 번 가볍게 결정 권장
추천 진행 순서
| 우선순위 | 항목 | 작업량 | 가치 | 의존성 |
|---|---|---|---|---|
| 0 | 갈래 8 (LineNo 파생 정보 컬럼 추가) | 0.8일 | 모든 갈래에 가치 전파 | 없음 |
| 0+ | 갈래 9 (추출 결과 저장/폐기 UX) | 0.5~2일 (옵션별) | 높음 (실수 방지) | 갈래 8과 함께 마이그레이션 묶기 권장 |
| 1 | 갈래 1 (MCP 도구 2개) | 0.5~1일 | 높음 | 갈래 8 권장 |
| 2 | 갈래 5 (infer ↔ pid_equipment 통합 Excel) | 0.5일 | 높음 | 없음 |
| 3 | 갈래 2 (이벤트 컨텍스트) | 0.5일 | 높음 | 갈래 1 |
| 4 | 갈래 7 (Excel round-trip으로 service/role 보강) | 2.5일 | 매우 높음 | 갈래 8 권장 |
| 5 | 갈래 6 (옵시디언 노트 부트스트랩 + 하이브리드 RAG) | 3.5일 | 매우 높음 (장기) | 갈래 1·7·8 권장 |
| 6 | 갈래 3a (트리뷰 UI) | 1~2일 | 중 | 없음 |
| 7 | 갈래 4 일부 (누락 검출 리포트 단독) | 0.5일 | 중 | 갈래 5와 중복 — 갈래 5에 통합 권장 |
| 보류 | 갈래 3b (그래프 시각화) | 큼 | 사용 패턴 보고 결정 | from-to 추출 |
| 보류 | 갈래 4 전체 (정비 일정·KB 통합) | 큼 | 큼 | equipment_registry, 정비 시스템 |
추천 흐름
Phase 0 (반나절, 0.8일) — 모든 갈래의 가치 증폭
0. 갈래 8: pid_equipment에 service/fluid/size/material/flange/insul 7개 컬럼 추가 + 460건 재추출
- 이후 모든 갈래가 더 풍부한 데이터로 동작
Phase A (이번 주, 1~2일) — 즉시 효과
- 갈래 1:
find_pid_equipment/get_pid_equipment_info추가 → 갈래 8로 채워진 7개 필드까지 검색·표시 - 갈래 5 병행:
infer_field_instruments에pid_equipmentjoin 추가 → Excel 초안에 mechanical/누락 자산 자동 포함
Phase B (Phase A 사용 패턴 본 뒤, 0.5일) — 정착 단계 3. 갈래 2: 알람·이벤트 컨텍스트에 PID 정보 자동 첨부 → 보고서 품질 향상
Phase C (2.5일 + 운전원 채움 기간) — 마지막 연결고리 4. 갈래 7: Excel round-trip 인프라 구축 → 운전원이 service/role/contents/from-to 채움
- 자동 컬럼이 갈래 8 덕분에 7개 더 풍부 → 사용자 부담 줄어듦
- 구축 자체는 2.5일이지만 운전원이 채우는 데 며칠~몇 주 걸림 (영역별 분할)
- 일부라도 채워지면 즉시 갈래 1·2의 답변 품질이 올라감 (T-201 → "PGMEA 원료 탱크" 답변 가능)
Phase D (Phase C 진행 중 병행, 3.5일) — 지식 자산화로 진화 5. 갈래 6: PID stub 자동 생성 → 옵시디언 노트 시스템 부트스트랩 → 하이브리드 RAG
- 갈래 8·7의 결과가 stub frontmatter로 자동 반영되어 빈약하지 않음
- 운전원이 채팅에서 노트 작성 습관 들이면 시간이 갈수록 그래프가 자라남
- 장기적으로는 이 갈래가 시스템의 핵심 자산 — PID/Experion은 자동 입력 소스, 노트는 사람의 운영 지식 저장소
Phase E (필요해질 때) — 확장 6. 갈래 3a: 시각적 인벤토리 필요해지면 트리뷰 UI 작업 7. 갈래 4 전체 또는 갈래 3b: 정비 시스템 연동/그래프 시각화 등은 실제 운영 요구가 명확해진 시점에 착수
우선순위 배치 근거
- 갈래 8 최우선: 0.8일 작업으로 갈래 1·6·7 모두의 데이터 가치를 증폭. ROI 극단적으로 높음. 다른 모든 작업 전에 끝내는 게 합리적
- 갈래 5 > 갈래 4: 갈래 4의 핵심 산출물(양방향 차집합 리포트)이 갈래 5의 Excel 시트로 자연스럽게 포함됨. 운전원이 이미 익숙한 UX 위에 얹는 거라 학습 비용 0
- 갈래 7 > 갈래 6: 갈래 6 stub의 frontmatter는 갈래 7의 결과(service/role/contents)로 채워질 때 비로소 가치가 있음. 갈래 7 없이 갈래 6만 가면 빈 anchor만 잔뜩
- 갈래 7 > 갈래 3a: service/role이 채워지지 않은 상태에서 시각화는 "이름만 있는 그림" — 우선 의미를 채워야 함
- 갈래 6은 갈래 1·2·7·8 이후가 적기: 채팅에서 PID 데이터 활용 패턴이 나오고 메타데이터가 채워진 뒤라야 노트 시스템이 의미 있음
결정 필요 항목
- 갈래 8 즉시 착수 여부 —
pid_equipment7개 컬럼 추가 + 460건 재추출 (0.8일, ROI 최고) - 갈래 9 옵션 선택 — A(dry-run, 1일) / B(자동저장+취소, 0.5일) / C(절충, 1.5~2일) 중 하나 선택. 갈래 8 착수 전 결정 권장 (B/C면
extraction_batch_id컬럼을 갈래 8 마이그레이션에 함께 묶음) - 갈래 1 즉시 착수 여부 —
find_pid_equipment/get_pid_equipment_infoMCP 도구 추가 - 갈래 5 즉시 착수 여부 —
infer_field_instruments에pid_equipmentLEFT JOIN + 별도 시트 추가 - 갈래 2 진행 여부 — Phase A 정착 후
- 갈래 7 데이터 모델 확정 —
pid_equipment컬럼 추가 항목(service/role/contents/from_tag/to_tag/driver/capacity/power_kw/user_notes) 확인 - 갈래 7 legend dropdown 사전 시드값 — role/contents/driver 유효값 누가 정의
- 갈래 7 운전원 채우기 가이드 — 영역별 분할 방식(어떤 area부터?)
- 갈래 6 Step 1·2 일정 — PID stub 생성기 + 머지 보존 로직 (갈래 8·7 컬럼이 stub frontmatter로 흐르도록 같이 설계)
- 갈래 6 Step 5 (그래프 1-hop RAG) —
search_kb수정 시점 확정 필요 - 갈래 6 저진입 UX (채팅 답변 → 노트 저장 버튼) — UI 작업 일정
- 갈래 3a 트리뷰 UI 작업 일정 — 갈래 7 보강 데이터가 채워진 뒤가 효과적
- 갈래 4 단독 누락 검출 리포트 — 갈래 5에 흡수할지, 별도 페이지로 만들지
잔여 데이터 정합성 이슈
- 중복 추출: 현재 460건 중 동일 tag_no가 2번씩 들어간 행 다수 발견 (예: PSV-10101이 2회). DXF에서 같은 텍스트가 여러 위치에 그려져서 발생. unique index 또는 (tag_no, pid_drawing_no) 복합키로 해결 필요.
- pid_drawing_no NULL: 현재 모든 행 NULL. 도면 파일명을 자동 채우거나 사용자 입력 받도록 보강 필요 — 갈래 4 누락 검출에 도면 단위 추적 필요할 때.
- prefix 오분류: PFD, SP, SC, TR 등 도면 라벨/약어가 instrument로 잘못 분류되는 케이스 —
_PID_TAG_RE또는_classify_pid_tag에 예외 사전 추가 필요.