목차

AI TBM 코칭 시뮬레이터 구조 및 개발 방법

1. 서론

이 문서는 AI TBM (Tool Box Meeting) 코칭 시뮬레이터의 핵심 구조와 개발 방법론을 상세히 설명합니다. 본 시뮬레이터는 실제 건설 현장의 안전 관리 역량을 강화하기 위해 설계되었으며, Google의 Gemini AI 모델을 활용하여 현실적이고 동적인 TBM 시나리오 생성 및 관리자 코칭 기능을 제공합니다. 특히, API 키 관리, 시나리오 생성의 복잡성, 대화 역학 및 코칭 시스템, 그리고 작업 결과 산출 방식에 대한 심층적인 이해를 돕는 것을 목표로 합니다.

2. 시스템 개요

AI TBM 코칭 시뮬레이터는 관리자가 가상의 TBM 상황에서 작업자들과 소통하며 안전 문제를 해결하는 과정을 연습하고 피드백을 받을 수 있도록 돕는 시스템입니다.

1) AI TBM 코칭 시뮬레이터의 목적


2) 주요 구성 요소

시뮬레이터는 크게 세 가지 핵심 AI 기반 기능과 이를 지원하는 Flask API로 구성됩니다.

3. API 키 관리 및 설정

Google Gemini API를 안정적으로 사용하기 위해 다수의 API 키를 관리하고 순환 사용하는 전략을 채택합니다.


1) 환경 변수를 통한 API 키 로드

API 키는 보안을 위해 코드 내에 직접 명시하지 않고, 서버의 환경 변수에서 로드합니다.

이러한 환경 변수가 설정되어 있지 않으면 시스템은 심각한 오류를 보고하며 정상적으로 작동하지 않습니다.


2) API 키 순환 및 스레드 안전성

여러 API 키를 활용하여 API 호출 제한에 대비하고, 안정적인 서비스 운영을 도모합니다.


3) ''get_next_api_key()'' 함수 동작 방식

이 함수는 다음 API 키를 가져오는 로직을 캡슐화합니다.

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

4. 시나리오 생성 기능 상세

call_gemini_for_scenario_generation() 함수는 Gemini AI를 호출하여 TBM 시뮬레이션을 위한 시나리오를 생성합니다. 이 과정은 다양한 규칙과 제약 조건을 포함하여 현실적이고 교육적인 시나리오를 만듭니다.


1) ''call_gemini_for_scenario_generation()'' 함수

이 함수는 시나리오 생성의 핵심 로직을 담당합니다.


2) 시나리오 핵심 테마 (4가지)

AI는 매번 시나리오 생성 시 다음 네 가지 테마 중 하나를 강제적으로 선택하고, 해당 테마의 목표와 규칙에 맞춰 시나리오를 전개합니다.


3) 공통 시나리오 생성 규칙

AI는 테마별 지침 외에도 다음과 같은 공통 규칙을 준수하여 시나리오를 생성합니다.

  1. 동적 변수 조합 규칙 강화:
    1. 변수 재사용 제한 (쿨타임): 이전 2~3번의 시나리오에서 사용된 특정 '인적/관리적 변수'는 다시 사용하지 않아 시나리오의 다양성을 보장합니다.
  2. 숨겨진 정보 및 단서 설계:
    1. '정보 발견'이나 '위험 탐색' 테마에서는 사용자에게 보이지 않는 '숨겨진 결정적 정보'와 그것을 발견할 '정보 흔적'(1~3개)을 설계합니다.
    2. '관행 타파'나 '문제 해결' 테마는 숨겨진 정보가 없을 수 있으며, 이 경우 hidden_critical_infonull이 됩니다.
    3. 자기 복제 금지: 특정 소재(예: '야간 작업팀의 전기 배선 변경')의 반복 사용을 금지하며, 매번 새로운 소재를 사용합니다.
  3. 시나리오 구체화:
    1. '건설/작업 분야' 목록에서 무작위로 분야를 선택하고, 지정된 테마와 숨겨진 정보에 맞춰 구체적인 situation, task, weather 등을 작성합니다.
    2. 사용자에게 보여주는 situation에는 숨겨진 정보를 노출하지 않습니다.
  4. 페르소나 생성:
    1. 2~3명의 작업자 페르소나를 생성하며, 각 작업자는 이름, 역할, 그리고 서로 다른 독특한 대화 성향을 가집니다.
    2. 현실 반영 요구사항: 시뮬레이션의 난이도와 현실감을 높이기 위해, 최소 1명 이상은 비협조적이거나 안전에 무관심한 성향을 갖도록 페르소나를 조합합니다.
    3. 성향 키워드 풀: #일정중시, #안전불감증, #경험과신, #원칙주의(FM), #소극적/무관심, #불만많음, #꼼꼼함/신중함 등 1~2개를 조합하여 구체적인 성향을 만듭니다.
  5. 자기 검증 및 최종 JSON 생성:
    1. 생성된 '숨겨진 정보'가 시나리오와 논리적으로 타당한지 스스로 검증하는 과정을 거칩니다.
    2. 물리적, 화학적, 기계적 원리에 부합하고, 현실적으로 발생할 법한 위험인지, 작업자들이 놓칠 수 있는 위험인지 등을 체크합니다.

