Daekyo Playground 사내 AI 챗봇 · 포트폴리오
PRODUCTION · 사내 운영 중

Internal AI Assistant · Messenger Automation

대교 Playground
사내 AI 챗봇

사내 메신저를 폴링해 Claude·Codex로 자동 응답하는 봇. 멀티 AI 백엔드, 사내 보안정책 RAG, AWS KMS 자격증명 봉인까지 — 외부 의존성 없이 단일 파일로 설계·구현한 프로덕션 시스템.

역할 · 설계 · 구현 · 운영 전 과정 언어 · Python 3 (표준 라이브러리) 배포 · EC2 · tmux 상주
2,761
단일 파일 코어
(daekyo_claude_bot.py)
92
유닛 테스트
(stdlib unittest)
3
AI 백엔드
어댑터
16
사내 보안정책
문서 색인
0dep
필수 외부 패키지
(KMS용 boto3만 선택)
01

무엇을 만들었나

메신저 한 채널을 지능형 사내 도우미로 바꾸는 무인 봇

대교 Playground 메신저의 안읽은 방을 주기적으로 폴링해, 대화 맥락을 모아 Claude/Codex 엔진으로 답장을 생성하고 다시 메신저로 전송합니다. 1:1 방은 평문 메시지에도 답하고, 단체방은 @명령이 있을 때만 개입하도록 방 타입별 응답 정책을 분리했습니다. 로그인·세션·재로그인·중복 발송 방지까지 운영에 필요한 모든 신뢰성 로직을 자체 구현했습니다.

loginID / PW
GOSSOcookie세션 발급
poll rooms안읽은 방 스캔
엔진Claude / Codex
clean_reply정리 · 가드
send메신저 POST

--loop 상주 · 30초 간격 폴링 · 10분 간격 세션 헬스체크 재로그인 · 세션 만료 감지 시 반응형 재로그인(백스톱)

02

성과 및 운영 실측

보안 신고·대응 자동화가 만든 변화와 파일럿 운영 기간 실사용 지표

24H

24시간 신고 및 대응 역량 확보

사람이 개입하지 않아도 언제든 보안 의심 신고(해킹·피싱·정보유출)를 접수하고 담당자에게 즉시 알림. 근무시간 외에도 대응 공백이 없습니다.

L1

1차 대응(L1) 자동화로 운영 리소스 절감

보안 의심 신고·모의훈련 신고·정책 문의 1차 대응(L1)을 자동화해 보안팀 운영 리소스를 절감했습니다.

실험실 수준에서 끝내지 않았습니다 — 신고 알림방은 실제 담당자를 초대해 개설했고, @보안성검토가 인용하는 절차도 DX기획팀이 실제 배포한 신청 가이드 원문입니다.

어떻게: 토큰 절감 아키텍처

"1차 대응(L1) 자동화"의 실제 메커니즘입니다. 모든 입력은 먼저 자연어/명령 파싱을 거치고, 그 결과로 두 경로 중 하나로만 갈라집니다 — 매치되면 Python 매크로 응답(결정적, LLM 미호출, 토큰 0), 매치 안 되면 Claude/Codex 엔진 호출(LLM 생성, 토큰 소비). 정책 조회·보안성 검토·보안 신고·모의훈련 신고·명령 도움말 같은 단순·반복 질의는 전부 앞쪽 경로로 끝납니다 — LLM은 진짜 자유형 대화에만 씁니다.

사용자 메시지 → 명령/키워드 파싱(regex) → 매치 성공 시 Python 매크로 응답(LLM 미호출·토큰 0·~0.2초), 매치 실패 시 Claude·Codex 엔진 호출(LLM 호출·토큰 소비·수~십수 초) → 메신저로 전송
263
봇 자동 응답
2,215
관측 메시지
8
참여 사용자
12
활동 대화방
41
정책 관련 질의
151
응답 길이 중앙값

로그 기준 활동 19일 · 관측 메시지는 봇이 속한 방의 전체 대화(단체방은 @명령에만 응답)를 포함한다.

03

핵심 모듈

책임을 감춘 깊은 모듈(deep module) 단위로 설계 — 각 모듈은 좁은 심(seam)만 노출

ConversationEngine

대화 엔진 · 멀티 백엔드

