Files
ExperionCrawler/.rooBackup/2026-05-05-113700/P&ID-재설계-plan-코딩계획.md
2026-05-08 17:22:10 +09:00

16 KiB

P&ID 재설계 - 코딩 계획 (독립 프로세스 병렬 아키텍처)

작성일: 2026-05-05 상태: 진행 중 목표: No-10_Plant_PID.dxf(28,819 엔티티) 처리 시 30분 타임아웃 해결 아키텍처: pid_worker.py(코디네이터) + 5개 독립 추출 프로세스


제안 아키텍처

┌─────────────────────────────────────────────────────────────────┐
│                    pid_worker.py (코디네이터)                      │
│                                                                 │
│  Phase 1: 도면 분할 + 기하 추출 (순차)                            │
│  ├─ extractor.split_drawings() → 9개 도면 영역                    │
│  └─ extractor.extract_and_save() → geo.json                     │
│                                                                 │
│  Phase 2: 전체 텍스트 1회 추출                                    │
│  └─ DXF에서 TEXT/MTEXT → full_text.txt (1회만 읽기)               │
│                                                                 │
│  Phase 3: 5개 독립 프로세스 병렬 실행 ← 진짜 병렬                  │
│  ├─ subprocess: pid_extract_sensor.py  → results/sensor.json     │
│  ├─ subprocess: pid_extract_valve.py   → results/valve.json      │
│  ├─ subprocess: pid_extract_system.py  → results/system.json     │
│  ├─ subprocess: pid_extract_gauge.py   → results/gauge.json      │
│  └─ subprocess: pid_extract_pump.py    → results/pump.json       │
│                                                                 │
│  Phase 4: pid_worker가 결과 파일 읽어서 통합                      │
│  ├─ 5개 JSON 파일 로드                                           │
│  ├─ 중복 제거 (tagNo 기준)                                        │
│  └─ 위상 그래프 빌드 + 태그 매핑                                  │
│                                                                 │
│  Phase 5: 저장 + 응답                                            │
└─────────────────────────────────────────────────────────────────┘

기존 접근 vs 개선안 비교

항목 기존 (asyncio.gather) 개선안 (독립 프로세스)
vLLM 요청 단일 프로세스 → 단일 GPU 5개 프로세스 → 5개 GPU/큐 병렬
실제 병렬 가짜 (순차 처리) 진짜 동시 처리
메모리 pid_worker가 모든 텍스트 보유 각 프로세스 독립
실패 격리 하나 실패 → 전체 실패 하나 실패 → 나머지 결과 활용
테스트 통합 테스트만 가능 각 추출기 독립 테스트 가능

변경 대상 파일

파일 변경 내용
mcp-server/pipeline/extractor.py 도면 분할 로직 추가
mcp-server/worker/pid_worker.py 코디네이터 로직: 프로세스 관리, 결과 통합
mcp-server/worker/pid_extract_sensor.py 신규: 센서 전용 추출기 (독립 프로세스)
mcp-server/worker/pid_extract_valve.py 신규: 밸브 전용 추출기 (독립 프로세스)
mcp-server/worker/pid_extract_system.py 신규: 시스템 전용 추출기 (독립 프로세스)
mcp-server/worker/pid_extract_gauge.py 신규: 게이지 전용 추출기 (독립 프로세스)
mcp-server/worker/pid_extract_pump.py 신규: 펌프 전용 추출기 (독립 프로세스)
mcp-server/pipeline/mapper.py 기존 유지 (이미 배치 처리 구현됨)
mcp-server/pipeline/topology.py 기존 유지 (이미 SpatialGrid 구현됨)
mcp-server/pipeline/legend_parser.py 기존 유지 (이미 계측기 그룹 정의됨)

Phase 2: 독립 추출기 공통 템플릿

2-1. 공통 추출기 템플릿 작성

  • 파일: mcp-server/worker/pid_extract_template.py (신규)
  • 목표: 5개 추출기가 공유하는 공통 로직 템플릿
  • 작업 내용:
    • CLI 인자 파싱 (input_text, output_path, system_prompt)
    • vLLM HTTP 클라이언트 연결 (환경 변수 VLLM_ENDPOINT)
    • LLM 호출 → JSON 파싱 → 태그 목록 반환
    • max_tokens=65536 적용
    • finish_reason=length 복구 로직
    • 결과를 JSON 파일로 쓰기
  • 완료 기준: 템플릿 스크립트가 단독 실행 가능

