Initial commit (with migration template)

This commit is contained in:
JK Woo
2026-07-17 15:37:40 +00:00
commit 6cfbe6dcb5
63 changed files with 4992 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 KiB

View File

@@ -0,0 +1,228 @@
# HeliosLLM Router 내부 처리 프로세스 명세서 (요청/응답 상세 흐름 분리)
<p align="center">
<img src="./helios_logo.jpg" alt="HELIOS Logo" width="400">
</p>
이 문서는 이 프로젝트 환경에 실제로 구동 중인 **HeliosLLM Router** (LiteLLM Proxy 기반 커스텀 라우터) 및 모니터링 시스템의 물리적 포트, 환경 변수, 설정 파일, 소스 코드 로직을 매핑하여 실제 구현 사양을 기반으로 작성한 상세 명세서입니다.
프로세스의 구체적인 컴포넌트와 세부 정보를 유지하면서 **요청(Request) 처리 흐름**과 **응답(Response) 처리 흐름**을 분리하여 설명합니다.
---
## Part 1. 요청 처리 프로세스 (Request Flow)
요청 처리 흐름은 클라이언트가 API를 호출한 시점부터 HeliosLLM Router가 요청을 전처리하고 적절한 백엔드 LLM 인스턴스를 선택하여 요청을 전달하기까지의 과정을 다룹니다. 이 과정에서 유입된 요청 수(RPS) 및 대상 모델 정보 등의 메트릭이 실시간으로 프로메테우스 스택에 카운팅됩니다.
### 1. 요청 흐름 상세 플로우차트 (상세 디테일 / Light Theme)
![HeliosLLM Router Detailed Request Flow](./litellm_request_flow_final.png)
### 2. 요청 흐름 상세 플로우차트 (Mermaid)
```mermaid
flowchart TD
%% 스타일 정의
classDef client fill:#e1f5fe,stroke:#0288d1,stroke-width:2px;
classDef proxy fill:#efebe9,stroke:#5d4037,stroke-width:2px;
classDef hook fill:#ede7f6,stroke:#5e35b1,stroke-width:2px;
classDef router fill:#fff3e0,stroke:#f57c00,stroke-width:2px;
classDef backend fill:#e8f5e9,stroke:#388e3c,stroke-width:2px;
classDef metrics fill:#fce4ec,stroke:#c2185b,stroke-width:2px;
%% Client 영역
subgraph ClientZone [클라이언트 영역]
Client([API Client])
end
class Client client;
%% Gateway & Proxy Core
subgraph ProxyCore [HeliosLLM Router Gateway]
PortMapping[Docker Port Forwarding<br/>Host 8010 ──► Container 4000]
ProxyServer[HeliosLLM Router Core<br/>FastAPI / LiteLLM Proxy]
PortMapping --> ProxyServer
end
class PortMapping,ProxyServer proxy;
Client -->|1. HTTP POST /v1/chat/completions<br/>Payload: model, messages, stream| PortMapping
%% Pre-Call Hook (Multimodal Router)
subgraph PreCallHookZone [사전 전처리 필터: custom_logger.py]
HookEntry[MultimodalRouterHandler<br/>async_pre_call_hook]
CheckType{type이 'video_url' 이거나<br/>image_url 내 비디오 확장자<br/>.mp4, .webm 등이 있는가?}
CheckText{일반 텍스트(str/text) 내에<br/>비디오 URL 패턴이<br/>포함되어 있는가?}
RewriteModel[model 필드 값을<br/>'Helios-VL'로 재작성]
KeepModel[기존 요청 model명 유지]
ProxyServer -->|2. Hook Trigger| HookEntry
HookEntry --> CheckType
CheckType -->|Yes| RewriteModel
CheckType -->|No| CheckText
CheckText -->|Yes (비디오 URL 포함)| RewriteModel
CheckText -->|No| KeepModel
end
class HookEntry,CheckType,CheckText,RewriteModel,KeepModel hook;
%% Routing & Load Balancing (config.yaml)
subgraph RoutingZone [라우팅 및 분기 판단]
Router[HeliosLLM Router Core]
Decision{최종 model명이<br/>Helios-VL 인가?}
SimpleShuffle[simple-shuffle 로드밸런서<br/>50:50 Shuffle 분배]
RewriteModel -->|3. 가공된 데이터 반환| Router
KeepModel -->|3. 기존 데이터 반환| Router
Router --> Decision
Decision -->|Yes (멀티모달)| Port8003[Backend 3: Helios-VL<br/>Qwen3-VL-8B-Instruct<br/>Port 8003]
Decision -->|No (텍스트)| SimpleShuffle
SimpleShuffle -->|50% 확률 분배| Port8001[Backend 1: Helios-LLM<br/>Nex-N2-mini<br/>Port 8001]
SimpleShuffle -->|50% 확률 분배| Port8002[Backend 2: Helios-LLM<br/>Nex-N2-mini-fp8<br/>Port 8002]
end
class Router,Decision,SimpleShuffle router;
class Port8001,Port8002,Port8003 backend;
%% Monitoring Pipeline
subgraph ReqMetricsZone [실시간 메트릭 로깅]
PromCallback[Prometheus Callback]
MetricUpdate[litellm_request_total 누적 카운트<br/>Labels: model, api_key_hash]
Router -->|4. 요청 메트릭 로깅 트리거| PromCallback
PromCallback --> MetricUpdate
end
class PromCallback,MetricUpdate metrics;
```
### 2. 요청 흐름 세부 절차
#### ① API 요청 수집 및 포트 포워딩
- 클라이언트가 `http://localhost:8010/v1/chat/completions` 주소로 ChatCompletion POST 요청을 보냅니다.
- Docker Compose 포트 매핑(`8010:4000`)을 거쳐 컨테이너 내부 4000 포트에서 실행 중인 **HeliosLLM Router Core** 프로세스로 패킷이 인입됩니다.
#### ② Pre-Call Hook을 통한 멀티모달 자동 라우팅
- Router에 설정된 커스텀 로거 콜백에 의해 [custom_logger.py](file:///home/admin2/Workspace/LiteLLM/custom_logger.py)의 `MultimodalRouterHandler` 클래스 내 `async_pre_call_hook` 함수가 즉시 호출됩니다.
- **멀티모달 감지**:
- **이미지 검출**: 요청 JSON 바디의 `messages` 배열 내에 `{"type": "image_url"}` 데이터가 존재하는지 검사합니다.
- **동영상 검출**: `{"type": "video_url"}` 데이터가 존재하거나, `image_url` 타입 내의 url 주소가 동영상 확장자(`.mp4`, `.webm`, `.mov`, `.avi`, `.mkv`)를 포함하고 있는지 검사합니다.
- **텍스트 내 비디오 검출**: 메시지의 `content`가 일반 문자열(`str`)이거나 `type: "text"` 필드인 경우에도, 텍스트 내용 내에 `http` 링크와 비디오 확장자명이 함께 존재하는지 검사하여 동영상 요청으로 판별합니다.
- **모델 재작성 (Rewriting)**: 이미지 또는 동영상이 감지되었고 동시에 클라이언트가 지정한 타겟 모델이 일반 텍스트 모델인 **`Helios-LLM`**일 경우, 요청 딕셔너리의 `model` 필드 값을 VLM(비전-언어 모델) 전용 모델인 **`Helios-VL`**로 강제 교체합니다.
#### ③ Router의 백엔드 매핑 및 로드 밸런싱 (`config.yaml`)
- **Helios-LLM 분기**:
- `routing_strategy: simple-shuffle` 설정에 의해, 아래 두 백엔드 인스턴스로 요청이 균등하게 분산(Shuffle)됩니다.
- **백엔드 1**: `openai/nex-agi/Nex-N2-mini` (물리주소: 환경변수 `LLM_API_BASE_1`, Port `8001`)
- **백엔드 2**: `openai/nex-agi/Nex-N2-mini-fp8` (물리주소: 환경변수 `LLM_API_BASE_2`, Port `8002`)
- **Helios-VL 분기**:
- 사전 훅에서 모델명이 변경되었거나 처음부터 `Helios-VL`로 인입된 요청은 비전 전용 백엔드로 직접 라우팅됩니다.
- **백엔드 3**: `openai/Qwen/Qwen3-VL-8B-Instruct` (물리주소: 환경변수 `LLM_API_BASE_3`, Port `8003`)
#### ④ 요청 시점의 실시간 메트릭 로깅 (Request Monitoring)
- 클라이언트로부터 요청이 수신되는 즉시, Router의 Prometheus 콜백은 요청 상태를 체크하여 다음과 같은 동적 누적 메트릭을 기록합니다.
- **요청 횟수 누적**: `litellm_request_total` 카운터를 증가하여 초당 요청 수(RPS)를 측정할 수 있도록 합니다.
- **대상 모델 및 API 키 속성 기록**: 라우팅 대상 모델(`Helios-LLM` 또는 `Helios-VL`)과 요청에 사용된 API Key 해시 정보를 태그로 맵핑하여 Prometheus 메트릭 수집기(`/metrics`)에 실시간 반영합니다.
#### ⑤ API 포맷 규격 변환 및 API 전송
- Router Core 모듈이 선택된 타겟 백엔드의 API 주소(`api_base`) 규격에 맞게 HTTP Payload를 최종 직렬화(Serialization)하여 대상 서버로 비동기 호출을 실행합니다.
---
## Part 2. 응답 처리 프로세스 (Response Flow)
응답 처리 흐름은 백엔드 LLM 서버가 추론 결과를 반환한 시점부터 HeliosLLM Router가 이를 감지하여 규격을 가공하고, 지연 시간 및 토큰 소모량 메트릭을 계산한 후 최종 클라이언트에 응답을 전송하고 이를 시각화하기까지의 과정을 다룹니다.
### 1. 응답 및 모니터링 흐름 상세 플로우차트 (상세 디테일 / Light Theme)
![HeliosLLM Router Detailed Response Flow](./litellm_response_flow_final.png)
### 2. 응답 및 모니터링 흐름 상세 플로우차트 (Mermaid)
```mermaid
flowchart TD
%% 스타일 정의
classDef client fill:#e1f5fe,stroke:#0288d1,stroke-width:2px;
classDef proxy fill:#efebe9,stroke:#5d4037,stroke-width:2px;
classDef hook fill:#ede7f6,stroke:#5e35b1,stroke-width:2px;
classDef backend fill:#e8f5e9,stroke:#388e3c,stroke-width:2px;
classDef monitor fill:#fffde7,stroke:#fbc02d,stroke-width:2px;
classDef prometheus fill:#ffebee,stroke:#ef5350,stroke-width:2px;
%% Backends
subgraph BackendZone [실제 추론 서버]
Port8001[Backend 1: Nex-N2-mini<br/>Port 8001]
Port8002[Backend 2: Nex-N2-mini-fp8<br/>Port 8002]
Port8003[Backend 3: Helios-VL<br/>Port 8003]
end
class Port8001,Port8002,Port8003 backend;
%% Router Core Response processing
subgraph RouterResponseZone [HeliosLLM Router Core 응답 처리]
ResponseReceiver[HTTP 응답 수신 모듈<br/>스트림 청크 / 일반 JSON]
ResponseTranslator[Response Translation<br/>OpenAI 표준 JSON 규격 변환]
PostCallHook[Post-Call Callback 실행]
Port8001 -->|1. 추론 응답 반환| ResponseReceiver
Port8002 -->|1. 추론 응답 반환| ResponseReceiver
Port8003 -->|1. 추론 응답 반환| ResponseReceiver
ResponseReceiver --> ResponseTranslator
ResponseTranslator --> PostCallHook
end
class ResponseReceiver,ResponseTranslator,PostCallHook proxy;
%% Metrics calculation
subgraph MetricsCalculation [성능 지표 비동기 연산]
CalcLatency[API 소요 지연시간 연산<br/>ResponseTime - RequestTime]
CalcTokens[usage 필드 파싱 및 집계<br/>prompt_tokens, completion_tokens]
MetricServer[Prometheus Metrics Exporter<br/>/metrics Endpoint 노출]
PostCallHook -->|2. 비동기 지표 갱신| CalcLatency
PostCallHook -->|2. 비동기 지표 갱신| CalcTokens
CalcLatency --> MetricServer
CalcTokens --> MetricServer
end
class CalcLatency,CalcTokens,MetricServer prometheus;
%% Client Return
subgraph ClientReturnZone [클라이언트 최종 반환]
Client([API Client])
PostCallHook -->|3. OpenAI 규격화된 HTTP Response 반환| Client
end
class Client client;
%% Monitoring visualization 스택
subgraph MonitoringStack [실시간 모니터링 시각화 파이프라인]
PrometheusServer[Prometheus Server<br/>Port 9090]
GrafanaServer[Grafana Server<br/>Port 3000]
MetricServer -->|4. 15초 주기 Metrics Scrape| PrometheusServer
GrafanaServer -->|5. Prometheus 데이터 소스 쿼리| PrometheusServer
PrometheusServer -->|6. 시계열 지표 반환| GrafanaServer
end
class PrometheusServer,GrafanaServer monitor;
```
### 2. 응답 흐름 세부 절차
#### ① 백엔드 응답(Response/Stream) 수신
- 호출된 백엔드 LLM/VLM API 서버(Port 8001/8002/8003)가 추론 처리를 마치고 HTTP 응답을 반환합니다.
- **스트리밍(stream: true)인 경우**: 백엔드가 점진적으로 출력하는 SSE(Server-Sent Events) 스트림 데이터 트래픽을 감지하여 지속적인 커넥션을 유지하며 청크(Chunk) 단위로 읽어들입니다.
- **논스트리밍인 경우**: 단일 JSON 완성 객체를 수신합니다.
#### ② Response Translation (OpenAI 포맷 표준화)
- HeliosLLM Router Core는 수신한 응답 페이로드를 실시간으로 해체 및 파싱합니다.
- 다양한 종류의 백엔드 자체 응답 구조를 일관된 **OpenAI ChatCompletionResponse 규격**의 표준 JSON(또는 OpenAI stream 포맷)으로 재구조화하여 단일화합니다.
#### ③ Post-Call Callbacks (실시간 지표 계산 및 로깅)
- 표준 가공이 완료되면 사후 등록된 콜백들이 비동기로 실행되어 성능 지표를 분석합니다:
- **지연 시간(Latency) 연산**: 요청 시각과 응답 완료 시각의 차이를 계산하여 API 총 소요 속도 도출.
- **토큰 사용량(Usage) 측정**: 최종 응답 내부의 `usage` 필드를 파싱하여 입력 프롬프트 토큰 수(`prompt_tokens`) 및 완료 토큰 수(`completion_tokens`)를 추출.
- 버퍼에 수집된 수치는 Router의 `http://localhost:8010/metrics` 경로에 프로메테우스 표준 포맷의 시계열 메트릭 데이터로 업데이트되어 노출됩니다.
#### ④ HTTP Response 최종 반환
- 변환 완료된 OpenAI 표준 JSON 페이로드 혹은 SSE 스트림 데이터 라인을 대기 중이던 클라이언트에게 HTTP Response 패킷으로 최종 응답합니다.
#### ⑤ 모니터링 시각화 파이프라인 연동
- **Prometheus (Port 9090)**: 15초 간격으로 HeliosLLM Router의 `/metrics` 주소를 스크래핑(Scrape)하여 시계열 데이터베이스(TSDB)에 실시간으로 통계를 축적합니다.
- **Grafana (Port 3000)**: Prometheus를 데이터 소스로 연동하여, 수집된 시계열 메트릭(RPS, 대기 지연시간, 토큰 소모량 등)을 그라파나 대시보드 화면에 실시간 그래프와 대시보드 형태로 시각화합니다.

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

View File

@@ -0,0 +1,53 @@
# 시스템 아키텍처 다이어그램 (2026년 07월 14일 업데이트)
기존 시스템 구조에서 **두 모델 모두 256K Context를 지원**하도록 상향 적용된 변경 사항을 반영한 아키텍처 다이어그램입니다.
```mermaid
flowchart TD
%% 스타일 정의
classDef clientNode fill:#f4f6f9,stroke:#6c7a89,stroke-width:1px
classDef serverBox fill:#ffffff,stroke:#a6acaf,stroke-width:2px,rx:10,ry:10
classDef proxyNode fill:#e9ecef,stroke:#adb5bd,stroke-width:1px,rx:5,ry:5
classDef modelNode fill:#fcf3cf,stroke:#f1c40f,stroke-width:1px,rx:5,ry:5
classDef storageNode fill:#fef9e7,stroke:#f39c12,stroke-width:1px
subgraph ClientAppZone [" "]
ClientApp["💻 Client application<br/>React GUI"]:::clientNode
end
subgraph FrontServer ["Front Server"]
Nginx["🌐 Nginx Host Proxy"]:::proxyNode
end
subgraph DockerGUI ["Docker: GUI Container"]
Express["⚙️ Express Backend"]:::proxyNode
SessionMgt["🔑 Session<br/>Management"]:::proxyNode
FileStore[("📁 File Storage<br/>data/sessions.json")]:::storageNode
end
subgraph LLMServer1 ["LLM Server 1"]
Router["🔀 LLM Router<br/>Helios LLM - LiteLLM<br/>based"]:::proxyNode
Model1["🤖 nvidia/Gemma-4-31B-IT-NVFP4<br/>256K Context (Multimodal)"]:::modelNode
end
subgraph LLMServer2 ["LLM Server 2"]
Model2["🤖 google/gemma-4-26B-A4B-it<br/>256K Context (Multimodal)"]:::modelNode
end
%% 연결선 (Client -> Front Server)
ClientApp -- "HTTP / WebSocket" --> Nginx
%% 연결선 (Front Server -> GUI Container)
Nginx -- "Reverse Proxy" --> Express
%% GUI Container 내부
Express <--> SessionMgt
SessionMgt <--> FileStore
%% 연결선 (GUI Container -> LLM Server 1)
Express -- "API Request / Stream" --> Router
%% LLM Router 라우팅
Router -- "Local Route" --> Model1
Router -- "Remote Route" --> Model2
```