← 모든 글
DevOps

운영 업무 처리를 AI에게 맡기며 그은 선

운영 요청이 Slack 스레드에 비슷한 한 줄로 올라와 매번 열어 읽어야 했다. 읽고 분류하는 일은 AI에게 넘기고 스레드에 답글을 올리는 일만 사람에게 남겼는데, 그렇게 나눈 기준이 다시 할 수 있는 일이냐 아니냐였다는 것은 다 만들고 나서야 알았다.

운영 업무는 Slack 스레드로 올라온다. 종류는 여러 가지다. 어떤 건 장애고, 어떤 건 데이터 확인이고, 어떤 건 이미 합의가 끝나 티켓만 만들면 되는 일이다. 그런데 올라올 때는 다 비슷한 한 줄이라, 열어서 하나하나 읽어 봐야 무엇인지 알 수 있었다.

그 읽는 시간이 쌓였다. 스레드를 열고, 무엇을 해 달라는 건지 파악하고, 어느 작업으로 넘길지 정하는 데까지가 매번 반복된다. 이 일을 AI에게 넘기기로 했는데, 코드를 쓰기 전에 먼저 정할 것이 있었다. 어디까지 AI에게 맡기고, 어디서부터는 사람이 직접 할 것인가. 만드는 시간의 대부분이 기능보다 이 경계를 정하는 데 들어갔다.

요청 하나는 이렇게 흘러간다

자동화하기 전에 사람이 하던 일을 순서대로 적으면 이렇다.

1. 상담팀이 Slack 스레드에 올린다
   "이 회원 지급이 안 됐다는데 확인 부탁드려요"
2. 개발자가 스레드를 연다. 아래 달린 댓글까지 읽는다
3. 판단한다 — 장애인가, 단순 확인인가, 이미 정해진 작업인가
4. 장애면 로그를 뒤지고, 확인이면 데이터를 조회하고, 작업이면 이슈를 만든다
5. 결과를 그 스레드에 답글로 단다

이 다섯 단계 중 1번은 요청하는 쪽의 일이라 손댈 수 없다. 5번은 결과가 여러 사람 눈에 그대로 보이는 단계다. 자동화할 수 있는 건 그 사이의 2~4번이었고, 그중에서도 3번이 시간을 가장 많이 잡아먹었다. 열어 보기 전에는 어떤 종류인지 모르고, 열어서 파악하고 나면 이미 몇 분이 지나 있었다.

이 글에서 댓글은 요청한 사람이나 다른 사람이 스레드에 이어 단 글이고, 답글은 처리 결과를 알리려고 우리가 다는 글이다. 둘 다 같은 스레드에 붙지만 하는 일이 다르다.

무엇을 맡길지보다 무엇을 안 맡길지가 먼저였다

AI에게 넘길 수 있다고 본 이유는 흐름이 매번 같아서였다. 읽고, 분류하고, 맞는 작업으로 넘기고, 답한다. 순서가 정해져 있으니 사람이 붙어 있을 이유가 없어 보였다.

그런데 만들기 시작하기도 전에 한 군데가 마음에 걸렸다. 마지막 5번은 여러 사람이 보는 채널에 글을 올리는 일이다. 요청한 사람도 보고, 그 채널에 있는 다른 사람도 본다. AI가 판단을 잘못하면 잘못된 답이 그대로 모두에게 보인다.

그래서 5번만 사람에게 남기고 나머지는 AI에게 넘겼다.

단계누가
스레드 읽기AI
종류 판단AI
로그 조회·이슈 발행 같은 후속 작업AI
처리 시작·완료 표시AI
스레드에 답글 올리기사람

이때 따로 세운 기준은 없었다. 답글 올리는 일만 위험해 보였고 나머지는 깊이 따지지 않았다. 표로 정리해 놓으니 무슨 원칙이 있었던 것처럼 보이지만, 실제로는 위험해 보이는 한 곳만 빼고 나머지를 다 넘긴 것이다.

판단은 맡겼다

먼저 요청을 네 종류로 나눴다. 종류마다 다음에 할 일이 다르다.