2-2. 계측기 유형별 프롬프트 정의

  • 파일: 각 추출기 스크립트 상단에 상수로 정의
  • 목표: 각 유형별 전용 프롬프트
  • 프롬프트 목록:
    • _SENSOR_PROMPT — FT, FIT, LT, PT, TE, PG, LG, TG
    • _VALVE_PROMPT — FCV, TCV, LCV, PCV, XV, FV, LV, PV, TV
    • _SYSTEM_PROMPT — LI, PI, TI, FIQ, FICQ, TICA, PICA, LICA
    • _GAUGE_PROMPT — PG, TG, LG
    • _PUMP_PROMPT — P-10101, VP-10117, DP-10101 등 펌프
  • 완료 기준: 5개 프롬프트 상수 정의 완료

Phase 3: 5개 독립 추출기 스크립트 생성

3-1. pid_extract_sensor.py

  • 파일: mcp-server/worker/pid_extract_sensor.py (신규)
  • 목표: 센서/계측기 전용 추출
  • 작업 내용: Phase 2 템플릿 기반, _SENSOR_PROMPT 적용
  • 완료 기준: 단독 실행 시 sensor.json 출력

3-2. pid_extract_valve.py

  • 파일: mcp-server/worker/pid_extract_valve.py (신규)
  • 목표: 밸브 전용 추출
  • 작업 내용: Phase 2 템플릿 기반, _VALVE_PROMPT 적용
  • 완료 기준: 단독 실행 시 valve.json 출력

3-3. pid_extract_system.py

  • 파일: mcp-server/worker/pid_extract_system.py (신규)
  • 목표: 시스템/제어기 전용 추출
  • 작업 내용: Phase 2 템플릿 기반, _SYSTEM_PROMPT 적용
  • 완료 기준: 단독 실행 시 system.json 출력

3-4. pid_extract_gauge.py

  • 파일: mcp-server/worker/pid_extract_gauge.py (신규)
  • 목표: 게이지 전용 추출
  • 작업 내용: Phase 2 템플릿 기반, _GAUGE_PROMPT 적용
  • 완료 기준: 단독 실행 시 gauge.json 출력

3-5. pid_extract_pump.py

  • 파일: mcp-server/worker/pid_extract_pump.py (신규)
  • 목표: 펌프 전용 추출
  • 작업 내용: Phase 2 템플릿 기반, _PUMP_PROMPT 적용
  • 완료 기준: 단독 실행 시 pump.json 출력

3-6. 개별 추출기 테스트

  • 파일: test_individual_extractors.py (신규)
  • 목표: 5개 추출기 각각 단독 실행 테스트
  • 작업 내용:
    • full_text.txt를 각 추출기에 입력
    • 출력 JSON 검증 (schema, tagNo 필수 필드)
    • 처리 시간 측정
  • 완료 기준: 5개 모두 정상 출력, 각각 < 60초

Phase 4: pid_worker.py 코디네이터 리팩토링

4-1. 전체 텍스트 1회 추출 로직

  • 파일: mcp-server/worker/pid_worker.py
  • 목표: DXF에서 TEXT/MTEXT를 한 번만 읽어 full_text.txt 생성
  • 작업 내용:
    • ezdxf로 DXF 로드 → TEXT/MTEXT 엔티티 순회
    • 좌표 순 정렬 후 텍스트 연결
    • 결과를 임시 디렉토리의 full_text.txt에 저장
  • 완료 기준: full_text.txt 생성, 파일 크기 < 10MB

4-2. 5개 프로세스 병렬 실행 로직

  • 파일: mcp-server/worker/pid_worker.py
  • 목표: subprocess.Popen으로 5개 추출기 동시 실행
  • 작업 내용:
    • 임시 디렉토리 생성 (results/ 폴더)
    • 5개 스크립트 경로 확인 (동일 디렉토리)
    • subprocess.Popen()으로 5개 프로세스 동시 시작
    • proc.wait()로 전체 완료 대기 (timeout=300초)
    • 각 프로세스 returncode 확인 (실패 시 로깅 + 계속)
  • 완료 기준: 5개 프로세스 동시 실행, results/에 5개 JSON 생성

