Technical Overview

철도안전 AI 에이전트
핵심 기술 해설서

사고조사보고서 자동 분석부터 위험 예측까지 — 시스템을 구성하는 4가지 기술이
철도안전 업무에서 어떻게 작동하는지 설명합니다.

Ollama · 로컬 LLM LangChain · 파이프라인 LangGraph · 자율 에이전트 scikit-learn · ML 예측 DuckDB · 임베디드 DB
01

Ollama — 로컬 AI 언어 모델

langchain_ollama · ChatOllama · qwen2.5:3b
한 줄 정의: 인터넷 없이 업무용 PC에서 직접 구동되는 AI 언어 모델 실행 엔진입니다.
사고조사보고서(PDF) 안의 비정형 텍스트를 43개 표준 필드로 자동 추출할 때 사용됩니다.
기존 방식 — 클라우드 LLM
사고보고서 PDF (보안 문서) 인터넷 전송 ⚠ 외부 클라우드 OpenAI / 기타 ⚠ 보안 문서가 외부 서버로 전송됨 — 법적·규정 위반 위험 ⚠ 네트워크 의존 — 망분리 환경 사용 불가
Ollama 방식 — 로컬 LLM
사고보고서 PDF (보안 문서) 업무용 PC 내부 Ollama 로컬 서버 분석 결과 ✅ 데이터가 외부로 나가지 않음 — 망분리 환경 완벽 지원 ✅ 127.0.0.1:11434 소켓 통신 — 완전 오프라인 작동 ✅ 모델: qwen2.5:3b (3억 파라미터) — GPU 없이 실행 가능

Ollama가 처리하는 핵심 작업은 비정형 텍스트 → 표준 필드 추출입니다. 사고조사보고서는 기관마다 형식이 다르고 자연어로 서술된 내용이 많아 규칙 기반 파싱만으로는 한계가 있습니다.

PDF 사고보고서 → 43개 표준 필드 자동 추출 과정
📄
PDF 원문
기관별 상이한 양식
자연어 서술문
📝
pymupdf4llm
PDF → Markdown
텍스트 변환
🤖
Ollama LLM
qwen2.5:3b
필드 이해·추출
🔍
JSON 파싱
구조화 응답
유효성 검증
🗄️
DuckDB 저장
43개 필드
위험도 산정
기본 식별 정보
발생일자 발생시간 등록기관 철도구분 노선 발생역
사고 분류 (이벤트)
이벤트대분류 이벤트중분류 이벤트소분류 주원인 직접원인 근본원인
피해 규모
사망자수 부상자수 피해액 지연열차수 최대지연시간

02

LangChain — LLM 연결 파이프라인

langchain_ollama · ChatOllama · HumanMessage · SystemMessage
한 줄 정의: LLM(언어 모델)을 다양한 도구·데이터 소스와 연결하는 프레임워크입니다.
"Ollama 모델을 어떻게 호출하고, 프롬프트를 어떻게 구성하고, 응답을 어떻게 처리할까"를 표준화합니다.
🚦

철도 관제 비유

LangChain은 관제 시스템의 표준 통신 프로토콜과 같습니다.
다양한 신호설비(LLM 종류)가 있어도, 관제사(코드)는 같은 방식으로 명령을 내리고 응답을 받을 수 있습니다. Ollama로 교체해도, 나중에 다른 모델로 바꿔도 나머지 코드는 변경 없이 동작합니다.