종류이런 말이 있으면다음에 할 일
장애"실패", "오류", "안 돼요", 특정 회원 번호로 재현 요청로그를 뒤지고 코드를 거슬러 올라가며 원인을 찾는다
단순 확인"이거 왜 이래요?", "이 값 맞나요?", "이 데이터 뽑아 주세요"코드는 고치지 않고 답과 근거만 낸다
정해진 작업무엇을 할지 이미 정해져 있고 티켓만 만들면 됨이슈를 만든다
새 기능바꿔야 하는 건 맞는데 어디를 바꿀지는 아직 안 정해짐어디까지 영향이 가는지부터 분석한다

이 판단을 AI가 직접 내리게 한 것이 중요했다. AI가 "어느 종류로 보면 될까요?"라고 되묻는다면 일이 줄어든 게 아니라 대답할 질문이 하나 늘어난 것이다. 그래서 AI가 근거를 들어 종류를 정하고, 그 결과를 알린 뒤 바로 다음 단계로 넘어가게 했다. 정말 어느 쪽인지 애매할 때만 묻게 했는데, 그때도 "골라 주세요"가 아니라 "저는 장애로 봅니다, 맞나요?"처럼 자기 판단을 먼저 내놓게 했다.

판단을 맡기는 대신 읽는 범위는 넓게 잡았다. 가장 흔한 실수가 원본 메시지 한 줄만 보고 판단하는 것이었다. 진짜 요구는 댓글에 있는 경우가 많다. "아 그리고 이 회원도요", "금액이 아니라 날짜가 문제예요" 같은 추가와 정정이 댓글로 붙는다. 원본은 단순 확인이었는데 댓글에서 "그럼 고쳐 주세요"로 바뀌는 경우도 흔했다.

그래서 판단 기준을 원본 메시지가 아니라 마지막 댓글까지 다 읽은 뒤의 내용으로 정했다. 댓글이 요청의 종류를 바꾸면 바뀐 쪽을 따른다.

상태도 맡겼다

업무 관리 도구에는 보통 상태 칸과 담당자 칸이 있다. Slack에는 없다. 스레드는 그냥 대화라서 누가 맡았는지, 끝났는지가 어디에도 적히지 않는다. 그렇다고 이걸 사람이 기억하게 두면 자동화한 의미가 없다.

그래서 Slack에 이미 있는 기능으로 대신했다. 원본 메시지에 다는 이모지 리액션을 상태 표시로 썼다. 처리를 시작하면 진행 이모지를 붙이고, 답글까지 올려 일을 마치면 피드백 이모지를 붙인다.

문제는 한번 붙인 이모지를 뗄 수 없다는 것이었다. AI가 Slack을 다룰 때 쓰는 연동에는 리액션을 붙이는 기능만 있고 떼는 기능이 없었다. 그래서 상태가 바뀌는 게 아니라 쌓인다. 일이 끝나도 진행이 피드백으로 바뀌지 않고, 진행 옆에 피드백이 하나 더 붙는다.

붙어 있는 이모지     읽는 법
없음                 아무도 안 맡음
진행만 있음          처리 중
피드백 있음          끝남 (진행이 남아 있어도 상관없음)

그래서 마지막에 붙은 이모지가 아니라 어떤 이모지가 붙어 있는지로 상태를 읽게 했다. 피드백이 있으면 진행이 있든 없든 끝난 업무다. 끝난 업무에 남아 있는 진행은 오류로 보지 않고, 누군가 처리를 시작했었다는 기록으로 그냥 뒀다. 지울 수 없는 기록이라면 지우려고 애쓰기보다 읽는 규칙을 정하는 편이 나았다.

붙인 이름과 읽히는 이름이 달랐다

그렇게 돌리다 보니 이미 다른 사람이 맡은 업무를 AI가 또 맡는 일이 생겼다. 화면에는 먼저 맡은 사람이 붙인 진행 이모지가 분명히 보였는데, AI는 아무도 맡지 않았다고 판단했다.

원인은 이모지 이름이었다. Slack 커스텀 이모지에는 원래 이름 말고 별칭을 더 달 수 있다. 이 워크스페이스에 등록된 이모지의 원래 이름은 진행2였고, 진행은 거기에 붙은 별칭이었다. 별칭으로 붙인 리액션도 API로 읽으면 원래 이름으로 돌아온다.

붙일 때   "진행" 이라는 별칭으로 붙인다   -> 정상으로 붙고 화면에도 보인다
읽을 때   API는 "진행2" 라고 돌려준다     -> 별칭이 아니라 원래 이름이 온다

