Files
ExperionCrawler/dxf-graph/dxf-graph-checkby-gemma4.md
windpacer 7330711499 chore: 프로젝트 파일 구조 정리 - 루트 파일 폴더별 이동, 테스트/구버전 삭제
루트 파일 정리:
- DXF/P&ID 관련 → dxf-graph/
- fastTable 관련 → fastTable/
- plan/ → plans/ 통합 (최신 버전 유지)
- 테스트 출력 파일, 구버전 프로젝트 삭제
- 불필요한 루트 문서 삭제
2026-05-10 17:39:58 +09:00

7.8 KiB

MCP 서버 DXF Graph 로직 분석 보고서 (by Gemma 4)

1. DXF Graph 생성 파이프라인 흐름

전체 프로세스는 추출 \rightarrow 위상 구축 \rightarrow 매핑 \rightarrow 분석의 4단계로 구성됨.

  1. PidGeometricExtractor (extractor.py):
    • DXF 파일에서 TEXT, MTEXT, LINE, LWPOLYLINE, CIRCLE, ARC 엔티티 추출.
    • 각 엔티티의 Bounding Box(BBox) 및 좌표 정보 계산.
    • 결과를 기하학적 데이터 JSON으로 저장.
  2. PidTopologyBuilder (topology.py):
    • 추출된 엔티티를 NetworkX 그래프의 노드로 생성.
    • 태그-설비 연결: TEXT 노드와 가장 가까운 설비 노드를 associated_with 엣지로 연결.
    • 물리적 연결: LINE/LWPOLYLINE의 양 끝점(Endpoints)이 설비 BBox 내에 있거나 임계값 이내인 경우 pipe 엣지로 연결.
  3. IntelligentMapper (mapper.py):
    • 도면의 텍스트 태그를 실제 시스템 태그(Experion Tags)와 매핑.
    • RapidFuzz로 1차 후보를 뽑고, LLM(Qwen3)에 주변 위상 맥락(Neighbors)을 제공하여 최종 매핑 결정.
  4. PidAnalysisEngine (analyzer.py):
    • 구축된 그래프와 매핑 데이터를 로드.
    • flow_directionvalve_status를 고려하여 장애 전파 경로(Impact Analysis) 분석.

2. 주요 문제점 및 취약점 분석

🔴 심각도: HIGH (정확도 및 신뢰성 문제)

  • 단순 거리 기반 태그 매핑 (_find_nearest_equipment):
    • 문제: 단순히 가장 가까운 설비를 찾으므로, 도면이 밀집된 구역에서 엉뚱한 설비에 태그가 할당될 가능성이 매우 높음.
    • 영향: 잘못된 태그 매핑 \rightarrow 잘못된 영향도 분석 결과 도출.
  • 단순화된 배관 방향성 추론 (build_graph):
    • 문제: connected_nodes[0] \rightarrow connected_nodes[1] 식으로 단순히 발견 순서대로 방향을 설정함. 실제 공정 흐름(Flow)을 전혀 반영하지 못함.
    • 영향: analyzer.py에서 flow_direction을 기반으로 분석하지만, 데이터 생성 단계에서 이미 무작위 방향성이 부여되어 분석 결과가 무의미함.

🟠 심각도: MED (로직 결함 및 누락)

  • 배관-설비 연결의 한계:
    • 문제: LINE의 양 끝점만 체크함. 배관이 설비 BBox를 관통하거나, 중간에 꺾이는 LWPOLYLINE의 경우 끝점이 설비 밖에 있으면 연결이 누락됨.
    • 영향: 그래프의 단절(Disconnected Components) 발생 \rightarrow 영향도 분석 범위 축소.
  • LLM 매핑의 컨텍스트 부족:
    • 문제: get_node_context가 단순히 연결된 노드의 값만 나열함. 설비의 종류, 계층 구조, 도면 내 상대적 위치 등의 풍부한 정보가 부족함.
    • 영향: 매핑 정확도 저하.

🟡 심각도: LOW (유지보수 및 성능)

  • 하드코딩된 임계값:
    • 문제: dist_threshold=50.0, tag_threshold=100.0 등이 하드코딩되어 있음. 도면의 스케일(Scale)이 달라지면 작동하지 않음.
    • 영향: 도면마다 설정값을 수동으로 조정해야 하는 번거로움.
  • 에러 처리 미흡:
    • 문제: extractor.py 등에서 try-exceptprint만 수행하고 계속 진행함.
    • 영향: 일부 엔티티 누락 시 원인 파악이 어려움.

