# gRPC 추론 API

> 백엔드와 추론 런타임 사이의 gRPC 계약 — 스트리밍 추론, 모델 로딩, 검증, 헬스, 로그 스트리밍.

백엔드와 Python 추론 런타임은 **50051 포트의 gRPC**(`protos/inference.proto`, 서비스
`InferenceService`)를 통해 통신합니다. 운영자가 이 API를 직접 호출하는 경우는 드뭅니다 —
백엔드가 클라이언트입니다 — 하지만 파이프라인을 디버깅하거나, 박스에서 커스텀 클라이언트를
통합하거나, 추론 로그를 읽을 때는 이 계약이 중요합니다.

채널은 설계상 **평문 HTTP/2(TLS 없음, 인증 없음)**입니다. 박스 내부 Docker 네트워크에
머무르도록 의도되었습니다. 50051 포트를 호스트나 신뢰할 수 있는 관리 네트워크 밖으로 절대
공개하지 마세요 — [보안](/ko/security/)을 참조하세요.

## 서비스 메서드

| RPC | 유형 | 목적 |
|---|---|---|
| `StreamInference` | 양방향 스트림 | 센서 윈도우 입력, 예측 출력 — 실시간 핫 패스 |
| `LoadModel` | 단항(unary) | ONNX 모델 검증 + 등록 + 핫스왑(무중단) |
| `ValidateModel` | 단항(unary) | 비변경 검사: 형상 + SHA-256, 아무것도 로드하지 않음 |
| `HealthCheck` | 단항(unary) | 서비스 상태 + CPU/GPU/메모리 메트릭 |
| `StreamLogs` | 서버 스트림 | 최소 레벨로 필터링한 추론 로그 테일링 |

### StreamInference

각 `InferenceRequest`는 `request_id`, `timestamp`(Unix epoch ms, 센서 샘플링 시점에 백엔드가
한 번만 찍고 변경 없이 그대로 반환됨 — 따라서 시계 동기화 문제가 없습니다), 평탄한 `features`
배열, 그리고 메타데이터 맵을 전달합니다.

각 `InferenceResponse`는 `predictions`와 `confidence_scores`, 서빙 중인
`model_id`/`model_version`, `inference_time_ms`, 그리고 세 개의 타임스탬프를 반환합니다:

| 필드 | 의미 |
|---|---|
| `window_start_timestamp` | 예측 윈도우에서 가장 오래된 입력 샘플 |
| `window_end_timestamp` | 가장 최신 입력 샘플 — 예측의 "기준 시점" |
| `emitted_at` | 방출 시점의 벽시계 시간. `emitted_at − window_end_timestamp`는 엔드투엔드 지연 시간의 근사값 |

모델 워밍업 중(슬라이딩 윈도우가 아직 가득 차지 않음)에는 응답이
`metadata["warming_up"] = "true"`를 전달하며, 백엔드는 이를 대시보드에서 숨깁니다.

### LoadModel

모델 버전을 등록하고 이중 버퍼링으로 실행 중인 세션에 핫스왑합니다 — 새 세션은 락 **바깥에서**
로드 및 워밍업된 뒤, 참조가 원자적으로 교체되므로 스트리밍이 결코 멈추지 않습니다.

- **콘텐츠 해시 기준 멱등성:** 동일한 SHA-256으로 같은 `(model_id, version)`을 다시 보내면
  성공 no-op입니다. *다른* SHA-256으로 같은 버전을 보내면 `version_conflict`로 거부됩니다 —
  버전은 불변입니다.
- 응답은 `input_shape`, `output_shape`, `registered_path`, 그리고 계산된 `sha256`을
  반환합니다.
- 새 모델의 `(window_size, n_features)`가 이전 것과 다르면, 윈도잉 파이프라인이 재구성되고
  워밍업이 다시 시작됩니다.

### ValidateModel

모델 업로드 중 백엔드가 사용하는 순수 검사입니다. 일회용 런타임 세션을 열어 입력/출력 형상과
SHA-256을 추출하고, 아무것도 등록하지 않은 채 `{valid, message, input_shape, output_shape, sha256}`을
반환합니다.

검증은 모델 계약을 강제합니다:

- ONNX 파일 ≤ **500 MB**, 로드 가능, ONNX 체커 통과
- Opset **13–18**
- 입력 텐서 `input`의 형상 `(batch, window_size, n_features)` — 3차원 필수. 배치 차원은
  동적일 수 있음
- 출력 텐서 `output`의 형상 `(batch, 3)` =
  `[health_score, failure_probability, rul_normalized]`

### HealthCheck 및 StreamLogs

`HealthCheck`는 대시보드 헬스 패널(GPU 부하, 메모리, 가동 시간)을 구동합니다. `StreamLogs`는
Python 서비스의 로그 스트림을 백엔드로 전달하고, 백엔드는 이를 LogViewer용으로 영속화합니다 —
`min_level`로 필터링하세요.

## 런타임 구성

추론 컨테이너가 인식하는 환경 변수(compose 파일에서 설정):

| 변수 | 기본값 | 효과 |
|---|---|---|
| `EXECUTION_MODE` | `auto` | 실행 공급자: `auto`(TensorRT → CUDA → CPU), `tensorrt`, `cuda`, `cpu` |
| `STRICT_EP` | off | `1` = 핀 고정된 GPU 모드를 조용히 CPU로 저하시키는 대신 시작을 거부 |
| `MODEL_PATH` | `/app/models/predictive_maintenance.onnx` | 시작 시 로드되는 시드 모델 |
| `MODEL_STORAGE_PATH` | `/data/models` | 등록된 모델 버전이 저장되는 위치 |
| `LOG_DIR` | 미설정 | 회전형 온디스크 로그 파일(`inference.log`) 활성화. 미설정 = 콘솔 전용 |
| `FORCE_CPU` | off | `EXECUTION_MODE=cpu`의 레거시 별칭 |

`EXECUTION_MODE=auto`는 런타임의 공급자 목록을 신뢰하기 전에 TensorRT 네이티브 라이브러리를
프로브하며, GPU 모드가 CPU로 저하되면 큰 경고를 로깅합니다. 드라이버나 JetPack 업데이트 후에
이를 주시하세요 —
[실행 공급자가 CPU로 폴백함](/ko/troubleshooting/execution-provider-fallback/)을 참조하세요.

## 다음 단계

  - [API 개요](/ko/api-reference/overview/) — 백엔드의 REST API 표면.
  - [모델 배포](/ko/configure/models/) — UI에서 모델 버전을 업로드, 페어링, 활성화합니다.
  - [modelctl로 모델 준비하기](/ko/configure/prepare-models/) — 처음부터 검증을 통과하는 번들을 작성합니다.
  - [보안](/ko/security/) — 네트워크 태세 및 강화 체크리스트.
