이 문서는 AI TBM (Tool Box Meeting) 코칭 시뮬레이터의 핵심 구조와 개발 방법론을 상세히 설명합니다. 본 시뮬레이터는 실제 건설 현장의 안전 관리 역량을 강화하기 위해 설계되었으며, Google의 Gemini AI 모델을 활용하여 현실적이고 동적인 TBM 시나리오 생성 및 관리자 코칭 기능을 제공합니다. 특히, API 키 관리, 시나리오 생성의 복잡성, 대화 역학 및 코칭 시스템, 그리고 작업 결과 산출 방식에 대한 심층적인 이해를 돕는 것을 목표로 합니다.
AI TBM 코칭 시뮬레이터는 관리자가 가상의 TBM 상황에서 작업자들과 소통하며 안전 문제를 해결하는 과정을 연습하고 피드백을 받을 수 있도록 돕는 시스템입니다.
시뮬레이터는 크게 세 가지 핵심 AI 기반 기능과 이를 지원하는 Flask API로 구성됩니다.
Google Gemini API를 안정적으로 사용하기 위해 다수의 API 키를 관리하고 순환 사용하는 전략을 채택합니다.
API 키는 보안을 위해 코드 내에 직접 명시하지 않고, 서버의 환경 변수에서 로드합니다.
GOOGLE_API_KEY
GOOGLE_API_KEY_SUB
GOOGLE_API_KEY_THIRD
이러한 환경 변수가 설정되어 있지 않으면 시스템은 심각한 오류를 보고하며 정상적으로 작동하지 않습니다.
여러 API 키를 활용하여 API 호출 제한에 대비하고, 안정적인 서비스 운영을 도모합니다.
itertools.cycle
: 로드된 API 키들을 순환하며 사용하도록 합니다.threading.Lock
: 여러 스레드에서 동시에 API 키를 요청할 때 발생할 수 있는 경쟁 조건을 방지하고, 키 선택의 스레드 안전성을 보장합니다.이 함수는 다음 API 키를 가져오는 로직을 캡슐화합니다.
api_key_cycler
를 통해 키들을 순환하며 사용합니다. 이를 통해 각 키의 사용량을 분산시킵니다.def get_next_api_key(): global first_call_made with api_key_lock: if not first_call_made: # 첫 번째 호출 시 랜덤 선택 selected_key = random.choice(api_keys) first_call_made = True print(f"첫 번째 API 호출 - 랜덤 선택된 키 (ending with ...{selected_key[-4:]})") else: # 이후 호출은 순환 방식 selected_key = next(api_key_cycler) print(f"API 키 순환 사용 (ending with ...{selected_key[-4:]})") return selected_key
call_gemini_for_scenario_generation()
함수는 Gemini AI를 호출하여 TBM 시뮬레이션을 위한 시나리오를 생성합니다. 이 과정은 다양한 규칙과 제약 조건을 포함하여 현실적이고 교육적인 시나리오를 만듭니다.
이 함수는 시나리오 생성의 핵심 로직을 담당합니다.
get_next_api_key()
를 호출하여 사용할 Gemini API 키를 가져옵니다.gemini-2.5-flash
모델을 사용하여 프롬프트에 기반한 시나리오를 생성합니다.AI는 매번 시나리오 생성 시 다음 네 가지 테마 중 하나를 강제적으로 선택하고, 해당 테마의 목표와 규칙에 맞춰 시나리오를 전개합니다.
갈등 제시형
질문형 또는 중립형
관찰/감각 공유형
상황 공유 및 요청형
AI는 테마별 지침 외에도 다음과 같은 공통 규칙을 준수하여 시나리오를 생성합니다.
hidden_critical_info
는 null
이 됩니다.situation
, task
, weather
등을 작성합니다.situation
에는 숨겨진 정보를 노출하지 않습니다.#일정중시
, #안전불감증
, #경험과신
, #원칙주의(FM)
, #소극적/무관심
, #불만많음
, #꼼꼼함/신중함
등 1~2개를 조합하여 구체적인 성향을 만듭니다.첫 대사 생성 시, AI는 다음 변수 풀에서 0개 또는 1개의 변수를 무작위로 선택하여 조합합니다.
#강풍
, #폭우 직후
, #폭염
, #영하의 날씨
, #야간 작업
, #심한 소음
, #다량의 분진
#작업자 피로 누적
, #개인사정으로 인한 집중력 저하
, #팀원 간의 미묘한 갈등
, #성과 압박으로 인한 스트레스
#급작스러운 작업 변경
, #신규 장비 최초 사용
, #최근 현장 내 아차사고 발생
, #원청의 강력한 일정 압박
, #보호구(PPE) 일부 부족
이 조합된 변수와 작업자 페르소나를 종합적으로 고려하여 첫 대사가 생성됩니다.
AI는 현실적인 위험 상황 설정을 위해 다음과 같은 실제 사고 사례들을 참고하며, 단순히 복사하는 것이 아니라 창의적으로 변형하여 새로운 시나리오를 생성합니다.
창의적 변형 가이드를 통해 장비, 전기 위험, 고소작업, 밀폐공간 위험, 화학적 위험, 구조물 위험, 환경적 위험, 시간적 요인, 인적 요인, 조직적 요인 등을 다양하게 변형하여 시나리오를 풍부하게 만듭니다.
시나리오 생성 결과는 다음과 같은 엄격한 JSON 형식으로 출력됩니다.
{{ "scenario": {{ "situation": "string - 구체적인 TBM 상황 설명 (분야, 작업, 위험요소 포함, 200자 이내)", "task": "string - 오늘의 주요 작업 (구체적인 작업 내용, 100자 이내)", "weather": "string - 오늘의 날씨 및 환경 (작업에 영향을 주는 환경요인, 100자 이내)", "personnel_count": "number - 투입 인력 수 (예: 5)", "work_area_diagram": "string - 텍스트 기호로 만든 작업 구역 도면. 여러 줄일 경우 \\n으로 구분. (예: |----E----|\\n| |\\n| W |\\n|_________|) - 고정폭 폰트로 정렬되도록 주의", "diagram_legend": "string - 도면에 사용된 기호들의 설명. 여러 항목일 경우 \\n으로 구분. (예: W: 작업자\\nE: 장비\\n#: 벽\\n!!: 위험!)", "hidden_critical_info": "string - 숨겨진 결정적 정보 (테마 2, 3에만 해당, 다른 테마는 null)" }}, "workers": [ {{ "name": "string - 작업자 이름 (한국인 이름, 2-4글자)", "role": "string - 작업자 역할 (구체적인 분야와 경험 포함, 60자 이내)", "personality": "string - 구체적인 대화 성향 (안전의식, 경험, 성격 등을 종합적으로 표현, 100자 이내)" }}, {{ "name": "string - 작업자 이름 (한국인 이름, 2-4글자)", "role": "string - 작업자 역할 (구체적인 분야와 경험 포함, 60자 이내)", "personality": "string - 구체적인 대화 성향 (안전의식, 경험, 성격 등을 종합적으로 표현, 100자 이내)" }}, {{ "name": "string - 작업자 이름 (한국인 이름, 2-4글자)", "role": "string - 작업자 역할 (구체적인 분야와 경험 포함, 60자 이내)", "personality": "string - 구체적인 대화 성향 (안전의식, 경험, 성격 등을 종합적으로 표현, 100자 이내)" }} ], "initial_message": {{ "speaker_name": "string - 첫 대사를 말하는 작업자 이름", "text": "string - 첫 대사 내용 (현실적이고 구체적인 상황 반영, 반드시 관리자 호칭 포함, 200자 이내)" }} }}
call_gemini_for_tbm_coaching()
함수는 관리자와 작업자 간의 대화를 진행하고, 관리자의 소통 방식에 대한 피드백을 제공합니다.
이 함수는 대화 및 코칭의 핵심 로직을 수행합니다.
get_next_api_key()
를 호출하여 사용할 Gemini API 키를 가져옵니다.gemini-2.5-flash
모델을 사용하여 대화 응답 및 코칭 피드백을 생성합니다.worker_responses
필드가 비어있지 않은지 검증합니다.AI는 두 가지 주요 역할을 동시에 수행합니다.
AI는 단순한 질의응답을 넘어, 예측 불가능하고 현실적인 대화 흐름을 만듭니다. 다음 행동 패턴 중 가장 현실적인 것을 선택하여 대사를 생성합니다.
'숨겨진 정보'와 '정보 흔적'은 관리자가 올바른 리더십 행동을 보였을 때만 단계적으로 공개됩니다. 단순히 특정 단어를 언급하는 것만으로는 정보를 얻을 수 없습니다.
아주 낮은 확률(5~10%)로 대화 내용과 관련 있는 '돌발 상황'이 발생하여 시뮬레이션의 긴장감을 높입니다.
관리자의 발언을 분석하고 현재 안전 점수와 대화 맥락을 고려하여 3가지 유형의 피드백을 제공합니다. 피드백 텍스트에는 직접적인 점수 언급을 피합니다.
good
(따봉 👍):mixed
(체크 ✔️):suggestion
(전구 💡):TBM 코칭 및 대화 기능의 결과는 다음과 같은 JSON 형식으로 출력됩니다.
{{ "worker_responses": [ {{ "speaker_name": "string - 첫 번째 발언자 이름", "text": "string - 첫 번째 발언 내용 (150자 이내)" }}, {{ "speaker_name": "string - (선택사항) 두 번째 발언자 이름", "text": "string - (선택사항) 두 번째 발언 내용 (150자 이내)" }} ], "sudden_event": "string - 발생한 돌발 상황 텍스트 (없으면 null)", "safety_score_change": "number - 안전도 점수 변화 (-15에서 +15 사이의 정수)", "coach_feedback": {{ "type": "string - 피드백 유형 ('good', 'mixed', 또는 'suggestion' 중 하나)", "text": "string - 관리자의 발언에 대한 구체적이고 실용적인 코칭 내용 (점수 언급 없이, 300자 이내)" }}, "critical_info_revealed": "boolean - 숨겨진 정보가 공개되었는지 여부 (true/false)" }}
call_gemini_for_work_result()
함수는 TBM 시뮬레이션의 최종 안전 점수와 대화 내용을 바탕으로 실제 작업 결과를 시뮬레이션합니다.
이 함수는 작업 결과 생성의 핵심 로직을 수행합니다.
get_next_api_key()
를 호출하여 사용할 Gemini API 키를 가져옵니다.gemini-1.5-flash
모델을 사용하여 작업 결과 시나리오를 생성합니다.AI는 대한민국 '중대재해처벌법' 기준에 따라 재해 유형을 엄격하게 분류하고, 서사 내용과 숫자가 반드시 일치하도록 합니다.
narrative
부분에 사고의 전개 과정과 피해자들의 개별적인 부상 상태를 구체적으로 서술한 후, 서술된 피해자 한 명 한 명을 위 법적 정의에 대입하여 '중대재해'인지 '일반재해'인지 분류하고, 그 결과를 바탕으로 casualties
항목의 중대재해 및 일반재해 수를 정확하게 집계합니다.사고 경위를 서술할 때 단순한 결과 나열이 아닌, 논리적인 인과관계를 명확히 합니다.
결과 판정은 다음 규칙들을 반드시 순서대로, 그리고 최우선으로 적용하여 이루어집니다.
result_type: success
및 casualties: 중대재해 0명, 일반재해 0명
으로 결론 내립니다.narrative
는 관리자의 뛰어난 리더십으로 모든 잠재적 위험을 완벽하게 예방하고 성공적으로 작업을 마쳤다는 긍정적인 내용으로만 작성됩니다.critical_info_uncovered
가 false
라면, 안전 점수와 관계없이 '중대재해'가 발생합니다.success
(완벽한 성공)success_with_lessons
(교훈이 있는 성공). 물리적 사고는 발생하지 않고, TBM의 '사소한 흠결'이 '교훈'이 되었음을 서술합니다.near_miss
또는 minor_accident
. TBM의 실패가 어떻게 물리적인 위험 상황이나 실제 사고로 이어졌는지 인과관계를 명확히 서술합니다.작업 결과 생성 기능의 결과는 다음과 같은 JSON 형식으로 출력됩니다.
{{ "result_type": "string - 'success', 'success_with_lessons', 'near_miss', 'minor_accident', 'major_accident' 중 하나", "narrative": "string - AI가 생성한 구체적인 작업 결과 이야기", "casualties": "string - 최종 재해자 수 (예: 중대재해 0명, 일반재해 1명)" }}
Flask 애플리케이션은 다음 API 엔드포인트를 통해 시뮬레이터의 기능을 제공합니다. 모든 엔드포인트는 @token_required
데코레이터로 보호되어 인증된 사용자만 접근할 수 있습니다.
tbm_simulator_bp
정의: Blueprint의 URL 접두사로 인해 실제 경로는 /api/tbm/scenario
가 됩니다.call_gemini_for_scenario_generation()
함수를 호출합니다.scenario
), 작업자 정보 (workers
), 대화 기록 (history
), 관리자 메시지 (message
), 현재 안전 점수 (currentSafetyScore
), 숨겨진 결정적 정보 (hidden_critical_info
)를 JSON 형식으로 받습니다.call_gemini_for_tbm_coaching()
함수를 호출합니다.safetyScore
), 시나리오 정보 (scenario
), 작업자 정보 (workers
), 전체 대화 기록 (conversationHistory
), 숨겨진 정보 발견 여부 (criticalInfoUncovered
)를 JSON 형식으로 받습니다.call_gemini_for_work_result()
함수를 호출합니다.AI TBM 코칭 시뮬레이터는 Google Gemini AI의 강력한 생성 능력을 활용하여 건설 현장 안전 관리자들에게 실질적인 훈련 기회를 제공합니다. 다중 API 키 관리, 정교한 시나리오 및 페르소나 생성, 동적인 대화 역학 및 리더십 기반 정보 공개 시스템, 그리고 법적 기준을 반영한 현실적인 작업 결과 산출에 이르기까지, 이 시뮬레이터는 안전 교육의 질을 한 단계 높이는 데 기여할 것입니다. 지속적인 개선과 확장을 통해 더욱 다양한 현장 상황과 복잡한 문제 해결 시나리오를 지원하며, 궁극적으로는 실제 현장의 안전사고 감소에 이바지할 수 있을 것으로 기대됩니다.