Human-in-the-Loop: 에이전트를 위한 이메일 승인 워크플로우
요약
이메일 에이전트의 환각 및 오류를 방지하기 위해 '임시 저장함(Draft folder)'을 활용한 Human-in-the-Loop 승인 워크플로우를 제안합니다. LLM이 초안을 작성하면 사람이 검토 및 승인하는 결정론적 게이트를 통해 시스템의 안전성을 확보하는 방법론을 다룹니다.
핵심 포인트
- 임시 저장함(Drafts)을 활용해 모델의 오류가 고객에게 직접 전달되는 것을 방지
- 단순 질문은 자동 처리하고, 민감한 이슈는 사람의 승인을 거치는 하이브리드 방식
- 웹훅과 API 호출을 통해 초안 생성, 검토, 승인/거절의 워크플로우 구현 가능
- 확률론적 AI 시스템의 불확실성을 결정론적 게이트로 완화
이메일 에이전트를 위한 가장 효과적인 안전 제어 장치는 더 나은 모델이나 더 긴 시스템 프롬프트(System Prompt), 혹은 더 엄격한 평가 스위트(Eval Suite)가 아닙니다. 그것은 바로 임시 저장함(Draft folder)입니다.
설정은 다음과 같습니다. 현재 베타 버전인 Nylas Agent Accounts는 애플리케이션이 생성하고 API를 통해 완전히 제어하는 호스팅된 메일함입니다. 각 계정은 기존의 Messages, Drafts, Threads, Folders 엔드포인트에서 작동하는 grant_id를 가진 실제 주소이며, 각 메일함에는 inbox, sent, drafts, trash, junk, archive라는 6개의 시스템 폴더가 포함되어 있습니다. 그중 drafts 폴더가 바로 여러분의 승인 워크플로우(Approval workflow)가 존재하는 곳입니다.
완전한 자율성은 기본값이 아닌 선택입니다
지원 메일함의 일반적인 패턴은 다음과 같습니다: LLM이 일반적인 질문에 대한 답장 초안을 작성하면, 인간이 웹훅(Webhook) 흐름을 통해 민감한 답변을 승인하는 방식입니다. 에이전트는 비밀번호 재설정 안내, 배송 상태, "송장이 어디 있나요"와 같은 지루한 80%의 업무를 스스로 처리하며, 환불, 법적 문구 또는 화난 고객과 관련된 모든 사항은 먼저 사람을 거치게 됩니다.
여러분이 완화하고자 하는 위협은 일상적입니다: 바로 자신 있게 틀린 답을 내놓는 모델입니다. 환각(Hallucination)으로 인한 할인 적용, 잘못된 스레드에 대한 답장, 불만 사항에 대한 부적절한 어조의 응답 등입니다. 이것들은 이례적인 공격이 아닙니다. 확률론적 시스템(Probabilistic system)을 외부 발신 채널에 배치했을 때 발생하는 일상적인 실패 모드들이며, 이에 대한 완화책은 "모델이 무언가를 작성했다"와 "고객이 그것을 받았다" 사이에 결정론적 게이트(Deterministic gate)를 두는 것입니다.
게이트는 세 번의 API 호출로 이루어집니다
흐름은 다음과 같습니다: 메일이 도착하면 message.created 웹훅이 실행되고, 여러분의 분류기(Classifier)가 위험 수준을 결정하며, 위험도가 높은 답장은 발송되는 대신 초안(Drafts)이 됩니다. 초안은 /v3/grants/{grant_id}/drafts에서 완전한 CRUD를 지원하므로, 에이전트는 다음과 같이 초안을 생성합니다:
curl --request POST \
--url "https://api.us.nylas.com/v3/grants/$GRANT_ID/drafts" \
--header "Authorization: Bearer $NYLAS_API_KEY" \
...
아직 메일함에서 아무것도 발송되지 않습니다. 초안(draft)은 사용자의 승인 UI(또는 Slack 버튼, 혹은 일일 검토 큐)가 승인할 때까지 에이전트의 초안 폴더에 머물러 있습니다. 승인은 초안 자체에 대한 단일 POST 요청으로 이루어집니다. 기존 초안을 전송하는 것은 POST /messages/send와 정확히 동일하게 동작합니다:
curl --request POST \
--url "https://api.us.nylas.com/v3/grants/$GRANT_ID/drafts/$DRAFT_ID" \
--header "Authorization: Bearer $NYLAS_API_KEY"
거절(Rejection) 과정도 매우 깔끔합니다. 초안을 수정하여 업데이트하거나 삭제하면 됩니다. 초안 생성 시점에 reply_to_message_id가 설정되었기 때문에, 승인된 답장은 추가 작업 없이도 수신자의 클라이언트에서 올바르게 스레드(thread)로 묶입니다.
검토자는 관리자 패널이 아닌 Outlook에서 작업할 수 있습니다
이 패턴을 실무에서 더욱 유용하게 만드는 세부 사항이 하나 있습니다. 에이전트 계정(Agent Account) 권한(grant)은 IMAP 및 SMTP 액세스를 위한 app_password를 포함할 수 있습니다. 이는 검토자가 Outlook이나 Apple Mail을 에이전트의 메일함에 직접 연결하여 일반 메일 클라이언트에서 대기 중인 초안을 읽을 수 있음을 의미합니다. 즉, v1 단계에서는 별도의 커스텀 검토 대시보드가 필요하지 않습니다. mailboxes 가이드에서는 API 트래픽과 메일 클라이언트 트래픽이 어떻게 동일한 기본 메일함을 공유하는지 설명합니다. API를 통해 전송된 모든 것은 클라이언트의 보낸 편지함에 나타나며, 그 반대도 마찬가지입니다.
자율성의 경계 설정하기
이것을 이분법적으로 나누지 마세요. 유용한 구분 방식은 다음과 같습니다:
- 자동 발송 (Auto-send): 분류기(classifier)가 저위험군으로 표시하고, 알려진 템플릿 제품군과 일치하는 답장. 이들은
/messages/send를 통해 즉시 발송됩니다. - 초안 작성 후 승인 (Draft-and-approve): 돈, 계정 변경, 또는 에스컬레이션(escalation) 관련 용어가 언급된 모든 경우. 모델의 확신도(confidence)가 낮은 모든 경우. 귀하가 고가치(high-value)로 플래그를 지정한 도메인으로 발송되는 모든 경우.
- 인간 전용 (Human-only): 법적 위협, 언론 문의, 또는 에이전트가 초안조차 작성해서는 안 되는 모든 경우.
agent security guide에서 제시된 범위 설정 원칙 (scoping principle)이 직접적으로 적용됩니다. 검토를 위해 답장 초안을 작성하는 에이전트는 초안을 생성할 수 있는 권한만 있으면 되며, 실제 전송은 사람이 수행합니다. 프롬프트가 제대로 작동할 것이라고 믿기보다는, 에이전트의 자체 코드 경로 (code paths)에서 해당 경계를 강제할 수 있습니다.
인간 측의 규모도 솔직하게 산정해야 합니다. 무료 플랜의 경우 전송 한도는 계정당 하루 200개 메시지입니다. 이는 많아 보일 수 있지만, 검토자가 그 양의 4분의 1만 승인하더라도 매일 50건의 검토를 수행해야 한다는 점을 고려하면 이야기가 달라집니다. 만약 대기열 (queue)이 사람이 처리할 수 있는 수준을 넘어선다면, 이는 더 빠르게 형식적으로 승인 (rubber-stamp)할 것이 아니라 분류기 (classifier)를 강화해야 한다는 신호입니다. 즉, 더 많은 템플릿 제품군 (template families)을 자동 전송 (auto-send)으로 격상시켜야 합니다.
안전장치로서의 아웃바운드 규칙 (outbound rule) 추가
초안 게이트 (draft gate)는 애플리케이션 코드에 존재하므로, 애플리케이션 코드의 버그가 이를 우회할 수 있음을 의미합니다. /messages/send를 직접 호출하는 잘못된 코드 경로가 발생하면 대기열을 완전히 건너뛰게 되며, 모델은 그 차이를 전혀 알지 못합니다. 여기서 심층 방어 (Defense in depth) 전략은 아웃바운드 규칙 (outbound rule)을 사용하는 것입니다. 이는 어떤 코드 경로에서 요청했는지와 관계없이, Nylas가 이메일 제공업체에 전송되기 전에 서버 측에서 수행하는 검사입니다.
curl --request POST \
--url "https://api.us.nylas.com/v3/rules" \
--header "Authorization: Bearer $NYLAS_API_KEY" \
...
rule_ids 배열을 통해 에이전트의 워크스페이스 (workspace)에 규칙을 연결하면, 해당 워크스페이스의 모든 에이전트 계정 (Agent Account)이 이를 상속받습니다. 차단된 전송은 호출자에게 403을 반환하며 전송된 사본이 저장되지 않습니다. 즉, 수신자 입장에서는 해당 메시지가 존재하지 않았던 것과 같습니다. recipient.domain 조건은 BCC 및 SMTP envelope 수신자를 포함한 모든 수신자와 일치하므로, 프롬프트 인젝션 (prompt-injected)을 통한 "이 주소로도 BCC를 보내줘"와 같은 시도도 통과할 수 없습니다. 또한 모든 평가는 로그로 기록됩니다. GET /v3/grants/{grant_id}/rule-evaluations를 통해 어떤 규칙이 어느 단계에서 일치했는지, 어떤 조치가 적용되었는지 확인할 수 있습니다. 이는 새벽 2시에 왜 전송이 실패했는지 누군가 물었을 때 정확히 필요로 하는 정보입니다.
또한 outbound.type에 따라 규칙을 나눌 수 있습니다. 전송 시 reply_to_message_id (또는 In-Reply-To/References 헤더)를 포함하면 reply가 되고, 완전히 새로운 메시지인 경우 compose가 됩니다. 합리적인 태도는 다음과 같습니다: 승인된 답장(reply)은 그대로 흐르게 두되, 에이전트가 생성하는 모든 compose는 의심스러운 것으로 간주하는 것입니다. 답장 루프(reply loop)에 있는 에이전트가 새로운 대화를 시작해서는 안 되기 때문입니다.
승인 후 루프 닫기 (Close the loop after approval)
승인이 메시지 생명 주기의 끝은 아닙니다. 검토자가 초안을 전송한 후, Nylas는 세 가지 웹훅 트리거(webhook triggers)를 통해 실제 전송 과정에서 어떤 일이 일어났는지 보고합니다: 수신자 서버가 메시지를 수락하면 message.send_success, 수신자에게 도달하기 전에 전송이 중단되면 message.send_failed, 그리고 하드 바운스(hard bounce) 및 소프트 바운스(soft bounce)의 경우 message.bounce_detected가 발생합니다. 이를 동일한 승인 UI에 연결하십시오. 답장을 승인했으나 이후 바운스(bounce)가 발생한 경우, 검토자는 이를 확인해야 합니다. 왜냐하면 적절한 다음 조치(주소 수정, 사람 채널로 에스컬레이션) 또한 검토 결정의 일부이기 때문입니다.
미리 처리해 두어야 할 페이로드(payload) 세부 사항이 하나 있습니다: 만약 수신된 메시지 본문이 약 1MB를 초과하면, 웹훅은 본문이 생략된 message.created.truncated 형태로 도착합니다. 분류기(classifier)는 해당 케이스를 감지하고, 위험 수준을 결정하기 전에 GET /messages/{id}를 통해 전체 메시지를 가져와야 합니다. 잘린(truncated) 페이로드를 분류한다는 것은 제목(subject line)만으로 분류한다는 것을 의미하기 때문입니다.
대비해야 할 실패 모드 (Failure modes to plan for)
이 시스템을 구축하는 팀들이 겪는 두 가지 문제가 있습니다:
- 오래된 초안 (Stale drafts). 월요일에 작성되어 목요일에 승인된 초안은 고객이 이미 다시 질문한 내용에 대한 답변일 수 있습니다. 전송하기 전에 스레드(thread)를 다시 가져오고, 새로운 메시지가 도착했다면 해당 초안을 무효화하십시오.
- 중복 승인 (Double approval). 두 명의 검토자가 동일한 큐(queue)에서 작업할 수 있는 경우, 전송 POST 요청은 귀하의 측에서 멱등성(idempotent)을 유지해야 합니다. 이미 전송한 초안 ID를 추적하고, 두 번째 승인은 아무 작업도 수행하지 않는(no-op) 것으로 처리하십시오.
퀵스타트 (quickstart)를 이용하면 API 키에서 작동하는 메일함까지 5분 이내에 구축할 수 있으며, 초안 (drafts) 엔드포인트는 생성한 모든 계정에서 즉시 작동합니다. 모든 프로세스를 초안 게이트 (draft gate)를 통해 라우팅하는 것으로 시작하여, 사람이 모델의 출력물을 실제로 얼마나 자주 수정하는지 측정하고, 그 결과에 따라 점진적으로 제한을 완화하십시오.
여러분의 수정률 (edit rate)은 어느 정도인가요? 만약 검토자들이 초안의 95%를 수정 없이 승인한다면, 어떤 카테고리가 자동화하기에 안전하다고 판단했는지 댓글로 알려주시면 감사하겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기