4-3. 결과 통합 + 중복 제거

  • 파일: mcp-server/worker/pid_worker.py
  • 목표: 5개 JSON 파일 로드 → tagNo 기준 중복 제거
  • 작업 내용:
    • results/*.json 로드 (실패한 파일 스킵)
    • tagNo를 키로 하는 딕셔너리에 병합 (첫 번째 우선)
    • 통합 통계 출력 (총 태그 수, 유형별 수)
  • 완료 기준: 중복 없는 통합 태그 목록 생성

4-4. 위상 그래프 빌드 + 태그 매핑 호출

  • 파일: mcp-server/worker/pid_worker.py
  • 목표: 기존 topology.py, mapper.py 호출
  • 작업 내용:
    • 통합 태그 목록을 IntelligentMapper에 전달
    • 매핑 결과를 TopologyBuilder에 전달
    • 그래프 JSON 생성
  • 완료 기준: 기존 API 호환 유지

4-5. _build_pid_graph_parallel() 전체 리팩토링

  • 파일: mcp-server/worker/pid_worker.py
  • 목표: 기존 함수를 새 아키텍처로 교체
  • 전체 흐름:
    1. 도면 분할 (extractor.split_drawings())
    2. 기하 추출 (extractor.extract_and_save() → geo.json)
    3. 전체 텍스트 1회 추출 (→ full_text.txt)
    4. 5개 프로세스 병렬 실행 (→ results/*.json)
    5. 결과 통합 + 중복 제거
    6. 위상 그래프 빌드 + 태그 매핑
    7. 저장 + 응답
    
  • 완료 기준: 전체 처리 < 5분, 기존 API 호환

Phase 1: 도면 분할 로직 (extractor.py)

1-1. 도면 분할 테스트 스크립트 작성

  • 파일: test_drawing_split.py (신규)
  • 목표: No-10_Plant_PID.dxf를 TITLE 레이어 LINE으로 분할하는 로직 프로토타입
  • 작업 내용:
    • ezdxf로 DXF 로드
    • TITLE 레이어의 LINE 엔티티 탐색
    • 수직 LINE(X 좌표가 일정)을 도면 경계로 감지
    • 각 도면별 X/Y 범위 출력
  • 검증: 9개 도면 영역이 올바르게 분리되는지 확인
  • 완료 기준: 콘솔에 9개 도면의 X/Y 범위가 출력됨

1-2. PidGeometricExtractor에 도면 분할 메서드 추가

  • 파일: mcp-server/pipeline/extractor.py
  • 목표: split_drawings() 메서드 추가
  • 작업 내용:
    • split_drawings() -> List[DrawingRegion] 메서드 추가
    • DrawingRegion 데이터클래스 정의 (drawing_no, x_min, x_max, y_min, y_max)
    • TITLE 레이어 LINE 기반 경계 감지
    • 레전드 페이지(X < 2000) 제외
    • FFD 페이지도 제외 (최상단 텍스트 기반)
  • 완료 기준: split_drawings() 호출 시 9개 DrawingRegion 반환

1-3. 영역별 추출 메서드 추가

  • 파일: mcp-server/pipeline/extractor.py
  • 목표: extract_region() 메서드 추가
  • 작업 내용:
    • extract_region(region: DrawingRegion) -> List[GeometricEntity] 메서드 추가
    • bbox가 region 범위 내에 있는 엔티티만 필터링
    • 기존 extract_and_save() 로직 재사용
  • 완료 기준: 각 도면별 엔티티 수 합계가 전체 엔티티 수와 일치

1-4. 도면 분할 통합 테스트

  • 파일: test_drawing_split.py
  • 목표: 전체 파이프라인 테스트
  • 작업 내용:
    • DXF 로드 → 분할 → 영역별 추출 → 결과 검증
    • 각 도면별 엔티티 수, 태그 수 확인
    • 처리 시간 측정
  • 완료 기준: 9개 도면 모두 정상 추출, 총 처리 시간 < 30초

Phase 5: 통합 테스트 + 검증

5-1. 전체 파이프라인 통합 테스트

  • 파일: test_full_pipeline_parallel.py (신규)
  • 목표: No-10_Plant_PID.dxf 전체 처리
  • 작업 내용:
    • _build_pid_graph_parallel() 호출
    • 각 단계별 시간 측정 (Phase 1~5)
    • 추출된 태그 수, 매핑 수, 그래프 노드/에지 수 확인
  • 완료 기준: 전체 처리 < 5분, 태그 추출 수 >= 기존

5-2. 실패 격리 테스트

  • 파일: test_failure_isolation.py (신규)
  • 목표: 일부 추출기 실패 시 나머지 결과 활용 확인
  • 작업 내용:
    • 하나의 추출기 스크립트 고의 실패 유도
    • 나머지 4개 결과로 정상 통합되는지 확인
    • 에러 로깅 확인
  • 완료 기준: 4/5 성공 시 정상 통합, 에러 로그 출력

5-3. 메모리 사용량 측정

  • 파일: test_memory_usage.py (신규)
  • 목표: 각 프로세스 메모리 독립성 확인
  • 작업 내용:
    • 5개 프로세스 각각 메모리 사용량 측정
    • pid_worker 메모리 사용량 확인 (텍스트 불보유)
  • 완료 기준: pid_worker 메모리 < 500MB, 각 추출기 < 1GB

실행 순서 및 의존성

Phase 1 (도면 분할)
  ├── 1-1 → 1-2 → 1-3 → 1-4  (순차)
  │
Phase 2 (공통 템플릿)
  ├── 2-1 → 2-2  (순차, Phase 1 완료 후)
  │
Phase 3 (5개 추출기 생성)
  ├── 3-1 ~ 3-5  (병렬 가능, Phase 2 완료 후)
  ├── 3-6        (순차, 3-1~3-5 완료 후)
  │
Phase 4 (pid_worker 코디네이터)
  ├── 4-1 → 4-2 → 4-3 → 4-4 → 4-5  (순차, Phase 3 완료 후)
  │
Phase 5 (통합 테스트)
  ├── 5-1 → 5-2 → 5-3  (순차, Phase 4 완료 후)

각 단계 완료 기준 및 예상 시간

단계 완료 기준 예상 시간
1-1 9개 도면 영역 콘솔 출력 30분
1-2 split_drawings() 9개 Region 반환 1시간
1-3 extract_region() 정상 동작 30분
1-4 전체 분할 테스트 통과 30분
2-1 템플릿 스크립트 단독 실행 가능 1시간
2-2 5개 프롬프트 상수 정의 30분
3-1~3-5 5개 추출기 각각 JSON 출력 각 30분 (병렬 가능)
3-6 5개 모두 단독 테스트 통과 30분
4-1 full_text.txt 생성 30분
4-2 5개 프로세스 동시 실행 1시간
4-3 중복 없는 통합 태그 목록 30분
4-4 그래프 빌드 + 매핑 호출 30분
4-5 전체 리팩토링 완료, API 호환 1시간
5-1 전체 처리 < 5분 1시간
5-2 실패 격리 테스트 통과 30분
5-3 메모리 사용량 확인 30분

총 예상 시간: 약 14시간


체크리스트

Phase 1: 도면 분할

  • 1-1. 도면 분할 테스트 스크립트 작성
  • 1-2. PidGeometricExtractor에 도면 분할 메서드 추가
  • 1-3. 영역별 추출 메서드 추가
  • 1-4. 도면 분할 통합 테스트

Phase 2: 독립 추출기 공통 템플릿

  • 2-1. 공통 추출기 템플릿 작성
  • 2-2. 계측기 유형별 프롬프트 정의

Phase 3: 5개 독립 추출기 스크립트

  • 3-1. pid_extract_sensor.py
  • 3-2. pid_extract_valve.py
  • 3-3. pid_extract_system.py
  • 3-4. pid_extract_gauge.py
  • 3-5. pid_extract_pump.py
  • 3-6. 개별 추출기 테스트

Phase 4: pid_worker.py 코디네이터

  • 4-1. 전체 텍스트 1회 추출 로직
  • 4-2. 5개 프로세스 병렬 실행 로직
  • 4-3. 결과 통합 + 중복 제거
  • 4-4. 위상 그래프 빌드 + 태그 매핑 호출
  • 4-5. _build_pid_graph_parallel() 전체 리팩토링

Phase 5: 통합 테스트

  • 5-1. 전체 파이프라인 통합 테스트
  • 5-2. 실패 격리 테스트
  • 5-3. 메모리 사용량 측정

주의 사항

  1. 백업 필수: 각 파일 수정 전 .rooBackup/에 백업
  2. diff 제시: 변경 내용 diff 형식으로 제시 후 확인
  3. 작은 단계: 각 단계를 독립적으로 완료하고 검증
  4. 테스트 우선: 테스트 스크립트 먼저 작성 후 구현
  5. 기존 코드 유지: topology.py, mapper.py는 기존 유지 (이미 잘 구현됨)
  6. 프로세스 간 통신: 파일 기반 (JSON)으로만 통신. 공유 메모리 금지
  7. 임시 파일 정리: 각 요청 완료 후 임시 디렉토리 삭제

다음 시작 시

  1. 이 파일의 체크리스트에서 첫 번째 미완료 항목부터 시작
  2. 각 단계 완료 시 체크리스트 업데이트
  3. 문제가 발생하면 해당 단계에서 중단하고 원인 분석
  4. 완료 기준을 충족해야 다음 단계로 진행