LangChain 메시지 구조 — 철도안전 에이전트 적용
SystemMessage (역할 정의) 당신은 철도안전 AI 에이전트입니다. 사망자 발생 사고는 반드시 High 이상 분류. 위험도 High/Critical 시 notify_tool 즉시 실행. 목표 달성 시 "완료:" 로 시작하는 응답 반환. HumanMessage (목표 지시) "이번 주 High 이상 사고 조회 후 담당자에게 알림 발송해줘." ChatOllama model=qwen2.5:3b temperature=0 num_ctx=16384 bind_tools(TOOLS) ↑ 7개 도구 연결 AIMessage tool_calls: query_db_tool( risk_grade= "High") → LangGraph가 도구 실행 LangChain은 SystemMessage + HumanMessage + AIMessage 형식으로 대화 맥락을 관리합니다. bind_tools()로 7개 도구를 LLM에 연결 — LLM이 스스로 어떤 도구를 쓸지 판단합니다.
LangChain 없이 (직접 구현)
# HTTP 요청 직접 구성 payload = { "model": "qwen2.5:3b", "messages": [...], "tools": [...], # 직접 스키마 작성 } resp = requests.post("http://...", json=payload) tool_calls = resp.json()["message"]["tool_calls"] # 에러처리, 재시도, 스트리밍... 모두 직접 구현
LangChain 사용 (실제 코드)
from langchain_ollama import ChatOllama llm = ChatOllama( model="qwen2.5:3b", temperature=0, num_ctx=16384 ) # 도구 자동 스키마 생성 + 바인딩 llm_with_tools = llm.bind_tools(TOOLS) # 호출 — 에러처리·재시도 내장 response = llm_with_tools.invoke(messages)

03

LangGraph — 자율 판단 에이전트 루프

StateGraph · ToolNode · AgentState · supervisor_node
한 줄 정의: LLM이 목표를 받아 스스로 계획을 세우고, 도구를 실행하고, 결과를 보고, 다음 행동을 결정하는 자율 반복 루프를 만드는 프레임워크입니다.
🎯

관제 지휘관 비유

LangGraph는 현장 대응 지휘관과 같습니다.
"이번 주 고위험 사고 조회 후 담당자 알림"이라는 목표를 받으면 → DB 조회 → 결과 분석 → 조건 확인 → 알림 발송 → 완료 판단까지 단계별로 스스로 판단하며 실행합니다. 중간에 오류가 있으면 다른 방법을 찾아 재시도합니다.

LangGraph StateGraph 실행 구조
START "이번 주 High 이상 사고 조회 후 알림" Supervisor Node LLM이 현재 상태 분석 다음 행동 결정 iteration: 0 → 15 (상한) AgentState (공유 상태) messages: 대화 히스토리 goal: 현재 목표 results: 도구 실행 결과 iteration: 반복 횟수 → 모든 노드가 이 상태를 읽고 씁니다 분기 판단 Tool Node 7개 도구 실행 결과를 ToolMessage로 반환 tool_calls 있음 재계획 루프 END (완료) "완료:" 응답 or 반복 초과 7개 등록 도구 (Tools) ① extract_pdf_tool PDF → 43개 필드 추출 ② save_db_tool DB 저장 + 위험도 산정 ③ query_db_tool 사고 DB 조회·필터링 ④ assess_risk_tool 위험도 즉시 산정 ⑤ scenario_tool Bow-Tie 시나리오 생성 ⑥ web_collect_tool 외부 URL 데이터 수집 ⑦ notify_tool 담당자 알림 발송 무한루프 방지 iteration ≥ 15 → 강제 종료
실행 시나리오 예시 — "이번 주 High 이상 사고 조회 후 알림"
iter 1 Supervisor: "DB 조회가 필요하다" → query_db_tool(risk_grade="High", last_years=0) 호출
Tool DB에서 High/Critical 사고 5건 반환 → AgentState.results에 저장
iter 2 Supervisor: "결과 확인 — 알림 발송 필요" → notify_tool(risk_grade="High", message="...") 호출
Tool 이메일/로그 채널 알림 발송 완료
iter 3 Supervisor: "완료: High 이상 사고 5건 조회 및 담당자 알림 발송 완료" → END

04

ML 예측 모델 — 사고 예측과 위험도 분류

scikit-learn · IsolationForest · LinearRegression · RandomForest · EFI
한 줄 정의: 축적된 사고 이력 데이터로부터 패턴을 학습해 미래의 사고 발생 가능성을 예측하고, 개별 사고의 위험 등급을 자동 분류합니다.
축 1 — 시계열 예측 (월별 사고 발생 추이)

과거 월별 사고 건수 데이터를 학습해 향후 1~24개월의 사고 발생 건수를 예측합니다. 4가지 모델을 제공해 현황에 맞게 선택할 수 있습니다.