그런데 "이미 누가 맡았나?"를 확인하는 코드는 이름이 정확히 진행인 리액션을 찾고 있었다. 돌아온 이름은 진행2이니 조건에 걸리지 않는다. 그래서 아무도 안 맡은 업무로 보고 또 맡았다.

만약 확인 코드가 이름에 진행이 들어 있는지를 봤다면 진행2도 걸려서 문제가 드러나지 않았을 것이다. 별칭 문제를 모르는 채로 운 좋게 맞게 돌아갔을 뿐이다. 같은 데이터를 두고 비교 방법 하나에 따라 맞기도 하고 틀리기도 하는 상태였다.

이 일로 알게 된 것은 붙이기에 성공했다고 읽기도 성공하는 건 아니라는 점이다. 화면에 이모지가 보이니 다 된 줄 알았지만, 붙이는 동작과 읽는 동작은 서로 다른 이름을 쓰고 있었다. 그 뒤로 확인 코드가 원래 이름인 진행2를 찾도록 바꿨다.

미리 막아 둔 장치가 없었는데도 큰 사고로 번지지는 않았다. 같은 업무에 진행이 하나 더 붙었을 뿐이고, 두 쪽이 겹쳐 맡았다는 것도 금방 알아챘다. 틀려도 다시 정리하면 되는 일이었기 때문인데, 그때는 그걸 따져 보고 AI에게 맡긴 게 아니었다.

답글 올리기는 맡기지 않았다

흐름의 마지막 단계만 사람에게 남겼다.

flowchart TD
  A["Slack 업무 스레드"] --> B["진행 이모지로 맡았다고 표시"]
  B --> C["원본과 댓글 전부 읽기"]
  C --> D["종류 판단"]
  D --> E["로그 조회·이슈 발행 등 후속 작업"]
  E --> F["결과와 답글 초안을 사람에게 보고"]
  F --> G{"사람이 초안을 읽고 승인"}
  G -- "승인" --> H["스레드에 답글 올리기"]
  H --> I["피드백 이모지로 완료 표시"]
  G -- "보류" --> F

코드 배포와 비슷하다고 봤다. 배포할 준비가 끝났다고 곧바로 내보내지 않고 언제 내보낼지는 사람이 정하듯, 답글도 초안이 준비된 것과 지금 올려도 되는 것은 따로 판단한다. 다른 점은 배포는 잘못되면 롤백이라도 할 수 있지만 답글은 그것도 안 된다는 것이다. 메시지를 지워도 이미 읽은 사람의 기억까지 지울 수는 없다.

순서도 정해 뒀다. 조치가 확정되기 전에는 답글부터 올리지 않는다. 빨리 답하고 싶어서 일단 답부터 달면 나중에 정정 메시지를 한 번 더 올리게 되고, 요청한 쪽은 두 번 읽어야 한다.

승인이 형식이 되지 않게 했다

승인 단계를 두는 것만으로는 부족했다. 승인은 금방 형식이 된다. 무엇을 올릴지 보여 주지 않고 "게시할까요?"만 물으면 사람은 대개 그러라고 한다. 그러면 사람이 확인하라고 만들어 둔 단계가 버튼 한 번 누르고 지나가는 절차로 바뀐다.

그래서 AI가 답글 초안을 올라갈 문장 그대로 전부 보여 주게 했다. 요약만 보여 주거나 버튼만 띄워 놓고 확인받는 것은 승인으로 치지 않았다.

승인이 아닌 것   "답변 정리했어요. 게시할까요?"
                 [게시] [수정] 버튼만 보여 주기
승인인 것        올라갈 답글 전문을 그대로 펼쳐 놓고 묻기

읽지 않고 누른 승인은 확인이 아니라 그냥 통과다. 사람을 남겨 둔 이유가 나가기 전에 문장을 한 번 읽게 하려는 것인데, 읽을 수 없는 형태로 물으면 사람을 남겨 둔 의미가 없다.

조용히 틀리는 쪽을 먼저 막았다

AI가 Slack에 메시지를 보내는 기능을 연결하면서, 호출을 잘못했을 때 무슨 일이 생기는지 하나씩 따져 봤다. 실수마다 위험이 달랐고, 차이를 가른 건 틀렸을 때 에러가 나느냐였다.

