QA Agent Langfuse 연동 완료와 Slack 토큰 가로채기 사건

26년 04월 10일

Langfuse 연동 완료

QA Agent 알파 환경 관측성과 배포를 마무리한 날이었다.

Langfuse 추적을 연동하고 ARM64 네이티브 빌드를 배포했다.

그리고 하루 종일 삽질하게 만든 Slack 토큰 가로채기 문제도 잡았다.

며칠 전에 Langfuse 연동을 설계했다.

오늘 그 연동을 완성했다.

문제는 QA Agent가 LLM을 호출하지만 그 호출을 관측할 수단이 없다는 거였다.

어느 단계에서 토큰을 얼마나 쓰는지, 프롬프트 품질이 어떤지, 비용이 얼마나 나오는지 전부 안 보였다.

관측할 수 없으면 개선할 수 없다.

그래서 Langfuse 프록시를 LLM 프로바이더 앞에 뒀다.

LLM 호출마다 입력, 출력, 토큰 사용량을 추적한다.

단계별 성능 분석, 프롬프트 품질 모니터링, 비용 추적까지 가능해진다.

프로바이더별 프록시

구조는 프로바이더별로 프록시를 따로 두는 걸로 잡았다.

LLM 프로바이더마다 호출 방식이 다르니까, 각자 전용 프록시를 둬서 추적하는 게 깔끔했다.

그리고 세션 상관관계를 위해 헤더를 활용한다.

각 실행의 전체 LLM 호출 체인을 하나의 트레이스로 재구성할 수 있다.

도구 호출까지 추적해서 실행 흐름 전체를 한눈에 볼 수 있게 만들었다.

ARM64 네이티브 빌드 배포

인프라 쪽에서는 ARM64 네이티브 빌드를 배포했다.

그 전까지는 크로스 빌드해서 이미지를 레지스트리에 푸시하는 방식이었다.

근데 이번에는 Graviton 인스턴스 위에서 직접 빌드하는 방식으로 바꿨다.

네 개의 컨테이너를 호스트에서 직접 빌드했다.

크로스 빌드의 호환성 문제를 피하는 게 목적이었다.

배포는 AWS SSM Run Command로 돌린다.

SSH 키 관리 없이 SSM 에이전트가 명령을 실행한다.

VPN이랑 AWS SSO가 전제 조건이다.

호스트에 소스를 받아서 도커 컴포즈로 빌드하고 띄우는 흐름이다.

메모리 디렉토리는 호스트에 마운트해서 Fixture Knowledge가 이미지 리빌드해도 살아남게 만들었다.

그리고 네트워크는 호스트 모드로 잡아서 같은 호스트에 있는 서비스들이 서로 접근할 수 있게 했다.

Slack 토큰 가로채기 사건

이날 가장 오래 걸린 문제는 Slack 토큰 가로채기였다.

증상이 이상했다.

알파 환경 QA 봇이 이상하게 동작했다.

분명히 운영 환경에 배포했는데, 동작이 운영 환경 것이 아닌 것 같았다.

메시지가 이상한 곳으로 가고 응답이 꼬였다.

원인을 추적해보니 로컬 도커 인스턴스가 범인이었다.

로컬에서 도커를 띄워놓고 17시간 동안 켜두었던 거다.

이 로컬 도커가 운영 봇의 Slack 토큰을 가로채고 있었다.

같은 Slack 앱 자격증명을 공유하고 있으니까, 두 인스턴스가 충돌한 거다.

해결은 단순했다.

로컬 도커를 끄면 됐다.

근데 이 문제를 찾는 데 시간이 꽤 걸렸다.

배포 문제인 줄 알고 배포 쪽을 계속 뒤졌으니까.

구조적 예방

이런 충돌을 막으려면 로컬이랑 운영 환경을 명확히 분리해야 한다.

배포 문서에 로컬은 -dev 접미사가 붙은 명령을 따로 두고 환경변수 파일도 분리하는 가이드가 있다.

같은 Slack 앱 자격증명을 공유하면 이런 충돌이 나니까, 애초에 분리해두는 게 맞다.

근데 그날은 내가 로컬 도커를 켜둔 채로 잊고 있었다.

그래서 운영 봇이 이상하게 동작한 거다.

“내 컴퓨터에서 돌아가는 게 왜 운영에 영향을 주지”라고 생각하면 답이 안 나오지만 같은 토큰을 공유하고 있으니까 당연히 영향을 줬다.

마무리

Langfuse 연동으로 LLM 호출이 드디어 보이기 시작했다.

관측할 수 없으면 개선할 수 없는데, 이제 호출마다 토큰, 비용, 품질이 추적된다.

이건 앞으로 QA Agent를 개선하는 데 필수적인 기반이다.

ARM64 네이티브 빌드도 안정적으로 배포됐다.

크로스 빌드의 호환성 문제를 피하니까 배포가 더 단순해졌다.

그리고 Slack 토큰 가로채기는 교훈이 컸다.

로컬이랑 운영이 같은 자격증명을 공유하면 충돌이 난다.

이건 내가 잊고 있던 사실이었는데, 17시간짜리 삽질로 다시 배웠다.

로컬에서 뭘 띄울 때는 운영에 영향을 줄 수 있는지 항상 확인해야 한다.