客服
把客服工单分流成有依据的回复草稿
先脱敏工单,用 Chat 判断意图和优先级,从文档里检索能回答的段落,检查是否有公开事故讨论,再留下一份带路由的回复草稿给人工审批。
复制 prompt
把方括号里的字段替换掉,然后粘贴到 Claude Code、Codex 或任何能访问终端的 AI。它会安装 Felo skill、在花额度前询问,并执行这套 workflow。
对这个支持工单做分诊,并写一份供人工审阅的回复草稿:[粘贴工单,先删除姓名、邮箱、账号 ID、支付数据和其他可识别信息]。 产品领域:[产品]。套餐或地区:[仅在回答需要时]。文档来源:[帮助中心 URL 或 LiveDoc short_id]。 审批路径:[谁审阅]。升级队列:[团队或渠道]。 输出: 1. 意图:一个类别,加一句理由。 2. 优先级:紧急 / 普通 / 低,附适用规则。 3. 依据:能回答工单的文档段落,附标题和相关度。 4. 故障检查:公开报告是否暗示大范围故障。附链接和日期,或写“无公开信号”。 5. 路由:起草回复、向客户补充信息,或升级——并说明原因。 6. 回复草稿:两到四句,只基于证据,并点名所依据的来源。 规则: - 不要把姓名、邮箱、订单号、令牌或支付数据放进 API 调用或输出。只处理已脱敏的工单。 - 只根据检索到的文档回答。没有依据时升级,不要猜测。 - 不要承诺退款、折扣、时限或账户变更;这些转给升级流程。 - 公开故障传闻是信号,不是证据。引用帖子和日期。 - 消耗额度前,先展示计划执行的调用并等待我批准。 - 不要发送回复、更新工单或操作账户。把草稿返回给我审阅。 - 将结果写入 ./support-triage.md,并在对话中总结。
复制的内容也包含安装步骤和安全规则。
你会得到什么
一次运行的示例输出,不是实时生成。
分诊 — 示例工单
意图
账单 / 续费问题。客户询问为什么方案又续费了。
优先级
普通。这是账单问题,不是故障,客户没有被阻塞。
依据
- “账单常见问题” — 续费时间和扣款失败重试。相关度:高。
- “方案变更” — 续费之间的降级。相关度:中。
故障检查
过去 48 小时没有公开报告。
路由
起草回复。文档覆盖了这个问题。
回复草稿
你好——你的方案在每月 1 日续费,银行卡扣款失败后会重试三天,然后席位暂停。你可以在账单设置中更换银行卡;账单常见问题 有分步说明。如果需要更改续费日期,请回复,我们会升级给账单团队。
审核备注
批准、编辑,或升级到账单队列。
实际调用
给开发者:同一套 workflow 的可复制代码,按执行顺序排列。
展开实际 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 检索出的段落。没有命中时 workflow 会升级,而不是猜。
它会直接回复或关闭工单吗?
不会。它只生成草稿和路由,发送和关闭必须由人工或你的系统完成。
优先级怎么定?
由你定义的规则决定;模型给出建议和理由,最终优先级由路由规则确认。
文档没有覆盖时怎么办?
升级到人工队列,并在分流包里注明“未覆盖”。
一次分流要花多少?
Chat、检索和 X 搜索按用量计费;当前费率在价格页面,prompt 会先请求确认。
相关 workflow
改成你的版本
同一套配方,按你实际的交付方式调整。
只做分类
不生成回复,只输出意图、优先级和建议队列。
接入工单系统
通过你自己的 webhook 把分流包写进工单,不自动发送。
升级为知识库回答
文档命中时,交给客服知识库 workflow 生成更完整的回答。
继续深入
这套配方背后的参考页面,以及下一步可以看什么。