운영 업무 처리를 AI에게 맡기며 그은 선
운영 업무가 매번 비슷한 한 줄로 올라와 하나하나 열어 확인해야 했다. 그 확인을 AI에게 넘기면서 스레드에 답글 다는 일만 사람에게 남긴 과정과, 그 선이 무엇을 가르고 있었는지 나중에야 알게 된 것을 적었다.
운영 업무는 Slack 스레드로 올라온다. 종류는 여러 가지다. 어떤 건 장애고, 어떤 건 데이터 확인이고, 어떤 건 이미 합의가 끝나 티켓만 만들면 되는 일이다. 그런데 올라올 때는 다 비슷한 한 줄이라, 열어서 하나하나 읽어 봐야 무엇인지 알 수 있었다.
그 읽는 시간이 쌓였다. 스레드를 열고, 무엇을 요구하는지 파악하고, 어디로 보낼지 정하는 데까지가 매 건 반복된다. 이걸 AI에게 넘기기로 했고, 코드보다 먼저 정할 것이 있었다. 어디까지 맡기고 어디서 세울 것인가. 만드는 시간의 대부분이 기능이 아니라 거기에 들어갔다.
요청 하나는 이렇게 흘러간다
자동화하기 전에 사람이 하던 일을 그대로 적으면 이렇다.
1. 상담팀이 Slack 스레드에 올린다
"이 회원 지급이 안 됐다는데 확인 부탁드려요"
2. 개발자가 스레드를 연다. 리플까지 읽는다
3. 판단한다 — 장애인가, 단순 확인인가, 이미 정해진 작업인가
4. 장애면 로그를 뒤지고, 확인이면 데이터를 조회하고, 작업이면 이슈를 만든다
5. 결과를 그 스레드에 답글로 단다
1번은 우리가 정할 수 없고 5번은 사람이 읽는다. 자동화할 수 있는 건 2~4번이고, 그중에서도 3번이 시간을 제일 많이 먹었다. 열어 보기 전에는 무슨 종류인지 모르고, 열어 보고 나면 이미 몇 분이 갔다.
무엇을 맡길지보다 무엇을 안 맡길지가 먼저였다
넘길 수 있는 일이라고 생각한 이유는 흐름이 매번 같아서였다. 읽고, 분류하고, 보내고, 답한다. 순서가 정해져 있으니 사람이 붙어 있을 이유가 없어 보였다.
그런데 첫 줄을 쓰기 전에 걸렸다. 이 흐름의 마지막인 5번이 사람들이 읽는 채널에 글을 올리는 일이다. 요청한 사람도 보고 그 채널에 있는 사람도 본다. AI가 판단을 잘못하면 잘못된 답이 그대로 올라간다.
그래서 5번만 사람에게 남기고 나머지는 넘겼다.
| 단계 | 누가 |
|---|---|
| 스레드 읽기 | AI |
| 종류 판단 | AI |
| 로그 조회·이슈 발행 같은 후속 작업으로 넘기기 | AI |
| 착수·마감 표시 | AI |
| 스레드에 답글 게시 | 사람 |
이때 기준이랄 것은 없었다. 답글만 눈에 걸렸고 나머지는 따로 따지지 않았다. 지금 표로 적어 놓으니 무슨 원칙이 있었던 것처럼 보이지만, 실제로는 위험해 보이는 한 자리를 빼놓고 나머지를 다 넘긴 것이다.
판단은 맡겼다
먼저 요청을 네 종류로 나눴다. 종류마다 다음에 할 일이 다르다.
| 종류 | 이런 말이 있으면 | 다음에 할 일 |
|---|---|---|
| 장애 | "실패", "오류", "안 돼요", 특정 회원 번호로 재현 요청 | 로그를 뒤지고 코드를 역추적한다 |
| 단순 확인 | "이거 왜 이래요?", "이 값 맞나요?", "이 데이터 뽑아 주세요" | 코드 수정 없이 답과 근거를 낸다 |
| 정해진 작업 | 무엇을 할지 이미 확정, 티켓만 만들면 됨 | 이슈를 발행한다 |
| 새 기능 | 바꿔야 하는데 어디를 바꿀지가 아직 열려 있음 | 영향 범위부터 분석한다 |
이 판단을 AI가 하게 두는 것이 중요했다. "어느 종류로 보면 될까요?"라고 되묻는 도구는 자동화가 아니라 질문이 하나 늘어난 것이다. 근거를 들어 결론을 내고 통보한 뒤 곧장 다음으로 가게 했다. 신호가 정말 반반일 때만 묻되, 그때도 "골라 주세요"가 아니라 "저는 장애로 봅니다, 맞나요?"처럼 추천을 먼저 낸다.
대신 읽는 범위를 좁게 잡지 않았다. 가장 자주 틀리는 것이 원본 한 줄만 읽고 판단하는 것이었다. 진짜 요구는 리플에 있다. "아 그리고 이 회원도요", "금액이 아니라 날짜가 문제예요" 같은 정정이 리플에 붙는다. 원본은 단순 확인이었는데 리플에서 "그럼 고쳐 주세요"로 넘어간 경우가 흔했다.
그래서 판단을 스레드의 마지막 상태 기준으로 못 박았다. 리플까지 전부 읽고, 리플이 종류를 뒤집으면 뒤집힌 쪽을 따른다.
상태도 맡겼다
업무 관리 도구라면 상태 칸과 담당자 칸이 있다. Slack에는 없다. 스레드는 그냥 대화라서 누가 잡았는지, 끝났는지가 어디에도 안 적힌다. 이걸 사람이 기억하게 두면 자동화의 의미가 없다.
있는 것으로 대신했다. 원본 메시지에 붙이는 리액션(이모지)을 상태로 썼다. 착수하면 진행 이모지를 붙이고, 끝나면 피드백 이모지를 붙인다.
문제는 뗄 수가 없다는 것이었다. 쓰고 있는 연동에 리액션을 붙이는 기능은 있는데 떼는 기능이 없다. 그래서 상태가 바뀌는 게 아니라 쌓인다. 진행이 피드백으로 바뀌는 게 아니라 진행 옆에 피드백이 하나 더 붙는다.
리액션 없음 -> 아무도 안 잡음
진행 만 있음 -> 처리 중
피드백 있음 -> 끝남 (진행 이 남아 있어도 무관)
그래서 현재 상태를 마지막 값이 아니라 우선순위로 읽게 했다. 피드백이 있으면 진행이 있든 없든 끝난 것이다. 남아 있는 진행은 흠이 아니라 착수 이력으로 뒀다. 지울 수 없는 기록이라면 지우려 들 것이 아니라 읽는 규칙을 정하면 된다.
붙인 이름과 읽히는 이름이 달랐다
맡겨 놓고 돌리다 보니 이미 누가 잡은 업무를 또 잡는 일이 있었다. AI는 "아무도 안 잡았다"고 판단했는데, 앞사람이 붙인 진행 이모지는 화면에 분명히 있었다.
원인은 이모지 이름이었다. Slack 커스텀 이모지에는 별명을 달 수 있는데, 이 워크스페이스에서 진행은 진행2라는 이모지의 별명이었다. 그래서 이런 일이 생긴다.
붙일 때 "진행" 이라는 이름으로 붙인다 -> 정상 등록. 화면에 보인다
읽을 때 API가 "진행2" 라고 돌려준다 -> 별명이 본명으로 풀려서
붙이는 데 쓴 이름과 읽었을 때 돌아오는 이름이 다르다. 그런데 "이미 누가 잡았나?"를 확인하는 코드는 진행과 정확히 같은 이름을 찾고 있었다. 진행2는 그 조건에 안 걸린다. 그러니 아무도 안 잡은 것으로 읽었고, 또 잡았다.
반대로 진행이 포함된 이름을 찾았다면 진행2도 걸렸을 것이다. 우연히 통과했을 거라는 뜻이다. 같은 데이터인데 비교 방식에 따라 답이 갈리는 상태였다.
남길 문장은 이것이다. 붙이기에 성공했다고 읽기도 성공하는 건 아니다. 화면에 이모지가 보이니 다 되는 줄 알았는데, 붙이는 것과 읽는 것은 다른 동작이고 각자 다른 이름을 쓰고 있었다. 그 뒤로 확인 기준은 본명인 진행2로 바뀌었다.
따로 막아 두지 않았는데도 사고로 이어지지는 않았다. 진행이 하나 더 붙었을 뿐이고, 중복으로 잡은 것을 알아채는 데도 오래 걸리지 않았다. 이 자리가 되돌릴 수 있는 쪽이었기 때문인데, 그때는 그걸 따져 보고 넘긴 것이 아니었다.
답글 게시는 맡기지 않았다
흐름의 마지막만 사람에게 남겼다.
flowchart TD
A["Slack 업무 스레드"] --> B["진행 리액션으로 선점"]
B --> C["원본과 리플 전부 읽기"]
C --> D["종류 판단"]
D --> E["로그 조회·이슈 발행 등 후속 작업"]
E --> F["결과와 답글 초안을 사람에게 보고"]
F --> G{"사람이 읽고 승인"}
G -- "승인" --> H["스레드에 답글 게시"]
H --> I["피드백 리액션"]
G -- "보류" --> F
배포와 같은 성격이라고 봤다. 준비가 된 것과 지금 나가도 되는 것은 다른 판단이고, 뒤의 것은 사람이 시점을 고른다. 다른 점은 배포가 롤백이라도 되는 데 비해 이쪽은 그것도 안 된다는 것이다. 읽은 사람의 머릿속은 되돌릴 수 없다.
그리고 순서를 고정했다. 조치가 확정되기 전에 답글부터 내보내지 않는다. 빨리 답하고 싶어서 "일단 답변부터" 하면 나중에 정정 메시지를 한 번 더 보내게 되고, 요청한 쪽은 두 번 읽어야 한다.
승인이 형식이 되지 않게 했다
사람을 세워 두는 것만으로는 부족했다. 승인 단계는 형식으로 굳기 쉽다. 무엇을 승인하는지 안 보여 주고 "게시할까요?"만 물으면 사람은 대개 그렇다고 한다. 그러면 선을 그어 둔 자리가 그냥 통과 지점으로 바뀐다.
그래서 답글 초안을 전문 그대로 대화에 출력하게 했다. 요약이나 선택지 라벨 안에 접어 넣고 확인만 받는 것은 승인으로 치지 않기로 했다.
승인이 아닌 것 "답변 정리했어요. 게시할까요?"
[게시] [수정] 버튼만 보여 주기
승인인 것 나갈 답글 전문을 그대로 펼쳐 놓고 묻기
읽지 않고 누른 승인은 승인이 아니라 통과다. 사람을 남겨 둔 이유가 문장을 읽히기 위해서인데, 읽을 수 없는 형태로 물으면 남겨 둔 의미가 없다.
조용히 틀리는 쪽을 먼저 막았다
Slack에 메시지를 보내는 함수를 붙이면서 틀릴 수 있는 자리를 훑었는데, 위험도가 같지 않았다. 갈린 기준은 틀렸을 때 알려 주느냐였다.
본문을 담는 인자 이름을 틀림 -> 에러. 전송 자체가 안 됨
thread_ts(스레드 지정)를 빠뜨림 -> 성공. 다만 스레드 답글이 아니라
채널에 새 글로 올라감
Slack에서 답글은 "어느 메시지에 붙는지"를 thread_ts라는 값으로 지정한다. 이 값을 빼먹으면 에러가 나는 게 아니라 정상 응답이 돌아온다. 답변이 스레드가 아니라 채널 맨 아래에, 앞뒤 맥락 없이, 채널 전체에게 보이는 상태로 올라가 있을 뿐이다.
앞의 것은 에러가 나서 그 자리에서 고친다. 뒤의 것은 아무도 안 알려 준다. 앞서 쓰던 협업 도구에서는 대상을 지정하지 않으면 호출 자체가 안 돼서 구조적으로 못 틀리던 실수인데, Slack은 조용히 통과시킨다.
그래서 thread_ts를 매 호출 확인 항목으로 못 박았다. 조용히 틀리는 것은 재발할 때까지 아무도 모르기 때문에, 시끄럽게 틀리는 것보다 먼저 막아야 했다.
공개 채널이라 기준을 한 단계 올렸다
앞서 쓰던 도구의 프로젝트는 참여자만 봤다. Slack 공개 채널 답글은 누구나 본다. 같은 문장이라도 읽는 사람의 범위가 다르다.
그래서 회원 식별자와 계좌, 개인정보를 답글에 넣는 기준을 한 단계 세게 걸었다. 첨부된 스크린샷도 마찬가지다. 화면 값이 판단에 필요해서 읽기는 하되, 요약만 하고 원본 민감 내용을 업무 맥락 밖으로 옮기지 않게 했다.
읽는 사람에 맞춰 쓰는 규칙도 함께 뒀다. 운영이나 상담 담당자가 읽는 답글에는 테이블이나 클래스 이름을 넣지 않는다. "회원 등록정보를 초기화했다"로 충분한 자리에 내부 식별자를 적으면 정확해지는 것이 아니라 안 읽힌다. 진단 근거는 기록에 남기고 답글은 결과와 조치만 담게 했다.
손을 떼려고 만들었는데 안 떼는 자리가 생겼다
자동화를 시작할 때 목표는 손을 떼는 것이었다. 만들고 나니 일부러 손을 대는 자리가 남았고, 그게 실패로 보이지 않는다.
그 선을 어떤 기준으로 그었는지는 나중에 알았다. 처음에는 답글만 위험해 보여서 거기만 뺐을 뿐이다. 다 만들어 놓고 보니 AI가 가져간 것은 전부 다시 하면 되는 일이었고, 사람에게 남은 하나는 다시 할 수 없는 일이었다. 시간을 먹던 쪽은 앞의 것이었고 사고가 나는 쪽은 뒤의 것이었으니, 나눠 놓은 자리가 우연히 맞았다.
그래서 다음에 자동화할 것이 생기면 이 기준부터 볼 생각이다. 그때는 위험해 보이는 자리를 감으로 골랐는데, 감이 안 통하는 흐름도 있을 것이다.
남은 한계는 그 선의 안쪽에 있다. 종류 판단이 틀리면 엉뚱한 후속 작업을 한 바퀴 돌고 나서야 드러난다. 다시 하면 되는 일이라 넘긴 것은 맞는데, 다시 한 횟수를 세는 장치는 두지 않았다. 판단 근거는 기록에 남기게 했으니 나중에 셀 수는 있고 아직 세지 않았다.
그리고 이 도구는 요청이 스레드 하나로 들어온다는 전제 위에 서 있다. 여러 스레드에 걸쳐 이어지는 요청이나 대화 밖에서 합의된 건은 여전히 사람이 집어 넣어야 한다. 운영 업무가 전부 한 줄로 도착하지는 않는다.