dev.to

How to Moderate Live Chat in Real Time with Jev and Composio (Discord + Twitch)

Jev와 Composio로 Discord·Twitch 실시간 채팅 관리하기

Jev의 확률 기반 판단과 Composio를 이용해 Discord·Twitch 채팅을 실시간으로 분류하고 삭제하는 봇을 만드는 튜토리얼입니다. Discord 소규모 테스트에서 메시지 수신부터 삭제까지 중앙값은 979ms였으며, 유해 메시지 5개 중 4개를 잡고 정상 메시지는 삭제하지 않았습니다.

AI 요약

실시간 채팅에서는 운영자가 메시지를 확인하기 전에 다른 참여자들이 이미 내용을 볼 수 있습니다. 이 글은 생성형 답변 대신 분류 확률을 내놓는 TypeSafe의 Jev를 활용해 Discord와 Twitch에서 메시지를 판별하고, 기준에 따라 자동 삭제하거나 검토 대상으로 남기는 봇을 구현합니다. Jev 호출은 Composio의 Jev toolkit을 사용하며, 두 플랫폼이 같은 판별 함수를 공유합니다.

생성형 모델 대신 확률로 판정합니다

일반적인 LLM은 문장을 생성하지만, Jev는 입력 상태와 질문을 받아 판단 결과를 반환합니다. 글에서는 세 가지 질문 형식 가운데 참·거짓 여부와 확률을 돌려주는 Noul을 유해성 판별에 씁니다. “이 메시지는 특정인을 향한 적대적 발언인가?”라고 묻고, 0에서 1 사이의 확률을 받습니다. Choice 질문도 함께 실행해 메시지를 insult, harassment, spam, fine으로 분류하지만, 이 범주는 주로 로그를 확인하고 디버깅하는 데 쓰며 삭제 여부를 결정하지 않습니다.

판별 기준은 유해 확률이 0.8 이상이면 삭제, 0.5 이상 0.8 미만이면 검토용 로그에 남김, 그보다 낮으면 유지하는 방식입니다. 욕설처럼 보이는 표현이라도 게임이나 제품에 대한 불만, 자기비하 농담, 과장된 감탄은 적대적 발언으로 보지 않도록 질문에 예외를 명시합니다. 확률 임계값을 조정해 자동 삭제의 엄격도를 바꿀 수 있습니다.

Composio로 Jev를 호출합니다

코드는 Composio의 JEV_EVALUATE_STATE 도구를 실행해 메시지와 질문을 전달합니다. 별도 HTTP 클라이언트를 만들거나 Jev API 키를 코드에 직접 넣지 않고, Composio API 키와 연결된 사용자 ID를 환경 변수로 관리합니다. 글에 나온 코드에서는 최신 toolkit을 사용하려고 dangerouslySkipVersionCheck: true를 지정합니다. 버전을 고정하지도 않고 이 옵션도 지정하지 않으면 SDK가 ToolVersionRequiredError를 낼 수 있다고 안내합니다.

Discord와 Twitch에 같은 판별 로직을 연결합니다

Discord 봇은 discord.js의 MessageCreate 이벤트로 메시지를 받고, 대상 채널과 메시지 내용을 확인한 뒤 공통 judge() 함수를 호출합니다. Discord의 Message Content Intent와 메시지 삭제 권한이 필요합니다. Composio Discord toolkit에는 새 메시지를 실시간으로 받는 트리거가 없어, 글에서는 메시지 수신에 discord.js를 쓰고 Jev 호출에만 Composio를 사용합니다. 폴링으로 새 메시지를 확인하면 지연이 늘어날 수 있기 때문입니다.

Twitch는 EventSub WebSocket으로 채팅 이벤트를 받습니다. 연결 후 session_welcome 메시지에 담긴 세션 ID로 10초 안에 구독을 등록하고, 새 메시지가 오면 Discord와 동일한 judge()를 실행합니다. 삭제 요청은 Twitch Helix API로 보냅니다. 인증에는 Device Code 흐름을 써서 별도의 리디렉션 서버를 마련하지 않습니다. EventSub 재연결과 연결 상태 확인도 처리합니다. 테스트할 때는 방송자 본인이나 다른 운영자가 쓴 메시지를 Twitch가 봇으로 삭제하지 못하므로 일반 사용자 계정에서 메시지를 보내야 합니다.

부하 테스트와 측정 결과

저장소에는 일반 메시지와 유해 메시지를 섞어 테스트 채팅에 보내는 flooder가 포함되어 있습니다. Discord에서는 Jev 요청 동시 실행 수를 제한하고, 메시지가 몰리면 채널별 삭제 큐에서 bulkDelete()를 사용해 개별 삭제 요청에 따른 Discord rate limit 부담을 줄입니다. 예시 명령은 봇과 flooder를 각각 실행한 뒤 60개 메시지를 보내는 방식입니다.

작성자의 Discord 첫 10개 메시지 테스트에서 Jev 판정 지연 중앙값은 399ms, 메시지 수신부터 삭제까지의 중앙값은 979ms였습니다. 유해 메시지 5개 가운데 4개를 잡았고, 정상 메시지 5개는 삭제하지 않았습니다. 연결이 안정된 뒤 Jev 응답은 대체로 340~460ms였으며, Discord가 실제 삭제를 처리하는 시간이 Jev 판정보다 더 오래 걸리는 경우도 있었다고 설명합니다. 이 결과는 소규모 테스트에서 얻은 수치입니다.

비용은 입력 토큰 100만 개당 0.042달러, 출력 비용은 사실상 무료라고 소개합니다. 메시지 하나에 입력 토큰 약 400개를 쓴다고 가정하면 1,000개 판정 비용은 2센트 미만입니다. 다만 자동 판정 봇이므로 사람 운영자를 계속 두는 편이 좋다고 글은 덧붙입니다. YouTube Live용 코드는 완성본이 아니라 개략 예시로 제시합니다. liveChatMessages.list로 폴링하거나 streamList를 검토할 수 있으며, 플랫폼별 수신·삭제 코드는 달라도 Jev 판별 함수는 그대로 재사용합니다.

dev.to 반응

  • @shricodev — 댓글로 의견을 알려 주세요!
  • @aavash_parajuli_72 — 꽤 실용적인 사례네요. 공유해 주셔서 감사합니다.
    • @shekharrr — Jev는 이런 활용 사례를 염두에 두고 만들어진 것 같아요.

원문: dev.to / 번역·요약: Trawling