본문을 담는 인자 이름을 틀림     -> 에러. 메시지가 아예 안 나간다
thread_ts(스레드 지정)를 빠뜨림  -> 성공. 다만 스레드 답글이 아니라
                                    채널에 새 글로 올라간다

Slack에서 답글이 어느 메시지 밑에 달릴지는 thread_ts라는 값으로 정한다. 이 값을 빼먹어도 에러가 나지 않고 정상 응답이 돌아온다. 그사이 답글은 스레드가 아니라 채널 맨 아래에, 앞뒤 맥락 없이, 채널 전체가 보는 새 글로 올라가 있다.

인자 이름을 틀리면 에러가 나니 그 자리에서 고친다. thread_ts를 빠뜨리면 아무것도 알려 주지 않는다. 누군가 채널에서 엉뚱한 글을 발견하기 전까지는 틀린 줄도 모른다.

그래서 답글을 보낼 때마다 thread_ts가 들어 있는지 확인하게 했다. 에러가 나는 실수는 내버려 둬도 드러나지만, 에러 없이 틀리는 실수는 다시 일어날 때까지 아무도 모르기 때문에 이쪽을 먼저 막았다.

누구나 보는 채널이라 답글에 담을 것을 가렸다

Slack 공개 채널에 단 답글은 요청한 사람만 보는 게 아니다. 그 채널에 들어온 사람이면 누구나 읽을 수 있다.

그래서 답글에 회원 식별자나 계좌, 개인정보가 들어가지 않는지 더 엄격하게 따지게 했다. 요청에 첨부된 스크린샷도 마찬가지다. 판단하려면 화면 속 값을 읽어야 하지만, 답글에는 필요한 내용만 요약해 적고 화면에 있던 민감한 값은 옮겨 적지 않게 했다.

읽는 사람에 맞춰 쓰는 규칙도 함께 뒀다. 운영이나 상담 담당자가 읽는 답글에는 테이블 이름이나 클래스 이름을 넣지 않는다. "회원 등록정보를 초기화했다"면 충분한 자리에 내부 이름을 적으면 정확해지는 게 아니라 읽히지 않는다. 진단 근거는 작업 기록에 남기고, 답글에는 결과와 조치만 담게 했다.

손을 떼려고 만들었는데 안 떼는 자리가 생겼다

자동화를 시작할 때 목표는 사람이 손을 떼는 것이었다. 다 만들고 나니 일부러 사람이 손을 대는 자리가 하나 남았는데, 그게 실패로 보이지는 않는다.

그 경계를 어떤 기준으로 그었는지는 나중에야 알았다. 처음에는 답글만 위험해 보여서 그 하나만 뺐을 뿐이다. 다 만들어 놓고 보니 AI가 가져간 일은 전부 틀려도 다시 하면 되는 일이었고, 사람에게 남은 하나는 한번 하면 되돌릴 수 없는 일이었다. 시간을 많이 잡아먹던 건 다시 하면 되는 쪽이었고, 사고가 나는 건 되돌릴 수 없는 쪽이었다. 감으로 나눈 자리가 우연히 맞아떨어진 셈이다.

다음에 무언가를 자동화하게 되면 이 기준부터 볼 생각이다. 이번에는 위험해 보이는 곳을 감으로 골랐지만, 감이 통하지 않는 흐름도 있을 것이다.

아쉬운 점은 AI에게 맡긴 쪽에 남아 있다. 종류 판단이 틀리면 엉뚱한 후속 작업을 한 바퀴 다 돌고 나서야 틀린 걸 안다. 다시 하면 되는 일이라 맡긴 건 맞지만, 판단이 틀려 다시 한 일이 얼마나 되는지는 세지 않았다. 판단 근거를 작업 기록에 남기게 했으니 나중에 셀 수는 있는데, 아직 세 보지 않았다.

그리고 이 도구는 요청 하나가 스레드 하나로 들어온다는 전제 위에서 돈다. 여러 스레드에 걸쳐 이어지는 요청이나 스레드 밖에서 합의된 일은 여전히 사람이 직접 챙겨서 AI에게 넘겨야 한다. 운영 업무가 전부 한 줄로 도착하지는 않는다.