고객이 답변 처리 수준을 결정하며, 다운그레이드는 스스로 레벨을 한 단계 낮춘다
요약
Nakodo는 크리에이터를 대신해 브랜드에 이메일을 보내고, 답변 처리 수준을 캠페인별로 설정할 수 있게 합니다. 'introduce', 'answer', 'negotiate' 세 가지 레벨 중 필요한 만큼만 작동하여 효율성을 높입니다. 특히 고객이 다운그레이드해도 캠페인 로직이 안전하게 유지되도록 설계한 것이 핵심입니다.
핵심 포인트
- 답변 처리 수준(Reply Level)을 캠페인별로 설정 가능합니다.
- introduce, answer, negotiate 세 가지 레벨로 기능 범위가 나뉩니다.
- 다운그레이드 시에도 기존 캠페인 로직이 안전하게 유지됩니다.
- 레벨 결정은 읽힐 때마다 이루어져 데이터베이스에 저장된 값만 반영합니다.
Nakodo는 크리에이터를 대신하여 브랜드에게 이메일을 보내고, '예'라고 답하는 사람들에게 브랜드를 소개합니다. 브랜드는 주소를 절대 볼 수 없기 때문에 모든 회신은 먼저 저희에게 도착하며, 흥미로운 제품 질문은 우리가 어떤 추가 질문 없이 그 답변 중 얼마나 많은 부분을 처리할 수 있느냐입니다.
만능의 정답은 없습니다. 첫 캠페인을 진행하는 브랜드는 모든 것을 읽고 싶어 합니다. 다섯 번째 캠페인을 진행하는 브랜드는 '예'라는 답만 보고 다른 것은 보고 싶지 않아 합니다. 따라서 이 양(amount)은 캠페인별 설정이며, 전체 내용은 34줄에 걸쳐 있습니다:
export const REPLY_LEVELS = ["introduce", "answer", "negotiate"] as const;
export type ReplyLevel = (typeof REPLY_LEVELS)[number];
export const DEFAULT_REPLY_LEVEL: ReplyLevel = "answer";
...
introduce는 진행하고 싶어 하거나 작동 방식에 대해 질문하는 모든 사람에게 캠페인 세부 정보를 첨부하여 소개하며, 브랜드가 그 다음을 처리합니다. answer는 또한 브랜드가 승인한 제안서 외의 질문에도 답변합니다. negotiate는 브랜드가 설정한 한도 내에서 수수료까지 합의합니다. 이 세 가지의 공개적인 문구와 수수료 관련 내용은 작동 방식에 있으며, 수수료 관련 내용은 Business plan 항목에 있습니다.
레벨을 한 단계 낮출 수 있는 두 가지 경우
비즈니스 캠페인은 합의해야 할 크리에이터 수수료가 없으므로, 협상(negotiating)은 무의미합니다. 그리고 수수료를 합의하는 것은 별도의 플랜에 속하므로 Pro 고객이 이 기능을 사용할 수 없습니다. 이 두 가지 모두는 선택이 이루어진 후에도 발생할 수 있습니다: 캠페인의 종류는 고정되지만, 플랜은 그렇지 않습니다. 따라서 Pro로 이동한 Business 고객도 여전히 캠페인 설정에 replies: "negotiate"가 남아있습니다.
명백한 해결책은 다운그레이드하는 동안 해당 열(column)을 다시 작성하는 것입니다. 하지만 저희는 그렇게 하지 않았는데, 왜냐하면 플랜을 낮출 수 있는 모든 경로(path)가 이를 기억해야 하기 때문입니다: Stripe 웹훅(webhook), 기간 종료 시 취소, 결제 실패, 컴포넌트 제거, 관리자 패널에서의 수동 변경 등. 이 중 하나라도 누락되면 캠페인은 해당 플랜에 포함되지 않는 상태에서도 계속 협상하게 되는데, 이것이 여기에서 타인의 돈을 쓰게 만드는 유일한 오류 모드입니다.
대신 레벨은 읽힐 때마다 결정되며, 저장된 값은 오직 고객이 선택한 것만을 반영합니다:
export const levelsFor = (kind: CampaignKind): ReplyLevel[] =>
kind === "creators" ? [...REPLY_LEVELS] : ["introduce", "answer"];
...
여기서 두 가지 속성이 파생됩니다. 다운그레이드는 어떤 캠페인 행도 건드리지 않고 안전하며, 업그레이드는 선택 사항이 덮어쓰여진 적이 없기 때문에 이전 동작을 아무것도 건드리지 않고 복원합니다. 또한 ?? DEFAULT_REPLY_LEVEL은 설정(setting)이 존재하기 이전에 생성된 캠페인 전체 마이그레이션입니다: replies는 설정 JSON 컬럼 내부의 선택적 필드 중 하나이며, 이것이 없는 캠페인은 중간 레벨로 읽히는데, 이는 선택지가 존재하기 전 캠페인이 작동하던 방식과 정확히 일치합니다.
테스트는 데이터베이스 없이 네 가지 단언문(assertion)으로 구성되어 있습니다:
assert.equal(replyLevel(settings("negotiate"), "creators", { negotiation: true }), "negotiate");
assert.equal(replyLevel(settings("negotiate"), "creators", { negotiation: false }), "answer");
assert.equal(replyLevel(settings("negotiate"), "businesses", { negotiation: true }), "answer");
...
레벨은 두 개의 분기점만 건드립니다
답변은 모델에 의해 의도(intent), 신뢰도(confidence) 및 추출된 필드와 함께 분류되어 읽히고, 그 후 순수 함수(pure function)가 무슨 일이 일어날지 결정합니다. 이 함수는 의도에 대한 스위치이며, 레벨과 관련되는 것은 단 두 개의 팔(arm)뿐입니다:
switch (c.intent) {
case "opt_out":
// 잘못되었을 때 비용이 적게 들고; '중지'라고 말한 사람에게 메일을 보내는 것은 큰 비용이 듭니다.
...
모든 팔은 동일한 탈출구(escape hatch)를 가지고 있습니다. ask()는 { type: "needs_you" }를 생성하여 대화를 브랜드 앞으로 가져가고 한 줄의 질문을 던집니다. 충분히 확신하지 못하면 레벨이 없으며, 답변의 경우: 모든 것이 같은 곳으로 끝납니다. 그리고 브랜드는 어차피 보게 될 스레드를 봅니다. 조용히 아무것도 하지 않는 분기는 없습니다.
여기에는 자체적인 한 줄을 가질 만한 세 가지 세부 사항이 있습니다.
신뢰도 임계값(confidence thresholds)은 단일한 상수가 아닙니다. 0.4의 판독 결과로 누군가를 제외하는 것은 틀렸을 때 값싸지만, 그 비용은 이 브랜드를 다시는 듣지 못하게 되는 한 명의 창작자입니다. 0.4 판독 결과에 거절하거나 도입하는 것은 값이 싸지 않기 때문에, 사람들은 0.7을 원하고 브랜드 이름으로 답변하는 것은 0.75를 원합니다. 그 숫자는 분류가 얼마나 어려운지가 아니라 실수가 비용이 얼마인지에 의해 설정됩니다.
MAX_AI_ANSWERS는 3입니다. 한 스레드에서 자체적으로 세 번의 답변을 한 후, 다음 답장은 브랜드가 무엇을 하든 간에 브랜드에게 전달됩니다. 네 번째 답변이 필요한 대화는 잘 진행되고 있는 대화가 아닙니다.
그리고 제가 나머지를 삭제해야 한다면 유지할 하나의 규칙은 onItsOwn입니다:
// brandWrote: 브랜드가 이 대화에서 직접 작성했으므로,
// 처리하고 있으며 Nakodo는 더 이상 자체적으로 답변하지 않습니다.
const onItsOwn = !opts.brandWrote;
브랜드의 주소는 서론에 복사되어 있으며, 어떤 것도 브랜드가 스레드 초기에 답장하는 것을 막지 못합니다. 그들이 하는 순간, 두 명의 발신자가 다른 한 창작자에게 무엇이 방금 약속되었는지 전혀 모른 채 글을 쓰게 됩니다. 따라서 브랜드가 스레드에서 단 하나의 메시지를 보내면, 모든 자동 답변은 모든 레벨에서 영구적으로 꺼집니다. 이것은 설정이 아니며 다시 켤 방법도 없습니다.
전혀 레벨에 관계없이 무시하는 또 다른 기능이 있습니다:
// 헤더가 기계가 작성했음을 나타냄: 답장하지 않음, 어떤 텍스트를 담고 있든 간에.
if (opts.automated && c.intent !== "bounce") return { type: "snooze", returnDate: c.returnDate };
부재중 자동 응답(out of office)은 종종 따뜻하고, 상세하며, 열정적으로 보이는 텍스트 조각입니다. 이 결정은 텍스트가 투표를 받기 전에 헤더에서 내려집니다.
본 포스트에 포함되지 않은 내용
분류기(classifier)의 지침, 의도 목록(intent list)의 정확한 의미론(semantics), 그리고 적합성 점수(fit scoring)는 공개되지 않으며, 레벨은 절대로 모델에게 자유 텍스트 지침으로 도달하지 않습니다. 대신 사용되는 지침 블록을 선택하며, 위의 코드가 결과에 어떤 일이 일어날지 결정합니다. 모델이 읽고 초안을 작성하고, 스위치가 결정하며, 협상(negotiate) 레벨의 한계는 프롬프트에 전혀 나타나지 않습니다. 이 마지막 부분은 별도의 게시물이 필요합니다.
이 코드가 지키기 위해 존재하는 약속들을 보고 싶다면, 그것들은 공개적입니다. 작동 방식에서 서술된 세 가지 레벨, 약관에 있는
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기