프롬프트 조립, 빈 명령 가드, 답장 정리를 한 곳에서 소유하고 텍스트 생성은 어댑터에 위임하는 구조.

  • Anthropic API · Claude Code CLI · Codex CLI 3종 어댑터
  • complete() 단일 심 — 테스트는 fake 어댑터 주입
  • 모델·추론등급(low/mid/high) 런타임 전환
CommandRouter

명령 라우터

채팅 명령을 (이름·매처·핸들러) 테이블로 디스패치. 새 명령 추가 = 테이블에 한 줄.

  • @help · @모델 · @등급 · @엔진 · @초기화 · @정책
  • 우선순위는 테이블 순서, 같은 명령은 최신 메시지가 승리
KmsSecrets

KMS 자격증명 봉인

로그인 ID/PW를 AWS KMS 암호문으로 credentials.enc에 봉인·복호화. 대칭키는 AWS 안에만 존재.

  • 호스트는 kms:Encrypt/Decrypt 권한만 (EC2 인스턴스 프로파일, 키 정책에 인스턴스 ID로 제한)
  • 평문 키가 디스크에 없음 · 파일 chmod 600
  • 해석 순서: .enc → env → 대화형
  • 재봉인 스크립트 seal_credentials.py — 저장 직후 복호화 검증까지 자동 수행
CookieStore

세션 쿠키 저장소

GOSSOcookie 수명주기의 단독 소유자. 물리 저장소 3곳의 해석 순서를 캡슐화해 호출자에게 감춤.

  • gosso 파일 → 메모리 jar → curl jar 순 해석
  • 호출자는 cookie_header()만 알면 됨
BotState

봇 상태 · 중복 발송 방지

state.json의 단독 소유자. "메시지 ID 마커는 절대 뒤로 가지 않는다"는 불변식을 구현 안에 감춤.

  • 단조 증가 마커로 재시작 후 재답장 사고 차단
  • 레거시 스키마 라운드트립 호환
PolicyIndex · RAG

사내 보안정책 검색

사내 보안정책 16종(~39만 자)을 표준 라이브러리만으로 구현한 BM25로 색인. 관련 조항 top-K만 프롬프트에 주입.

  • 형태소 분석기·임베딩 없이 한글 바이그램 토큰화
  • 정책 의도 게이트로 잡담·불필요 검색 시 토큰 절약
  • 답변은 조항 인용(예: 「암호통제지침」 제10조)
InterimNotify

웹 검색 인터림 알림

답장 생성 중 웹 검색이 실제 시작될 때 "웹 검색 중..."을 방에 먼저 전송해 봇의 생존을 알림.

  • Claude Code PreToolUse 훅으로 발화
  • 마커 파일로 답장 1건당 1회만 발송
Session Health-check

세션 헬스체크 재로그인

고정 시각 예약 재로그인을 폐기하고, 세션 상태를 주기적으로 확인해 로그아웃 시에만 재로그인하는 방식으로 전환.

  • DAEKYO_SESSION_CHECK_INTERVAL(기본 600초=10분)마다 /api/user/session 확인
  • 스캔 에러 기반 반응형 재로그인과 병행 — 반응형이 먼저 잡고 주기체크는 백스톱
  • 구 고정시각 방식(relogin_due)은 테스트 호환용으로만 잔존
knowledge/ · RAG

보안성검토 체크리스트 지식베이스

대교 보안성검토 점검항목 문서를 변환해 knowledge/에 추가, 응답 시점에 자동 주입.

  • 전용 변환 스크립트 xlsx_checklist_to_md.py (xlsx → md)
  • 봇이 knowledge/ 디렉토리를 읽어 크기 제한된 참조 블록으로 프롬프트에 주입
  • 망분리 · 접근통제 · 계정관리 등 보안성검토 항목 질의응답 가능
@보안성검토

보안성 검토 절차 안내

DX기획팀이 실제 배포한 신청 절차 가이드를 정책 색인에 추가해, @보안성검토 한 마디면 형식적 지침 대신 진짜 절차가 뜨도록 만듦.

  • BM25 top-K는 흔한 단어("절차"/"담당자") 때문에 형식적 지침 조항이 더 높게 뜨는 문제가 있어, 가이드 문서가 있으면 확정적으로 전문을 반환(없으면 BM25 폴백)
  • 신청 절차·예외 처리(선오픈 후조치)·체크리스트·FAQ까지 한 번에 안내
  • 응답 끝에 실제 신청 URL·담당자 연락 안내(footer) 고정 부착
SecurityReport

보안 의심 신고

