들어가며: Slack에서 에이전트가 멘션 없이 일하는 시대
AI 에이전트를 Slack에 붙여 쓰는 건 이제 흔한 일이 됐죠. 하지만 기존에는 매번 멘션(@)을 해야만 에이전트가 반응해서, 대화가 끊기기 일쑤였습니다. Vercel의 Eve 에이전트가 새로 발표한 기능들을 활용하면 이 문제를 해결할 수 있어요.
이번 업데이트의 핵심은 두 가지입니다:
- 스레드 내 자동 응답: 한 번 활성화된 스레드에서는 멘션 없이도 에이전트가 계속 응답합니다.
- 이벤트 훅 확장:
reaction_added,team_join등 Slack 앱이 구독하는 모든 이벤트에 반응할 수 있습니다.
이 글에서는 실제 코드를 통해 어떻게 구현하는지, 그리고 실무에서 주의할 점은 무엇인지 하나씩 살펴보겠습니다.
왜 이 기능이 중요한가?
Slack에서 에이전트를 운영할 때 가장 큰 불편은 '멘션 의존'이었습니다. 사용자가 매번 @Eve를 붙여야 했기 때문에 대화가 단절되고, 팀원들이 에이전트를 깜빡 잊는 일도 많았죠. 이번 업데이트로 에이전트가 스레드 내에서 능동적으로 대화를 이어갈 수 있게 되면서, 마치 동료와 대화하는 듯한 경험을 제공합니다.
또한 이벤트 훅이 추가되면서, Slack에서 발생하는 모든 이벤트(예: 새 멤버 합류, 반응 추가)를 에이전트의 트리거로 사용할 수 있게 되었어요. 이는 온보딩 자동화, 알림 처리 등 다양한 시나리오로 확장 가능합니다.
이 글에서 다루는 내용
onMessage훅과 헬퍼 함수 (isBotMentioned,isSubscribed)- 스레드 참여자 확인과 채널 히스토리 권한
ctx.cancel()과ctx.reset()로 세션 제어하기onEvent훅으로 이벤트 팬아웃하기- 실무 적용 시 주의사항과 다음 단계 학습 방향

본론 1: 핵심 개념 및 코드 예제
1. onMessage 훅으로 멘션 없이 대화 이어가기
Eve 에이전트가 스레드에서 멘션 없이도 응답하게 하려면 onMessage 훅에서 ctx.isSubscribed()를 사용하면 됩니다. 아래 코드는 DM, 명시적 멘션, 그리고 활성 스레드의 후속 메시지를 모두 처리하는 예시입니다.
// Eve 에이전트의 Slack 채널 설정
import { slackChannel } from "@vercel/eve";
export default slackChannel({
credentials: connectSlackCredentials("slack/my-agent"),
async onMessage(ctx, message) {
// 봇의 메시지에는 응답하지 않음
if (message.author?.isBot) return null;
// DM인지 확인
const isDirectMessage = message.raw.channel_type === "im";
// DM, 명시적 멘션, 또는 활성 스레드의 메시지인 경우에만 처리
const shouldHandle = isDirectMessage || ctx.isBotMentioned() || (await ctx.isSubscribed());
return shouldHandle ? { auth: null } : null;
},
});
주요 포인트:
ctx.isBotMentioned(): 메시지에 봇 멘션이 있는지 확인ctx.isSubscribed(): 메시지가 활성 세션이 있는 스레드에 속하는지 확인message.raw.channel_type === "im": DM 여부 확인
2. 스레드 참여자 목록 가져오기
스레드에 누가 참여했는지에 따라 라우팅을 다르게 하고 싶다면, ctx.thread.listParticipants()를 사용할 수 있습니다. 이 함수는 고유한 인간 사용자 ID를 첫 등장 순서대로 반환합니다.
// 스레드 참여자 목록 가져오기
const participants = await ctx.thread.listParticipants();
if (participants.includes("U123456")) {
// 특정 사용자가 참여한 경우 다른 로직 실행
}
권한 참고:
- 공개 채널:
message.channels트리거 이벤트와channels:history봇 스코프 필요 - 비공개 채널:
message.groups와groups:history추가 필요
3. 세션 취소 및 리셋
사용자가 실수로 메시지를 보냈거나 대화를 초기화하고 싶을 때, ctx.cancel()과 ctx.reset()을 사용할 수 있습니다.
// 중간에 잘못된 메시지를 보낸 경우 - 현재 턴 취소
export default slackChannel({
credentials: connectSlackCredentials("slack/my-agent"),
async onMessage(ctx, message) {
// "취소" 명령어가 오면 현재 턴을 취소하고 메시지를 새 입력으로 큐잉
if (message.text.trim() === "!cancel") {
await ctx.cancel();
return { auth: null };
}
// 그 외에는 기존 로직 실행
},
});
// 대화를 완전히 초기화하고 싶은 경우 - 세션 리셋
export default slackChannel({
credentials: connectSlackCredentials("slack/my-agent"),
async onMessage(ctx, message) {
if (message.text.trim() !== "!new") return null;
await ctx.reset({ reason: "Slack user requested !new" });
await ctx.thread.post("새 대화를 시작합니다.");
return null;
},
});
차이점:
ctx.cancel(): 현재 턴만 중단하고 세션은 유지, 새 메시지가 대체 입력으로 처리됨ctx.reset(): 세션을 완전히 종료하고 다음 메시지는 새로운 세션으로 시작
4. onEvent 훅으로 모든 이벤트 반응하기
이제 reaction_added, team_join, channel_created 등 Slack 앱이 구독하는 모든 이벤트를 처리할 수 있습니다. ctx.receive()를 호출하면 에이전트 턴이 시작되고, 여러 번 호출하면 하나의 이벤트를 여러 대상으로 팬아웃할 수 있습니다.
// 새 멤버가 합류하면 온보딩 메시지를 여러 채널에 전송하는 예시
const onboardingChannels = ["C0123ABC", "C0456DEF"];
export default slackChannel({
credentials: connectSlackCredentials("slack/my-agent"),
async onEvent({ receive }, event) {
// 팀 합류 이벤트만 처리
if (event.type !== "team_join") return;
// 각 온보딩 채널에 이벤트 정보를 전달하여 에이전트 턴 시작
await Promise.all(
onboardingChannels.map((channelId) =>
receive({
message: `새 멤버가 슬랙 워크스페이스에 합류했습니다. 이 이벤트를 기반으로 온보딩을 진행하세요:\n${JSON.stringify(event)}`,
target: { channelId },
auth: null,
})
)
);
},
});
활용 시나리오:
reaction_added: 특정 반응이 추가되면 알림 처리channel_created: 새 채널이 만들어지면 규칙 안내team_join: 신규 멤버 온보딩 자동화
5. 시작하는 방법
- Eve 에이전트 생성: Eve 공식 문서를 참고하세요.
- Slack 채널 추가: 터미널에서
eve channels add slack명령어 실행 - 템플릿 활용: Vercel 대시보드에서 템플릿을 선택하면 몇 분 안에 배포 가능

