389 lines
19 KiB
Markdown
389 lines
19 KiB
Markdown
# ExperionCrawler 코드 이슈 목록
|
|
> 생성일: 2026-04-26 | 분석 모델: GLM-4.7-Flash
|
|
|
|
## 요약 (2026-04-26 검수 완료)
|
|
- HIGH: 6건 → 전체 fixed
|
|
- MED: 8건 → fixed 5 / wont-fix 1 / needs-review 2
|
|
- LOW: 5건 → wont-fix 5
|
|
|
|
> **아키텍처 노트**: ExperionHypertableController(#3, #4)와 관련 DbContext 메서드는 레거시 관리 도구입니다.
|
|
> 앱 코어 경로는 `history_table`을 직접 조회(time_bucket 미사용)하도록 변경되어 있으며,
|
|
> 이 컨트롤러는 history_table → TimescaleDB hypertable 전환이 필요할 때를 위한 one-time 관리 UI로 보존합니다.
|
|
|
|
## 이슈 목록
|
|
|
|
| # | 파일 | 라인 | 심각도 | 분류 | 문제 설명 | 수정 방향 | 상태 |
|
|
|---|------|------|--------|------|-----------|-----------|------|
|
|
| 1 | src/Infrastructure/OpcUa/ExperionRealtimeService.cs | 101-122 | HIGH | bug | StartAsync 재진입 시 File.ReadAllTextAsync 예외가 발생해도 무시 - 실행 방해 가능성 | _restarting 재진입 플래그로 방지 | fixed |
|
|
| 2 | src/Core/Application/Services/TextToSqlService.cs | 587-602 | HIGH | security | CheckTagExistsAsync에서 예외 무시 후 true 반환 → SQL injection 우회 가능성 | 예외 로깅 후 false 반환하도록 수정 | fixed |
|
|
| 3 | src/Infrastructure/Database/ExperionDbContext.cs | 177-208 | HIGH | security | CreateHistoryHypertableIfNotExistsAsync에서 SQL interpolation 사용 - SQL injection 가능성 | NpgsqlParameter를 사용한 parameterized query로 변경 — ※ 레거시 관리 도구 (앱 시작 시 미호출, UI 수동 트리거 전용) | fixed |
|
|
| 4 | src/Web/Controllers/ExperionHypertableController.cs | 595 | HIGH | security | Create 메서드에서 직접 user input을 SQL 파라미터로 변환하지 않고 신뢰 - 파라미터 무결성 검증 부재 | 테이블명 allowlist + PostgreSQL 식별자 regex 검증 추가 — ※ 레거시 관리 도구 (history_table을 TimescaleDB hypertable로 전환하는 one-time 도구) | fixed |
|
|
| 5 | src/Web/Controllers/ExperionControllers.cs | 208-220 | HIGH | security | Import 메서드에서 파일 경로 조작 공격 가능성 | 파일명 경계 문자 검증 및 허용 문자 제한 추가 | fixed |
|
|
| 6 | src/Infrastructure/OpcUa/ExperionOpcServerService.cs | 278-288 | HIGH | quality | Dispose()에서 catch 블록이 예외를 무시 - 리소스 정리 실패 감지 불가 | 예외 로깅 후 실패 상태 반환하도록 수정 | fixed |
|
|
| 7 | src/Infrastructure/OpcUa/ExperionOpcServerService.cs | 291 | HIGH | quality | DisposeAsync()에서 예외를 무시하고 리소스 정리만 수행 - 행위 불일치 | 072d0c9에서 예외 로깅 추가 완료 | fixed |
|
|
| 8 | src/Infrastructure/OpcUa/ExperionOpcClient.cs | 519 | MED | quality | DisposeSessionAsync에서 await session.CloseAsync() 후 session.Dispose()가 여러 번 호출될 가능성 | e7409f7에서 _sessionClosedFlags ConcurrentDictionary 플래그 추가 완료 | fixed |
|
|
| 9 | src/Core/Application/Services/TextToSqlService.cs | 658 | MED | security | AnalyzeAsync에서 직접 입력을 SQL에 삽입 - SQL 인젝션 우회 가능성 | 544b257+dd6ff78에서 parameterized query 완료 | fixed |
|
|
| 10 | src/Core/Application/Services/SqlValidator.cs | 104 | MED | security | ";" 이후 추가 구문을 차단하지만 무시하고 계속 진행 - 서브쿼리 내 주석 우회 가능성 | needs-review: AST 기반 검증 필요, 현재 패턴(`;\s*\w`, `/**/`, `--`) 조합은 실용적 방어 수준 | needs-review |
|
|
| 11 | src/Core/Application/Services/SqlValidator.cs | 114 | MED | quality | Regex.IsMatch(pattern, RegexOptions.Singleline)에서 모든 줄바꿈 문자를 포함 - 예상치 못한 패턴 검출 | wont-fix: `.`이 `\n`까지 매칭해야 멀티라인 SQL injection 차단 가능 — 보안상 올바름 | wont-fix |
|
|
| 12 | src/Core/Application/Services/KoreanTimeRangeExtractor.cs | 145 | MED | bug | TryKoreanDatePattern에서 2025년 1월 3일과 같은 과거 날짜 파싱 시 연도 추론 오류 | 테스트 없이 날짜 추론 로직 변경 불가 — 별도 단위 테스트 작성 후 수정 필요 | needs-review |
|
|
| 13 | src/Web/Controllers/TextToSqlController.cs | 102-131 | MED | quality | QueryHistoryInterval 예외 처리에서 모든 예외를 Ok()로 반환 + _logger 필드 누락 | 500 상태코드 반환 + ILogger 주입 추가 | fixed |
|
|
| 14 | src/Infrastructure/OpcUa/ExperionOpcServerNodeManager.cs | 101-110 | LOW | perf | UpdateNodeValue이 Navigate에서 Lock 사용 - high-frequency 호출 시 성능 저하 가능성 | wont-fix: OPC UA SDK CustomNodeManager2.Lock 패턴 — SDK 요구사항 | wont-fix |
|
|
| 15 | src/Web/Program.cs | 72-73 | LOW | security | CORS가 AllowAnyOrigin() - SameSite cookie 문제 및 CSRF 공격 노출 | wont-fix: 내부망 전용 도구 — 배포 구성에서 처리 | wont-fix |
|
|
| 16 | src/Web/Program.cs | 32-33 | LOW | quality | DbContext 사용 시 connection pooling 설정 미사용 - 포맷팅 불일치 (UseNpgsql) | wont-fix: Npgsql 기본 connection pool 내장, 별도 설정 불필요 | wont-fix |
|
|
| 17 | src/Infrastructure/OpcUa/ExperionOpcClient.cs | 367-369 | LOW | performance | DataType 배치 읽기 실패 시 Unknown 반환 - 실패 감지 및 재시도 메커니즘 부재 | wont-fix: OPC UA 재연결 로직이 ExperionRealtimeService에 이미 존재 | wont-fix |
|
|
| 18 | src/Infrastructure/OpcUa/ExperionOpcClient.cs | 519 | LOW | quality | CloseAsync() 실패 후 무시하고 Dispose() - 리소스 누수 감지 불가 | wont-fix: #8(e7409f7)에서 _sessionClosedFlags 추가로 중복 정리 방지 완료 | wont-fix |
|
|
| 19 | src/Core/Application/DTOs/TextToSqlDtos.cs | 21 | LOW | bug | Interval 기본값이 "5 min"이지만 코드에서는 "1 minute" 사용 - 호환성 문제 가능성 | wont-fix: "5 min"은 DetermineTimeBucketFromInterval에서 "minute"로 정상 매핑됨 — 기능 일치 | wont-fix |
|
|
| 20 | src/Core/Application/Interfaces/IExperionServices.cs | 181 | LOW | quality | LiveValueUpdate 표현으로 readonly record 사용 - 멀티스레드 환경에서 값 변경 감지 불가능 | wont-fix: ConcurrentDictionary 값으로 record 적합, volatile 불필요 | wont-fix |
|
|
| 21 | P&ID_병렬LLM_아키텍처_개선안_v2-코딩.md | - | HIGH | architecture | 기존 `mcp-server/pipeline/mapper.py`와 아키텍처 불일치 | pending |
|
|
| 22 | mcp-server/pipeline/topology.py | - | HIGH | missing | R-tree 공간 인덱스 구현 누락 | pending |
|
|
| 23 | mcp-server/run_parallel_extract.sh | - | HIGH | reliability | 병렬 실행 시 실패 프로세스 감지 로직 부재 | pending |
|
|
| 24 | mcp-server/pipeline/mapper.py | - | MED | quality | GPU 자원 활용 전략 검증 부족 | pending |
|
|
| 25 | mcp-server/pipeline/merge_results.py | - | MED | quality | 결과 병합 시 태그 중복 제거 로직 미검증 | pending |
|
|
|
|
---
|
|
|
|
## 상세 분석
|
|
|
|
### HIGH 우선순위 이슈
|
|
|
|
**#1 ExperionRealtimeService.cs:120** - 재진입 예외 처리 누락
|
|
```csharp
|
|
if (cfg != null)
|
|
{
|
|
_logger.LogInformation("[Realtime] 자동 재시작 플래그 감지 — 구독 자동 시작");
|
|
await StartAsync(cfg); // 재귀 호출 시 예외 발생 시 Unknown
|
|
}
|
|
```
|
|
**문제**: 재진입 시 파일 읽기 예외가 발생해도 무시됨
|
|
**수정**: 예외 로깅 후 safe fallback 처리 추가
|
|
|
|
**#2 TextToSqlService.cs:601** - 예외 무시 → SQL injection 위험
|
|
```csharp
|
|
catch
|
|
{
|
|
// 확인 실패 시 true 반환 (쿼리 실행 시 에러 처리)
|
|
return true;
|
|
}
|
|
```
|
|
**문제**: 태그 존재 여부 확인 실패 시 억지로 true 반환 → 태그가 없는 데이터 조회 → SQL injection 우회될 수 있음
|
|
**수정**: 예외 로깅 후 false 반환
|
|
|
|
**#3 ExperionDbContext.cs:216** - SQL interpolation
|
|
```csharp
|
|
await _ctx.Database.ExecuteSqlRawAsync(
|
|
$"SELECT create_hypertable('{tableName}', '{timeColumn}'::text, ...)");
|
|
```
|
|
**문제**: Interpolated string 사용 → SQL injection 위험
|
|
**수정**: NpgsqlParameter 사용 또는 매우 엄격한 식별자 검증
|
|
|
|
**#4 ExperionHypertableController.cs:595** - 파라미터 검증 없음
|
|
```csharp
|
|
var dbSvc = scope.ServiceProvider.GetRequiredService<IExperionDbService>();
|
|
await dbSvc.CreateHypertableAsync(createRequest);
|
|
```
|
|
**문제**: 요청 DTO는 검증되었지만 클라이언트는 JSON 생성자를 통해 직접 생성 가능 → 위조 요청 가능
|
|
**수정**: 클라이언트 검증 지원 또는 서버 측 DTO 검증 강화
|
|
|
|
**#5 ExperionControllers.cs:212-213** - 파일 경로 조작
|
|
```csharp
|
|
if (!string.IsNullOrEmpty(dto.ServerHostName) &&
|
|
dto.FileName.StartsWith(dto.ServerHostName, StringComparison.OrdinalIgnoreCase))
|
|
```
|
|
**문제**: 파일 이름만 path traversal 검증 → 무의미한 파일 접근 방어 불가
|
|
**수정**: 전체 경로 점검 및 확장자 하드코딩
|
|
|
|
**#6 ExperionOpcServerService.cs:286** - 예외 무시
|
|
```csharp
|
|
catch { /* ignore */ }
|
|
```
|
|
**문제**: 리소스 정리 중 예외가 무시되어 문제 감지 불가
|
|
**수정**: 최소한 로그 기록 필요
|
|
|
|
### MED 우선순위 이슈
|
|
|
|
**#8 ExperionOpcClient.cs:519** - 세션 중복 해제
|
|
```csharp
|
|
private static async Task DisposeSessionAsync(ISession? session)
|
|
{
|
|
if (session == null) return;
|
|
try { await session.CloseAsync(); } catch { /* ignore */ }
|
|
session.Dispose(); // CloseAsync 실패 후에도 Dispose 호출
|
|
}
|
|
```
|
|
**문제**: 이미 close된 session에서 Dispose()가 호출될 경우 DuplicateOperationException 발생 가능
|
|
**수정**: isClosed 플래그 관리
|
|
|
|
**#9 TextToSqlService.cs:658** - SQL injection
|
|
```csharp
|
|
WHERE tagname = '{escapedTagName}' ...
|
|
```
|
|
**문제**: 단순히 작은따옴표 이스케이프만 수행
|
|
**수정**: PostgreSQL parameterized query 사용
|
|
|
|
**#12 KoreanTimeRangeExtractor.cs:145** - 날짜 추론 오류
|
|
```csharp
|
|
if (dt > KstToday.AddDays(1)) dt = dt.AddYears(-1);
|
|
```
|
|
**문제**: 2025년 1월 3일 (현재가 2026년 4월 26일)인 경우 올해가 아닌 작년으로 처리 → 날짜 추론 오류
|
|
**수정**: 경과 시간 계산 후 올바른 연도 계산
|
|
|
|
### LOW 우선순위 이슈
|
|
|
|
**#15 Program.cs:72-73** - CORS AllowAnyOrigin
|
|
```csharp
|
|
opt.AddDefaultPolicy(p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
|
|
```
|
|
**문제**: SameSite cookie 문제 및 CSRF 공격 노출 가능성
|
|
**수정**: Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy 헤더 추가 또는 커스텀 Origin 정책
|
|
|
|
---
|
|
|
|
## 범주별 이슈 집계
|
|
|
|
| 분류 | HIGH | MED | LOW |
|
|
|------|------|-----|-----|
|
|
| bug | 1 | 1 | 0 |
|
|
| security | 4 | 2 | 0 |
|
|
| quality | 1 | 3 | 3 |
|
|
| perf | 0 | 0 | 2 |
|
|
| tổng | 6 | 8 | 5 |
|
|
|
|
---
|
|
|
|
## P&ID_병렬LLM_아키텍처_개선안_v2-코딩.md 감독자 평가 (2026-05-02)
|
|
|
|
### 개요
|
|
문서 `P&ID_병렬LLM_아키텍처_개선안_v2-코딩.md`의 프로그램이 발생시킬 수 있는 문제점을 감독자 입장에서 평가합니다.
|
|
|
|
### 평가 결과 요약
|
|
|
|
| # | 심각도 | 분류 | 내용 | 상태 |
|
|
|---|--------|------|------|------|
|
|
| 21 | HIGH | architecture | 기존 `mcp-server/pipeline/mapper.py`와 아키텍처 불일치 | pending |
|
|
| 22 | HIGH | missing | R-tree 공간 인덱스 구현 누락 (topology.py) | pending |
|
|
| 23 | HIGH | reliability | 병렬 실행 시 실패 프로세스 감지 로직 부재 | pending |
|
|
| 24 | MED | quality | GPU 자원 활용 전략 검증 부족 | pending |
|
|
| 25 | MED | quality | 결과 병합 시 태그 중복 제거 로직 미검증 | pending |
|
|
|
|
---
|
|
|
|
### 상세 분석
|
|
|
|
#### #21: 아키텍처 불일치 (HIGH) - pending
|
|
|
|
**문제 설명:**
|
|
문서는 4개 별도 Python 프로그램(`pid_extractor_text.py`, `pid_extractor_valve.py`, `pid_extractor_equipment.py`, `pid_extractor_system.py`)을 제안하지만, 현재 프로젝트는 `mcp-server/pipeline/mapper.py`에서 `asyncio.gather()`를 사용한 비동기 병렬 처리를 이미 구현하고 있습니다.
|
|
|
|
**현재 구조 (`mcp-server/pipeline/mapper.py`):**
|
|
```python
|
|
async def extract_transmitters(self, node_ids: List[str]) -> Dict[str, MappingResult]:
|
|
prompt = "당신은 계측기 전문 엔지니어입니다..."
|
|
tasks = [self._resolve_generic(nid, prompt) for nid in node_ids]
|
|
results = await asyncio.gather(*tasks) # 이미 병렬 처리
|
|
return dict(zip(node_ids, results))
|
|
```
|
|
|
|
**문서 제안 구조:**
|
|
```python
|
|
# 4개 별도 프로그램 실행
|
|
python -m pipeline.pid_extractor_text ... &
|
|
python -m pipeline.pid_extractor_valve ... &
|
|
python -m pipeline.pid_extractor_equipment ... &
|
|
python -m pipeline.pid_extractor_system ... &
|
|
```
|
|
|
|
**권장 조치:**
|
|
- 기존 `mapper.py` 구조를 유지하고, 문서 제안의 카테고리별 프롬프트 분리 아이디어만 채택
|
|
- 별도 프로그램 실행은 GPU 메모리 제한이 있을 경우에만 고려
|
|
|
|
---
|
|
|
|
#### #22: R-tree 공간 인덱스 구현 누락 (HIGH) - pending
|
|
|
|
**문제 설명:**
|
|
문서는 `topology.py`에 R-tree 공간 인덱스 도입을 제안하지만, 현재 `mcp-server/pipeline/topology.py`는 `_merge_nodes()` 메서드가 존재하지 않으며, O(n²) 병합 로직을 사용하고 있습니다.
|
|
|
|
**현재 구조 (`mcp-server/pipeline/topology.py`):**
|
|
```python
|
|
def build_graph(self):
|
|
# 1. 모든 객체를 노드로 추가
|
|
for item in self.data:
|
|
bbox_vals = item['bbox']
|
|
bbox_geom = box(bbox_vals['min_x'], ...)
|
|
self.G.add_node(item['entity_id'], ...)
|
|
|
|
# 2. 분산 추출된 태그 통합 및 노드 추가
|
|
for tag in self.all_tags:
|
|
bbox_vals = tag['bbox']
|
|
bbox_geom = box(bbox_vals['min_x'], ...)
|
|
self.G.add_node(tag['entity_id'], ...)
|
|
|
|
# 3. 태그-설비 논리적 연결
|
|
# 4. 배관 기반 물리적 연결
|
|
# NOTE: _merge_nodes() 메서드 없음
|
|
```
|
|
|
|
**문서 제안 구조:**
|
|
```python
|
|
def _build_spatial_index(self):
|
|
p = index.Property()
|
|
self.idx = index.Index(properties=p)
|
|
for i, item in enumerate(self.data):
|
|
bbox = item['bbox']
|
|
self.idx.insert(i, (bbox['min_x'], ...))
|
|
|
|
def _merge_nodes_spatial(self):
|
|
neighbors = list(self.idx.intersection((...))) # O(n log n)
|
|
```
|
|
|
|
**권장 조치:**
|
|
- 문서 제안의 R-tree 구현을 `topology.py`에 추가
|
|
- `pyproject.toml`에 `rtree = "^1.3.0"` 의존성 추가 필요
|
|
|
|
---
|
|
|
|
#### #23: 병렬 실행 시 실패 프로세스 감지 로직 부재 (HIGH) - pending
|
|
|
|
**문제 설명:**
|
|
문서의 `run_parallel_extract.sh` 스크립트는 `wait` 명령어만 사용하여 모든 프로세스 종료를 대기하지만, 실패한 프로세스 감지 로직이 없습니다.
|
|
|
|
**현재 스크립트 문제점:**
|
|
```bash
|
|
python -m pipeline.pid_extractor_text "$DXF_FILE" "$OUTPUT_DIR" &
|
|
python -m pipeline.pid_extractor_valve "$DXF_FILE" "$OUTPUT_DIR" &
|
|
python -m pipeline.pid_extractor_equipment "$DXF_FILE" "$OUTPUT_DIR" &
|
|
python -m pipeline.pid_extractor_system "$DXF_FILE" "$OUTPUT_DIR" &
|
|
|
|
wait # 실패 프로세스 감지 불가
|
|
|
|
# 결과 병합
|
|
python -m pipeline.merge_results "$OUTPUT_DIR" "$OUTPUT_DIR/merged_tags.json"
|
|
```
|
|
|
|
**문제 시나리오:**
|
|
1. `pid_extractor_text.py` 실행 중 GPU 메모리 부족으로 실패
|
|
2. `wait`는 실패 프로세스 종료를 기다리지만, 에러 메시지 무시
|
|
3. `merge_results.py`가 부분적인 결과 파일만 읽고 에러 발생
|
|
|
|
**권장 조치:**
|
|
```bash
|
|
#!/bin/bash
|
|
set -e # 첫 실패 시 스크립트 종료
|
|
|
|
# 프로세스 PID 저장
|
|
pids=()
|
|
|
|
python -m pipeline.pid_extractor_text "$DXF_FILE" "$OUTPUT_DIR" &
|
|
pids+=($!)
|
|
|
|
python -m pipeline.pid_extractor_valve "$DXF_FILE" "$OUTPUT_DIR" &
|
|
pids+=($!)
|
|
|
|
# ... 다른 프로세스들
|
|
|
|
# 각 프로세스 종료 상태 확인
|
|
for pid in "${pids[@]}"; do
|
|
if ! wait "$pid"; then
|
|
echo "ERROR: Process $pid failed"
|
|
exit 1
|
|
fi
|
|
done
|
|
```
|
|
|
|
---
|
|
|
|
#### #24: GPU 자원 활용 전략 검증 부족 (MED) - pending
|
|
|
|
**문제 설명:**
|
|
문서는 "vLLM의 GPU 할당 방식"을 설명하며 단일 프로세스는 단일 GPU만 사용한다고 가정하지만, vLLM의 실제 동작 방식은 다음과 같습니다:
|
|
|
|
**vLLM 실제 동작:**
|
|
- 단일 프로세스 내에서 여러 요청을 병렬 처리 가능
|
|
- `max_num_seqs` 및 `max_num_batched_tokens` 설정에 따라 자동 분산
|
|
- 병렬 프로세스 실행이 반드시 GPU 활용 향상으로 이어지지 않음
|
|
|
|
**문서 가정:**
|
|
```
|
|
단일 프로세스 → GPU 0만 사용
|
|
4개 병렬 프로세스 → GPU 0,1,2,3 각 100% 사용
|
|
```
|
|
|
|
**실제 가능성:**
|
|
- 단일 프로세스로도 `asyncio.gather()`를 사용하면 병렬 요청 처리 가능
|
|
- vLLM 서버가 GPU 메모리 및 토큰 제한을 자동 관리
|
|
|
|
**권장 조치:**
|
|
- 단일 프로세스 비동기 병렬 처리 성능 벤치마크 수행
|
|
- GPU 메모리 제한이 실제로 발생할 경우에만 병렬 프로세스 실행 고려
|
|
|
|
---
|
|
|
|
#### #25: 결과 병합 시 태그 중복 제거 로직 미검증 (MED) - pending
|
|
|
|
**문제 설명:**
|
|
`merge_results.py`는 `seen_tags` 집합만 사용하여 태그 중복을 제거하지만, 동일 태그명이 다른 카테고리에서 추출될 경우 문제 발생 가능.
|
|
|
|
**문제 시나리오:**
|
|
```json
|
|
// text_tags.json
|
|
[{"tagNo": "FICQ-101", "confidence": 0.95}]
|
|
|
|
// valve_tags.json
|
|
[{"tagNo": "FICQ-101", "confidence": 0.85}] // 동일 태그명, 다른 confidence
|
|
```
|
|
|
|
**현재 병합 로직:**
|
|
```python
|
|
seen_tags = set()
|
|
for filepath in glob.glob(f'{input_dir}/*_tags.json'):
|
|
with open(filepath, 'r') as f:
|
|
tags = json.load(f)
|
|
for tag in tags:
|
|
tag_no = tag.get('tagNo')
|
|
if tag_no and tag_no not in seen_tags:
|
|
seen_tags.add(tag_no)
|
|
all_tags.append(tag) # 첫 번째 발견된 태그만 추가
|
|
```
|
|
|
|
**문제:**
|
|
- `FICQ-101`이 TEXT와 VALVE 모두에서 추출된 경우, 첫 번째 발견된 태그만 유지
|
|
- confidence가 낮은 태그가 유지될 가능성
|
|
|
|
**권장 조치:**
|
|
```python
|
|
# 카테고리별로 태그를 구분하여 병합
|
|
from collections import defaultdict
|
|
|
|
category_tags = defaultdict(list)
|
|
for filepath in glob.glob(f'{input_dir}/*_tags.json'):
|
|
category = filepath.split('_tags.json')[0].split('/')[-1]
|
|
with open(filepath, 'r') as f:
|
|
tags = json.load(f)
|
|
for tag in tags:
|
|
tag_no = tag.get('tagNo')
|
|
if tag_no:
|
|
category_tags[tag_no].append((category, tag))
|
|
|
|
# 각 태그명에 대해 가장 높은 confidence 선택
|
|
all_tags = []
|
|
for tag_no, candidates in category_tags.items():
|
|
best = max(candidates, key=lambda x: x[1].get('confidence', 0))
|
|
all_tags.append(best[1])
|
|
```
|
|
|
|
---
|
|
|
|
### 총평
|
|
|
|
문서 `P&ID_병렬LLM_아키텍처_개선안_v2-코딩.md`는 병렬 처리 아이디어는 우수하지만, 다음과 같은 문제점이 있습니다:
|
|
|
|
1. **기존 구조와의 호환성 고려 부족**: `mcp-server/pipeline/mapper.py`의 기존 비동기 병렬 처리 구조를 무시
|
|
2. **R-tree 구현 누락**: `topology.py`에 R-tree 공간 인덱스가 구현되지 않음
|
|
3. **실패 처리 로직 부재**: 병렬 실행 시 실패 프로세스 감지 로직 없음
|
|
4. **GPU 활용 전략 검증 부족**: vLLM의 실제 동작 방식과 불일치 가능성
|
|
5. **병합 로직 미검증**: 태그 중복 제거 시 confidence 고려 부족
|
|
|
|
**권장 조치:**
|
|
- 문서 제안의 아이디어(카테고리별 프롬프트 분리, R-tree 공간 인덱스)는 채택하되, 기존 구조와의 호환성을 고려하여 수정
|
|
- 실패 처리 로직 및 병합 로직을 개선하여 프로덕션 환경에서 안정적으로 동작하도록 수정
|