4) 동적 변수 조합 가이드

첫 대사 생성 시, AI는 다음 변수 풀에서 0개 또는 1개의 변수를 무작위로 선택하여 조합합니다.

이 조합된 변수와 작업자 페르소나를 종합적으로 고려하여 첫 대사가 생성됩니다.


5) 실제 사고 사례 참고 및 변형

AI는 현실적인 위험 상황 설정을 위해 다음과 같은 실제 사고 사례들을 참고하며, 단순히 복사하는 것이 아니라 창의적으로 변형하여 새로운 시나리오를 생성합니다.

창의적 변형 가이드를 통해 장비, 전기 위험, 고소작업, 밀폐공간 위험, 화학적 위험, 구조물 위험, 환경적 위험, 시간적 요인, 인적 요인, 조직적 요인 등을 다양하게 변형하여 시나리오를 풍부하게 만듭니다.


6) 최종 JSON 출력 형식

시나리오 생성 결과는 다음과 같은 엄격한 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자 이내)"
  }}
}}

5. TBM 코칭 및 대화 기능 상세

call_gemini_for_tbm_coaching() 함수는 관리자와 작업자 간의 대화를 진행하고, 관리자의 소통 방식에 대한 피드백을 제공합니다.


1) ''call_gemini_for_tbm_coaching()'' 함수

이 함수는 대화 및 코칭의 핵심 로직을 수행합니다.


2) AI의 다중 페르소나 역할

AI는 두 가지 주요 역할을 동시에 수행합니다.


3) 대화 역학(Dynamics) 심층 가이드

AI는 단순한 질의응답을 넘어, 예측 불가능하고 현실적인 대화 흐름을 만듭니다. 다음 행동 패턴 중 가장 현실적인 것을 선택하여 대사를 생성합니다.


4) 정보 잠금 해제: 리더십 행동 기반 규칙

'숨겨진 정보'와 '정보 흔적'은 관리자가 올바른 리더십 행동을 보였을 때만 단계적으로 공개됩니다. 단순히 특정 단어를 언급하는 것만으로는 정보를 얻을 수 없습니다.


5) 돌발 상황 연출

아주 낮은 확률(5~10%)로 대화 내용과 관련 있는 '돌발 상황'이 발생하여 시뮬레이션의 긴장감을 높입니다.


6) 코칭 평가 및 피드백 시스템

관리자의 발언을 분석하고 현재 안전 점수와 대화 맥락을 고려하여 3가지 유형의 피드백을 제공합니다. 피드백 텍스트에는 직접적인 점수 언급을 피합니다.


7) 최종 JSON 출력 형식

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)"
}}

6. 작업 결과 생성 기능 상세

call_gemini_for_work_result() 함수는 TBM 시뮬레이션의 최종 안전 점수와 대화 내용을 바탕으로 실제 작업 결과를 시뮬레이션합니다.


1) ''call_gemini_for_work_result()'' 함수

이 함수는 작업 결과 생성의 핵심 로직을 수행합니다.


2) 재해자 수치 산정 최종 규칙

AI는 대한민국 '중대재해처벌법' 기준에 따라 재해 유형을 엄격하게 분류하고, 서사 내용과 숫자가 반드시 일치하도록 합니다.


3) 사고 시나리오의 인과관계 및 개연성 강화 규칙

