TCP/IP 기반 차량용 지능형 V2X 안전 분석 시스템
V2X Safety Agent는 차량-사물 통신(V2X) 환경에서 실시간 위험을 분석하고, AI 기반 운전자 브리핑을 제공하는 end-to-end 지능형 안전 서비스입니다. React Cockpit UI, FastAPI HTTP-to-TCP Bridge, Python TCP Client/Server, Agent Controller, MCP Tool 체인, Gemini AI 대화 엔진을 결합하여 실제 실행 가능한 시스템으로 구성되어 있습니다.
GitHub: https://github.com/deephoon/V2X_Agent.git
- 프로젝트 개요
- 핵심 기능
- 기술 스택
- 시스템 아키텍처
- TCP/IP 통신 프로토콜
- 디렉터리 구조
- 모듈 상세 설명
- MCP Tool 체인
- 위험도 분석 알고리즘
- Gemini AI 대화 엔진
- Fallback 전략
- 시나리오 데이터
- 실행 방법
- 테스트
- 시연 시나리오: S002
- 알려진 한계
V2X Safety Agent의 목적은 V2X 인프라 센서가 감지한 사각지대 보행자, 교차 교통 차량, 통신 품질 저하 등의 위험 상황을 실시간으로 분석하고, 그 결과를 운전자에게 설명 가능한 AI(XAI) 브리핑으로 전달하는 것입니다.
시스템의 모든 분석 요청은 Python TCP Socket 통신을 경유합니다. React UI가 직접 MCP Tool이나 Gemini를 호출하지 않으며, FastAPI는 HTTP 요청을 TCP 요청으로 변환하는 브릿지 역할만 수행합니다. 실제 AI Agent 로직과 MCP Tool 호출은 TCP Server 내부에서 실행됩니다.
사용자가 시나리오 선택 → React UI → FastAPI Bridge → TCP Client → TCP Server
→ Agent Controller → MCP Tool 체인 → Gemini Briefing → TCP Response → React UI 렌더링
| 기능 | 설명 |
|---|---|
| 다중 MCP Tool 체인 | 차량 정보, 날씨, 교통, 위험도, 네트워크 QoS, EV 충전소 등 7개 Tool을 순차적으로 호출하여 종합 분석 |
| 다단계 위험도 분석 | TTC, 거리, 객체 유형, 통신 상태 기반 base score 산출 후 차량·날씨·교통 보정 계수를 곱한 adjusted score로 최종 판정 |
| Gemini AI XAI 브리핑 | 분석 결과를 종합하여 운전자에게 즉각 조치, 판단 근거, 음성 브리핑, 능동적 제안을 한국어로 생성 |
| 운전자-AI 실시간 대화 | 분석 이후 운전자가 AI에게 추가 질문·응답할 수 있는 TCP 경유 채팅 기능 |
| TTS 음성 출력 | Web Speech API로 AI 브리핑을 한국어 음성으로 자동 읽어줌 |
| 차량 레이더 뷰 | 자차와 감지 객체의 상대 위치를 실시간 시각화 |
| TCP 통신 안정성 | <END> marker 기반 message boundary 처리로 partial recv 문제 해결 |
| 전 계층 Fallback | 외부 API 실패, Gemini 호출 실패, TCP 오류 시에도 시스템이 안정적으로 동작 |
| 국내 공개 API 확장 구조 | 기상청, 한국도로공사, 에어코리아 등 API Key만 설정하면 실제 데이터로 전환 가능 |
| 구성 요소 | 기술 |
|---|---|
| TCP Server | Python socket (순수 TCP/IP) |
| HTTP Bridge | FastAPI + Uvicorn |
| AI Agent | Google Gemini API (google-genai) |
| 외부 API 호출 | requests |
| 데이터 처리 | pandas |
| 환경변수 관리 | python-dotenv |
| 스키마 검증 | pydantic |
| 테스트 | pytest |
| 구성 요소 | 기술 |
|---|---|
| Framework | React 19 |
| Build Tool | Vite 8 |
| 언어 | TypeScript 6 |
| 아이콘 | Lucide React |
| TTS | Web Speech API |
| 스타일링 | Vanilla CSS (커스텀 디자인 시스템) |
┌─────────────────────────────────────────────────────────────────────┐
│ React Cockpit UI │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Scenario │ │ XAI HUD │ │ Evidence │ │ MCP │ │ TCP Flow │ │
│ │ Panel │ │ Panel │ │ Grid │ │ Timeline │ │ Panel │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Weather │ │ Traffic │ │ EV │ │ Vehicle │ │ Radar │ │
│ │ Card │ │ Card │ │ Charging │ │ Info │ │ View │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└────────────────────────────┬────────────────────────────────────────┘
│ HTTP (fetch)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ FastAPI HTTP-to-TCP Bridge │
│ GET /api/health │ GET /api/scenarios │ POST /api/analyze │
│ │ │ POST /api/chat │
└────────────────────────────┬────────────────────────────────────────┘
│ TCP Socket (JSON + <END> marker)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Python TCP Server (9000) │
│ │ │
│ Agent Controller │
│ │ │
│ ┌───────────────────────────┼───────────────────────────────┐ │
│ │ MCP Tool Chain │ │
│ │ │ │
│ │ 1. VehicleInfoTool ──→ NHTSA vPIC API │ │
│ │ 2. WeatherContextTool ──→ KMA / Open-Meteo API │ │
│ │ 3. RoadTrafficContextTool ──→ 한국도로공사 / fallback │ │
│ │ 4. RiskAnalysisTool ──→ 위험도 계산 (TTC, 거리, 보정) │ │
│ │ 5. NetworkQoSTool ──→ V2X QoS 평가 │ │
│ │ 6. EVChargingStationTool ──→ HIGH일 때만 호출 │ │
│ └───────────────────────────┼───────────────────────────────┘ │
│ │ │
│ Gemini Briefing Agent │
│ (XAI 운전자 브리핑 생성) │
└─────────────────────────────────────────────────────────────────────┘
- React UI — 순수 프레젠테이션 레이어. TCP/MCP/Gemini를 직접 호출하지 않음
- FastAPI Bridge — HTTP ↔ TCP 프로토콜 변환만 수행
- TCP Client —
socket.connect()→sendall(JSON + <END>)→recv루프 - TCP Server — TCP 요청 수신 → Agent Controller 실행 → TCP 응답 전송
- Agent Controller — MCP Tool 호출 순서 오케스트레이션
- MCP Tools — 각각 독립된 Python 모듈. 외부 API 호출 또는 내부 계산 수행
- Gemini Agent — MCP Tool 결과를 종합하여 AI 브리핑 생성
TCP는 stream protocol이므로 단일 recv() 호출로 전체 메시지를 수신할 수 없습니다. 이 문제를 해결하기 위해 공통 프로토콜 모듈 tcp_protocol.py를 도입했습니다.
프로토콜 규격:
[JSON payload bytes][<END>]
- 모든 요청과 응답은
JSON + <END>marker로 구분됩니다 ensure_ascii=False로 직렬화하여 한글이 포함된 JSON도 가독성 있게 전송합니다socket.sendall()로 전체 buffer를 한번에 전송합니다
핵심 함수 3개:
| 함수 | 역할 |
|---|---|
recv_until_marker() |
bytes 기준으로 <END> marker가 올 때까지 chunk를 누적 수신. UTF-8 문자가 chunk 경계에서 잘리는 문제 방지 |
send_json_with_marker() |
dict → JSON 직렬화 → <END> 부착 → sendall() |
recv_json_with_marker() |
marker까지 수신 후 json.loads() 파싱. 실패 시 raw 500자를 로그에 기록 |
React UI
→ POST /api/analyze { scenario_id: "S002" }
FastAPI Bridge
→ TCP Client: socket.connect(127.0.0.1:9000)
→ sendall(JSON_REQUEST + "<END>")
TCP Server
→ recv loop until "<END>"
→ json.loads() → Agent Controller 실행
→ sendall(JSON_RESPONSE + "<END>")
TCP Client
→ recv loop until "<END>"
→ json.loads()
FastAPI Bridge
→ HTTP JSON Response (+ tcp_roundtrip_ms 측정값 포함)
React UI
→ Cockpit 렌더링
분석 요청 (V2X_SAFETY_REQUEST):
{
"type": "V2X_SAFETY_REQUEST",
"request_id": "REQ-S002",
"timestamp": "2026-05-30T14:00:00Z",
"vehicle_id": "EGO-001",
"payload": {
"scenario_id": "S002",
"scenario_name": "blind_spot_pedestrian",
"ego": { "speed_mps": 12.5, "accel_mps2": -1.2, "heading_deg": 0 },
"object": { "object_id": "PED-001", "object_type": "pedestrian", "x": 18, "y": 3, ... },
"network": { "latency_ms": 120, "packet_loss": 0.048, ... },
"environment": { "road_friction": 0.3, "visibility_m": 50 },
"vehicle": { "vin": "1HGCM82633A004352" },
"location": { "lat": 37.4963, "lon": 126.9572, "name": "Soongsil University" }
}
}채팅 요청 (V2X_CHAT_REQUEST):
{
"type": "V2X_CHAT_REQUEST",
"request_id": "chat_1717059600000",
"payload": {
"message": "네, 감속해 주세요",
"current_gemini": { "driver_briefing": "...", "proactive_suggestion": "..." },
"context": { ... }
}
}v2x-safety-agent/
├── backend/ # FastAPI HTTP-to-TCP Bridge
│ ├── api_bridge.py # /api/health, /api/scenarios, /api/analyze, /api/chat
│ └── schemas.py # Pydantic 요청 스키마 (AnalyzeRequest, ChatRequest)
│
├── client/ # Python TCP Client
│ ├── scenario_loader.py # CSV → dict payload 변환
│ └── tcp_client.py # send_v2x_request(), send_chat_request()
│
├── data/
│ └── v2x_scenarios.csv # 시나리오 데이터 (5개 시나리오)
│
├── frontend/ # React Vite TypeScript 앱
│ └── src/
│ ├── api/v2xApi.ts # FastAPI Bridge HTTP 클라이언트
│ ├── components/ # 13개 UI 컴포넌트
│ │ ├── CockpitHeader.tsx # 상단 헤더 (Bridge 연결 상태)
│ │ ├── ScenarioPanel.tsx # 시나리오 선택 + TCP 설정 + Analyze 버튼
│ │ ├── XaiHudPanel.tsx # XAI HUD (위험도, AI 브리핑, 채팅, TTS)
│ │ ├── VehicleRadarView.tsx # 자차-객체 상대 위치 레이더 뷰
│ │ ├── EvidenceGrid.tsx # 증거 지표 그리드 (TTC, 거리, 통신 등)
│ │ ├── GeminiBriefingCard.tsx # Gemini 브리핑 카드
│ │ ├── WeatherCard.tsx # 날씨 컨텍스트 카드
│ │ ├── TrafficContextCard.tsx # 교통 컨텍스트 카드
│ │ ├── EVChargingStationCard.tsx # EV 충전소/안전 정차 카드
│ │ ├── VehicleInfoCard.tsx # 차량 정보 + 제동 프로필 카드
│ │ ├── RecommendedActions.tsx # 권장 조치 목록
│ │ ├── McpTimeline.tsx # MCP Tool 호출 순서 타임라인
│ │ └── TcpFlowPanel.tsx # TCP 통신 흐름 시각화
│ ├── styles/globals.css # 전체 CSS 디자인 시스템
│ └── types/v2x.ts # TypeScript 타입 정의 (225줄)
│
├── mcp_tools/ # MCP Tool 모듈
│ ├── vehicle_info_tool.py # NHTSA vPIC VIN 디코딩 + 제동 프로필 추정
│ ├── weather_context_tool.py # KMA → Open-Meteo → fallback 날씨 조회
│ ├── road_traffic_context_tool.py # 한국도로공사/MOLIT/TOPIS → fallback 교통 조회
│ ├── risk_analysis_tool.py # 다단계 위험도 계산 (base + adjusted)
│ ├── network_qos_tool.py # V2X 통신 품질 평가
│ ├── ev_charging_station_tool.py # 전기차 충전소/안전 정차 지점 조회
│ └── air_quality_context_tool.py # 대기질 조회 (확장 후보)
│
├── server/ # TCP Server + Agent
│ ├── tcp_server.py # TCP 소켓 서버 (127.0.0.1:9000)
│ ├── agent_controller.py # MCP Tool 오케스트레이션 + 응답 구성
│ └── gemini_briefing_agent.py # Gemini API 호출 + XAI 브리핑 생성 + 채팅
│
├── tests/ # pytest 테스트
│ ├── test_risk_analysis.py # 위험도 계산 검증
│ ├── test_vehicle_info_tool.py # VIN 디코딩 fallback 검증
│ ├── test_tcp_protocol.py # TCP marker 프로토콜 검증
│ └── test_public_api_tools.py # 날씨/교통/EV/대기질 fallback 검증
│
├── tcp_protocol.py # 공통 TCP 프로토콜 (JSON + <END> marker)
├── requirements.txt # Python 의존성
├── .env.example # 환경변수 템플릿
└── .gitignore
127.0.0.1:9000에서 TCP 연결을 대기합니다- 연결마다 30초 socket timeout을 설정합니다
- 요청 type에 따라
V2X_SAFETY_REQUEST는run_agent(),V2X_CHAT_REQUEST는run_agent_chat()을 호출합니다 - 예외 발생 시에도 서버 프로세스가 종료되지 않고 JSON error response를 반환합니다
SO_REUSEADDR옵션으로 포트 재사용을 허용합니다TCP_SERVER_HOST,TCP_SERVER_PORT환경변수로 바인딩 주소를 변경할 수 있습니다
HTTP-to-TCP 프로토콜 변환 역할만 수행합니다. Bridge가 MCP Tool이나 Gemini를 직접 호출하지 않습니다.
| Endpoint | 메서드 | 역할 |
|---|---|---|
/api/health |
GET | Bridge 상태 확인 |
/api/scenarios |
GET | CSV 기반 시나리오 목록 조회 |
/api/analyze |
POST | TCP Client를 통해 분석 요청 전송 + 응답 반환 |
/api/chat |
POST | TCP Client를 통해 채팅 요청 전송 + 응답 반환 |
- TCP round trip 시간을
tcp_roundtrip_ms로 측정하여 응답에 포함합니다 ConnectionRefusedError,socket.timeout,JSONDecodeError등 예외별로 React가 이해할 수 있는 구조화된 에러 JSON을 반환합니다- CORS는
localhost:5173,127.0.0.1:5173을 허용합니다
send_v2x_request(): 시나리오 ID → CSV 로드 → TCP 요청 구성 → socket 연결 → 전송 → 응답 수신send_chat_request(): 채팅 메시지 + 현재 Gemini 상태 + 컨텍스트 → TCP 요청 전송 → 응답 수신build_v2x_request(): CSV 데이터를 표준 TCP 요청 JSON 구조로 변환
data/v2x_scenarios.csv에서 시나리오 데이터를 로드하고, TCP 요청에 필요한 구조화된 dict로 변환합니다.
변환 결과에는 ego (자차 상태), object (감지 객체), network (V2X 통신), environment (도로 환경), vehicle (VIN), location (위치) 정보가 포함됩니다.
MCP Tool의 호출 순서를 관리하고 최종 TCP 응답 JSON을 구성합니다.
분석 실행 순서 (run_agent):
1. VehicleInfoTool → 차량 정보 + 제동 프로필
2. WeatherContextTool → 날씨 + weather_risk_multiplier
3. RoadTrafficContextTool → 교통 + traffic_risk_multiplier
4. RiskAnalysisTool → 위험도 계산 (위 3개 Tool 결과를 입력으로 받음)
5. NetworkQoSTool → V2X 통신 품질 평가
6. EVChargingStationTool → risk_level이 HIGH일 때만 호출
7. GeminiBriefingAgent → XAI 운전자 브리핑 생성
8. Recommendations 생성 → 위험도, QoS, 날씨, 교통 기반 최대 4개
VehicleInfoTool, WeatherContextTool, RoadTrafficContextTool을 RiskAnalysisTool보다 먼저 호출하는 이유: 제동거리 보정 계수, 날씨 위험 보정 계수, 교통 위험 보정 계수를 위험도 계산에 반영해야 하기 때문입니다.
채팅 실행 (run_agent_chat):
운전자 메시지 + 현재 AI 상태 + 센서 컨텍스트를 Gemini에 전달하여 대화 응답을 생성합니다.
서버 로그 출력 예시:
[AGENT] Start V2X Safety Analysis
[MCP] Tool Called: VehicleInfoTool
[MCP] VehicleInfoTool Result: { ... }
[MCP] Tool Called: WeatherContextTool
[MCP] WeatherContextTool Result: { ... }
[MCP] Tool Called: RoadTrafficContextTool
[MCP] RoadTrafficContextTool Result: { ... }
[MCP] Tool Called: RiskAnalysisTool
[MCP] RiskAnalysisTool Result: { ... }
[MCP] Tool Called: NetworkQoSTool
[MCP] NetworkQoSTool Result: { ... }
[MCP] Tool Called: EVChargingStationTool
[MCP] EVChargingStationTool Result: { ... }
[AGENT] Calling Gemini Briefing Agent
[AGENT] Final safety briefing generated
13개 컴포넌트로 구성된 차량 안전 대시보드입니다. FastAPI Bridge의 /api/analyze와 /api/chat만 호출합니다.
| 컴포넌트 | 역할 |
|---|---|
| CockpitHeader | 상단 헤더. FastAPI Bridge 연결 상태 표시 |
| ScenarioPanel | 시나리오 목록, TCP 설정(host/port), Analyze 버튼 |
| XaiHudPanel | 핵심 HUD. 위험도 레벨/점수, AI 브리핑, 채팅 UI, TTS 토글, 레이더 뷰 |
| VehicleRadarView | SVG 기반 자차-객체 상대 위치 시각화 (거리, TTC 표시) |
| EvidenceGrid | 증거 지표 그리드 (TTC, 거리, 가속도, 마찰계수, latency, packet loss 등) |
| WeatherCard | 날씨 컨텍스트 (기온, 강수, 풍속, 위험 보정 계수) |
| TrafficContextCard | 교통 컨텍스트 (도로명, 평균속도, 혼잡도, 위험 보정 계수) |
| EVChargingStationCard | EV 충전소/안전 정차 후보 (HIGH 위험 시에만 표시) |
| VehicleInfoCard | 차량 정보 + 제동 프로필 (category, multiplier, confidence) |
| GeminiBriefingCard | Gemini 브리핑 상세 (source, model, 요약) |
| RecommendedActions | 시스템 권장 조치 목록 (최대 4개) |
| McpTimeline | MCP Tool 호출 순서 타임라인 시각화 |
| TcpFlowPanel | TCP 통신 흐름 다이어그램 (host, port, roundtrip, request ID, status) |
XAI HUD 기능:
- 위험 수준별 glowing 애니메이션 (HIGH: 빨강, MEDIUM: 노랑, LOW: 시안)
- base score / adjusted score / 보정 계수 실시간 표시
- AI 브리핑 + 채팅 히스토리 (버블 UI)
- TTS 음성 출력 on/off 토글
- 운전자 입력 → TCP 경유 → Gemini 응답 → 채팅 히스토리 업데이트
파일: mcp_tools/vehicle_info_tool.py
외부 API: NHTSA vPIC API
VIN(Vehicle Identification Number)을 디코딩하여 make, model, model_year, vehicle_type, body_class, fuel_type을 조회합니다. 이 정보를 기반으로 **제동 프로필(braking profile)**을 추정합니다.
제동 프로필 분류 규칙:
| vehicle_type / body_class 키워드 | category | braking_distance_multiplier |
|---|---|---|
| TRUCK, SUV, MULTIPURPOSE | suv_or_truck |
1.15 |
| BUS | bus |
1.25 |
| MOTORCYCLE | motorcycle |
0.95 |
| PASSENGER, SEDAN | passenger_sedan |
1.00 |
| 알 수 없음 | unknown_vehicle |
1.10 |
참고: NHTSA vPIC는 실제 제동거리나 제동 성능 데이터를 직접 제공하지 않습니다.
braking_distance_multiplier는 vehicle type/body class에서 추정한 보수적(conservative) 보정 계수입니다.
API 실패 시 status="fallback"과 unknown_vehicle 기준 1.1x multiplier를 반환합니다.
파일: mcp_tools/weather_context_tool.py
외부 API: 기상청(KMA) API → Open-Meteo API → fallback
조회 우선순위:
- KMA API (환경변수
KMA_API_KEY,KMA_API_URL설정 시) - Open-Meteo API (무료, API Key 불필요)
- Deterministic fallback
날씨 위험 보정 계수:
| 조건 | weather_status | weather_risk_multiplier |
|---|---|---|
| 강수 > 0 | RAIN_RISK |
1.12 |
| 풍속 ≥ 10 m/s | WIND_RISK |
1.08 |
| 정상 | NORMAL |
1.00 |
파일: mcp_tools/road_traffic_context_tool.py
외부 API: 한국도로공사 / 국토교통부(MOLIT) / 서울 TOPIS → fallback
3개 국내 교통 API 제공자를 순차적으로 시도하며, 모두 실패하거나 API Key가 없으면 시나리오별 fallback을 사용합니다.
교통 위험 보정 계수:
| 평균 속도 | traffic_status | traffic_risk_multiplier |
|---|---|---|
| < 25 km/h | CONGESTED |
1.08 |
| < 45 km/h | SLOW |
1.05 |
| ≥ 45 km/h | FREE_FLOW |
1.00 |
파일: mcp_tools/risk_analysis_tool.py
위험도 분석의 핵심 모듈입니다. 자세한 알고리즘은 9장을 참고하세요.
파일: mcp_tools/network_qos_tool.py
V2X 통신 품질을 평가합니다. 외부 API 호출 없이 시나리오 데이터 기반으로 판정합니다.
WARNING 발생 조건:
| 지표 | 임계값 | 의미 |
|---|---|---|
| latency_ms | > 100ms | 메시지 지연 |
| packet_loss | > 3% | 패킷 손실 |
| message_age_ms | > 150ms | 메시지 노후 |
하나라도 초과하면 qos_status = "WARNING", 모두 정상이면 "NORMAL".
파일: mcp_tools/ev_charging_station_tool.py
외부 API: 전국전기차충전소표준데이터 / 한국환경공단 API → fallback
risk_level이 HIGH일 때만 Agent Controller가 호출합니다. API Key가 없으면 Soongsil Univ EV Safe Stop fallback을 반환합니다.
파일: mcp_tools/air_quality_context_tool.py
외부 API: 에어코리아 실시간 대기오염정보 API → fallback
현재 Agent Controller의 기본 호출 순서에는 포함되어 있지 않습니다. PM10 ≥ 80 또는 PM2.5 ≥ 35일 때 시야 저하 위험(VISIBILITY_RISK)을 반환하는 구조만 갖추고 있습니다.
distance = √(object_x² + object_y²)
relative_speed = max(ego_speed - object_speed, 0.1)
TTC (Time-To-Collision) = distance / relative_speed
| 조건 | 가산 점수 | 근거 |
|---|---|---|
객체가 보행자 (pedestrian) |
+0.25 | 취약 도로 사용자 |
감지 출처가 인프라 (infrastructure) |
+0.15 | 자차 센서 미감지 사각지대 객체 |
| 거리 < 20m | +0.20 | 근접 위험 |
| TTC < 3초 | +0.25 | 임박한 충돌 위험 |
| latency > 100ms | +0.10 | V2X 메시지 지연 |
| packet_loss > 3% | +0.10 | 패킷 손실로 정보 신뢰도 저하 |
| message_age > 150ms | +0.10 | 수신 데이터 노후화 |
base_risk_score = min(합계, 1.0)
adjusted_risk_score = min(
base_risk_score × braking_multiplier × weather_risk_multiplier × traffic_risk_multiplier,
1.0
)
| adjusted_risk_score | risk_level |
|---|---|
| ≥ 0.75 | HIGH |
| ≥ 0.45 | MEDIUM |
| < 0.45 | LOW |
{
"distance_m": 18.25,
"ttc_sec": 1.64,
"base_risk_score": 1.0,
"adjusted_risk_score": 1.0,
"braking_multiplier": 1.0,
"weather_risk_multiplier": 1.0,
"traffic_risk_multiplier": 1.08,
"risk_score": 1.0,
"risk_level": "HIGH",
"reasons": [
"보행자 객체가 감지됨",
"인프라 센서가 감지한 객체",
"객체와의 거리가 20m 미만 (18.25m)",
"TTC가 3초 미만 (1.64초)",
"V2X 메시지 latency가 100ms 초과 (120ms)",
"packet loss가 3% 초과 (4.8%)",
"message age가 150ms 초과 (180ms)",
"교통 흐름 위험 보정 계수 적용 (1.08x)"
]
}MCP Tool 결과 전체를 Gemini에 전달하여 4개 필드를 생성합니다:
| 필드 | 설명 | 예시 |
|---|---|---|
Immediate_Action |
AI가 수행한 즉각 조치 | "긴급 제동 (AEB) 개입 및 조향 보조 활성화" |
Agent_Reasoning |
AI 판단 근거 1문장 | "V2X 통신 지연으로 로컬 센서 데이터를 우선 적용하여..." |
Voice_Briefing |
운전자 음성 브리핑 1~2문장 | "보행자가 접근 중입니다. 충돌 방지를 위해..." |
Proactive_Suggestion |
능동적 질문/제안 | "관제 센터에 위험 알림을 전송할까요?" |
프롬프트 설계 특징:
- Gemini를 "차량용 초지능형 V2X Safety Agent" 페르소나로 설정
- 단순 데이터 요약이 아니라 능동적으로 판단하고 보고하는 톤 지시
response_mime_type: "application/json"으로 구조화된 JSON 응답 강제- Gemini 2.5 모델 사용 시
thinking_budget=0으로 빠른 응답 확보
분석 완료 후 운전자가 AI에게 추가 질문하거나 제안에 응답할 수 있습니다.
운전자: "네, 감속해 주세요"
↓ TCP 경유
AI: "네, 알겠습니다. 현재 30km/h로 속도를 낮춰 결빙 구간을 통과하겠습니다."
+ "관제 센터에 위험 알림을 전송할까요?"
이전 AI 브리핑 + 운전자 응답 + 현재 센서 컨텍스트를 종합하여 자연스러운 대화를 이어갑니다.
Gemini API 오류는 3가지로 분류하여 각각 다른 fallback 메시지를 제공합니다:
| 분류 | 조건 | Fallback 메시지 |
|---|---|---|
rate_limit |
HTTP 429, quota 초과 | "Gemini API 무료 티어 한도 초과로 AI 통신망 응답이 지연..." |
overload |
HTTP 5xx, 서버 과부하 | "Gemini API 서버 과부하로 AI 통신망 응답이 지연..." |
unknown |
기타 | "통신 상태가 불안정하여 자체 로컬 데이터로 상황을 판단..." |
overload 에러 시 0.8초 대기 후 1회 재시도합니다.
시스템은 어떤 외부 의존성이 실패하더라도 안정적으로 동작하도록 설계되었습니다.
| 실패 지점 | Fallback 동작 |
|---|---|
| NHTSA vPIC API 실패 | status="fallback", unknown 차량 기준 braking multiplier 1.1x 반환 |
| KMA API 실패 또는 미설정 | Open-Meteo API로 자동 전환 |
| Open-Meteo API 실패 | status="fallback", 기본 안전 수칙 메시지 반환 |
| 국내 교통 API 미설정 | 시나리오별 deterministic fallback 교통 컨텍스트 반환 |
| EV 충전소 API 미설정 | Soongsil Univ EV Safe Stop fallback 반환 |
| Gemini API Key 미설정 | Deterministic fallback 브리핑 생성 (위험 수준별 즉각 조치 + 기본 근거) |
| Gemini API 호출 실패 | 에러 종류별 fallback 메시지 + 기본 브리핑 구조 반환 |
| TCP Server 요청 처리 예외 | 서버 프로세스 유지, status="error" JSON 응답 반환 |
| TCP Server 미실행 | FastAPI Bridge가 tcp_server_unavailable 에러 JSON 반환 |
| TCP 응답 timeout | FastAPI Bridge가 tcp_timeout 에러 JSON 반환 |
| TCP 응답 JSON 파싱 실패 | FastAPI Bridge가 tcp_invalid_json 에러 JSON 반환 |
data/v2x_scenarios.csv에 5개 시나리오가 정의되어 있습니다.
| ID | 이름 | 객체 유형 | 감지 출처 | 핵심 특징 |
|---|---|---|---|---|
| S001 | normal_following |
vehicle | vehicle | 정상 차량 추종. 낮은 위험도 |
| S002 | blind_spot_pedestrian |
pedestrian | infrastructure | 사각지대 보행자. 높은 위험도, 통신 품질 저하 |
| S003 | cross_traffic_vehicle |
vehicle | infrastructure | 교차 교통 차량. 중간 위험도 |
| S004 | stale_v2x_message |
pedestrian | infrastructure | 극심한 통신 지연 (230ms, 7.5% loss, 320ms age) |
| S005 | low_confidence_object |
unknown | infrastructure | 낮은 감지 신뢰도 (0.52) |
cd v2x-safety-agent
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtcp .env.example .env최소 설정 (Gemini 브리핑 사용 시):
GEMINI_API_KEY=your_actual_api_key
GEMINI_MODEL=gemini-2.5-flash국내 공개 API 확장 (선택사항):
KMA_API_KEY=your_kma_key
KMA_API_URL=https://...
KOREA_EXPRESSWAY_API_KEY=your_key
KOREA_EXPRESSWAY_API_URL=https://...
MOLIT_TRAFFIC_API_KEY=your_key
MOLIT_TRAFFIC_API_URL=https://...
SEOUL_TOPIS_API_KEY=your_key
SEOUL_TOPIS_API_URL=https://...
KOREA_EV_CHARGING_API_KEY=your_key
KOREA_EV_CHARGING_API_URL=https://...
AIRKOREA_API_KEY=your_key
AIRKOREA_API_URL=https://...API Key가 없어도 모든 Tool은 fallback으로 동작하므로 시스템 전체 실행에 지장이 없습니다.
python -m server.tcp_server==================================================
V2X Safety Agent - TCP Server
==================================================
[SERVER] Listening on 127.0.0.1:9000
포트 변경이 필요한 경우:
TCP_SERVER_PORT=9001 python -m server.tcp_serveruvicorn backend.api_bridge:app --reload --host 127.0.0.1 --port 8000Bridge 상태 확인:
curl http://127.0.0.1:8000/api/health
# {"status":"ok","service":"V2X Safety FastAPI Bridge"}cd frontend
npm install
npm run dev브라우저에서 http://localhost:5173 접속
- React UI에서 시나리오를 선택합니다 (기본: S002
blind_spot_pedestrian) - Analyze 버튼을 클릭합니다
- TCP Server 터미널에서 MCP Tool 호출 로그를 확인합니다
- React UI에 위험도, AI 브리핑, 증거 지표가 표시됩니다
- AI 브리핑이 TTS로 읽어집니다 (브라우저 TTS 지원 시)
- AI의 제안에 대해 채팅으로 응답할 수 있습니다
python -m pytest| 테스트 파일 | 검증 내용 |
|---|---|
test_risk_analysis.py |
S002 입력 시 risk_level == "HIGH" 확인, braking multiplier 적용 시 adjusted >= base 확인 |
test_vehicle_info_tool.py |
NHTSA API timeout fallback 시에도 braking_profile 존재 확인 |
test_tcp_protocol.py |
<END> marker 기반 chunked JSON 수신 검증, 한글 JSON roundtrip 검증 |
test_public_api_tools.py |
Weather/RoadTraffic/EVCharging/AirQuality fallback 동작 및 multiplier 검증 |
cd frontend
npm run build# Health check
curl http://127.0.0.1:8000/api/health
# 시나리오 목록
curl http://127.0.0.1:8000/api/scenarios
# S002 분석 요청
curl -X POST http://127.0.0.1:8000/api/analyze \
-H "Content-Type: application/json" \
-d '{"scenario_id":"S002","tcp_host":"127.0.0.1","tcp_port":9000}'S002 blind_spot_pedestrian은 인프라 센서가 사각지대 보행자를 감지하고, V2X 통신 품질 저하와 도로 환경을 종합하여 HIGH 위험으로 판단하는 시나리오입니다.
| 조건 | 값 | 가산 |
|---|---|---|
| 보행자 객체 | pedestrian | +0.25 |
| 인프라 센서 감지 | infrastructure | +0.15 |
| 거리 < 20m | ~18.25m | +0.20 |
| TTC < 3초 | ~1.64초 | +0.25 |
| latency > 100ms | 120ms | +0.10 |
| packet_loss > 3% | 4.8% | +0.10 |
| message_age > 150ms | 180ms | +0.10 |
base_risk_score = 1.0 (상한)
보정 계수 적용:
- braking_multiplier: 1.00 (passenger sedan)
- weather_risk_multiplier: 현재 날씨에 따라 결정
- traffic_risk_multiplier: 1.08 (CONGESTED fallback)
adjusted_risk_score ≥ 0.75 → risk_level = HIGH
| 항목 | 설명 |
|---|---|
| 제동 프로필 | NHTSA vPIC는 실제 제동거리/성능 데이터를 제공하지 않음. braking_distance_multiplier는 차량 유형 기반 추정값 |
| 날씨/교통 API | 국내 API Key 미설정 시 fallback 사용. 실제 실시간 데이터와 차이 가능 |
| Gemini 의존성 | API Key 미설정 또는 google-genai 패키지 문제 시 deterministic fallback 브리핑 사용 |
| 외부 API 가용성 | 네트워크 상태에 따라 success/fallback이 달라질 수 있음 |
| TTS | 브라우저 Web Speech API 지원 및 한국어 음성 엔진 유무에 따라 동작 여부가 달라짐 |
| 동시 접속 | TCP Server는 순차 처리 방식. 동시 다수 요청 시 대기 발생 가능 |