지원
지원 티켓을 근거 있는 답변 초안으로 분류하기
티켓을 마스킹하고 Chat으로 의도와 우선순위를 판단하며 문서에서 답변 구절을 검색하고 공개 인시던트 논의를 확인한 뒤 사람이 승인할 라우팅 포함 답변 초안을 남깁니다.
프롬프트 복사
대괄호 항목을 바꾼 뒤 Claude Code, Codex 또는 터미널에 접근할 수 있는 AI에 붙여넣으세요. Felo 스킬을 설치하고 크레딧을 쓰기 전에 확인한 뒤 워크플로를 실행합니다.
이 지원 티켓을 분류하고 사람이 검토할 답변 초안을 작성해 주세요: [이름, 이메일, 계정 ID, 결제 데이터, 기타 식별 정보를 제거한 티켓을 붙여넣기]. 제품 영역: [제품]. 플랜 또는 지역: [답변에 필요할 때만]. 문서 소스: [헬프 센터 URL 또는 LiveDoc short_id]. 승인 경로: [누가 검토하는가]. 에스컬레이션 큐: [팀 또는 채널]. 다음을 작성해 주세요. 1. 의도: 한 카테고리와 한 문장 근거. 2. 우선순위: 긴급 / 보통 / 낮음. 적용한 규칙 포함. 3. 근거: 티켓에 답하는 문서 구절, 제목과 관련도 포함. 4. 장애 확인: 공개 보고가 광범위한 장애를 시사하는지. 링크와 날짜, 또는 "공개 신호 없음". 5. 라우팅: 초안 작성, 고객에게 추가 정보 요청, 에스컬레이션 중 무엇인지와 이유. 6. 답변 초안: 두세 문장, 근거만 사용하고 의존한 출처를 명시. 규칙: - 이름, 이메일, 주문 번호, 토큰, 결제 데이터를 API 호출이나 출력에 넣지 마세요. 마스킹된 티켓만 다루세요. - 검색된 문서만 근거로 답하세요. 근거가 없으면 에스컬레이션하고 추측하지 마세요. - 환불, 할인, 기한, 계정 변경을 약속하지 마세요. 그런 것은 에스컬레이션으로 보내세요. - 공개 장애 소문은 신호이지 증거가 아닙니다. 게시물과 날짜를 인용하세요. - 크레딧을 쓰기 전에 실행할 호출을 보여 주고 제 승인을 기다려 주세요. - 답변 전송, 티켓 업데이트, 계정 작업을 하지 마세요. 초안을 검토용으로 반환하세요. - 결과를 ./support-triage.md에 쓰고 채팅에서 요약해 주세요.
복사 내용에는 설치 단계와 안전 규칙도 포함됩니다.
완성되는 것
실행 시 예제 출력입니다. 실시간 생성이 아닙니다.
트리아지 — 예시 티켓
의도
결제 / 갱신 질문. 고객이 왜 플랜이 다시 갱신됐는지 묻는다.
우선순위
보통. 결제 질문이며 장애가 아니고 고객이 막히지 않았다.
증거
- “결제 자주 묻는 질문” — 갱신 시점과 카드 실패 재시도. 관련도: 높음.
- “플랜 변경” — 갱신 사이 다운그레이드. 관련도: 중간.
장애 확인
지난 48시간 공개 보고 없음.
라우트
초안. 문서가 질문을 다룬다.
답변 초안
안녕하세요. 플랜은 매월 1일에 갱신되며, 카드 결제가 실패하면 3일 동안 재시도한 뒤 시트가 일시 중지됩니다. 결제 설정에서 카드를 바꿀 수 있고, 결제 자주 묻는 질문에 단계별 안내가 있습니다. 갱신일을 옮겨야 하면 회신해 주세요. 결제 팀으로 에스컬레이션하겠습니다.
검토자 메모
승인, 편집, 또는 결제 큐로 에스컬레이션.
실제 호출
개발자용: 같은 워크플로를 실행 순서대로 담은 복사 가능한 코드.
실제 API 호출 보기
마스킹 후 분류하기
코드로 이메일, 전화, 주문 번호 등 PII를 제거하고 Chat으로 의도와 우선순위를 판단합니다.
triage.ts const BASE = "https://openapi.felo.ai"; const headers = { Authorization: `Bearer ${process.env.FELO_API_KEY}`, "Content-Type": "application/json", }; async function felo<T>(path: string, body?: unknown): Promise<T> { const res = await fetch(`${BASE}${path}`, { method: body ? "POST" : "GET", headers, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); return res.json() as Promise<T>; } const redact = (text: string) => text .replace(/[\w.+-]+@[\w.-]+\.\w+/g, "[email]") .replace(/\b(?:acct|account|order|invoice)[-_ ]?\w+\b/gi, "[id]") .replace(/\b(?:\d[ -]?){13,19}\b/g, "[card]"); type Ticket = { id: string; product: string; subject: string; body: string; plan?: string; sensitive?: boolean; }; const ticket: Ticket = { id: "T-1042", product: "Acme Workspace", subject: "Why did my plan renew?", body: "I was charged again and cannot find the renewal date on my account.", plan: "team", }; const summary = redact(`${ticket.subject}\n\n${ticket.body}`).slice(0, 1500); type ChatData = { data: { answer: string; resources: { link: string; title: string; snippet: string }[]; }; }; const triage = await felo<ChatData>("/v2/chat", { query: `Classify this support question by intent and priority, and list what is missing:\n\n${summary}`, }); console.log(triage.data.answer);예제 출력
{ "answer": "Intent: billing / renewal question. Priority: normal. Missing: the renewal date the customer expects.", "resources": [ { "link": "https://example.com/billing-faq", "title": "Billing FAQ", "snippet": "…" } ] }문서 증거 검색하기
지원 지식 베이스 LiveDoc에서 관련 구절을 검색하고 제목과 점수를 남깁니다.
triage.ts type Hit = { title: string; content: string; score: number }; const KB = process.env.SUPPORT_LIVEDOC_ID!; // the help-center LiveDoc short_id const retrieved = await felo<{ data: Hit[] }>( `/v2/livedocs/${KB}/resources/retrieve`, { query: summary }, ); const hits = retrieved.data.filter((hit) => hit.score >= 0.7).slice(0, 4); if (hits.length === 0) { console.log("No grounded evidence: escalate instead of drafting"); }예제 출력
[ { "title": "Billing FAQ", "content": "Your plan renews on the first of the month; a failed card retries for three days…", "score": 0.91 } ]공개 인시던트 확인하기
X에서 제품명과 “장애/다운” 같은 단어를 검색하고 48시간으로 제한해 공개 신호로만 씁니다.
triage.ts type XData = { data: { tweets: { content: string; author: { username: string }; created_at: string; url: string; }[]; }; }; const since = Math.floor((Date.now() - 48 * 60 * 60 * 1000) / 1000); const incident = await felo<XData>("/v2/x/tweet/search", { query: `"${ticket.product}" (outage OR "not working" OR error)`, limit: 20, since_time: since, }); const reports = incident.data.tweets.map((post) => ({ text: post.content, handle: post.author.username, at: post.created_at.slice(0, 10), link: post.url, }));예제 출력
[ { "text": "Workspace login is failing for my whole team.", "handle": "example_user", "at": "2026-10-30", "link": "https://x.com/example_user/status/..." } ]라우팅 정하고 답변 조립하기
규칙으로 큐를 정하고 증거, 다음 단계, 답변 초안을 묶습니다.
triage.ts type Route = "draft" | "ask-customer" | "escalate"; function decideRoute(): { route: Route; reason: string } { if (hits.length === 0) { return { route: "escalate", reason: "no grounded evidence in the knowledge base" }; } if (ticket.sensitive) { return { route: "escalate", reason: "an account or billing action is requested" }; } if (reports.length >= 3) { return { route: "escalate", reason: "public reports suggest a wider issue" }; } if (!ticket.plan) { return { route: "ask-customer", reason: "the plan is needed to answer the question" }; } return { route: "draft", reason: "the documentation covers the question" }; } const decision = decideRoute(); const packet = [ `# Triage — ${ticket.id}`, "", `Route: ${decision.route} (${decision.reason})`, "", "## Intent and priority", triage.data.answer, "", "## Evidence", ...hits.map((hit) => `- ${hit.title} (score ${hit.score})`), "", "## Public signal", ...(reports.length ? reports.map((report) => `- @${report.handle} (${report.at}): ${report.text} — ${report.link}`) : ["No public reports in the last 48 hours."]), "", "## Reply draft", "[Written by the host Agent from the evidence above — human review required]", ].join("\n"); console.log(packet);예제 출력
# Triage — T-1042 Route: draft (the documentation covers the question) ## Intent and priority Intent: billing / renewal question. Priority: normal. ## Evidence - Billing FAQ (score 0.91)
트리아지 기록하기
트리아지 결과를 LiveDoc에 써 회고와 감사에 씁니다.
triage.ts type LiveDocData = { data: { short_id: string } }; const log = await felo<LiveDocData>("/v2/livedocs", { name: "Support triage log", description: "One document resource per triaged ticket", }); await felo(`/v2/livedocs/${log.data.short_id}/resources/doc`, { title: `Triage — ${ticket.id}`, content: packet, }); console.log(log.data.short_id); // reuse it for the next ticket예제 출력
{ "short_id": "PvyKouzJirXjFdst4uKRK3" }
포함되는 것
- 마스킹 후 의도와 우선순위 분류
- 점수가 있는 문서 증거
- 공개 인시던트 확인
- 라우팅 포함 답변 초안
- 트리아지 기록 LiveDoc
하지 않는 것
- 답변 전송, 티켓 종료, 계정 작업은 하지 않음
- 비밀번호, 결제 정보, 전체 고객 데이터를 API로 보내지 않음
- 문서 히트가 없으면 반드시 에스컬레이션
- X는 공개 인시던트 신호이며 지원 시스템 상태가 아님
- 우선순위 규칙은 직접 정의하고 모델은 제안만
자주 묻는 질문
어떤 티켓 데이터를 보낼 수 있나요?
마스킹한 제품, 문제 설명, 플랜, 지역 등 필요한 맥락만 보냅니다. 비밀번호, 결제 정보, 전체 주소, 사적 대화는 보내지 마세요.
답변은 어디서 오나요?
문서 LiveDoc에서 검색한 구절에서 옵니다. 히트가 없으면 워크플로는 추측하지 않고 에스컬레이션합니다.
직접 답변하거나 종료하나요?
아니요. 초안과 라우팅만 만듭니다. 전송과 종료는 사람이나 자체 시스템이 합니다.
우선순위는 어떻게 정하나요?
직접 정의한 규칙으로 정합니다. 모델은 제안과 이유를 내고 최종 우선순위는 라우팅 규칙이 확인합니다.
문서에 없으면?
사람 큐로 에스컬레이션하고 트리아지 패키지에 “미커버”로 기록합니다.
한 번 비용은?
Chat, 검색, X 검색은 사용량 기반 크레딧입니다. 현재 요금은 가격 페이지에 있고 프롬프트는 쓰기 전에 승인을 요청합니다.
관련 워크플로
자신의 문서로 지원 질문에 답하기
LiveDoc을 만들고 헬프 센터와 내부 runbook을 읽어 들인 뒤 티켓에 답할 구절을 검색하고 그 증거만으로 모델이 답하게 합니다.
워크플로 열기콘텐츠소셜 대화를 주간 리스닝 브리프로 바꾸기
지난주 브랜드와 경쟁사 관련 X 게시물을 검색하고 출처 있는 웹 맥락을 더하고 배경 페이지를 읽은 뒤 매호를 아카이브해 다음 주는 아는 것에서 시작합니다.
워크플로 열기리서치질문 하나를 출처 있는 리서치 브리프로 바꾸기
웹에 질문을 던지고, 답변의 근거 페이지를 Markdown으로 가져오고, X의 실무자 의견을 더한 뒤 증거를 나중에도 검색할 수 있는 LiveDoc에 남깁니다.
워크플로 열기내 방식으로 바꾸기
같은 레시피를 실제 배포 방식에 맞게 조정합니다.
분류만 하기
답변 없이 의도, 우선순위, 권장 큐만 출력합니다.
티켓 시스템에 연결하기
자체 webhook으로 트리아지 패키지를 티켓에 쓰고 자동 전송은 하지 않습니다.
지식 베이스 답변으로 승격하기
문서 히트가 있으면 지원 지식 베이스 워크플로로 더 완전한 답변을 만듭니다.
더 알아보기
이 레시피의 배경이 되는 참고 페이지와 다음에 볼 곳.