사고 경위를 서술할 때 단순한 결과 나열이 아닌, 논리적인 인과관계를 명확히 합니다.


4) 결과 보고서 작성 규칙 (우선순위)

결과 판정은 다음 규칙들을 반드시 순서대로, 그리고 최우선으로 적용하여 이루어집니다.

  1. 황금률: 완벽한 점수 = 완벽한 결과:
    1. 최종 안전 점수가 90점 이상이라면, 다른 모든 규칙과 서사적 가능성을 무시하고, 반드시 result_type: successcasualties: 중대재해 0명, 일반재해 0명으로 결론 내립니다.
    2. narrative는 관리자의 뛰어난 리더십으로 모든 잠재적 위험을 완벽하게 예방하고 성공적으로 작업을 마쳤다는 긍정적인 내용으로만 작성됩니다.
  2. 최우선 원칙: 관리자의 마지막 행동 존중:
    1. (황금률에 해당하지 않을 경우) 관리자가 마지막에 명확하고 안전한 조치를 지시했다면, 반드시 '사고 예방 성공' 또는 '교훈이 있는 성공' 수준의 긍정적인 결과가 나옵니다.
    2. 관리자의 올바른 지시를 무효로 만드는 새로운 부정적 상황을 결과 서사에서 창작하지 않습니다.
    3. 중대재해는 오직 관리자가 위험을 인지하지 못했거나, 무시했거나, 혹은 불분명하고 위험한 지시를 내렸을 경우에만 발생합니다.
  3. 1순위 판정 기준: 숨겨진 정보 발견 여부:
    1. 위 '최우선 원칙'에 해당하지 않는 경우, critical_info_uncoveredfalse라면, 안전 점수와 관계없이 '중대재해'가 발생합니다.
    2. 사고 서사는 TBM 과정의 '좋은 과정'에도 불구하고 '결정적 실수'로 인해 사고가 났음을 명확히 서술합니다.
  4. 2순위 판정 기준: 안전 점수:
    1. '최우선 원칙'과 '1순위 판정 기준'에 해당하지 않을 때만, 안전 점수에 따라 결과의 질을 결정합니다.
    2. 90점 이상: success (완벽한 성공)
      1. 70점 ~ 89점: success_with_lessons (교훈이 있는 성공). 물리적 사고는 발생하지 않고, TBM의 '사소한 흠결'이 '교훈'이 되었음을 서술합니다.
      2. 70점 미만: near_miss 또는 minor_accident. TBM의 실패가 어떻게 물리적인 위험 상황이나 실제 사고로 이어졌는지 인과관계를 명확히 서술합니다.

5) 최종 JSON 출력 형식

작업 결과 생성 기능의 결과는 다음과 같은 JSON 형식으로 출력됩니다.

{{
    "result_type": "string - 'success', 'success_with_lessons', 'near_miss', 'minor_accident', 'major_accident' 중 하나",
    "narrative": "string - AI가 생성한 구체적인 작업 결과 이야기",
    "casualties": "string - 최종 재해자 수 (예: 중대재해 0명, 일반재해 1명)"
}}

7. Flask API 엔드포인트

Flask 애플리케이션은 다음 API 엔드포인트를 통해 시뮬레이터의 기능을 제공합니다. 모든 엔드포인트는 @token_required 데코레이터로 보호되어 인증된 사용자만 접근할 수 있습니다.


1) ''/api/tbm/scenario'' (GET)


2) ''/api/tbm/chat'' (POST)


3) ''/api/tbm/result'' (POST)

8. 결론

AI TBM 코칭 시뮬레이터는 Google Gemini AI의 강력한 생성 능력을 활용하여 건설 현장 안전 관리자들에게 실질적인 훈련 기회를 제공합니다. 다중 API 키 관리, 정교한 시나리오 및 페르소나 생성, 동적인 대화 역학 및 리더십 기반 정보 공개 시스템, 그리고 법적 기준을 반영한 현실적인 작업 결과 산출에 이르기까지, 이 시뮬레이터는 안전 교육의 질을 한 단계 높이는 데 기여할 것입니다. 지속적인 개선과 확장을 통해 더욱 다양한 현장 상황과 복잡한 문제 해결 시나리오를 지원하며, 궁극적으로는 실제 현장의 안전사고 감소에 이바지할 수 있을 것으로 기대됩니다.