3. 개선 방향 제안

  1. 위상 기반 태그 매핑: 단순 거리 \rightarrow (거리 + 텍스트 방향 + 인접 배관 연결성)을 종합한 가중치 모델 도입.
  2. 흐름 방향 추론 고도화:
    • 체크밸브, 펌프 등 방향성이 명확한 심볼을 기준으로 흐름 방향 전파(Propagation).
    • LLM에게 배관 연결 리스트를 주고 공정 상식에 기반한 방향성 추론 요청.
  3. 기하학적 연결 검사 강화: Point.distance 대신 LineString.intersects(Box) 또는 LineString.distance(Box)를 사용하여 관통/접촉 여부를 정밀하게 판별.
  4. 동적 스케일링: 도면의 전체 크기나 표준 심볼 크기를 기준으로 임계값을 자동 계산하는 로직 추가.

4. [추가 진단] End-to-End 프로세스 및 UI 반환 흐름 진단

diagnosis-checklist.md 규칙에 따라 UI부터 파이프라인, MCP 서버까지의 전체 호출 계층을 진단한 결과입니다.

호출 계층 지도 (Call Hierarchy)

UI (pid-viewer.js) \rightarrow Web API (PidGraphController.cs) \rightarrow Service (PidGraphService.cs) \rightarrow MCP Client (McpClient.cs) \rightarrow MCP Server (server.py) \rightarrow Worker (pid_worker.py) \rightarrow Pipeline (extractor/topology/mapper) \rightarrow Storage (JSON files) \rightarrow UI (Polling/Fetch)

🔴 HIGH: 런타임 및 데이터 무결성 위험

  1. 상태 관리의 휘발성 (In-Memory Store)

    • 문제: PidGraphController.cs:17에서 _statusStorestatic ConcurrentDictionary로 관리함.
    • 영향: 서버 재시작 시 모든 진행 중인 taskId가 소멸됨. UI(pid-viewer.js)는 localStoragetaskId를 저장하고 복구를 시도하지만, 서버에 데이터가 없어 NotFound 발생 및 사용자 혼란 초래.
    • 수정: Redis 또는 DB 기반의 상태 저장소 도입 필요.
  2. One-Shot 워커의 강제 종료 타이밍 (Race Condition)

    • 문제: pid_worker.py:430_schedule_shutdownasyncio.sleep(0.5)os.kill을 수행함.
    • 영향: 네트워크 지연이나 응답 크기가 클 경우, HTTP 응답이 클라이언트에 완전히 전달되기 전에 프로세스가 종료되어 Connection Reset 또는 Empty Response 발생 가능성 높음.
    • 수정: FastAPI의 BackgroundTasks를 사용하여 응답 전송 완료 후 종료하거나, MCP 서버가 워커의 종료를 확인하는 핸드셰이크 메커니즘 도입.

🟠 MED: 동시성 및 리소스 효율성

  1. P&ID 워커의 직렬화 병목 (Semaphore)

    • 문제: server.py:1455 등에서 _pid_sem = asyncio.Semaphore(1)을 사용하여 모든 P&ID 관련 도구를 전역적으로 직렬화함.
    • 영향: 여러 사용자가 서로 다른 도면을 처리하려 해도 한 번에 하나의 요청만 처리 가능. 특히 build_pid_graph_parallel처럼 오래 걸리는 작업이 있을 때 전체 시스템 응답성 저하.
    • 수정: graph_id 또는 filepath 단위로 Lock을 세분화하여 서로 다른 도면 작업은 병렬로 처리 가능하게 개선.
  2. UI-서버 간의 비효율적 폴링 (Polling Overhead)

    • 문제: pid-viewer.js:70에서 1초 간격으로 /api/pidgraph/status/{taskId}를 호출함.
    • 영향: 작업 시간이 길어질 경우 불필요한 HTTP 요청이 누적되며, 서버 리소스 낭비.
    • 수정: WebSocket 또는 Server-Sent Events(SSE)를 도입하여 서버가 상태 변경 시 푸시하도록 변경.

🟡 LOW: 코드 구조 및 사용자 경험

  1. 하드코딩된 Graph ID (UI)

    • 문제: pid-viewer.js:342에서 graphId = "No-10_Plant_PID_graph.json"가 하드코딩되어 있음.
    • 영향: 다른 도면을 로드했을 때 영향도 분석 요청이 항상 특정 파일로 고정되어 잘못된 결과 반환.
    • 수정: pidLoadDrawing 시점에 서버로부터 받은 graphId를 전역 변수에 저장하고 이를 사용하도록 수정.
  2. 에러 응답 형식의 불일치

    • 문제: PidGraphController.csnew { error = ... } 형식을 사용하지만, MCP 서버/워커는 {"success": false, "error": ...} 형식을 사용함.
    • 영향: 프론트엔드에서 에러 처리 로직을 작성할 때 응답 구조에 따라 분기 처리가 복잡해짐.
    • 수정: 전사적인 공통 응답 DTO(Standard Response Format) 정의 및 적용.