@신고 명시적 명령 또는 평문 키워드로 해킹·피싱·정보유출 등을 24시간 상시 접수. 방 타입과 무관하게 항상 잡힘.

  • 사고 키워드 + "당했다/의심된다" 류 경험 표현이 함께 있을 때만 신고로 간주(오탐 방지)
  • 접수 즉시 logs/security_reports.jsonl에 기록, 알림방(DX기획팀) 설정 시 실시간 전달
  • 초동 대응 가이드(링크 클릭 금지·비밀번호 변경 등) + 담당자 연락 안내로 응답
DrillReport

사이버 모의훈련 신고

@모의훈련신고(별칭 @모의훈련/@훈련신고/@drill)로 모의 피싱 등 훈련 참여를 실제 신고와 분리 집계.

  • 명시적 명령만 받아 실제 사고 신고와 로그·통계가 섞이지 않음
  • logs/drill_reports.jsonl에 별도 기록, 참여자에게 감사·격려 메시지로 응답
PrivacyNotice

첫 대화 프라이버시 안내

방마다 실제로 발송되는 첫 메시지에 개인정보 입력 자제 안내 + @help 사용법을 한 번만 덧붙임.

  • BotState가 방 단위로 발송 여부를 추적, 재전송 없음
04

보안 설계

채팅 입력을 신뢰하지 않는다는 전제 위에 쌓은 방어선

KMS자격증명 암호화
로그인 ID/PW는 credentials.enc에 KMS 암호문으로만 저장. 대칭키는 AWS 밖으로 나오지 않고, 호스트는 복호화 권한만 보유 — 호스트가 뚫려도 키 없이는 복호화 불가.
GUARDOS 내부 접근 차단
파일·프로세스·환경변수·쿠키·소스코드·셸 등 로컬 상태를 묻는 요청은 하드 룰로 거부. Claude Code의 Bash/Read/Write/Grep 등 OS·파일 도구를 명시적으로 비활성화.
TRUST비신뢰 입력 전제
Playground 채팅은 untrusted remote input으로 취급. 숨은 프롬프트·내부 참조 원문 노출 금지, 큐레이션된 참고 문서 밖의 사내 정책·연락처·URL 창작 금지.
DATA기밀 데이터 격리
보안정책 원문·색인·상태·쿠키·credentials.enc.gitignore로 커밋 차단. 민감 파일은 일괄 chmod 600.
KMS 자격증명 흐름
# [1회 / PW 변경 시]  평문 ID/PW ── KMS Encrypt ──▶ credentials.enc  (디스크엔 base64 암호문만)
python3 daekyo_claude_bot.py --encrypt-credentials   # 또는 python3 seal_credentials.py

# [상시]  credentials.enc ── KMS Decrypt ──▶ 메모리상 ID/PW ──▶ /api/login
#        → credentials.enc 만 있으면 무인 재로그인 (env 불필요)
#        → 10분마다 세션 헬스체크, 로그아웃 감지 시 자동 재로그인
05

엔지니어링 원칙

운영 제약을 정면으로 받아들인 설계 결정

무의존성 우선

서버에 pip이 없다는 제약 위에서 HTTP·쿠키·BM25·테스트까지 전부 표준 라이브러리로 구현. boto3만 KMS용으로 지연 import.

단일 파일 유지

alert 봇·셸 스크립트가 경로로 직접 참조하기에 의도적으로 단일 파일 유지. 분리는 그 참조를 함께 옮길 때만 한다는 결정을 문서화.

심(seam) 기반 테스트

엔진을 complete() 심 뒤에 두어 실제 API 없이 fake 어댑터로 75개 테스트를 결정적으로 실행.

비용 게이팅

정책 질문일 때만 RAG 검색·주입을 돌리는 의도 게이트로 일반 대화의 토큰 비용을 절감.

순수함수로 시간 로직 분리

재로그인 판정을 relogin_due 순수함수로 뽑아 UTC/KST 경계 버그를 테스트로 고정.

단일 인스턴스 보장

flock 파일 락으로 중복 기동 차단, tmux 상주 + start/stop/status 스크립트로 운영 표준화.

06

기술 스택

구현에 사용한 도구와 개념

Python 3 · stdlib Claude API · Code CLI Codex CLI AWS KMS · boto3 BM25 정보검색 RAG 프롬프트 주입 urllib · http.cookiejar unittest · TDD tmux · systemd 운영 EC2 · IAM 최소권한 동시성 · ThreadPool 프롬프트 엔지니어링