본론 2: 주의사항 및 심화 팁
주의사항
- 권한 설정: 공개 채널과 비공개 채널에 필요한 스코프가 다릅니다. 이벤트가 동작하지 않으면 스코프를 먼저 확인하세요.
- 무한 루프 방지: 봇 메시지에 반응하지 않도록
message.author.isBot체크는 필수입니다. - 세션 관리:
ctx.reset()은 세션을 종료하므로, 사용자에게 명확한 피드백을 주는 것이 좋습니다. - 이벤트 팬아웃: 여러 채널에 동시에 메시지를 보낼 때는
Promise.all을 사용하되, API 호출 한도에 주의하세요.
심화 팁
- 상태 관리: 세션이 활성화된 스레드에서만 동작하므로, 긴 대화가 필요한 작업은 스레드를 유지하는 것이 좋습니다.
- 에러 처리:
onMessage에서 예외가 발생하면 기본적으로 에이전트가 중단됩니다.try-catch로 감싸서 로그를 남기세요. - 테스트: Vercel 대시보드에서 세션별 디버깅이 가능하므로, 배포 전에 다양한 시나리오를 테스트하세요.
한국 개발 생태계에서의 적용 맥락
국내 기업에서는 Slack보다 자체 메신저를 사용하는 경우가 많지만, 최근 스타트업과 IT 기업을 중심으로 Slack 도입이 늘어나고 있습니다. 특히 원격 근무가 보편화되면서 Slack 기반 자동화에 대한 수요가 높아지고 있어요. 이번 업데이트는 기존에 멘션에 의존하던 에이전트 운영 방식을 개선하여, 실제 업무에서 더 자연스럽게 활용할 수 있는 계기가 될 것입니다.

결론: 실무 적용 조언 및 마무리
이번 Eve 에이전트 업데이트는 Slack에서 AI 에이전트를 운영하는 방식을 한 단계 끌어올렸습니다. 멘션 없이 대화를 이어가고, 이벤트 훅으로 다양한 알림에 반응하는 기능은 실무에서 매우 유용하게 사용될 수 있어요.
실무 적용 팁
- 온보딩 자동화:
team_join이벤트를 활용하면 신규 입사자에게 자동으로 환영 메시지를 보내고 필요한 문서를 안내할 수 있습니다. - 고객 지원: 스레드 내에서 고객 문의를 처리할 때
ctx.cancel()을 활용하면 잘못된 답변을 빠르게 수정할 수 있습니다. - 모니터링:
reaction_added이벤트로 특정 반응이 달리면 관리자에게 알림을 보내는 등 모니터링 자동화가 가능합니다.
다음 단계 학습 방향
- Eve 공식 문서: Slack 채널 설정과 더 많은 예제를 확인하세요.
- ADK Go 1.0: Go 기반 AI 에이전트 개발에 관심이 있다면 ADK Go 1.0 공개 글을 참고하세요.
- AI 모델 최적화: AI로 콘크리트 배합을 최적화한 사례가 궁금하다면 BOxCrete 오픈소스 모델 해부를 읽어보세요.