선형 회귀 2차 다항 회귀 이동평균 3M 지수평활
축 2 — 위험도 점수 산정 (EFI 모델)

개별 사고의 사망자·부상자·피해액·지연시간을 등가사망지수(EFI) 기반으로 0~100점으로 환산, Critical/High/Medium/Low 4등급 분류합니다.

Critical ≥ 80 High ≥ 60 Medium ≥ 25 Low < 25
월별 사고 발생 예측 — 4가지 모델 비교
등가사망지수(EFI) 기반 위험도 산정 공식
# 인명피해 점수 (최대 40점) efi = dead + injured / 100.0 # 부상자 100명 = 사망자 1명 score = min(efi × 20, 40) # 물적 피해 (최대 20점), 운행 지연 (최대 15점) score += min(damage / 50, 20) # 단위: 백만원 score += min(delay / 40, 15) # 단위: 분 # 이벤트 유형 가중치 (최대 15점) if 이벤트소분류 in [탈선, 충돌, 화재, 폭발, 추락]: score += 15 # ★ 철도안전 절대 기준 (Hard Constraint) if dead >= 1: score = max(score, 60.0) # 반드시 High 이상 if dead >= 3 or injured >= 20: score = max(score, 80.0) # Critical if dead >= 5: score = max(score, 90.0) # Critical 최상위
Hard Constraint 원칙: 사망자가 1명이라도 있으면, 다른 피해 수치가 낮더라도 반드시 High 이상(60점)으로 강제 상향됩니다. 단순 통계적 점수만으로는 인명 사고를 과소평가할 수 있기 때문에, 철도안전 기준을 코드로 구현한 것입니다.
위험 등급 분류 기준 및 예시
등급점수 범위사망자 기준부상자 기준대응 원칙
Critical 80 ~ 100점 3명 이상 또는 5명+ → 90점 20명 이상 즉시 임원 보고 + notify_tool 발동
High 60 ~ 79점 1명 이상 (절대 하한) 10명 이상 or 대형 피해 안전관리팀 즉시 알림
Medium 25 ~ 59점 0명 1~9명 또는 고비용 손실 정기 보고 + 예방 계획 수립
Low 0 ~ 24점 0명 0명 (장애류, 경미한 지연) 데이터 축적 + 통계 분석
추가 — IsolationForest 이상 탐지

IsolationForest는 정상 사고 패턴에서 크게 벗어난 "비정상적으로 심각한 사고"를 자동 탐지하는 비지도학습 모델입니다. 기존 위험도 점수가 모든 지표를 선형으로 합산한다면, IsolationForest는 여러 변수의 조합이 평소와 얼마나 다른지를 기준으로 판단합니다.

예: 사망자 없는 탈선이라도 피해액이 극도로 크고 지연 시간이 이례적으로 길면 → 이상 탐지
정상 사고 패턴 대부분의 사고 이상탐지 비정상 패턴 이상 의심 클러스터 밖 고립도 = 이상 점수

05

통합 아키텍처 — 4개 기술이 함께 작동하는 방식

safety_analytics.py · railway_safety_agent.py · DuckDB
사고 발생 조사보고서 PDF ① Ollama 로컬 LLM qwen2.5:3b 43필드 추출 ② LangChain 메시지 관리 도구 바인딩 ChatOllama 연결 ③ LangGraph 자율 에이전트 7개 도구 실행 재계획 루프 DuckDB 사고 데이터 위험도 포함 저장 ④ ML 모델 EFI 위험도 시계열 예측 분석 결과 출력 📊 대시보드 (탭1~4) 🔮 미래 예측 차트 🎯 Bow-Tie 분석 🔔 담당자 알림 📥 CSV 보고서 철도안전 AI 시스템 전체 데이터 흐름 사고조사보고서 PDF → 자동 분석 → 위험도 산정 → 예측 → 알림 Ollama LangChain LangGraph ML 모델 DuckDB 데이터 연동
🤖
Ollama
오프라인 LLM
보안 문서 처리
🔗
LangChain
LLM 표준 인터페이스
도구 연결 프레임워크
🎯
LangGraph
자율 판단 루프
멀티 스텝 실행
📈
ML 모델
EFI 위험도 산정
시계열 예측